/* Common target dependent code for GDB on ARM systems. Copyright (C) 1988-2013 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "defs.h" #include /* XXX for isupper (). */ #include "frame.h" #include "inferior.h" #include "gdbcmd.h" #include "gdbcore.h" #include "gdb_string.h" #include "dis-asm.h" /* For register styles. */ #include "regcache.h" #include "reggroups.h" #include "doublest.h" #include "value.h" #include "arch-utils.h" #include "osabi.h" #include "frame-unwind.h" #include "frame-base.h" #include "trad-frame.h" #include "objfiles.h" #include "dwarf2-frame.h" #include "gdbtypes.h" #include "prologue-value.h" #include "remote.h" #include "target-descriptions.h" #include "user-regs.h" #include "observer.h" #include "arm-tdep.h" #include "gdb/sim-arm.h" #include "elf-bfd.h" #include "coff/internal.h" #include "elf/arm.h" #include "gdb_assert.h" #include "vec.h" #include "record.h" #include "record-full.h" #include "features/arm-with-m.c" #include "features/arm-with-m-fpa-layout.c" #include "features/arm-with-m-vfp-d16.c" #include "features/arm-with-iwmmxt.c" #include "features/arm-with-vfpv2.c" #include "features/arm-with-vfpv3.c" #include "features/arm-with-neon.c" static int arm_debug; /* Macros for setting and testing a bit in a minimal symbol that marks it as Thumb function. The MSB of the minimal symbol's "info" field is used for this purpose. MSYMBOL_SET_SPECIAL Actually sets the "special" bit. MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol. */ #define MSYMBOL_SET_SPECIAL(msym) \ MSYMBOL_TARGET_FLAG_1 (msym) = 1 #define MSYMBOL_IS_SPECIAL(msym) \ MSYMBOL_TARGET_FLAG_1 (msym) /* Per-objfile data used for mapping symbols. */ static const struct objfile_data *arm_objfile_data_key; struct arm_mapping_symbol { bfd_vma value; char type; }; typedef struct arm_mapping_symbol arm_mapping_symbol_s; DEF_VEC_O(arm_mapping_symbol_s); struct arm_per_objfile { VEC(arm_mapping_symbol_s) **section_maps; }; /* The list of available "set arm ..." and "show arm ..." commands. */ static struct cmd_list_element *setarmcmdlist = NULL; static struct cmd_list_element *showarmcmdlist = NULL; /* The type of floating-point to use. Keep this in sync with enum arm_float_model, and the help string in _initialize_arm_tdep. */ static const char *const fp_model_strings[] = { "auto", "softfpa", "fpa", "softvfp", "vfp", NULL }; /* A variable that can be configured by the user. */ static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO; static const char *current_fp_model = "auto"; /* The ABI to use. Keep this in sync with arm_abi_kind. */ static const char *const arm_abi_strings[] = { "auto", "APCS", "AAPCS", NULL }; /* A variable that can be configured by the user. */ static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO; static const char *arm_abi_string = "auto"; /* The execution mode to assume. */ static const char *const arm_mode_strings[] = { "auto", "arm", "thumb", NULL }; static const char *arm_fallback_mode_string = "auto"; static const char *arm_force_mode_string = "auto"; /* Internal override of the execution mode. -1 means no override, 0 means override to ARM mode, 1 means override to Thumb mode. The effect is the same as if arm_force_mode has been set by the user (except the internal override has precedence over a user's arm_force_mode override). */ static int arm_override_mode = -1; /* Number of different reg name sets (options). */ static int num_disassembly_options; /* The standard register names, and all the valid aliases for them. Note that `fp', `sp' and `pc' are not added in this alias list, because they have been added as builtin user registers in std-regs.c:_initialize_frame_reg. */ static const struct { const char *name; int regnum; } arm_register_aliases[] = { /* Basic register numbers. */ { "r0", 0 }, { "r1", 1 }, { "r2", 2 }, { "r3", 3 }, { "r4", 4 }, { "r5", 5 }, { "r6", 6 }, { "r7", 7 }, { "r8", 8 }, { "r9", 9 }, { "r10", 10 }, { "r11", 11 }, { "r12", 12 }, { "r13", 13 }, { "r14", 14 }, { "r15", 15 }, /* Synonyms (argument and variable registers). */ { "a1", 0 }, { "a2", 1 }, { "a3", 2 }, { "a4", 3 }, { "v1", 4 }, { "v2", 5 }, { "v3", 6 }, { "v4", 7 }, { "v5", 8 }, { "v6", 9 }, { "v7", 10 }, { "v8", 11 }, /* Other platform-specific names for r9. */ { "sb", 9 }, { "tr", 9 }, /* Special names. */ { "ip", 12 }, { "lr", 14 }, /* Names used by GCC (not listed in the ARM EABI). */ { "sl", 10 }, /* A special name from the older ATPCS. */ { "wr", 7 }, }; static const char *const arm_register_names[] = {"r0", "r1", "r2", "r3", /* 0 1 2 3 */ "r4", "r5", "r6", "r7", /* 4 5 6 7 */ "r8", "r9", "r10", "r11", /* 8 9 10 11 */ "r12", "sp", "lr", "pc", /* 12 13 14 15 */ "f0", "f1", "f2", "f3", /* 16 17 18 19 */ "f4", "f5", "f6", "f7", /* 20 21 22 23 */ "fps", "cpsr" }; /* 24 25 */ /* Valid register name styles. */ static const char **valid_disassembly_styles; /* Disassembly style to use. Default to "std" register names. */ static const char *disassembly_style; /* This is used to keep the bfd arch_info in sync with the disassembly style. */ static void set_disassembly_style_sfunc(char *, int, struct cmd_list_element *); static void set_disassembly_style (void); static void convert_from_extended (const struct floatformat *, const void *, void *, int); static void convert_to_extended (const struct floatformat *, void *, const void *, int); static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch, struct regcache *regcache, int regnum, gdb_byte *buf); static void arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache, int regnum, const gdb_byte *buf); static int thumb_insn_size (unsigned short inst1); struct arm_prologue_cache { /* The stack pointer at the time this frame was created; i.e. the caller's stack pointer when this function was called. It is used to identify this frame. */ CORE_ADDR prev_sp; /* The frame base for this frame is just prev_sp - frame size. FRAMESIZE is the distance from the frame pointer to the initial stack pointer. */ int framesize; /* The register used to hold the frame pointer for this frame. */ int framereg; /* Saved register offsets. */ struct trad_frame_saved_reg *saved_regs; }; static CORE_ADDR arm_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR prologue_start, CORE_ADDR prologue_end, struct arm_prologue_cache *cache); /* Architecture version for displaced stepping. This effects the behaviour of certain instructions, and really should not be hard-wired. */ #define DISPLACED_STEPPING_ARCH_VERSION 5 /* Addresses for calling Thumb functions have the bit 0 set. Here are some macros to test, set, or clear bit 0 of addresses. */ #define IS_THUMB_ADDR(addr) ((addr) & 1) #define MAKE_THUMB_ADDR(addr) ((addr) | 1) #define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1) /* Set to true if the 32-bit mode is in use. */ int arm_apcs_32 = 1; /* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode. */ int arm_psr_thumb_bit (struct gdbarch *gdbarch) { if (gdbarch_tdep (gdbarch)->is_m) return XPSR_T; else return CPSR_T; } /* Determine if FRAME is executing in Thumb mode. */ int arm_frame_is_thumb (struct frame_info *frame) { CORE_ADDR cpsr; ULONGEST t_bit = arm_psr_thumb_bit (get_frame_arch (frame)); /* Every ARM frame unwinder can unwind the T bit of the CPSR, either directly (from a signal frame or dummy frame) or by interpreting the saved LR (from a prologue or DWARF frame). So consult it and trust the unwinders. */ cpsr = get_frame_register_unsigned (frame, ARM_PS_REGNUM); return (cpsr & t_bit) != 0; } /* Callback for VEC_lower_bound. */ static inline int arm_compare_mapping_symbols (const struct arm_mapping_symbol *lhs, const struct arm_mapping_symbol *rhs) { return lhs->value < rhs->value; } /* Search for the mapping symbol covering MEMADDR. If one is found, return its type. Otherwise, return 0. If START is non-NULL, set *START to the location of the mapping symbol. */ static char arm_find_mapping_symbol (CORE_ADDR memaddr, CORE_ADDR *start) { struct obj_section *sec; /* If there are mapping symbols, consult them. */ sec = find_pc_section (memaddr); if (sec != NULL) { struct arm_per_objfile *data; VEC(arm_mapping_symbol_s) *map; struct arm_mapping_symbol map_key = { memaddr - obj_section_addr (sec), 0 }; unsigned int idx; data = objfile_data (sec->objfile, arm_objfile_data_key); if (data != NULL) { map = data->section_maps[sec->the_bfd_section->index]; if (!VEC_empty (arm_mapping_symbol_s, map)) { struct arm_mapping_symbol *map_sym; idx = VEC_lower_bound (arm_mapping_symbol_s, map, &map_key, arm_compare_mapping_symbols); /* VEC_lower_bound finds the earliest ordered insertion point. If the following symbol starts at this exact address, we use that; otherwise, the preceding mapping symbol covers this address. */ if (idx < VEC_length (arm_mapping_symbol_s, map)) { map_sym = VEC_index (arm_mapping_symbol_s, map, idx); if (map_sym->value == map_key.value) { if (start) *start = map_sym->value + obj_section_addr (sec); return map_sym->type; } } if (idx > 0) { map_sym = VEC_index (arm_mapping_symbol_s, map, idx - 1); if (start) *start = map_sym->value + obj_section_addr (sec); return map_sym->type; } } } } return 0; } /* Determine if the program counter specified in MEMADDR is in a Thumb function. This function should be called for addresses unrelated to any executing frame; otherwise, prefer arm_frame_is_thumb. */ int arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr) { struct bound_minimal_symbol sym; char type; struct displaced_step_closure* dsc = get_displaced_step_closure_by_addr(memaddr); /* If checking the mode of displaced instruction in copy area, the mode should be determined by instruction on the original address. */ if (dsc) { if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: check mode of %.8lx instead of %.8lx\n", (unsigned long) dsc->insn_addr, (unsigned long) memaddr); memaddr = dsc->insn_addr; } /* If bit 0 of the address is set, assume this is a Thumb address. */ if (IS_THUMB_ADDR (memaddr)) return 1; /* Respect internal mode override if active. */ if (arm_override_mode != -1) return arm_override_mode; /* If the user wants to override the symbol table, let him. */ if (strcmp (arm_force_mode_string, "arm") == 0) return 0; if (strcmp (arm_force_mode_string, "thumb") == 0) return 1; /* ARM v6-M and v7-M are always in Thumb mode. */ if (gdbarch_tdep (gdbarch)->is_m) return 1; /* If there are mapping symbols, consult them. */ type = arm_find_mapping_symbol (memaddr, NULL); if (type) return type == 't'; /* Thumb functions have a "special" bit set in minimal symbols. */ sym = lookup_minimal_symbol_by_pc (memaddr); if (sym.minsym) return (MSYMBOL_IS_SPECIAL (sym.minsym)); /* If the user wants to override the fallback mode, let them. */ if (strcmp (arm_fallback_mode_string, "arm") == 0) return 0; if (strcmp (arm_fallback_mode_string, "thumb") == 0) return 1; /* If we couldn't find any symbol, but we're talking to a running target, then trust the current value of $cpsr. This lets "display/i $pc" always show the correct mode (though if there is a symbol table we will not reach here, so it still may not be displayed in the mode it will be executed). */ if (target_has_registers) return arm_frame_is_thumb (get_current_frame ()); /* Otherwise we're out of luck; we assume ARM. */ return 0; } /* Remove useless bits from addresses in a running program. */ static CORE_ADDR arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val) { /* On M-profile devices, do not strip the low bit from EXC_RETURN (the magic exception return address). */ if (gdbarch_tdep (gdbarch)->is_m && (val & 0xfffffff0) == 0xfffffff0) return val; if (arm_apcs_32) return UNMAKE_THUMB_ADDR (val); else return (val & 0x03fffffc); } /* Return 1 if PC is the start of a compiler helper function which can be safely ignored during prologue skipping. IS_THUMB is true if the function is known to be a Thumb function due to the way it is being called. */ static int skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb) { enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); struct bound_minimal_symbol msym; msym = lookup_minimal_symbol_by_pc (pc); if (msym.minsym != NULL && SYMBOL_VALUE_ADDRESS (msym.minsym) == pc && SYMBOL_LINKAGE_NAME (msym.minsym) != NULL) { const char *name = SYMBOL_LINKAGE_NAME (msym.minsym); /* The GNU linker's Thumb call stub to foo is named __foo_from_thumb. */ if (strstr (name, "_from_thumb") != NULL) name += 2; /* On soft-float targets, __truncdfsf2 is called to convert promoted arguments to their argument types in non-prototyped functions. */ if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0) return 1; if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0) return 1; /* Internal functions related to thread-local storage. */ if (strncmp (name, "__tls_get_addr", strlen ("__tls_get_addr")) == 0) return 1; if (strncmp (name, "__aeabi_read_tp", strlen ("__aeabi_read_tp")) == 0) return 1; } else { /* If we run against a stripped glibc, we may be unable to identify special functions by name. Check for one important case, __aeabi_read_tp, by comparing the *code* against the default implementation (this is hand-written ARM assembler in glibc). */ if (!is_thumb && read_memory_unsigned_integer (pc, 4, byte_order_for_code) == 0xe3e00a0f /* mov r0, #0xffff0fff */ && read_memory_unsigned_integer (pc + 4, 4, byte_order_for_code) == 0xe240f01f) /* sub pc, r0, #31 */ return 1; } return 0; } /* Support routines for instruction parsing. */ #define submask(x) ((1L << ((x) + 1)) - 1) #define bit(obj,st) (((obj) >> (st)) & 1) #define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st))) #define sbits(obj,st,fn) \ ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st)))) #define BranchDest(addr,instr) \ ((CORE_ADDR) (((unsigned long) (addr)) + 8 + (sbits (instr, 0, 23) << 2))) /* Extract the immediate from instruction movw/movt of encoding T. INSN1 is the first 16-bit of instruction, and INSN2 is the second 16-bit of instruction. */ #define EXTRACT_MOVW_MOVT_IMM_T(insn1, insn2) \ ((bits ((insn1), 0, 3) << 12) \ | (bits ((insn1), 10, 10) << 11) \ | (bits ((insn2), 12, 14) << 8) \ | bits ((insn2), 0, 7)) /* Extract the immediate from instruction movw/movt of encoding A. INSN is the 32-bit instruction. */ #define EXTRACT_MOVW_MOVT_IMM_A(insn) \ ((bits ((insn), 16, 19) << 12) \ | bits ((insn), 0, 11)) /* Decode immediate value; implements ThumbExpandImmediate pseudo-op. */ static unsigned int thumb_expand_immediate (unsigned int imm) { unsigned int count = imm >> 7; if (count < 8) switch (count / 2) { case 0: return imm & 0xff; case 1: return (imm & 0xff) | ((imm & 0xff) << 16); case 2: return ((imm & 0xff) << 8) | ((imm & 0xff) << 24); case 3: return (imm & 0xff) | ((imm & 0xff) << 8) | ((imm & 0xff) << 16) | ((imm & 0xff) << 24); } return (0x80 | (imm & 0x7f)) << (32 - count); } /* Return 1 if the 16-bit Thumb instruction INST might change control flow, 0 otherwise. */ static int thumb_instruction_changes_pc (unsigned short inst) { if ((inst & 0xff00) == 0xbd00) /* pop {rlist, pc} */ return 1; if ((inst & 0xf000) == 0xd000) /* conditional branch */ return 1; if ((inst & 0xf800) == 0xe000) /* unconditional branch */ return 1; if ((inst & 0xff00) == 0x4700) /* bx REG, blx REG */ return 1; if ((inst & 0xff87) == 0x4687) /* mov pc, REG */ return 1; if ((inst & 0xf500) == 0xb100) /* CBNZ or CBZ. */ return 1; return 0; } /* Return 1 if the 32-bit Thumb instruction in INST1 and INST2 might change control flow, 0 otherwise. */ static int thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2) { if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000) { /* Branches and miscellaneous control instructions. */ if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000) { /* B, BL, BLX. */ return 1; } else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00) { /* SUBS PC, LR, #imm8. */ return 1; } else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380) { /* Conditional branch. */ return 1; } return 0; } if ((inst1 & 0xfe50) == 0xe810) { /* Load multiple or RFE. */ if (bit (inst1, 7) && !bit (inst1, 8)) { /* LDMIA or POP */ if (bit (inst2, 15)) return 1; } else if (!bit (inst1, 7) && bit (inst1, 8)) { /* LDMDB */ if (bit (inst2, 15)) return 1; } else if (bit (inst1, 7) && bit (inst1, 8)) { /* RFEIA */ return 1; } else if (!bit (inst1, 7) && !bit (inst1, 8)) { /* RFEDB */ return 1; } return 0; } if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00) { /* MOV PC or MOVS PC. */ return 1; } if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000) { /* LDR PC. */ if (bits (inst1, 0, 3) == 15) return 1; if (bit (inst1, 7)) return 1; if (bit (inst2, 11)) return 1; if ((inst2 & 0x0fc0) == 0x0000) return 1; return 0; } if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000) { /* TBB. */ return 1; } if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010) { /* TBH. */ return 1; } return 0; } /* Analyze a Thumb prologue, looking for a recognizable stack frame and frame pointer. Scan until we encounter a store that could clobber the stack frame unexpectedly, or an unknown instruction. Return the last address which is definitely safe to skip for an initial breakpoint. */ static CORE_ADDR thumb_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR start, CORE_ADDR limit, struct arm_prologue_cache *cache) { enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); int i; pv_t regs[16]; struct pv_area *stack; struct cleanup *back_to; CORE_ADDR offset; CORE_ADDR unrecognized_pc = 0; for (i = 0; i < 16; i++) regs[i] = pv_register (i, 0); stack = make_pv_area (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch)); back_to = make_cleanup_free_pv_area (stack); while (start < limit) { unsigned short insn; insn = read_memory_unsigned_integer (start, 2, byte_order_for_code); if ((insn & 0xfe00) == 0xb400) /* push { rlist } */ { int regno; int mask; if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) break; /* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says whether to save LR (R14). */ mask = (insn & 0xff) | ((insn & 0x100) << 6); /* Calculate offsets of saved R0-R7 and LR. */ for (regno = ARM_LR_REGNUM; regno >= 0; regno--) if (mask & (1 << regno)) { regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4); pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]); } } else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */ { offset = (insn & 0x7f) << 2; /* get scaled offset */ if (insn & 0x80) /* Check for SUB. */ regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -offset); else regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], offset); } else if ((insn & 0xf800) == 0xa800) /* add Rd, sp, #imm */ regs[bits (insn, 8, 10)] = pv_add_constant (regs[ARM_SP_REGNUM], (insn & 0xff) << 2); else if ((insn & 0xfe00) == 0x1c00 /* add Rd, Rn, #imm */ && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM)) regs[bits (insn, 0, 2)] = pv_add_constant (regs[bits (insn, 3, 5)], bits (insn, 6, 8)); else if ((insn & 0xf800) == 0x3000 /* add Rd, #imm */ && pv_is_register (regs[bits (insn, 8, 10)], ARM_SP_REGNUM)) regs[bits (insn, 8, 10)] = pv_add_constant (regs[bits (insn, 8, 10)], bits (insn, 0, 7)); else if ((insn & 0xfe00) == 0x1800 /* add Rd, Rn, Rm */ && pv_is_register (regs[bits (insn, 6, 8)], ARM_SP_REGNUM) && pv_is_constant (regs[bits (insn, 3, 5)])) regs[bits (insn, 0, 2)] = pv_add (regs[bits (insn, 3, 5)], regs[bits (insn, 6, 8)]); else if ((insn & 0xff00) == 0x4400 /* add Rd, Rm */ && pv_is_constant (regs[bits (insn, 3, 6)])) { int rd = (bit (insn, 7) << 3) + bits (insn, 0, 2); int rm = bits (insn, 3, 6); regs[rd] = pv_add (regs[rd], regs[rm]); } else if ((insn & 0xff00) == 0x4600) /* mov hi, lo or mov lo, hi */ { int dst_reg = (insn & 0x7) + ((insn & 0x80) >> 4); int src_reg = (insn & 0x78) >> 3; regs[dst_reg] = regs[src_reg]; } else if ((insn & 0xf800) == 0x9000) /* str rd, [sp, #off] */ { /* Handle stores to the stack. Normally pushes are used, but with GCC -mtpcs-frame, there may be other stores in the prologue to create the frame. */ int regno = (insn >> 8) & 0x7; pv_t addr; offset = (insn & 0xff) << 2; addr = pv_add_constant (regs[ARM_SP_REGNUM], offset); if (pv_area_store_would_trash (stack, addr)) break; pv_area_store (stack, addr, 4, regs[regno]); } else if ((insn & 0xf800) == 0x6000) /* str rd, [rn, #off] */ { int rd = bits (insn, 0, 2); int rn = bits (insn, 3, 5); pv_t addr; offset = bits (insn, 6, 10) << 2; addr = pv_add_constant (regs[rn], offset); if (pv_area_store_would_trash (stack, addr)) break; pv_area_store (stack, addr, 4, regs[rd]); } else if (((insn & 0xf800) == 0x7000 /* strb Rd, [Rn, #off] */ || (insn & 0xf800) == 0x8000) /* strh Rd, [Rn, #off] */ && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM)) /* Ignore stores of argument registers to the stack. */ ; else if ((insn & 0xf800) == 0xc800 /* ldmia Rn!, { registers } */ && pv_is_register (regs[bits (insn, 8, 10)], ARM_SP_REGNUM)) /* Ignore block loads from the stack, potentially copying parameters from memory. */ ; else if ((insn & 0xf800) == 0x9800 /* ldr Rd, [Rn, #immed] */ || ((insn & 0xf800) == 0x6800 /* ldr Rd, [sp, #immed] */ && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM))) /* Similarly ignore single loads from the stack. */ ; else if ((insn & 0xffc0) == 0x0000 /* lsls Rd, Rm, #0 */ || (insn & 0xffc0) == 0x1c00) /* add Rd, Rn, #0 */ /* Skip register copies, i.e. saves to another register instead of the stack. */ ; else if ((insn & 0xf800) == 0x2000) /* movs Rd, #imm */ /* Recognize constant loads; even with small stacks these are necessary on Thumb. */ regs[bits (insn, 8, 10)] = pv_constant (bits (insn, 0, 7)); else if ((insn & 0xf800) == 0x4800) /* ldr Rd, [pc, #imm] */ { /* Constant pool loads, for the same reason. */ unsigned int constant; CORE_ADDR loc; loc = start + 4 + bits (insn, 0, 7) * 4; constant = read_memory_unsigned_integer (loc, 4, byte_order); regs[bits (insn, 8, 10)] = pv_constant (constant); } else if (thumb_insn_size (insn) == 4) /* 32-bit Thumb-2 instructions. */ { unsigned short inst2; inst2 = read_memory_unsigned_integer (start + 2, 2, byte_order_for_code); if ((insn & 0xf800) == 0xf000 && (inst2 & 0xe800) == 0xe800) { /* BL, BLX. Allow some special function calls when skipping the prologue; GCC generates these before storing arguments to the stack. */ CORE_ADDR nextpc; int j1, j2, imm1, imm2; imm1 = sbits (insn, 0, 10); imm2 = bits (inst2, 0, 10); j1 = bit (inst2, 13); j2 = bit (inst2, 11); offset = ((imm1 << 12) + (imm2 << 1)); offset ^= ((!j2) << 22) | ((!j1) << 23); nextpc = start + 4 + offset; /* For BLX make sure to clear the low bits. */ if (bit (inst2, 12) == 0) nextpc = nextpc & 0xfffffffc; if (!skip_prologue_function (gdbarch, nextpc, bit (inst2, 12) != 0)) break; } else if ((insn & 0xffd0) == 0xe900 /* stmdb Rn{!}, { registers } */ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) { pv_t addr = regs[bits (insn, 0, 3)]; int regno; if (pv_area_store_would_trash (stack, addr)) break; /* Calculate offsets of saved registers. */ for (regno = ARM_LR_REGNUM; regno >= 0; regno--) if (inst2 & (1 << regno)) { addr = pv_add_constant (addr, -4); pv_area_store (stack, addr, 4, regs[regno]); } if (insn & 0x0020) regs[bits (insn, 0, 3)] = addr; } else if ((insn & 0xff50) == 0xe940 /* strd Rt, Rt2, [Rn, #+/-imm]{!} */ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) { int regno1 = bits (inst2, 12, 15); int regno2 = bits (inst2, 8, 11); pv_t addr = regs[bits (insn, 0, 3)]; offset = inst2 & 0xff; if (insn & 0x0080) addr = pv_add_constant (addr, offset); else addr = pv_add_constant (addr, -offset); if (pv_area_store_would_trash (stack, addr)) break; pv_area_store (stack, addr, 4, regs[regno1]); pv_area_store (stack, pv_add_constant (addr, 4), 4, regs[regno2]); if (insn & 0x0020) regs[bits (insn, 0, 3)] = addr; } else if ((insn & 0xfff0) == 0xf8c0 /* str Rt,[Rn,+/-#imm]{!} */ && (inst2 & 0x0c00) == 0x0c00 && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) { int regno = bits (inst2, 12, 15); pv_t addr = regs[bits (insn, 0, 3)]; offset = inst2 & 0xff; if (inst2 & 0x0200) addr = pv_add_constant (addr, offset); else addr = pv_add_constant (addr, -offset); if (pv_area_store_would_trash (stack, addr)) break; pv_area_store (stack, addr, 4, regs[regno]); if (inst2 & 0x0100) regs[bits (insn, 0, 3)] = addr; } else if ((insn & 0xfff0) == 0xf8c0 /* str.w Rt,[Rn,#imm] */ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) { int regno = bits (inst2, 12, 15); pv_t addr; offset = inst2 & 0xfff; addr = pv_add_constant (regs[bits (insn, 0, 3)], offset); if (pv_area_store_would_trash (stack, addr)) break; pv_area_store (stack, addr, 4, regs[regno]); } else if ((insn & 0xffd0) == 0xf880 /* str{bh}.w Rt,[Rn,#imm] */ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) /* Ignore stores of argument registers to the stack. */ ; else if ((insn & 0xffd0) == 0xf800 /* str{bh} Rt,[Rn,#+/-imm] */ && (inst2 & 0x0d00) == 0x0c00 && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) /* Ignore stores of argument registers to the stack. */ ; else if ((insn & 0xffd0) == 0xe890 /* ldmia Rn[!], { registers } */ && (inst2 & 0x8000) == 0x0000 && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) /* Ignore block loads from the stack, potentially copying parameters from memory. */ ; else if ((insn & 0xffb0) == 0xe950 /* ldrd Rt, Rt2, [Rn, #+/-imm] */ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) /* Similarly ignore dual loads from the stack. */ ; else if ((insn & 0xfff0) == 0xf850 /* ldr Rt,[Rn,#+/-imm] */ && (inst2 & 0x0d00) == 0x0c00 && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) /* Similarly ignore single loads from the stack. */ ; else if ((insn & 0xfff0) == 0xf8d0 /* ldr.w Rt,[Rn,#imm] */ && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM)) /* Similarly ignore single loads from the stack. */ ; else if ((insn & 0xfbf0) == 0xf100 /* add.w Rd, Rn, #imm */ && (inst2 & 0x8000) == 0x0000) { unsigned int imm = ((bits (insn, 10, 10) << 11) | (bits (inst2, 12, 14) << 8) | bits (inst2, 0, 7)); regs[bits (inst2, 8, 11)] = pv_add_constant (regs[bits (insn, 0, 3)], thumb_expand_immediate (imm)); } else if ((insn & 0xfbf0) == 0xf200 /* addw Rd, Rn, #imm */ && (inst2 & 0x8000) == 0x0000) { unsigned int imm = ((bits (insn, 10, 10) << 11) | (bits (inst2, 12, 14) << 8) | bits (inst2, 0, 7)); regs[bits (inst2, 8, 11)] = pv_add_constant (regs[bits (insn, 0, 3)], imm); } else if ((insn & 0xfbf0) == 0xf1a0 /* sub.w Rd, Rn, #imm */ && (inst2 & 0x8000) == 0x0000) { unsigned int imm = ((bits (insn, 10, 10) << 11) | (bits (inst2, 12, 14) << 8) | bits (inst2, 0, 7)); regs[bits (inst2, 8, 11)] = pv_add_constant (regs[bits (insn, 0, 3)], - (CORE_ADDR) thumb_expand_immediate (imm)); } else if ((insn & 0xfbf0) == 0xf2a0 /* subw Rd, Rn, #imm */ && (inst2 & 0x8000) == 0x0000) { unsigned int imm = ((bits (insn, 10, 10) << 11) | (bits (inst2, 12, 14) << 8) | bits (inst2, 0, 7)); regs[bits (inst2, 8, 11)] = pv_add_constant (regs[bits (insn, 0, 3)], - (CORE_ADDR) imm); } else if ((insn & 0xfbff) == 0xf04f) /* mov.w Rd, #const */ { unsigned int imm = ((bits (insn, 10, 10) << 11) | (bits (inst2, 12, 14) << 8) | bits (inst2, 0, 7)); regs[bits (inst2, 8, 11)] = pv_constant (thumb_expand_immediate (imm)); } else if ((insn & 0xfbf0) == 0xf240) /* movw Rd, #const */ { unsigned int imm = EXTRACT_MOVW_MOVT_IMM_T (insn, inst2); regs[bits (inst2, 8, 11)] = pv_constant (imm); } else if (insn == 0xea5f /* mov.w Rd,Rm */ && (inst2 & 0xf0f0) == 0) { int dst_reg = (inst2 & 0x0f00) >> 8; int src_reg = inst2 & 0xf; regs[dst_reg] = regs[src_reg]; } else if ((insn & 0xff7f) == 0xf85f) /* ldr.w Rt,