|
3 | 3 | # Cross Platform and Multi Architecture Advanced Binary Emulation Framework |
4 | 4 | # |
5 | 5 |
|
6 | | -class QlRegisterManager(): |
7 | | - """ |
8 | | - This class exposes the ql.reg features that allows you to directly access |
| 6 | +from typing import Any, Mapping, MutableMapping, Union |
| 7 | + |
| 8 | +from qiling import Qiling |
| 9 | + |
| 10 | +class QlRegisterManager: |
| 11 | + """This class exposes the ql.reg features that allows you to directly access |
9 | 12 | or assign values to CPU registers of a particular architecture. |
10 | 13 |
|
11 | 14 | Registers exposed are listed in the *_const.py files in the respective |
12 | 15 | arch directories and are mapped to Unicorn Engine's definitions |
13 | 16 | """ |
14 | | - def __init__(self, ql): |
15 | | - self.register_mapping = {} |
16 | | - self.reverse_mapping = {} |
| 17 | + |
| 18 | + def __init__(self, ql: Qiling): |
| 19 | + # this funny way of initialization is used to avoid calling self setattr and |
| 20 | + # getattr upon init. if it did, it would go into an endless recursion |
| 21 | + self.register_mapping: MutableMapping[str, int] |
| 22 | + super().__setattr__('register_mapping', {}) |
| 23 | + |
17 | 24 | self.ql = ql |
18 | 25 | self.uc_pc = 0 |
19 | 26 | self.uc_sp = 0 |
20 | | - |
21 | 27 |
|
22 | | - def __getattribute__(self, name): |
| 28 | + def __getattr__(self, name: str) -> Any: |
23 | 29 | name = name.lower() |
24 | | - if name in ("register_mapping", "ql", "uc_pc", "uc_sp"): |
25 | | - return super(QlRegisterManager, self).__getattribute__(name) |
26 | 30 |
|
27 | | - elif name in self.register_mapping: |
| 31 | + if name in self.register_mapping: |
28 | 32 | return self.ql.uc.reg_read(self.register_mapping[name]) |
29 | 33 |
|
30 | | - return super(QlRegisterManager, self).__getattribute__(name) |
| 34 | + else: |
| 35 | + return super().__getattribute__(name) |
31 | 36 |
|
32 | 37 |
|
33 | | - def __setattr__(self, name, value): |
34 | | - name=name.lower() |
35 | | - if name in ("register_mapping", "ql", "uc_pc", "uc_sp"): |
36 | | - super(QlRegisterManager, self).__setattr__(name, value) |
| 38 | + def __setattr__(self, name: str, value: Any): |
| 39 | + name = name.lower() |
37 | 40 |
|
38 | | - elif name in self.register_mapping: |
| 41 | + if name in self.register_mapping: |
39 | 42 | self.ql.uc.reg_write(self.register_mapping[name], value) |
| 43 | + |
40 | 44 | else: |
41 | | - super(QlRegisterManager, self).__setattr__(name, value) |
| 45 | + super().__setattr__(name, value) |
42 | 46 |
|
43 | 47 |
|
44 | | - def expand_mapping(self, expanded_map): |
45 | | - self.register_mapping = {**self.register_mapping, **expanded_map} |
| 48 | + def expand_mapping(self, extra: Mapping[str, int]) -> None: |
| 49 | + """Expand registers mapping with additional ones. |
| 50 | + """ |
| 51 | + |
| 52 | + self.register_mapping.update(extra) |
46 | 53 |
|
47 | 54 |
|
48 | 55 | # read register |
49 | | - def read(self, register): |
50 | | - if isinstance(register, str): |
51 | | - register = self.register_mapping.get(register.lower(), None) |
| 56 | + def read(self, register: Union[str, int]): |
| 57 | + """Read a register value. |
| 58 | + """ |
| 59 | + |
| 60 | + if type(register) is str: |
| 61 | + register = self.register_mapping[register.lower()] |
| 62 | + |
52 | 63 | return self.ql.uc.reg_read(register) |
53 | 64 |
|
54 | 65 |
|
55 | | - def write(self, register, value): |
56 | | - if isinstance(register, str): |
57 | | - register = self.register_mapping.get(register.lower(), None) |
| 66 | + def write(self, register: Union[str, int], value: int) -> None: |
| 67 | + """Write a register value. |
| 68 | + """ |
| 69 | + |
| 70 | + if type(register) is str: |
| 71 | + register = self.register_mapping[register.lower()] |
| 72 | + |
58 | 73 | return self.ql.uc.reg_write(register, value) |
59 | 74 |
|
60 | 75 |
|
61 | | - def msr(self, msr, addr= None): |
62 | | - if not addr: |
| 76 | + def msr(self, msr: int, value: int = None): |
| 77 | + """Read or write a model-specific register (MSR) value. |
| 78 | + Intel architecture only |
| 79 | + """ |
| 80 | + |
| 81 | + if value is None: |
63 | 82 | return self.ql.uc.msr_read(msr) |
64 | | - else: |
65 | | - self.ql.uc.msr_write(msr, addr) |
66 | 83 |
|
| 84 | + self.ql.uc.msr_write(msr, value) |
67 | 85 |
|
68 | | - # ql.reg.save |
69 | | - def save(self): |
70 | | - reg_dict = {} |
71 | | - for reg in self.register_mapping: |
72 | | - reg_v = self.read(reg) |
73 | | - reg_dict[reg] = reg_v |
74 | | - return reg_dict |
75 | 86 |
|
| 87 | + def save(self) -> MutableMapping[str, Any]: |
| 88 | + """Save CPU context. |
| 89 | + """ |
76 | 90 |
|
77 | | - # ql.reg.restore |
78 | | - def restore(self, value = {}): |
79 | | - for reg in self.register_mapping: |
80 | | - reg_v= value[reg] |
81 | | - self.write(reg, reg_v) |
| 91 | + return dict((reg, self.read(reg)) for reg in self.register_mapping) |
82 | 92 |
|
83 | 93 |
|
84 | | - # ql.reg.bit() - Register bit |
85 | | - #FIXME: This needs to be implemented for all archs |
86 | | - def bit(self, uc_reg): |
87 | | - return self.ql.arch.get_reg_bit(uc_reg) |
| 94 | + def restore(self, context: MutableMapping[str, Any] = {}) -> None: |
| 95 | + """Restore CPU context. |
| 96 | + """ |
| 97 | + |
| 98 | + for reg, val in context.items(): |
| 99 | + self.write(reg, val) |
| 100 | + |
| 101 | + |
| 102 | + # TODO: This needs to be implemented for all archs |
| 103 | + def bit(self, reg: Union[str, int]) -> int: |
| 104 | + """Get register size in bits. |
| 105 | + """ |
| 106 | + |
| 107 | + if type(reg) is str: |
| 108 | + reg = self.register_mapping[reg] |
| 109 | + |
| 110 | + return self.ql.arch.get_reg_bit(reg) |
88 | 111 |
|
89 | 112 |
|
90 | 113 | # Generic methods to get SP and IP across Arch's # |
91 | 114 | # These functions should only be used if the # |
92 | 115 | # caller is dealing with multiple Arch's # |
93 | | - def register_sp(self, sp_id): |
| 116 | + def register_sp(self, sp_id: int): |
94 | 117 | self.uc_sp = sp_id |
95 | 118 |
|
96 | 119 |
|
97 | | - def register_pc(self, pc_id): |
| 120 | + def register_pc(self, pc_id: int): |
98 | 121 | self.uc_pc = pc_id |
99 | 122 |
|
100 | 123 |
|
101 | 124 | @property |
102 | | - def arch_pc(self): |
| 125 | + def arch_pc(self) -> int: |
| 126 | + """Get the value of the architectural program counter register. |
| 127 | + """ |
| 128 | + |
103 | 129 | return self.ql.uc.reg_read(self.uc_pc) |
104 | 130 |
|
105 | 131 |
|
106 | 132 | @arch_pc.setter |
107 | | - def arch_pc(self, value): |
| 133 | + def arch_pc(self, value: int) -> None: |
| 134 | + """Set the value of the architectural program counter register. |
| 135 | + """ |
| 136 | + |
108 | 137 | return self.ql.uc.reg_write(self.uc_pc, value) |
109 | 138 |
|
110 | 139 | @property |
111 | | - def arch_pc_name(self): |
112 | | - return self.ql.reg.reverse_mapping[self.uc_pc] |
| 140 | + def arch_pc_name(self) -> str: |
| 141 | + """Get the architectural program counter register name. |
| 142 | + """ |
| 143 | + |
| 144 | + return next(k for k, v in self.register_mapping.items() if v == self.uc_pc) |
113 | 145 |
|
114 | 146 | @property |
115 | | - def arch_sp(self): |
| 147 | + def arch_sp(self) -> int: |
| 148 | + """Get the value of the architectural stack pointer register. |
| 149 | + """ |
| 150 | + |
116 | 151 | return self.ql.uc.reg_read(self.uc_sp) |
117 | 152 |
|
118 | 153 |
|
119 | 154 | @arch_sp.setter |
120 | | - def arch_sp(self, value): |
121 | | - return self.ql.uc.reg_write(self.uc_sp, value) |
122 | | - |
| 155 | + def arch_sp(self, value: int) -> None: |
| 156 | + """Set the value of the architectural stack pointer register. |
| 157 | + """ |
123 | 158 |
|
124 | | - def get_uc_reg(self, uc_reg_name): |
125 | | - return self.register_mapping.get(uc_reg_name, None) |
126 | | - |
127 | | - |
128 | | - def create_reverse_mapping(self): |
129 | | - self.reverse_mapping = {v:k for k, v in self.register_mapping.items()} |
| 159 | + return self.ql.uc.reg_write(self.uc_sp, value) |
0 commit comments