-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support additional API on Python 3 bindings #2016
Changes from all commits
40dcb07
37ce0e7
d032dd1
07cdb57
c012827
c4c595a
30e7d0b
8ba1364
9bb6408
038b92d
0c34496
e21dfef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
""" | ||
# @author elicn | ||
|
||
from typing import Any, Callable, Sequence, Tuple | ||
from typing import Any, Callable, Tuple, Type | ||
|
||
import ctypes | ||
|
||
|
@@ -64,6 +64,8 @@ class UcIntel(Uc): | |
"""Unicorn subclass for Intel architecture. | ||
""" | ||
|
||
REG_RANGE_MSR = (const.UC_X86_REG_MSR,) | ||
|
||
REG_RANGE_MMR = ( | ||
const.UC_X86_REG_IDTR, | ||
const.UC_X86_REG_GDTR, | ||
|
@@ -127,67 +129,42 @@ def __hook_insn_cpuid_cb(uc: Uc, key: int) -> int: | |
|
||
return getattr(self, '_Uc__do_hook_add')(htype, fptr, begin, end, insn) | ||
|
||
@staticmethod | ||
def __select_reg_class(reg_id: int): | ||
"""Select class for special architectural registers. | ||
@classmethod | ||
def _select_reg_class(cls, reg_id: int) -> Type: | ||
"""Select the appropriate class for the specified architectural register. | ||
""" | ||
|
||
reg_class = ( | ||
(UcIntel.REG_RANGE_MSR, UcRegMSR), | ||
(UcIntel.REG_RANGE_MMR, UcRegMMR), | ||
(UcIntel.REG_RANGE_FP, UcRegFPR), | ||
(UcIntel.REG_RANGE_XMM, UcReg128), | ||
(UcIntel.REG_RANGE_YMM, UcReg256), | ||
(UcIntel.REG_RANGE_ZMM, UcReg512) | ||
) | ||
|
||
return next((cls for rng, cls in reg_class if reg_id in rng), None) | ||
|
||
def reg_read(self, reg_id: int, aux: Any = None): | ||
# select register class for special cases | ||
reg_cls = UcIntel.__select_reg_class(reg_id) | ||
|
||
if reg_cls is None: | ||
# backward compatibility: msr read through reg_read | ||
if reg_id == const.UC_X86_REG_MSR: | ||
if type(aux) is not int: | ||
raise UcError(UC_ERR_ARG) | ||
|
||
value = self.msr_read(aux) | ||
|
||
else: | ||
value = super().reg_read(reg_id, aux) | ||
else: | ||
value = self._reg_read(reg_id, reg_cls) | ||
|
||
return value | ||
return next((c for rng, c in reg_class if reg_id in rng), cls._DEFAULT_REGTYPE) | ||
|
||
def reg_write(self, reg_id: int, value) -> None: | ||
# select register class for special cases | ||
reg_cls = UcIntel.__select_reg_class(reg_id) | ||
def msr_read(self, msr_id: int) -> int: | ||
"""Read a model-specific register. | ||
|
||
if reg_cls is None: | ||
# backward compatibility: msr write through reg_write | ||
if reg_id == const.UC_X86_REG_MSR: | ||
if type(value) is not tuple or len(value) != 2: | ||
raise UcError(UC_ERR_ARG) | ||
Args: | ||
msr_id: MSR index | ||
|
||
self.msr_write(*value) | ||
return | ||
Returns: MSR value | ||
""" | ||
|
||
super().reg_write(reg_id, value) | ||
else: | ||
self._reg_write(reg_id, reg_cls, value) | ||
|
||
def msr_read(self, msr_id: int) -> int: | ||
return self._reg_read(const.UC_X86_REG_MSR, UcRegMSR, msr_id) | ||
return self.reg_read(const.UC_X86_REG_MSR, msr_id) | ||
|
||
def msr_write(self, msr_id: int, value: int) -> None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems the same as above, which should raise an exception, but maybe next time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not following on this one. What should raise an exception? It marks this line: return self.reg_read(const.UC_X86_REG_MSR, msr_id) |
||
self._reg_write(const.UC_X86_REG_MSR, UcRegMSR, (msr_id, value)) | ||
"""Write to a model-specific register. | ||
|
||
def reg_read_batch(self, reg_ids: Sequence[int]) -> Tuple: | ||
reg_types = [UcIntel.__select_reg_class(rid) or self._DEFAULT_REGTYPE for rid in reg_ids] | ||
Args: | ||
msr_id: MSR index | ||
value: new MSR value | ||
""" | ||
|
||
return self._reg_read_batch(reg_ids, reg_types) | ||
self.reg_write(const.UC_X86_REG_MSR, (msr_id, value)) | ||
|
||
|
||
__all__ = ['UcRegMMR', 'UcRegMSR', 'UcRegFPR', 'UcIntel'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not make
cpr_read/write
raise anUC_ERR_ARG
? Terminating the whole process without a chance to catch seems too aggressive.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally speaking, exceptions are thrown when the arguments normally make sense but there is a specific problem this time (e.g. opening a file which happens to be inaccessible, etc.). In these cases the user may catch the exception and choose how to handle it.
Here the assertions come to block an invalid usage with incorrect arguments: it is not a call that may sometimes work and sometimes not -- rather it is invalid. There is no way to "handle" such case other than re-writing that piece of code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I also forget
AssertionError
can be caught so let it go.