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