X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Farm-tdep.c;h=12254ecebc703a4cee87dc05d1029afe7ed8be24;hb=2117c711ae07700adb57ea5b5ca61e4c32d7e3d2;hp=f6a84367a1b0c65faa5ed91a47edc37a35bcb690;hpb=0d39a07082291dc1bfc36568ea6a60a78739db41;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index f6a84367a1..12254ecebc 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -1,8 +1,6 @@ /* Common target dependent code for GDB on ARM systems. - Copyright (C) 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 1988-2014 Free Software Foundation, Inc. This file is part of GDB. @@ -19,16 +17,18 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include /* XXX for isupper () */ - #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 +#include "dis-asm.h" /* For register styles. */ #include "regcache.h" +#include "reggroups.h" #include "doublest.h" #include "value.h" #include "arch-utils.h" @@ -40,8 +40,10 @@ #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" @@ -53,6 +55,17 @@ #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 @@ -62,7 +75,7 @@ static int arm_debug; MSYMBOL_SET_SPECIAL Actually sets the "special" bit. MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol. */ -#define MSYMBOL_SET_SPECIAL(msym) \ +#define MSYMBOL_SET_SPECIAL(msym) \ MSYMBOL_TARGET_FLAG_1 (msym) = 1 #define MSYMBOL_IS_SPECIAL(msym) \ @@ -90,7 +103,7 @@ 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 *fp_model_strings[] = +static const char *const fp_model_strings[] = { "auto", "softfpa", @@ -105,7 +118,7 @@ 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 *arm_abi_strings[] = +static const char *const arm_abi_strings[] = { "auto", "APCS", @@ -118,20 +131,31 @@ 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 *arm_mode_strings[] = +static const char *const arm_mode_strings[] = { "auto", "arm", - "thumb" + "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. */ +/* 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; @@ -172,12 +196,9 @@ static const struct { "tr", 9 }, /* Special names. */ { "ip", 12 }, - { "sp", 13 }, { "lr", 14 }, - { "pc", 15 }, /* Names used by GCC (not listed in the ARM EABI). */ { "sl", 10 }, - { "fp", 11 }, /* A special name from the older ATPCS. */ { "wr", 7 }, }; @@ -208,13 +229,15 @@ static void convert_from_extended (const struct floatformat *, const void *, static void convert_to_extended (const struct floatformat *, void *, const void *, int); -static void arm_neon_quad_read (struct gdbarch *gdbarch, - struct regcache *regcache, - int regnum, gdb_byte *buf); +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 @@ -255,12 +278,24 @@ static CORE_ADDR arm_analyze_prologue (struct gdbarch *gdbarch, 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. */ -static int +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 @@ -268,7 +303,7 @@ arm_frame_is_thumb (struct frame_info *frame) trust the unwinders. */ cpsr = get_frame_register_unsigned (frame, ARM_PS_REGNUM); - return (cpsr & CPSR_T) != 0; + return (cpsr & t_bit) != 0; } /* Callback for VEC_lower_bound. */ @@ -339,30 +374,48 @@ arm_find_mapping_symbol (CORE_ADDR memaddr, CORE_ADDR *start) return 0; } -static CORE_ADDR arm_get_next_pc_raw (struct frame_info *frame, - CORE_ADDR pc, int insert_bkpt); - /* 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. */ -static int -arm_pc_is_thumb (CORE_ADDR memaddr) +int +arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr) { - struct obj_section *sec; - struct minimal_symbol *sym; + 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) @@ -370,8 +423,8 @@ arm_pc_is_thumb (CORE_ADDR memaddr) /* Thumb functions have a "special" bit set in minimal symbols. */ sym = lookup_minimal_symbol_by_pc (memaddr); - if (sym) - return (MSYMBOL_IS_SPECIAL (sym)); + 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) @@ -383,29 +436,9 @@ arm_pc_is_thumb (CORE_ADDR memaddr) 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). - - As a further heuristic if we detect that we are doing a single-step we - see what state executing the current instruction ends up with us being - in. */ + displayed in the mode it will be executed). */ if (target_has_registers) - { - struct frame_info *current_frame = get_current_frame (); - CORE_ADDR current_pc = get_frame_pc (current_frame); - int is_thumb = arm_frame_is_thumb (current_frame); - CORE_ADDR next_pc; - if (memaddr == current_pc) - return is_thumb; - else - { - struct gdbarch *gdbarch = get_frame_arch (current_frame); - next_pc = arm_get_next_pc_raw (current_frame, current_pc, FALSE); - if (memaddr == gdbarch_addr_bits_remove (gdbarch, next_pc)) - return IS_THUMB_ADDR (next_pc); - else - return is_thumb; - } - } + return arm_frame_is_thumb (get_current_frame ()); /* Otherwise we're out of luck; we assume ARM. */ return 0; @@ -415,48 +448,68 @@ arm_pc_is_thumb (CORE_ADDR memaddr) 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); } -/* When reading symbols, we need to zap the low bit of the address, - which may be set to 1 for Thumb functions. */ -static CORE_ADDR -arm_smash_text_address (struct gdbarch *gdbarch, CORE_ADDR val) -{ - return val & ~1; -} - /* Return 1 if PC is the start of a compiler helper function which - can be safely ignored during prologue skipping. */ + 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 (CORE_ADDR pc) +skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb) { - struct minimal_symbol *msym; - const char *name; + 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 == NULL || SYMBOL_VALUE_ADDRESS (msym) != pc) - return 0; + if (msym.minsym != NULL + && SYMBOL_VALUE_ADDRESS (msym.minsym) == pc + && SYMBOL_LINKAGE_NAME (msym.minsym) != NULL) + { + const char *name = SYMBOL_LINKAGE_NAME (msym.minsym); - name = SYMBOL_LINKAGE_NAME (msym); - if (name == NULL) - return 0; + /* The GNU linker's Thumb call stub to foo is named + __foo_from_thumb. */ + if (strstr (name, "_from_thumb") != NULL) + name += 2; - /* 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; - /* 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; } @@ -468,7 +521,168 @@ skip_prologue_function (CORE_ADDR pc) #define sbits(obj,st,fn) \ ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st)))) #define BranchDest(addr,instr) \ - ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2))) + ((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 @@ -488,6 +702,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, 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); @@ -625,9 +840,8 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, constant = read_memory_unsigned_integer (loc, 4, byte_order); regs[bits (insn, 8, 10)] = pv_constant (constant); } - else if ((insn & 0xe000) == 0xe000 && cache == NULL) + else if (thumb_insn_size (insn) == 4) /* 32-bit Thumb-2 instructions. */ { - /* Only recognize 32-bit instructions for prologue skipping. */ unsigned short inst2; inst2 = read_memory_unsigned_integer (start + 2, 2, @@ -654,62 +868,263 @@ thumb_analyze_prologue (struct gdbarch *gdbarch, if (bit (inst2, 12) == 0) nextpc = nextpc & 0xfffffffc; - if (!skip_prologue_function (nextpc)) + 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 & 0xfe50) == 0xe800 /* stm{db,ia} Rn[!], { registers } */ + + 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 & 0xfe50) == 0xe840 /* strd Rt, Rt2, [Rn, #imm] */ + + 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)) + + 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 & 0xfbf0) == 0xf100 /* add.w Rd, Rn, #imm */ - && (inst2 & 0x8000) == 0x0000) - /* Since we only recognize this for prologue skipping, do not bother - to compute the constant. */ - regs[bits (inst2, 8, 11)] = regs[bits (insn, 0, 3)]; - else if ((insn & 0xfbf0) == 0xf1a0 /* sub.w Rd, Rn, #imm12 */ - && (inst2 & 0x8000) == 0x0000) - /* Since we only recognize this for prologue skipping, do not bother - to compute the constant. */ - regs[bits (inst2, 8, 11)] = regs[bits (insn, 0, 3)]; - else if ((insn & 0xfbf0) == 0xf2a0 /* sub.w Rd, Rn, #imm8 */ - && (inst2 & 0x8000) == 0x0000) - /* Since we only recognize this for prologue skipping, do not bother - to compute the constant. */ - regs[bits (inst2, 8, 11)] = regs[bits (insn, 0, 3)]; - else if ((insn & 0xff50) == 0xf850 /* ldr.w Rd, [Rn, #imm]{!} */ + + 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 & 0xff50) == 0xe950 /* ldrd Rt, Rt2, [Rn, #imm]{!} */ + + 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 & 0xff50) == 0xf800 /* strb.w or strh.w */ + + 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 + + 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,