Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/archinfo/arch_arm.py: 74%
151 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
1import logging
3from .arch import Arch, register_arch, Endness, Register
4from .tls import TLSArchInfo
6log = logging.getLogger("archinfo.arch_arm")
8try:
9 import capstone as _capstone
10except ImportError:
11 _capstone = None
13try:
14 import keystone as _keystone
15except ImportError:
16 _keystone = None
18try:
19 import unicorn as _unicorn
20except ImportError:
21 _unicorn = None
24# TODO: determine proper base register (if it exists)
25# TODO: handle multiple return registers?
26# TODO: which endianness should be default?
29def is_arm_arch(a):
30 return a.name.startswith("ARM")
33def get_real_address_if_arm(arch, addr):
34 """
35 Obtain the real address of an instruction. ARM architectures are supported.
37 :param archinfo.Arch arch: The Arch object.
38 :param int addr: The instruction address.
39 :return: The real address of an instruction.
40 :rtype: int
41 """
43 return ((addr >> 1) << 1) if is_arm_arch(arch) else addr
46class ArchARM(Arch):
47 """
48 ARM architecture specific subclass
49 """
51 def __init__(self, endness=Endness.LE):
52 instruction_endness = None
53 if endness == Endness.LE:
54 instruction_endness = Endness.LE
56 super().__init__(endness, instruction_endness=instruction_endness)
57 if endness == Endness.BE:
58 self.function_prologs = {
59 # br"\xe9\x2d[\x40-\x7f\xc0-\xff][\x00-\xff]", # stmfd sp!, {xxxxx, lr}
60 rb"\xe5\x2d\xe0\x04", # push {lr}
61 rb"\xe1\xa0\xc0\x0c\xe5\x2d\xe0\x04",
62 }
63 self.thumb_prologs = {
64 # push.w {r4, r5, r7, r8, lr}
65 rb"\xe9\x2d\x41\xb0",
66 # push.w {r4-r7, r8, lr} | push.w {r4-r9, lr} | push.w {r4-r7, r9, r10, lr} | push.w {r4-r10, lr} |
67 # push.w {r4-r8, r10, r11, lr} | push.w {r4-r11, lr}
68 rb"\xe9\x2d[\x41\x43\x46\x47\x4d\x4f]\xf0",
69 # push.w {r3-r9, lr} | push.w {r3-r7, r9, r10, lr} | push.w {r3-r11, lr}
70 rb"\xe9\x2d[\x43\x46\x4f]\xf8",
71 rb"[\xb4\xb5][\x00\x10\x30\x70\xf0]\xb0[\x80-\x8f\xa3\xa8]",
72 # push {??, ??, ..., ??, lr}; sub sp, sp, #??
73 rb"\xb4\x80\xb0[\x80-\xff]", # push {r7}; sub sp, sp, #??
74 rb"\xb4[\x00-\xff]\xb5\x00\xb0[\x80-\xff]", # push {r?, r?}; push {lr}; sub sp, sp, #??
75 rb"\xb0[\x80-\xff]\x90[\x00-\xff]", # sub sp, sp, #??; str r0, [sp, ?]
76 # stmt0: push {lr} | push {r3, lr} | push {r4, lr} | push {r4, r5, lr} | push {r3, r4, r5, lr} |
77 # push {r4, r5, r6, lr} | push {r4, r5, r6, r7, lr} | push {r3, r4, r5, r6, r7, lr}
78 # stmt1: ldr r4, [pc, #??]
79 # stmt2: add sp, r4
80 rb"\xb5[\x00\x08\x10\x30\x38\x70\xf0\xf8]\x4c[\x00-\xff]\x44\xa5",
81 # stmt0: push {lr} | push {r3, lr} | push {r4, lr} | push {r4, r5, lr} | push {r3, r4, r5, lr} |
82 # push {r4, r5, r6, lr} | push {r4, r5, r6, r7, lr} | push {r3, r4, r5, r6, r7, lr}
83 # stmt1: mov r3/r4/r5/r6/r7, r0 | mov r4/r5/r6/r7, r1 | mov r6/r7, r3
84 rb"\xb5[\x00\x08\x10\x30\x38\x70\xf0\xf8]\x46[\x03-\x07\x0c-\x0f\x1e-\x1f]",
85 # stmt0: push {r3, lr}
86 # stmt1: movs r2/r3, #0
87 rb"\xb5\x08[\x22\x23]\x00",
88 # ldr r3, [pc, #??]; ldr r2, [pc, #??]; add r3, pc; push {r4,r5,lr}
89 rb"\x4b[\x00-\xff]\x4a[\x00-\xff]\x44\x7b\xb5\x30",
90 # push {r3,r4,r5,lr}; mov r3, #0;
91 rb"\xb5\x38\xf2\x40\x03\x00\xf2\xc0\x03\x00",
92 }
93 self.function_epilogs = {
94 rb"\xe8\xbd[\x00-\xff]{2}\xe1\x2f\xff\x1e" # pop {xxx}; bx lr
95 rb"\xe4\x9d\xe0\x04\xe1\x2f\xff\x1e" # pop {xxx}; bx lr
96 }
98 def __getstate__(self):
99 self._cs = None
100 self._cs_thumb = None
101 self._ks = None
102 self._ks_thumb = None
103 return super().__getstate__()
105 @property
106 def capstone_thumb(self):
107 if _capstone is None:
108 log.warning("Capstone is not installed!")
109 return None
110 if self._cs_thumb is None:
111 self._cs_thumb = _capstone.Cs(self.cs_arch, self.cs_mode + _capstone.CS_MODE_THUMB)
112 self._cs_thumb.detail = True
113 return self._cs_thumb
115 @property
116 def keystone_thumb(self):
117 if _keystone is None:
118 log.warning("Keystone is not installed!")
119 return None
120 if self._ks_thumb is None:
121 self._ks_thumb = _keystone.Ks(self.ks_arch, _keystone.KS_MODE_THUMB)
122 return self._ks_thumb
124 @property
125 def unicorn_thumb(self):
126 if _unicorn is None:
127 log.warning("Unicorn is not installed!")
128 return None
129 return _unicorn.Uc(self.uc_arch, self.uc_mode + _unicorn.UC_MODE_THUMB)
131 def m_addr(self, addr, *args, **kwargs):
132 """
133 Given the address of some code block, convert it to the address where this block
134 is stored in memory. The memory address can also be referred to as the "real" address.
136 For ARM-architecture, the "real" address is always even (has its lowest bit clear).
138 :param addr: The address to convert.
139 :return: The "real" address in memory.
140 :rtype: int
141 """
142 return addr & ~1
144 # pylint: disable=keyword-arg-before-vararg, arguments-differ
145 def x_addr(self, addr, thumb=None, *args, **kwargs):
146 """
147 Given the address of some code block, convert it to the value that should be assigned
148 to the instruction pointer register in order to execute the code in that block.
150 :param addr: The address to convert.
151 :param thumb: Set this parameter to True if you want to convert the address into the THUMB form.
152 Set this parameter to False if you want to convert the address into the ARM form.
153 Set this parameter to None (default) if you want to keep the address as is.
154 :return: The "execution" address.
155 :rtype: int
156 """
157 if thumb is None:
158 return addr
159 elif not thumb:
160 return addr & ~1
161 else: # thumb
162 return addr | 1
164 def is_thumb(self, addr): # pylint:disable=unused-argument
165 """
166 Return True, if the address is the THUMB address. False otherwise.
168 :param addr: The address to check.
169 :return: Whether the given address is the THUMB address.
170 """
171 return bool(addr & 1)
173 bits = 32
174 vex_arch = "VexArchARM"
175 name = "ARMEL"
176 qemu_name = "arm"
177 ida_processor = "armb"
178 linux_name = "arm"
179 triplet = "arm-linux-gnueabihf"
180 max_inst_bytes = 4
181 ret_offset = 8
182 fp_ret_offset = 8
183 vex_conditional_helpers = True
184 syscall_num_offset = 36
185 call_pushes_ret = False
186 stack_change = -4
187 memory_endness = Endness.LE
188 register_endness = Endness.LE
189 sizeof = {"short": 16, "int": 32, "long": 32, "long long": 64}
190 if _capstone:
191 cs_arch = _capstone.CS_ARCH_ARM
192 cs_mode = _capstone.CS_MODE_LITTLE_ENDIAN
193 _cs_thumb = None
194 if _keystone:
195 ks_arch = _keystone.KS_ARCH_ARM
196 ks_mode = _keystone.KS_MODE_ARM + _keystone.KS_MODE_LITTLE_ENDIAN
197 _ks_thumb = None
198 uc_arch = _unicorn.UC_ARCH_ARM if _unicorn else None
199 uc_mode = _unicorn.UC_MODE_LITTLE_ENDIAN if _unicorn else None
200 uc_mode_thumb = _unicorn.UC_MODE_LITTLE_ENDIAN + _unicorn.UC_MODE_THUMB if _unicorn else None
201 uc_const = _unicorn.arm_const if _unicorn else None
202 uc_prefix = "UC_ARM_" if _unicorn else None
203 # self.ret_instruction = b"\x0E\xF0\xA0\xE1" # this is mov pc, lr
204 ret_instruction = b"\x1E\xFF\x2F\xE1" # this is bx lr
205 nop_instruction = b"\x00\x00\x00\x00"
206 function_prologs = {
207 # br"[\x00-\xff][\x40-\x7f\xc0-\xff]\x2d\xe9", # stmfd sp!, {xxxxx,lr}
208 rb"\x04\xe0\x2d\xe5", # push {lr}
209 rb"\r\xc0\xa0\xe1[\x00-\xff][\x40-\x7f\xc0-\xff]\x2d\xe9", # mov r12, sp; stmfd sp!, {xxxxx,lr}
210 rb"\r\xc0\xa0\xe1\x04\xe0\x2d\xe5", # mov r12, sp; push {lr}
211 }
212 thumb_prologs = {
213 # push.w {r4, r5, r7, r8, lr}
214 rb"\x2d\xe9\xb0\x41",
215 # push.w {r4-r7, r8, lr} | push.w {r4-r9, lr} | push.w {r4-r7, r9, r10, lr} | push.w {r4-r10, lr} |
216 # push.w {r4-r8, r10, r11, lr} | push.w {r4-r11, lr}
217 rb"\x2d\xe9\xf0[\x41\x43\x46\x47\x4d\x4f]",
218 # push.w {r3-r9, lr} | push.w {r3-r7, r9, r10, lr} | push.w {r3-r11, lr}
219 rb"\x2d\xe9\xf8[\x43\x46\x4f]",
220 rb"[\x00\x10\x30\x70\xf0][\xb4\xb5][\x80-\x8f\xa3\xa8]\xb0", # push {??, ??, ..., ??, lr}; sub sp, sp, #??
221 rb"\x80\xb4[\x80-\xff]\xb0", # push {r7}; sub sp, sp, #??
222 rb"[\x00-\xff]\xb4\x00\xb5[\x80-\xff]\xb0", # push {r?, r?}; push {lr}; sub sp, sp, #??
223 rb"[\x80-\xff]\xb0[\x00-\xff]\x90", # sub sp, sp, #??; str r0, [sp, ?]
224 # stmt0: push {lr} | push {r3, lr} | push {r4, lr} | push {r4, r5, lr} | push {r3, r4, r5, lr} |
225 # push {r4, r5, r6, lr} | push {r4, r5, r6, r7, lr} | push {r3, r4, r5, r6, r7, lr}
226 # stmt1: ldr r4, [pc, #??]
227 # stmt2: add sp, r4
228 rb"[\x00\x08\x10\x30\x38\x70\xf0\xf8]\xb5[\x00-\xff]\x4c\xa5\x44",
229 # stmt0: push {lr} | push {r3, lr} | push {r4, lr} | push {r4, r5, lr} | push {r3, r4, r5, lr} |
230 # push {r4, r5, r6, lr} | push {r4, r5, r6, r7, lr} | push {r3, r4, r5, r6, r7, lr}
231 # stmt1: mov r3/r4/r5/r6/r7, r0 | mov r4/r5/r6/r7, r1 | mov r6/r7, r3
232 rb"[\x00\x08\x10\x30\x38\x70\xf0\xf8]\xb5[\x03-\x07\x0c-\x0f\x1e-\x1f]\x46",
233 # stmt0: push {r3, lr}
234 # stmt1: movs r2/r3, #0
235 rb"\x08\xb5\x00[\x22\x23]",
236 # ldr r3, [pc, #??]; ldr r2, [pc, #??]; add r3, pc; push {r4,r5,lr}
237 rb"[\x00-\xff]\x4b[\x00-\xff]\x4a\x7b\x44\x30\xb5",
238 # push {r3,r4,r5,lr}; mov r3, #0;
239 rb"\x38\xb5\x40\xf2\x00\x03\xc0\xf2\x00\x03",
240 }
241 function_epilogs = {
242 rb"[\x00-\xff]{2}\xbd\xe8\x1e\xff\x2f\xe1" # pop {xxx}; bx lr
243 rb"\x04\xe0\x9d\xe4\x1e\xff\x2f\xe1" # pop {xxx}; bx lr
244 }
245 instruction_alignment = 2 # cuz there is also thumb mode
246 register_list = [
247 Register(
248 name="r0",
249 size=4,
250 alias_names=("a1",),
251 general_purpose=True,
252 argument=True,
253 linux_entry_value="ld_destructor",
254 ),
255 Register(name="r1", size=4, alias_names=("a2",), general_purpose=True, argument=True),
256 Register(name="r2", size=4, alias_names=("a3",), general_purpose=True, argument=True),
257 Register(name="r3", size=4, alias_names=("a4",), general_purpose=True, argument=True),
258 Register(name="r4", size=4, alias_names=("v1",), general_purpose=True),
259 Register(name="r5", size=4, alias_names=("v2",), general_purpose=True),
260 Register(name="r6", size=4, alias_names=("v3",), general_purpose=True),
261 Register(name="r7", size=4, alias_names=("v4",), general_purpose=True),
262 Register(name="r8", size=4, alias_names=("v5",), general_purpose=True),
263 Register(name="r9", size=4, alias_names=("v6", "sb"), general_purpose=True),
264 Register(name="r10", size=4, alias_names=("v7", "sl"), general_purpose=True),
265 Register(name="r11", size=4, alias_names=("v8", "fp", "bp"), general_purpose=True),
266 Register(name="r12", size=4, general_purpose=True),
267 # r12 is sometimes known as "ip" (intraprocedural call scratch) but we can't have that...
268 Register(
269 name="sp",
270 size=4,
271 alias_names=("r13",),
272 general_purpose=True,
273 default_value=(Arch.initial_sp, True, "global"),
274 ),
275 Register(name="lr", size=4, alias_names=("r14",), general_purpose=True, concretize_unique=True),
276 Register(name="pc", size=4, vex_name="r15t", alias_names=("r15", "ip")),
277 Register(name="cc_op", size=4, default_value=(0, False, None), artificial=True, concrete=False),
278 Register(name="cc_dep1", size=4, default_value=(0, False, None), artificial=True, concrete=False),
279 Register(name="cc_dep2", size=4, default_value=(0, False, None), artificial=True, concrete=False),
280 Register(name="cc_ndep", size=4, default_value=(0, False, None), artificial=True, concrete=False),
281 Register(name="qflag32", size=4, default_value=(0, False, None), artificial=True, concrete=False),
282 Register(name="geflag0", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
283 Register(name="geflag1", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
284 Register(name="geflag2", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
285 Register(name="geflag3", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
286 Register(name="emnote", size=4, vector=True, default_value=(0, False, None), artificial=True, concrete=False),
287 Register(name="cmstart", size=4, artificial=True, vector=True, default_value=(0, False, None), concrete=False),
288 Register(name="cmlen", size=4, artificial=True, default_value=(0, False, None), concrete=False),
289 Register(name="nraddr", size=4, artificial=True, default_value=(0, False, None), concrete=False),
290 Register(name="ip_at_syscall", size=4, artificial=True, concrete=False),
291 Register(name="d0", size=8, floating_point=True, vector=True, subregisters=[("s0", 0, 4), ("s1", 4, 4)]),
292 Register(name="d1", size=8, floating_point=True, vector=True, subregisters=[("s2", 0, 4), ("s3", 4, 4)]),
293 Register(name="d2", size=8, floating_point=True, vector=True, subregisters=[("s4", 0, 4), ("s5", 4, 4)]),
294 Register(name="d3", size=8, floating_point=True, vector=True, subregisters=[("s6", 0, 4), ("s7", 4, 4)]),
295 Register(name="d4", size=8, floating_point=True, vector=True, subregisters=[("s8", 0, 4), ("s9", 4, 4)]),
296 Register(name="d5", size=8, floating_point=True, vector=True, subregisters=[("s10", 0, 4), ("s11", 4, 4)]),
297 Register(name="d6", size=8, floating_point=True, vector=True, subregisters=[("s12", 0, 4), ("s13", 4, 4)]),
298 Register(name="d7", size=8, floating_point=True, vector=True, subregisters=[("s14", 0, 4), ("s15", 4, 4)]),
299 Register(name="d8", size=8, floating_point=True, vector=True, subregisters=[("s16", 0, 4), ("s17", 4, 4)]),
300 Register(name="d9", size=8, floating_point=True, vector=True, subregisters=[("s18", 0, 4), ("s19", 4, 4)]),
301 Register(name="d10", size=8, floating_point=True, vector=True, subregisters=[("s20", 0, 4), ("s21", 4, 4)]),
302 Register(name="d11", size=8, floating_point=True, vector=True, subregisters=[("s22", 0, 4), ("s23", 4, 4)]),
303 Register(name="d12", size=8, floating_point=True, vector=True, subregisters=[("s24", 0, 4), ("s25", 4, 4)]),
304 Register(name="d13", size=8, floating_point=True, vector=True, subregisters=[("s26", 0, 4), ("s27", 4, 4)]),
305 Register(name="d14", size=8, floating_point=True, vector=True, subregisters=[("s28", 0, 4), ("s29", 4, 4)]),
306 Register(name="d15", size=8, floating_point=True, vector=True, subregisters=[("s30", 0, 4), ("s31", 4, 4)]),
307 Register(name="d16", size=8, floating_point=True, vector=True),
308 Register(name="d17", size=8, floating_point=True, vector=True),
309 Register(name="d18", size=8, floating_point=True, vector=True),
310 Register(name="d19", size=8, floating_point=True, vector=True),
311 Register(name="d20", size=8, floating_point=True, vector=True),
312 Register(name="d21", size=8, floating_point=True, vector=True),
313 Register(name="d22", size=8, floating_point=True, vector=True),
314 Register(name="d23", size=8, floating_point=True, vector=True),
315 Register(name="d24", size=8, floating_point=True, vector=True),
316 Register(name="d25", size=8, floating_point=True, vector=True),
317 Register(name="d26", size=8, floating_point=True, vector=True),
318 Register(name="d27", size=8, floating_point=True, vector=True),
319 Register(name="d28", size=8, floating_point=True, vector=True),
320 Register(name="d29", size=8, floating_point=True, vector=True),
321 Register(name="d30", size=8, floating_point=True, vector=True),
322 Register(name="d31", size=8, floating_point=True, vector=True),
323 Register(name="fpscr", size=4, floating_point=True, artificial=True, concrete=False),
324 Register(name="tpidruro", size=4, artificial=True, concrete=False),
325 Register(name="itstate", size=4, artificial=True, default_value=(0, False, None), concrete=False),
326 ]
328 got_section_name = ".got"
329 ld_linux_name = "ld-linux.so.3"
330 elf_tls = TLSArchInfo(1, 8, [], [0], [], 0, 0)
331 # elf_tls = TLSArchInfo(1, 32, [], [0], [], 0, 0)
332 # that line was lying in the original CLE code and I have no clue why it's different
335class ArchARMHF(ArchARM):
336 """
337 This is an architecture description for the ARM hard-float (armhf).
338 It supports at least an ARM 32-bit processor with ARMv7 architecture, Thumb-2 and VFP3D16.
339 """
341 name = "ARMHF"
342 triplet = "arm-linux-gnueabihf"
343 ld_linux_name = "ld-linux-armhf.so.3"
344 fp_ret_offset = 128 # s0
347class ArchARMEL(ArchARM):
348 """
349 This is an architecture description for ARM EABI (armel).
350 It targets a range of older 32-bit ARM devices without hardware FPUs.
351 """
353 name = "ARMEL"
354 triplet = "arm-linux-gnueabi"
355 ld_linux_name = "ld-linux.so.3"
356 elf_tls = TLSArchInfo(1, 8, [], [0], [], 0, 0)
359class ArchARMCortexM(ArchARMEL):
360 """
361 This is an architecture description for ARM Cortex-M microcontroller-class CPUs.
363 These CPUs have the following unusual / annoying distinctions from their relatives:
364 - Explicitly only support the Thumb-2 instruction set. Executing with the T-bit off causes the processor to fault
365 instantly
366 - Always little-endian
367 - Coprocessors? Nope, none of that rubbish
368 - Well-known standard memory map across all devices
369 - Rarely use an MPU, even though this does exist on some devices
370 - A built-in "NVIC" (Nested Vectored Interrupt Controller) as part of the standard.
371 - Standardized "blob format" including the IVT, with initial SP and entry prepended
372 - Usually don't run an OS (SimLinux? No thanks)
373 - As part of the above, handle syscalls (SVC) instructions through an interrupt (now called PendSV)
374 Uses its own fancy stack layout for this, which (UGH) varies by sub-sub-architecture
375 - Some fancy instructions normally never seen in other uses of Thumb (CPSID, CPSIE, WFI, MRS.W, MSR.W)
376 - New registers, namely:
377 * FAULTMASK
378 * PRIMASK
379 * BASEPRI
380 * CONTROL
381 * SP, banked as PSP or MSP
382 * PSR, now just one PSR, with a few meta-registers APSR, IPSR, and EPSR which take a chunk of that each
384 """
386 name = "ARMCortexM"
387 triplet = "arm-none-eabi" # ARM's own CM compilers use this triplet
389 # These are the standard THUMB prologs. We leave these off for other ARMs due to their length
390 # For CM, we assume the FPs are OK, as they are almost guaranteed to appear all over the place
391 function_prologs = {}
393 thumb_prologs = {rb"[\x00-\xff]\xb5", rb"\x2d\xe9[\x00-\xff][\x00-\xff]"} # push {xxx,lr} # push.w {xxx, lr}
394 function_epilogs = {
395 rb"[\x00-\xff]\xbd" # pop {xxx, pc}
396 # TODO: POP.W
397 }
399 register_list = [
400 Register(
401 name="r0",
402 size=4,
403 alias_names=("a1",),
404 general_purpose=True,
405 argument=True,
406 linux_entry_value="ld_destructor",
407 ),
408 Register(name="r1", size=4, alias_names=("a2",), general_purpose=True, argument=True),
409 Register(name="r2", size=4, alias_names=("a3",), general_purpose=True, argument=True),
410 Register(name="r3", size=4, alias_names=("a4",), general_purpose=True, argument=True),
411 Register(name="r4", size=4, alias_names=("v1",), general_purpose=True),
412 Register(name="r5", size=4, alias_names=("v2",), general_purpose=True),
413 Register(name="r6", size=4, alias_names=("v3",), general_purpose=True),
414 Register(name="r7", size=4, alias_names=("v4",), general_purpose=True),
415 Register(name="r8", size=4, alias_names=("v5",), general_purpose=True),
416 Register(name="r9", size=4, alias_names=("v6", "sb"), general_purpose=True),
417 Register(name="r10", size=4, alias_names=("v7", "sl"), general_purpose=True),
418 Register(name="r11", size=4, alias_names=("v8", "fp", "bp"), general_purpose=True),
419 # r11 is used as frame pointer
420 Register(name="r12", size=4, general_purpose=True),
421 # r12 is sometimes known as "ip" (intraprocedural call scratch) but we can't have that...
422 Register(
423 name="sp",
424 size=4,
425 alias_names=("r13",),
426 general_purpose=True,
427 default_value=(Arch.initial_sp, True, "global"),
428 ),
429 Register(name="lr", size=4, alias_names=("r14",), general_purpose=True, concretize_unique=True),
430 Register(name="pc", size=4, vex_name="r15t", alias_names=("r15", "ip")),
431 # Control registers for Cortex-M33 with ArmV8 securtiy extension enabled (Trustzone)
432 Register(name="msp", size=4, general_purpose=True),
433 Register(name="msp_s", size=4, general_purpose=True),
434 Register(name="msp_ns", size=4, general_purpose=True),
435 Register(name="psp", size=4, general_purpose=True),
436 Register(name="psp_s", size=4, general_purpose=True),
437 Register(name="psp_ns", size=4, general_purpose=True),
438 Register(name="msplim", size=4, general_purpose=True),
439 Register(name="msplim_s", size=4, general_purpose=True),
440 Register(name="msplim_ns", size=4, general_purpose=True),
441 Register(name="msplim_ns", size=4, general_purpose=True),
442 # additional stack pointers for secure/non_secure world
443 Register(name="sp_process", size=4, general_purpose=True),
444 Register(name="sp_process_s", size=4, general_purpose=True),
445 Register(name="sp_process_ns", size=4, general_purpose=True),
446 Register(name="sp_main", size=4, general_purpose=True),
447 Register(name="sp_main_s", size=4, general_purpose=True),
448 Register(name="sp_main_ns", size=4, general_purpose=True),
449 Register(name="cc_op", size=4, default_value=(0, False, None), artificial=True, concrete=False),
450 Register(name="cc_dep1", size=4, default_value=(0, False, None), artificial=True, concrete=False),
451 Register(name="cc_dep2", size=4, default_value=(0, False, None), artificial=True, concrete=False),
452 Register(name="cc_ndep", size=4, default_value=(0, False, None), artificial=True, concrete=False),
453 Register(name="qflag32", size=4, default_value=(0, False, None), artificial=True, concrete=False),
454 Register(name="ip_at_syscall", size=4, artificial=True, concrete=False),
455 # Cortex-M Has a different FPU from all other ARMs.
456 Register(name="d0", size=8, subregisters=[("s0", 0, 4), ("s1", 4, 4)], floating_point=True),
457 Register(name="d1", size=8, subregisters=[("s2", 0, 4), ("s3", 4, 4)], floating_point=True),
458 Register(name="d2", size=8, subregisters=[("s4", 0, 4), ("s5", 4, 4)], floating_point=True),
459 Register(name="d3", size=8, subregisters=[("s6", 0, 4), ("s7", 4, 4)], floating_point=True),
460 Register(name="d4", size=8, subregisters=[("s8", 0, 4), ("s9", 4, 4)], floating_point=True),
461 Register(name="d5", size=8, subregisters=[("s10", 0, 4), ("s11", 4, 4)], floating_point=True),
462 Register(name="d6", size=8, subregisters=[("s12", 0, 4), ("s13", 4, 4)], floating_point=True),
463 Register(name="d7", size=8, subregisters=[("s14", 0, 4), ("s15", 4, 4)], floating_point=True),
464 Register(name="d8", size=8, subregisters=[("s16", 0, 4), ("s17", 4, 4)], floating_point=True),
465 Register(name="d9", size=8, subregisters=[("s18", 0, 4), ("s19", 4, 4)], floating_point=True),
466 Register(name="d10", size=8, subregisters=[("s20", 0, 4), ("s21", 4, 4)], floating_point=True),
467 Register(name="d11", size=8, subregisters=[("s22", 0, 4), ("s23", 4, 4)], floating_point=True),
468 Register(name="d12", size=8, subregisters=[("s24", 0, 4), ("s25", 4, 4)], floating_point=True),
469 Register(name="d13", size=8, subregisters=[("s26", 0, 4), ("s27", 4, 4)], floating_point=True),
470 Register(name="d14", size=8, subregisters=[("s28", 0, 4), ("s29", 4, 4)], floating_point=True),
471 Register(name="d15", size=8, subregisters=[("s30", 0, 4), ("s31", 4, 4)], floating_point=True),
472 # xPSR register. Includes APSR, IPSR and EPSR.
473 Register(name="cpsr", size=4, default_value=(0, False, None)),
474 # TODO: NOTE: This is technically part of the EPSR, not its own register
475 Register(name="fpscr", size=4, floating_point=True),
476 # TODO: NOTE: This is also part of EPSR
477 Register(name="itstate", size=4, artificial=True, default_value=(0, False, None), concrete=False),
478 # Whether exceptions are masked or not. (e.g., everything but NMI)
479 Register(name="faultmask", size=4, default_value=(0, False, None)),
480 Register(name="faultmask_s", size=4, default_value=(0, False, None)),
481 Register(name="faultmask_ns", size=4, default_value=(0, False, None)),
482 # The one-byte priority, above which interrupts will not be handled if PRIMASK is 1.
483 # Yes, you can implement an RTOS scheduler in hardware with this and the NVIC, you monster!
484 Register(name="basepri", size=4, default_value=(0, False, None)),
485 Register(name="basepri_s", size=4, default_value=(0, False, None)),
486 Register(name="basepri_ns", size=4, default_value=(0, False, None)),
487 # Only the bottom bit of PRIMASK is relevant, even though the docs say its 32bit.
488 # Configures whether interrupt priorities are respected or not.
489 Register(name="primask", size=4, default_value=(0, False, None)),
490 Register(name="primask_s", size=4, default_value=(0, False, None)),
491 Register(name="primask_ns", size=4, default_value=(0, False, None)),
492 # NOTE: We specifically declare IEPSR here. Not PSR, .... variants.for
493 # VEX already handles the content of APSR, and half of EPSR (as ITSTATE) above.
494 # We only keep here the data not computed via CCalls
495 # The default is to have the T bit on.
496 Register(name="iepsr", size=4, default_value=(0x01000000, False, None)),
497 # CONTROL:
498 # Bit 2: Whether the FPU is active or not
499 # Bit 1: Whether we use MSP (0) or PSP (1)
500 # Bit 0: Thread mode privilege level. 0 for privileged, 1 for unprivileged.
501 Register(name="control", size=4, default_value=(0, False, None)),
502 ]
504 # Special handling of CM mode in *stone
505 if _capstone:
506 cs_arch = _capstone.CS_ARCH_ARM
507 cs_mode = _capstone.CS_MODE_LITTLE_ENDIAN + _capstone.CS_MODE_THUMB + _capstone.CS_MODE_MCLASS
508 _cs_thumb = None
509 if _keystone:
510 ks_arch = _keystone.KS_ARCH_ARM
511 ks_mode = _keystone.KS_MODE_THUMB + _keystone.KS_MODE_LITTLE_ENDIAN
512 _ks_thumb = None
513 uc_arch = _unicorn.UC_ARCH_ARM if _unicorn else None
514 uc_mode = _unicorn.UC_MODE_THUMB + _unicorn.UC_MODE_LITTLE_ENDIAN if _unicorn else None
515 uc_mode_thumb = _unicorn.UC_MODE_THUMB + _unicorn.UC_MODE_LITTLE_ENDIAN if _unicorn else None
517 dwarf_registers = [
518 "r0",
519 "r1",
520 "r2",
521 "r3",
522 "r4",
523 "r5",
524 "r6",
525 "r7",
526 "r8",
527 "r9",
528 "r10",
529 "r11",
530 "r12",
531 "sp",
532 "lr",
533 "pc",
534 ]
536 @property
537 def capstone_thumb(self):
538 return self.capstone
540 @property
541 def keystone_thumb(self):
542 return self.keystone
544 def __init__(self, *args, **kwargs):
545 super().__init__(*args, **kwargs)
547 # TODO: Make arm_spotter use these
548 # TODO: Make SimOS use these.
549 # TODO: Add.... the NVIC? to SimOS
552register_arch([r".*cortexm|.*cortex\-m.*|.*v7\-m.*"], 32, "any", ArchARMCortexM)
553register_arch([r".*armhf.*"], 32, "any", ArchARMHF)
554register_arch([r".*armeb|.*armbe"], 32, Endness.BE, ArchARM)
555register_arch([r".*armel|arm.*"], 32, Endness.LE, ArchARMEL)
556register_arch([r".*arm.*|.*thumb.*"], 32, "any", ArchARM)