| /* Common target dependent code for GDB on ARM systems. |
| |
| Copyright (C) 1988-1989, 1991-1993, 1995-1996, 1998-2012 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 <http://www.gnu.org/licenses/>. */ |
| |
| #include <ctype.h> /* XXX for isupper (). */ |
| |
| #include "defs.h" |
| #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 "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 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) |
| return (MSYMBOL_IS_SPECIAL (sym)); |
| |
| /* 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) |
| { |
| 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. 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 minimal_symbol *msym; |
| |
| msym = lookup_minimal_symbol_by_pc (pc); |
| if (msym != NULL |
| && SYMBOL_VALUE_ADDRESS (msym) == pc |
| && SYMBOL_LINKAGE_NAME (msym) != NULL) |
| { |
| const char *name = SYMBOL_LINKAGE_NAME (msym); |
| |
| /* 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) (((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,<label> */ |
| { |
| /* Constant pool loads. */ |
| unsigned int constant; |
| CORE_ADDR loc; |
| |
| offset = bits (insn, 0, 11); |
| if (insn & 0x0080) |
| loc = start + 4 + offset; |
| else |
| loc = start + 4 - offset; |
| |
| constant = read_memory_unsigned_integer (loc, 4, byte_order); |
| regs[bits (inst2, 12, 15)] = pv_constant (constant); |
| } |
| |
| else if ((insn & 0xff7f) == 0xe95f) /* ldrd Rt,Rt2,<label> */ |
| { |
| /* Constant pool loads. */ |
| unsigned int constant; |
| CORE_ADDR loc; |
| |
| offset = bits (insn, 0, 7) << 2; |
| if (insn & 0x0080) |
| loc = start + 4 + offset; |
| else |
| loc = start + 4 - offset; |
| |
| constant = read_memory_unsigned_integer (loc, 4, byte_order); |
| regs[bits (inst2, 12, 15)] = pv_constant (constant); |
| |
| constant = read_memory_unsigned_integer (loc + 4, 4, byte_order); |
| regs[bits (inst2, 8, 11)] = pv_constant (constant); |
| } |
| |
| else if (thumb2_instruction_changes_pc (insn, inst2)) |
| { |
| /* Don't scan past anything that might change control flow. */ |
| break; |
| } |
| else |
| { |
| /* The optimizer might shove anything into the prologue, |
| so we just skip what we don't recognize. */ |
| unrecognized_pc = start; |
| } |
| |
| start += 2; |
| } |
| else if (thumb_instruction_changes_pc (insn)) |
| { |
| /* Don't scan past anything that might change control flow. */ |
| break; |
| } |
| else |
| { |
| /* The optimizer might shove anything into the prologue, |
| so we just skip what we don't recognize. */ |
| unrecognized_pc = start; |
| } |
| |
| start += 2; |
| } |
| |
| if (arm_debug) |
| fprintf_unfiltered (gdb_stdlog, "Prologue scan stopped at %s\n", |
| paddress (gdbarch, start)); |
| |
| if (unrecognized_pc == 0) |
| unrecognized_pc = start; |
| |
| if (cache == NULL) |
| { |
| do_cleanups (back_to); |
| return unrecognized_pc; |
| } |
| |
| if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM)) |
| { |
| /* Frame pointer is fp. Frame size is constant. */ |
| cache->framereg = ARM_FP_REGNUM; |
| cache->framesize = -regs[ARM_FP_REGNUM].k; |
| } |
| else if (pv_is_register (regs[THUMB_FP_REGNUM], ARM_SP_REGNUM)) |
| { |
| /* Frame pointer is r7. Frame size is constant. */ |
| cache->framereg = THUMB_FP_REGNUM; |
| cache->framesize = -regs[THUMB_FP_REGNUM].k; |
| } |
| else |
| { |
| /* Try the stack pointer... this is a bit desperate. */ |
| cache->framereg = ARM_SP_REGNUM; |
| cache->framesize = -regs[ARM_SP_REGNUM].k; |
| } |
| |
| for (i = 0; i < 16; i++) |
| if (pv_area_find_reg (stack, gdbarch, i, &offset)) |
| cache->saved_regs[i].addr = offset; |
| |
| do_cleanups (back_to); |
| return unrecognized_pc; |
| } |
| |
| |
| /* Try to analyze the instructions starting from PC, which load symbol |
| __stack_chk_guard. Return the address of instruction after loading this |
| symbol, set the dest register number to *BASEREG, and set the size of |
| instructions for loading symbol in OFFSET. Return 0 if instructions are |
| not recognized. */ |
| |
| static CORE_ADDR |
| arm_analyze_load_stack_chk_guard(CORE_ADDR pc, struct gdbarch *gdbarch, |
| unsigned int *destreg, int *offset) |
| { |
| enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); |
| int is_thumb = arm_pc_is_thumb (gdbarch, pc); |
| unsigned int low, high, address; |
| |
| address = 0; |
| if (is_thumb) |
| { |
| unsigned short insn1 |
| = read_memory_unsigned_integer (pc, 2, byte_order_for_code); |
| |
| if ((insn1 & 0xf800) == 0x4800) /* ldr Rd, #immed */ |
| { |
| *destreg = bits (insn1, 8, 10); |
| *offset = 2; |
| address = bits (insn1, 0, 7); |
| } |
| else if ((insn1 & 0xfbf0) == 0xf240) /* movw Rd, #const */ |
| { |
| unsigned short insn2 |
| = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code); |
| |
| low = EXTRACT_MOVW_MOVT_IMM_T (insn1, insn2); |
| |
| insn1 |
| = read_memory_unsigned_integer (pc + 4, 2, byte_order_for_code); |
| insn2 |
| = read_memory_unsigned_integer (pc + 6, 2, byte_order_for_code); |
| |
| /* movt Rd, #const */ |
| if ((insn1 & 0xfbc0) == 0xf2c0) |
| { |
| high = EXTRACT_MOVW_MOVT_IMM_T (insn1, insn2); |
| *destreg = bits (insn2, 8, 11); |
| *offset = 8; |
| address = (high << 16 | low); |
| } |
| } |
| } |
| else |
| { |
| unsigned int insn |
| = read_memory_unsigned_integer (pc, 4, byte_order_for_code); |
| |
| if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, #immed */ |
| { |
| address = bits (insn, 0, 11); |
| *destreg = bits (insn, 12, 15); |
| *offset = 4; |
| } |
| else if ((insn & 0x0ff00000) == 0x03000000) /* movw Rd, #const */ |
| { |
| low = EXTRACT_MOVW_MOVT_IMM_A (insn); |
| |
| insn |
| = read_memory_unsigned_integer (pc + 4, 4, byte_order_for_code); |
| |
| if ((insn & 0x0ff00000) == 0x03400000) /* movt Rd, #const */ |
| { |
| high = EXTRACT_MOVW_MOVT_IMM_A (insn); |
| *destreg = bits (insn, 12, 15); |
| *offset = 8; |
| address = (high << 16 | low); |
| } |
| } |
| } |
| |
| return address; |
| } |
| |
| /* Try to skip a sequence of instructions used for stack protector. If PC |
| points to the first instruction of this sequence, return the address of |
| first instruction after this sequence, otherwise, return original PC. |
| |
| On arm, this sequence of instructions is composed of mainly three steps, |
| Step 1: load symbol __stack_chk_guard, |
| Step 2: load from address of __stack_chk_guard, |
| Step 3: store it to somewhere else. |
| |
| Usually, instructions on step 2 and step 3 are the same on various ARM |
| architectures. On step 2, it is one instruction 'ldr Rx, [Rn, #0]', and |
| on step 3, it is also one instruction 'str Rx, [r7, #immd]'. However, |
| instructions in step 1 vary from different ARM architectures. On ARMv7, |
| they are, |
| |
| movw Rn, #:lower16:__stack_chk_guard |
| movt Rn, #:upper16:__stack_chk_guard |
| |
| On ARMv5t, it is, |
| |
| ldr Rn, .Label |
| .... |
| .Lable: |
| .word __stack_chk_guard |
| |
| Since ldr/str is a very popular instruction, we can't use them as |
| 'fingerprint' or 'signature' of stack protector sequence. Here we choose |
| sequence {movw/movt, ldr}/ldr/str plus symbol __stack_chk_guard, if not |
| stripped, as the 'fingerprint' of a stack protector cdoe sequence. */ |
| |
| static CORE_ADDR |
| arm_skip_stack_protector(CORE_ADDR pc, struct gdbarch *gdbarch) |
| { |
| enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); |
| unsigned int basereg; |
| struct minimal_symbol *stack_chk_guard; |
| int offset; |
| int is_thumb = arm_pc_is_thumb (gdbarch, pc); |
| CORE_ADDR addr; |
| |
| /* Try to parse the instructions in Step 1. */ |
| addr = arm_analyze_load_stack_chk_guard (pc, gdbarch, |
| &basereg, &offset); |
| if (!addr) |
| return pc; |
| |
| stack_chk_guard = lookup_minimal_symbol_by_pc (addr); |
| /* If name of symbol doesn't start with '__stack_chk_guard', this |
| instruction sequence is not for stack protector. If symbol is |
| removed, we conservatively think this sequence is for stack protector. */ |
| if (stack_chk_guard |
| && strncmp (SYMBOL_LINKAGE_NAME (stack_chk_guard), "__stack_chk_guard", |
| strlen ("__stack_chk_guard")) != 0) |
| return pc; |
| |
| if (is_thumb) |
| { |
| unsigned int destreg; |
| unsigned short insn |
| = read_memory_unsigned_integer (pc + offset, 2, byte_order_for_code); |
| |
| /* Step 2: ldr Rd, [Rn, #immed], encoding T1. */ |
| if ((insn & 0xf800) != 0x6800) |
| return pc; |
| if (bits (insn, 3, 5) != basereg) |
| return pc; |
| destreg = bits (insn, 0, 2); |
| |
| insn = read_memory_unsigned_integer (pc + offset + 2, 2, |
| byte_order_for_code); |
| /* Step 3: str Rd, [Rn, #immed], encoding T1. */ |
| if ((insn & 0xf800) != 0x6000) |
| return pc; |
| if (destreg != bits (insn, 0, 2)) |
| return pc; |
| } |
| else |
| { |
| unsigned int destreg; |
| unsigned int insn |
| = read_memory_unsigned_integer (pc + offset, 4, byte_order_for_code); |
| |
| /* Step 2: ldr Rd, [Rn, #immed], encoding A1. */ |
| if ((insn & 0x0e500000) != 0x04100000) |
| return pc; |
| if (bits (insn, 16, 19) != basereg) |
| return pc; |
| destreg = bits (insn, 12, 15); |
| /* Step 3: str Rd, [Rn, #immed], encoding A1. */ |
| insn = read_memory_unsigned_integer (pc + offset + 4, |
| 4, byte_order_for_code); |
| if ((insn & 0x0e500000) != 0x04000000) |
| return pc; |
| if (bits (insn, 12, 15) != destreg) |
| return pc; |
| } |
| /* The size of total two instructions ldr/str is 4 on Thumb-2, while 8 |
| on arm. */ |
| if (is_thumb) |
| return pc + offset + 4; |
| else |
| return pc + offset + 8; |
| } |
| |
| /* Advance the PC across any function entry prologue instructions to |
| reach some "real" code. |
| |
| The APCS (ARM Procedure Call Standard) defines the following |
| prologue: |
| |
| mov ip, sp |
| [stmfd sp!, {a1,a2,a3,a4}] |
| stmfd sp!, {...,fp,ip,lr,pc} |
| [stfe f7, [sp, #-12]!] |
| [stfe f6, [sp, #-12]!] |
| [stfe f5, [sp, #-12]!] |
| [stfe f4, [sp, #-12]!] |
| sub fp, ip, #nn @@ nn == 20 or 4 depending on second insn. */ |
| |
| static CORE_ADDR |
| arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) |
| { |
| enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); |
| unsigned long inst; |
| CORE_ADDR skip_pc; |
| CORE_ADDR func_addr, limit_pc; |
| |
| /* See if we can determine the end of the prologue via the symbol table. |
| If so, then return either PC, or the PC after the prologue, whichever |
| is greater. */ |
| if (find_pc_partial_function (pc, NULL, &func_addr, NULL)) |
| { |
| CORE_ADDR post_prologue_pc |
| = skip_prologue_using_sal (gdbarch, func_addr); |
| struct symtab *s = find_pc_symtab (func_addr); |
| |
| if (post_prologue_pc) |
| post_prologue_pc |
| = arm_skip_stack_protector (post_prologue_pc, gdbarch); |
| |
| |
| /* GCC always emits a line note before the prologue and another |
| one after, even if the two are at the same address or on the |
| same line. Take advantage of this so that we do not need to |
| know every instruction that might appear in the prologue. We |
| will have producer information for most binaries; if it is |
| missing (e.g. for -gstabs), assuming the GNU tools. */ |
| if (post_prologue_pc |
| && (s == NULL |
| || s->producer == NULL |
| || strncmp (s->producer, "GNU ", sizeof ("GNU ") - 1) == 0)) |
| return post_prologue_pc; |
| |
| if (post_prologue_pc != 0) |
| { |
| CORE_ADDR analyzed_limit; |
| |
| /* For non-GCC compilers, make sure the entire line is an |
| acceptable prologue; GDB will round this function's |
| return value up to the end of the following line so we |
| can not skip just part of a line (and we do not want to). |
| |
| RealView does not treat the prologue specially, but does |
| associate prologue code with the opening brace; so this |
| lets us skip the first line if we think it is the opening |
| brace. */ |
| if (arm_pc_is_thumb (gdbarch, func_addr)) |
| analyzed_limit = thumb_analyze_prologue (gdbarch, func_addr, |
| post_prologue_pc, NULL); |
| else |
| analyzed_limit = arm_analyze_prologue (gdbarch, func_addr, |
| post_prologue_pc, NULL); |
| |
| if (analyzed_limit != post_prologue_pc) |
| return func_addr; |
| |
| return post_prologue_pc; |
| } |
| } |
| |
| /* Can't determine prologue from the symbol table, need to examine |
| instructions. */ |
| |
| /* Find an upper limit on the function prologue using the debug |
| information. If the debug information could not be used to provide |
| that bound, then use an arbitrary large number as the upper bound. */ |
| /* Like arm_scan_prologue, stop no later than pc + 64. */ |
| limit_pc = skip_prologue_using_sal (gdbarch, pc); |
| if (limit_pc == 0) |
| limit_pc = pc + 64; /* Magic. */ |
| |
| |
| /* Check if this is Thumb code. */ |
| if (arm_pc_is_thumb (gdbarch, pc)) |
| return thumb_analyze_prologue (gdbarch, pc, limit_pc, NULL); |
| |
| for (skip_pc = pc; skip_pc < limit_pc; skip_pc += 4) |
| { |
| inst = read_memory_unsigned_integer (skip_pc, 4, byte_order_for_code); |
| |
| /* "mov ip, sp" is no longer a required part of the prologue. */ |
| if (inst == 0xe1a0c00d) /* mov ip, sp */ |
| continue; |
| |
| if ((inst & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */ |
| continue; |
| |
| if ((inst & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */ |
| continue; |
| |
| /* Some prologues begin with "str lr, [sp, #-4]!". */ |
| if (inst == 0xe52de004) /* str lr, [sp, #-4]! */ |
| continue; |
| |
| if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */ |
| continue; |
| |
| if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */ |
| continue; |
| |
| /* Any insns after this point may float into the code, if it makes |
| for better instruction scheduling, so we skip them only if we |
| find them, but still consider the function to be frame-ful. */ |
| |
| /* We may have either one sfmfd instruction here, or several stfe |
| insns, depending on the version of floating point code we |
| support. */ |
| if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, <cnt>, [sp]! */ |
| continue; |
| |
| if ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */ |
| continue; |
| |
| if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */ |
| continue; |
| |
| if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */ |
| continue; |
| |
| if ((inst & 0xffffc000) == 0xe54b0000 /* strb r(0123),[r11,#-nn] */ |
| || (inst & 0xffffc0f0) == 0xe14b00b0 /* strh r(0123),[r11,#-nn] */ |
| || (inst & 0xffffc000) == 0xe50b0000) /* str r(0123),[r11,#-nn] */ |
| continue; |
| |
| if ((inst & 0xffffc000) == 0xe5cd0000 /* strb r(0123),[sp,#nn] */ |
| || (inst & 0xffffc0f0) == 0xe1cd00b0 /* strh r(0123),[sp,#nn] */ |
| || (inst & 0xffffc000) == 0xe58d0000) /* str r(0123),[sp,#nn] */ |
| continue; |
| |
| /* Un-recognized instruction; stop scanning. */ |
| break; |
| } |
| |
| return skip_pc; /* End of prologue. */ |
| } |
| |
| /* *INDENT-OFF* */ |
| /* Function: thumb_scan_prologue (helper function for arm_scan_prologue) |
| This function decodes a Thumb function prologue to determine: |
| 1) the size of the stack frame |
| 2) which registers are saved on it |
| 3) the offsets of saved regs |
| 4) the offset from the stack pointer to the frame pointer |
| |
| A typical Thumb function prologue would create this stack frame |
| (offsets relative to FP) |
| old SP -> 24 stack parameters |
| 20 LR |
| 16 R7 |
| R7 -> 0 local variables (16 bytes) |
| SP -> -12 additional stack space (12 bytes) |
| The frame size would thus be 36 bytes, and the frame offset would be |
| 12 bytes. The frame register is R7. |
| |
| The comments for thumb_skip_prolog() describe the algorithm we use |
| to detect the end of the prolog. */ |
| /* *INDENT-ON* */ |
| |
| static void |
| thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc, |
| CORE_ADDR block_addr, struct arm_prologue_cache *cache) |
| { |
| CORE_ADDR prologue_start; |
| CORE_ADDR prologue_end; |
| |
| if (find_pc_partial_function (block_addr, NULL, &prologue_start, |
| &prologue_end)) |
| { |
| /* See comment in arm_scan_prologue for an explanation of |
| this heuristics. */ |
| if (prologue_end > prologue_start + 64) |
| { |
| prologue_end = prologue_start + 64; |
| } |
| } |
| else |
| /* We're in the boondocks: we have no idea where the start of the |
| function is. */ |
| return; |
| |
| prologue_end = min (prologue_end, prev_pc); |
| |
| thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache); |
| } |
| |
| /* Return 1 if THIS_INSTR might change control flow, 0 otherwise. */ |
| |
| static int |
| arm_instruction_changes_pc (uint32_t this_instr) |
| { |
| if (bits (this_instr, 28, 31) == INST_NV) |
| /* Unconditional instructions. */ |
| switch (bits (this_instr, 24, 27)) |
| { |
| case 0xa: |
| case 0xb: |
| /* Branch with Link and change to Thumb. */ |
| return 1; |
| case 0xc: |
| case 0xd: |
| case 0xe: |
| /* Coprocessor register transfer. */ |
| if (bits (this_instr, 12, 15) == 15) |
| error (_("Invalid update to pc in instruction")); |
| return 0; |
| default: |
| return 0; |
| } |
| else |
| switch (bits (this_instr, 25, 27)) |
| { |
| case 0x0: |
| if (bits (this_instr, 23, 24) == 2 && bit (this_instr, 20) == 0) |
| { |
| /* Multiplies and extra load/stores. */ |
| if (bit (this_instr, 4) == 1 && bit (this_instr, 7) == 1) |
| /* Neither multiplies nor extension load/stores are allowed |
| to modify PC. */ |
| return 0; |
| |
| /* Otherwise, miscellaneous instructions. */ |
| |
| /* BX <reg>, BXJ <reg>, BLX <reg> */ |
| if (bits (this_instr, 4, 27) == 0x12fff1 |
| || bits (this_instr, 4, 27) == 0x12fff2 |
| || bits (this_instr, 4, 27) == 0x12fff3) |
| return 1; |
| |
| /* Other miscellaneous instructions are unpredictable if they |
| modify PC. */ |
| return 0; |
| } |
| /* Data processing instruction. Fall through. */ |
| |
| case 0x1: |
| if (bits (this_instr, 12, 15) == 15) |
| return 1; |
| else |
| return 0; |
| |
| case 0x2: |
| case 0x3: |
| /* Media instructions and architecturally undefined instructions. */ |
| if (bits (this_instr, 25, 27) == 3 && bit (this_instr, 4) == 1) |
| return 0; |
| |
| /* Stores. */ |
| if (bit (this_instr, 20) == 0) |
| return 0; |
| |
| /* Loads. */ |
| if (bits (this_instr, 12, 15) == ARM_PC_REGNUM) |
| return 1; |
| else |
| return 0; |
| |
| case 0x4: |
| /* Load/store multiple. */ |
| if (bit (this_instr, 20) == 1 && bit (this_instr, 15) == 1) |
| return 1; |
| else |
| return 0; |
| |
| case 0x5: |
| /* Branch and branch with link. */ |
| return 1; |
| |
| case 0x6: |
| case 0x7: |
| /* Coprocessor transfers or SWIs can not affect PC. */ |
| return 0; |
| |
| default: |
| internal_error (__FILE__, __LINE__, _("bad value in switch")); |
| } |
| } |
| |
| /* Analyze an ARM mode prologue starting at PROLOGUE_START and |
| continuing no further than PROLOGUE_END. If CACHE is non-NULL, |
| fill it in. Return the first address not recognized as a prologue |
| instruction. |
| |
| We recognize all the instructions typically found in ARM prologues, |
| plus harmless instructions which can be skipped (either for analysis |
| purposes, or a more restrictive set that can be skipped when finding |
| the end of the prologue). */ |
| |
| static CORE_ADDR |
| arm_analyze_prologue (struct gdbarch *gdbarch, |
| CORE_ADDR prologue_start, CORE_ADDR prologue_end, |
| 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 regno; |
| CORE_ADDR offset, current_pc; |
| pv_t regs[ARM_FPS_REGNUM]; |
| struct pv_area *stack; |
| struct cleanup *back_to; |
| int framereg, framesize; |
| CORE_ADDR unrecognized_pc = 0; |
| |
| /* Search the prologue looking for instructions that set up the |
| frame pointer, adjust the stack pointer, and save registers. |
| |
| Be careful, however, and if it doesn't look like a prologue, |
| don't try to scan it. If, for instance, a frameless function |
| begins with stmfd sp!, then we will tell ourselves there is |
| a frame, which will confuse stack traceback, as well as "finish" |
| and other operations that rely on a knowledge of the stack |
| traceback. */ |
| |
| for (regno = 0; regno < ARM_FPS_REGNUM; regno++) |
| regs[regno] = pv_register (regno, 0); |
| stack = make_pv_area (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch)); |
| back_to = make_cleanup_free_pv_area (stack); |
| |
| for (current_pc = prologue_start; |
| current_pc < prologue_end; |
| current_pc += 4) |
| { |
| unsigned int insn |
| = read_memory_unsigned_integer (current_pc, 4, byte_order_for_code); |
| |
| if (insn == 0xe1a0c00d) /* mov ip, sp */ |
| { |
| regs[ARM_IP_REGNUM] = regs[ARM_SP_REGNUM]; |
| continue; |
| } |
| else if ((insn & 0xfff00000) == 0xe2800000 /* add Rd, Rn, #n */ |
| && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM)) |
| { |
| unsigned imm = insn & 0xff; /* immediate value */ |
| unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ |
| int rd = bits (insn, 12, 15); |
| imm = (imm >> rot) | (imm << (32 - rot)); |
| regs[rd] = pv_add_constant (regs[bits (insn, 16, 19)], imm); |
| continue; |
| } |
| else if ((insn & 0xfff00000) == 0xe2400000 /* sub Rd, Rn, #n */ |
| && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM)) |
| { |
| unsigned imm = insn & 0xff; /* immediate value */ |
| unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ |
| int rd = bits (insn, 12, 15); |
| imm = (imm >> rot) | (imm << (32 - rot)); |
| regs[rd] = pv_add_constant (regs[bits (insn, 16, 19)], -imm); |
| continue; |
| } |
| else if ((insn & 0xffff0fff) == 0xe52d0004) /* str Rd, |
| [sp, #-4]! */ |
| { |
| if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) |
| break; |
| regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4); |
| pv_area_store (stack, regs[ARM_SP_REGNUM], 4, |
| regs[bits (insn, 12, 15)]); |
| continue; |
| } |
| else if ((insn & 0xffff0000) == 0xe92d0000) |
| /* stmfd sp!, {..., fp, ip, lr, pc} |
| or |
| stmfd sp!, {a1, a2, a3, a4} */ |
| { |
| int mask = insn & 0xffff; |
| |
| if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) |
| break; |
| |
| /* Calculate offsets of saved registers. */ |
| for (regno = ARM_PC_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 & 0xffff0000) == 0xe54b0000 /* strb rx,[r11,#-n] */ |
| || (insn & 0xffff00f0) == 0xe14b00b0 /* strh rx,[r11,#-n] */ |
| || (insn & 0xffffc000) == 0xe50b0000) /* str rx,[r11,#-n] */ |
| { |
| /* No need to add this to saved_regs -- it's just an arg reg. */ |
| continue; |
| } |
| else if ((insn & 0xffff0000) == 0xe5cd0000 /* strb rx,[sp,#n] */ |
| || (insn & 0xffff00f0) == 0xe1cd00b0 /* strh rx,[sp,#n] */ |
| || (insn & 0xffffc000) == 0xe58d0000) /* str rx,[sp,#n] */ |
| { |
| /* No need to add this to saved_regs -- it's just an arg reg. */ |
| continue; |
| } |
| else if ((insn & 0xfff00000) == 0xe8800000 /* stm Rn, |
| { registers } */ |
| && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM)) |
| { |
| /* No need to add this to saved_regs -- it's just arg regs. */ |
| continue; |
| } |
| else if ((insn & 0xfffff000) == 0xe24cb000) /* sub fp, ip #n */ |
| { |
| unsigned imm = insn & 0xff; /* immediate value */ |
| unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ |
| imm = (imm >> rot) | (imm << (32 - rot)); |
| regs[ARM_FP_REGNUM] = pv_add_constant (regs[ARM_IP_REGNUM], -imm); |
| } |
| else if ((insn & 0xfffff000) == 0xe24dd000) /* sub sp, sp #n */ |
| { |
| unsigned imm = insn & 0xff; /* immediate value */ |
| unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ |
| imm = (imm >> rot) | (imm << (32 - rot)); |
| regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm); |
| } |
| else if ((insn & 0xffff7fff) == 0xed6d0103 /* stfe f?, |
| [sp, -#c]! */ |
| && gdbarch_tdep (gdbarch)->have_fpa_registers) |
| { |
| if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) |
| break; |
| |
| regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12); |
| regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07); |
| pv_area_store (stack, regs[ARM_SP_REGNUM], 12, regs[regno]); |
| } |
| else if ((insn & 0xffbf0fff) == 0xec2d0200 /* sfmfd f0, 4, |
| [sp!] */ |
| && gdbarch_tdep (gdbarch)->have_fpa_registers) |
| { |
| int n_saved_fp_regs; |
| unsigned int fp_start_reg, fp_bound_reg; |
| |
| if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM])) |
| break; |
| |
| if ((insn & 0x800) == 0x800) /* N0 is set */ |
| { |
| if ((insn & 0x40000) == 0x40000) /* N1 is set */ |
| n_saved_fp_regs = 3; |
| else |
| n_saved_fp_regs = 1; |
| } |
| else |
| { |
| if ((insn & 0x40000) == 0x40000) /* N1 is set */ |
| n_saved_fp_regs = 2; |
| else |
| n_saved_fp_regs = 4; |
| } |
| |
| fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7); |
| fp_bound_reg = fp_start_reg + n_saved_fp_regs; |
| for (; fp_start_reg < fp_bound_reg; fp_start_reg++) |
| { |
| regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12); |
| pv_area_store (stack, regs[ARM_SP_REGNUM], 12, |
| regs[fp_start_reg++]); |
| } |
| } |
| else if ((insn & 0xff000000) == 0xeb000000 && cache == NULL) /* bl */ |
| { |
| /* Allow some special function calls when skipping the |
| prologue; GCC generates these before storing arguments to |
| the stack. */ |
| CORE_ADDR dest = BranchDest (current_pc, insn); |
| |
| if (skip_prologue_function (gdbarch, dest, 0)) |
| continue; |
| else |
| break; |
| } |
| else if ((insn & 0xf0000000) != 0xe0000000) |
| break; /* Condition not true, exit early. */ |
| else if (arm_instruction_changes_pc (insn)) |
| /* Don't scan past anything that might change control flow. */ |
| break; |
| else if ((insn & 0xfe500000) == 0xe8100000 /* ldm */ |
| && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM)) |
| /* Ignore block loads from the stack, potentially copying |
| parameters from memory. */ |
| continue; |
| else if ((insn & 0xfc500000) == 0xe4100000 |
| && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM)) |
| /* Similarly ignore single loads from the stack. */ |
| continue; |
| else if ((insn & 0xffff0ff0) == 0xe1a00000) |
| /* MOV Rd, Rm. Skip register copies, i.e. saves to another |
| register instead of the stack. */ |
| continue; |
| else |
| { |
| /* The optimizer might shove anything into the prologue, |
| so we just skip what we don't recognize. */ |
| unrecognized_pc = current_pc; |
| continue; |
| } |
| } |
| |
| if (unrecognized_pc == 0) |
| unrecognized_pc = current_pc; |
| |
| /* The frame size is just the distance from the frame register |
| to the original stack pointer. */ |
| if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM)) |
| { |
| /* Frame pointer is fp. */ |
| framereg = ARM_FP_REGNUM; |
| framesize = -regs[ARM_FP_REGNUM].k; |
| } |
| else |
| { |
| /* Try the stack pointer... this is a bit desperate. */ |
| framereg = ARM_SP_REGNUM; |
| framesize = -regs[ARM_SP_REGNUM].k; |
| } |
| |
| if (cache) |
| { |
| cache->framereg = framereg; |
| cache->framesize = framesize; |
| |
| for (regno = 0; regno < ARM_FPS_REGNUM; regno++) |
| if (pv_area_find_reg (stack, gdbarch, regno, &offset)) |
| cache->saved_regs[regno].addr = offset; |
| } |
| |
| if (arm_debug) |
| fprintf_unfiltered (gdb_stdlog, "Prologue scan stopped at %s\n", |
| paddress (gdbarch, unrecognized_pc)); |
| |
| do_cleanups (back_to); |
| return unrecognized_pc; |
| } |
| |
| static void |
| arm_scan_prologue (struct frame_info *this_frame, |
| struct arm_prologue_cache *cache) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| int regno; |
| CORE_ADDR prologue_start, prologue_end, current_pc; |
| CORE_ADDR prev_pc = get_frame_pc (this_frame); |
| CORE_ADDR block_addr = get_frame_address_in_block (this_frame); |
| pv_t regs[ARM_FPS_REGNUM]; |
| struct pv_area *stack; |
| struct cleanup *back_to; |
| CORE_ADDR offset; |
| |
| /* Assume there is no frame until proven otherwise. */ |
| cache->framereg = ARM_SP_REGNUM; |
| cache->framesize = 0; |
| |
| /* Check for Thumb prologue. */ |
| if (arm_frame_is_thumb (this_frame)) |
| { |
| thumb_scan_prologue (gdbarch, prev_pc, block_addr, cache); |
| return; |
| } |
| |
| /* Find the function prologue. If we can't find the function in |
| the symbol table, peek in the stack frame to find the PC. */ |
| if (find_pc_partial_function (block_addr, NULL, &prologue_start, |
| &prologue_end)) |
| { |
| /* One way to find the end of the prologue (which works well |
| for unoptimized code) is to do the following: |
| |
| struct symtab_and_line sal = find_pc_line (prologue_start, 0); |
| |
| if (sal.line == 0) |
| prologue_end = prev_pc; |
| else if (sal.end < prologue_end) |
| prologue_end = sal.end; |
| |
| This mechanism is very accurate so long as the optimizer |
| doesn't move any instructions from the function body into the |
| prologue. If this happens, sal.end will be the last |
| instruction in the first hunk of prologue code just before |
| the first instruction that the scheduler has moved from |
| the body to the prologue. |
| |
| In order to make sure that we scan all of the prologue |
| instructions, we use a slightly less accurate mechanism which |
| may scan more than necessary. To help compensate for this |
| lack of accuracy, the prologue scanning loop below contains |
| several clauses which'll cause the loop to terminate early if |
| an implausible prologue instruction is encountered. |
| |
| The expression |
| |
| prologue_start + 64 |
| |
| is a suitable endpoint since it accounts for the largest |
| possible prologue plus up to five instructions inserted by |
| the scheduler. */ |
| |
| if (prologue_end > prologue_start + 64) |
| { |
| prologue_end = prologue_start + 64; /* See above. */ |
| } |
| } |
| else |
| { |
| /* We have no symbol information. Our only option is to assume this |
| function has a standard stack frame and the normal frame register. |
| Then, we can find the value of our frame pointer on entrance to |
| the callee (or at the present moment if this is the innermost frame). |
| The value stored there should be the address of the stmfd + 8. */ |
| CORE_ADDR frame_loc; |
| LONGEST return_value; |
| |
| frame_loc = get_frame_register_unsigned (this_frame, ARM_FP_REGNUM); |
| if (!safe_read_memory_integer (frame_loc, 4, byte_order, &return_value)) |
| return; |
| else |
| { |
| prologue_start = gdbarch_addr_bits_remove |
| (gdbarch, return_value) - 8; |
| prologue_end = prologue_start + 64; /* See above. */ |
| } |
| } |
| |
| if (prev_pc < prologue_end) |
| prologue_end = prev_pc; |
| |
| arm_analyze_prologue (gdbarch, prologue_start, prologue_end, cache); |
| } |
| |
| static struct arm_prologue_cache * |
| arm_make_prologue_cache (struct frame_info *this_frame) |
| { |
| int reg; |
| struct arm_prologue_cache *cache; |
| CORE_ADDR unwound_fp; |
| |
| cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache); |
| cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); |
| |
| arm_scan_prologue (this_frame, cache); |
| |
| unwound_fp = get_frame_register_unsigned (this_frame, cache->framereg); |
| if (unwound_fp == 0) |
| return cache; |
| |
| cache->prev_sp = unwound_fp + cache->framesize; |
| |
| /* Calculate actual addresses of saved registers using offsets |
| determined by arm_scan_prologue. */ |
| for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++) |
| if (trad_frame_addr_p (cache->saved_regs, reg)) |
| cache->saved_regs[reg].addr += cache->prev_sp; |
| |
| return cache; |
| } |
| |
| /* Our frame ID for a normal frame is the current function's starting PC |
| and the caller's SP when we were called. */ |
| |
| static void |
| arm_prologue_this_id (struct frame_info *this_frame, |
| void **this_cache, |
| struct frame_id *this_id) |
| { |
| struct arm_prologue_cache *cache; |
| struct frame_id id; |
| CORE_ADDR pc, func; |
| |
| if (*this_cache == NULL) |
| *this_cache = arm_make_prologue_cache (this_frame); |
| cache = *this_cache; |
| |
| /* This is meant to halt the backtrace at "_start". */ |
| pc = get_frame_pc (this_frame); |
| if (pc <= gdbarch_tdep (get_frame_arch (this_frame))->lowest_pc) |
| return; |
| |
| /* If we've hit a wall, stop. */ |
| if (cache->prev_sp == 0) |
| return; |
| |
| /* Use function start address as part of the frame ID. If we cannot |
| identify the start address (due to missing symbol information), |
| fall back to just using the current PC. */ |
| func = get_frame_func (this_frame); |
| if (!func) |
| func = pc; |
| |
| id = frame_id_build (cache->prev_sp, func); |
| *this_id = id; |
| } |
| |
| static struct value * |
| arm_prologue_prev_register (struct frame_info *this_frame, |
| void **this_cache, |
| int prev_regnum) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| struct arm_prologue_cache *cache; |
| |
| if (*this_cache == NULL) |
| *this_cache = arm_make_prologue_cache (this_frame); |
| cache = *this_cache; |
| |
| /* If we are asked to unwind the PC, then we need to return the LR |
| instead. The prologue may save PC, but it will point into this |
| frame's prologue, not the next frame's resume location. Also |
| strip the saved T bit. A valid LR may have the low bit set, but |
| a valid PC never does. */ |
| if (prev_regnum == ARM_PC_REGNUM) |
| { |
| CORE_ADDR lr; |
| |
| lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM); |
| return frame_unwind_got_constant (this_frame, prev_regnum, |
| arm_addr_bits_remove (gdbarch, lr)); |
| } |
| |
| /* SP is generally not saved to the stack, but this frame is |
| identified by the next frame's stack pointer at the time of the call. |
| The value was already reconstructed into PREV_SP. */ |
| if (prev_regnum == ARM_SP_REGNUM) |
| return frame_unwind_got_constant (this_frame, prev_regnum, cache->prev_sp); |
| |
| /* The CPSR may have been changed by the call instruction and by the |
| called function. The only bit we can reconstruct is the T bit, |
| by checking the low bit of LR as of the call. This is a reliable |
| indicator of Thumb-ness except for some ARM v4T pre-interworking |
| Thumb code, which could get away with a clear low bit as long as |
| the called function did not use bx. Guess that all other |
| bits are unchanged; the condition flags are presumably lost, |
| but the processor status is likely valid. */ |
| if (prev_regnum == ARM_PS_REGNUM) |
| { |
| CORE_ADDR lr, cpsr; |
| ULONGEST t_bit = arm_psr_thumb_bit (gdbarch); |
| |
| cpsr = get_frame_register_unsigned (this_frame, prev_regnum); |
| lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM); |
| if (IS_THUMB_ADDR (lr)) |
| cpsr |= t_bit; |
| else |
| cpsr &= ~t_bit; |
| return frame_unwind_got_constant (this_frame, prev_regnum, cpsr); |
| } |
| |
| return trad_frame_get_prev_register (this_frame, cache->saved_regs, |
| prev_regnum); |
| } |
| |
| struct frame_unwind arm_prologue_unwind = { |
| NORMAL_FRAME, |
| default_frame_unwind_stop_reason, |
| arm_prologue_this_id, |
| arm_prologue_prev_register, |
| NULL, |
| default_frame_sniffer |
| }; |
| |
| /* Maintain a list of ARM exception table entries per objfile, similar to the |
| list of mapping symbols. We only cache entries for standard ARM-defined |
| personality routines; the cache will contain only the frame unwinding |
| instructions associated with the entry (not the descriptors). */ |
| |
| static const struct objfile_data *arm_exidx_data_key; |
| |
| struct arm_exidx_entry |
| { |
| bfd_vma addr; |
| gdb_byte *entry; |
| }; |
| typedef struct arm_exidx_entry arm_exidx_entry_s; |
| DEF_VEC_O(arm_exidx_entry_s); |
| |
| struct arm_exidx_data |
| { |
| VEC(arm_exidx_entry_s) **section_maps; |
| }; |
| |
| static void |
| arm_exidx_data_free (struct objfile *objfile, void *arg) |
| { |
| struct arm_exidx_data *data = arg; |
| unsigned int i; |
| |
| for (i = 0; i < objfile->obfd->section_count; i++) |
| VEC_free (arm_exidx_entry_s, data->section_maps[i]); |
| } |
| |
| static inline int |
| arm_compare_exidx_entries (const struct arm_exidx_entry *lhs, |
| const struct arm_exidx_entry *rhs) |
| { |
| return lhs->addr < rhs->addr; |
| } |
| |
| static struct obj_section * |
| arm_obj_section_from_vma (struct objfile *objfile, bfd_vma vma) |
| { |
| struct obj_section *osect; |
| |
| ALL_OBJFILE_OSECTIONS (objfile, osect) |
| if (bfd_get_section_flags (objfile->obfd, |
| osect->the_bfd_section) & SEC_ALLOC) |
| { |
| bfd_vma start, size; |
| start = bfd_get_section_vma (objfile->obfd, osect->the_bfd_section); |
| size = bfd_get_section_size (osect->the_bfd_section); |
| |
| if (start <= vma && vma < start + size) |
| return osect; |
| } |
| |
| return NULL; |
| } |
| |
| /* Parse contents of exception table and exception index sections |
| of OBJFILE, and fill in the exception table entry cache. |
| |
| For each entry that refers to a standard ARM-defined personality |
| routine, extract the frame unwinding instructions (from either |
| the index or the table section). The unwinding instructions |
| are normalized by: |
| - extracting them from the rest of the table data |
| - converting to host endianness |
| - appending the implicit 0xb0 ("Finish") code |
| |
| The extracted and normalized instructions are stored for later |
| retrieval by the arm_find_exidx_entry routine. */ |
| |
| static void |
| arm_exidx_new_objfile (struct objfile *objfile) |
| { |
| struct cleanup *cleanups; |
| struct arm_exidx_data *data; |
| asection *exidx, *extab; |
| bfd_vma exidx_vma = 0, extab_vma = 0; |
| bfd_size_type exidx_size = 0, extab_size = 0; |
| gdb_byte *exidx_data = NULL, *extab_data = NULL; |
| LONGEST i; |
| |
| /* If we've already touched this file, do nothing. */ |
| if (!objfile || objfile_data (objfile, arm_exidx_data_key) != NULL) |
| return; |
| cleanups = make_cleanup (null_cleanup, NULL); |
| |
| /* Read contents of exception table and index. */ |
| exidx = bfd_get_section_by_name (objfile->obfd, ".ARM.exidx"); |
| if (exidx) |
| { |
| exidx_vma = bfd_section_vma (objfile->obfd, exidx); |
| exidx_size = bfd_get_section_size (exidx); |
| exidx_data = xmalloc (exidx_size); |
| make_cleanup (xfree, exidx_data); |
| |
| if (!bfd_get_section_contents (objfile->obfd, exidx, |
| exidx_data, 0, exidx_size)) |
| { |
| do_cleanups (cleanups); |
| return; |
| } |
| } |
| |
| extab = bfd_get_section_by_name (objfile->obfd, ".ARM.extab"); |
| if (extab) |
| { |
| extab_vma = bfd_section_vma (objfile->obfd, extab); |
| extab_size = bfd_get_section_size (extab); |
| extab_data = xmalloc (extab_size); |
| make_cleanup (xfree, extab_data); |
| |
| if (!bfd_get_section_contents (objfile->obfd, extab, |
| extab_data, 0, extab_size)) |
| { |
| do_cleanups (cleanups); |
| return; |
| } |
| } |
| |
| /* Allocate exception table data structure. */ |
| data = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct arm_exidx_data); |
| set_objfile_data (objfile, arm_exidx_data_key, data); |
| data->section_maps = OBSTACK_CALLOC (&objfile->objfile_obstack, |
| objfile->obfd->section_count, |
| VEC(arm_exidx_entry_s) *); |
| |
| /* Fill in exception table. */ |
| for (i = 0; i < exidx_size / 8; i++) |
| { |
| struct arm_exidx_entry new_exidx_entry; |
| bfd_vma idx = bfd_h_get_32 (objfile->obfd, exidx_data + i * 8); |
| bfd_vma val = bfd_h_get_32 (objfile->obfd, exidx_data + i * 8 + 4); |
| bfd_vma addr = 0, word = 0; |
| int n_bytes = 0, n_words = 0; |
| struct obj_section *sec; |
| gdb_byte *entry = NULL; |
| |
| /* Extract address of start of function. */ |
| idx = ((idx & 0x7fffffff) ^ 0x40000000) - 0x40000000; |
| idx += exidx_vma + i * 8; |
| |
| /* Find section containing function and compute section offset. */ |
| sec = arm_obj_section_from_vma (objfile, idx); |
| if (sec == NULL) |
| continue; |
| idx -= bfd_get_section_vma (objfile->obfd, sec->the_bfd_section); |
| |
| /* Determine address of exception table entry. */ |
| if (val == 1) |
| { |
| /* EXIDX_CANTUNWIND -- no exception table entry present. */ |
| } |
| else if ((val & 0xff000000) == 0x80000000) |
| { |
| /* Exception table entry embedded in .ARM.exidx |
| -- must be short form. */ |
| word = val; |
| n_bytes = 3; |
| } |
| else if (!(val & 0x80000000)) |
| { |
| /* Exception table entry in .ARM.extab. */ |
| addr = ((val & 0x7fffffff) ^ 0x40000000) - 0x40000000; |
| addr += exidx_vma + i * 8 + 4; |
| |
| if (addr >= extab_vma && addr + 4 <= extab_vma + extab_size) |
| { |
| word = bfd_h_get_32 (objfile->obfd, |
| extab_data + addr - extab_vma); |
| addr += 4; |
| |
| if ((word & 0xff000000) == 0x80000000) |
| { |
| /* Short form. */ |
| n_bytes = 3; |
| } |
| else if ((word & 0xff000000) == 0x81000000 |
| || (word & 0xff000000) == 0x82000000) |
| { |
| /* Long form. */ |
| n_bytes = 2; |
| n_words = ((word >> 16) & 0xff); |
| } |
| else if (!(word & 0x80000000)) |
| { |
| bfd_vma pers; |
| struct obj_section *pers_sec; |
| int gnu_personality = 0; |
| |
| /* Custom personality routine. */ |
| pers = ((word & 0x7fffffff) ^ 0x40000000) - 0x40000000; |
| pers = UNMAKE_THUMB_ADDR (pers + addr - 4); |
| |
| /* Check whether we've got one of the variants of the |
| GNU personality routines. */ |
| pers_sec = arm_obj_section_from_vma (objfile, pers); |
| if (pers_sec) |
| { |
| static const char *personality[] = |
| { |
| "__gcc_personality_v0", |
| "__gxx_personality_v0", |
| "__gcj_personality_v0", |
| "__gnu_objc_personality_v0", |
| NULL |
| }; |
| |
| CORE_ADDR pc = pers + obj_section_offset (pers_sec); |
| int k; |
| |
| for (k = 0; personality[k]; k++) |
| if (lookup_minimal_symbol_by_pc_name |
| (pc, personality[k], objfile)) |
| { |
| gnu_personality = 1; |
| break; |
| } |
| } |
| |
| /* If so, the next word contains a word count in the high |
| byte, followed by the same unwind instructions as the |
| pre-defined forms. */ |
| if (gnu_personality |
| && addr + 4 <= extab_vma + extab_size) |
| { |
| word = bfd_h_get_32 (objfile->obfd, |
| extab_data + addr - extab_vma); |
| addr += 4; |
| n_bytes = 3; |
| n_words = ((word >> 24) & 0xff); |
| } |
| } |
| } |
| } |
| |
| /* Sanity check address. */ |
| if (n_words) |
| if (addr < extab_vma || addr + 4 * n_words > extab_vma + extab_size) |
| n_words = n_bytes = 0; |
| |
| /* The unwind instructions reside in WORD (only the N_BYTES least |
| significant bytes are valid), followed by N_WORDS words in the |
| extab section starting at ADDR. */ |
| if (n_bytes || n_words) |
| { |
| gdb_byte *p = entry = obstack_alloc (&objfile->objfile_obstack, |
| n_bytes + n_words * 4 + 1); |
| |
| while (n_bytes--) |
| *p++ = (gdb_byte) ((word >> (8 * n_bytes)) & 0xff); |
| |
| while (n_words--) |
| { |
| word = bfd_h_get_32 (objfile->obfd, |
| extab_data + addr - extab_vma); |
| addr += 4; |
| |
| *p++ = (gdb_byte) ((word >> 24) & 0xff); |
| *p++ = (gdb_byte) ((word >> 16) & 0xff); |
| *p++ = (gdb_byte) ((word >> 8) & 0xff); |
| *p++ = (gdb_byte) (word & 0xff); |
| } |
| |
| /* Implied "Finish" to terminate the list. */ |
| *p++ = 0xb0; |
| } |
| |
| /* Push entry onto vector. They are guaranteed to always |
| appear in order of increasing addresses. */ |
| new_exidx_entry.addr = idx; |
| new_exidx_entry.entry = entry; |
| VEC_safe_push (arm_exidx_entry_s, |
| data->section_maps[sec->the_bfd_section->index], |
| &new_exidx_entry); |
| } |
| |
| do_cleanups (cleanups); |
| } |
| |
| /* Search for the exception table entry covering MEMADDR. If one is found, |
| return a pointer to its data. Otherwise, return 0. If START is non-NULL, |
| set *START to the start of the region covered by this entry. */ |
| |
| static gdb_byte * |
| arm_find_exidx_entry (CORE_ADDR memaddr, CORE_ADDR *start) |
| { |
| struct obj_section *sec; |
| |
| sec = find_pc_section (memaddr); |
| if (sec != NULL) |
| { |
| struct arm_exidx_data *data; |
| VEC(arm_exidx_entry_s) *map; |
| struct arm_exidx_entry map_key = { memaddr - obj_section_addr (sec), 0 }; |
| unsigned int idx; |
| |
| data = objfile_data (sec->objfile, arm_exidx_data_key); |
| if (data != NULL) |
| { |
| map = data->section_maps[sec->the_bfd_section->index]; |
| if (!VEC_empty (arm_exidx_entry_s, map)) |
| { |
| struct arm_exidx_entry *map_sym; |
| |
| idx = VEC_lower_bound (arm_exidx_entry_s, map, &map_key, |
| arm_compare_exidx_entries); |
| |
| /* VEC_lower_bound finds the earliest ordered insertion |
| point. If the following symbol starts at this exact |
| address, we use that; otherwise, the preceding |
| exception table entry covers this address. */ |
| if (idx < VEC_length (arm_exidx_entry_s, map)) |
| { |
| map_sym = VEC_index (arm_exidx_entry_s, map, idx); |
| if (map_sym->addr == map_key.addr) |
| { |
| if (start) |
| *start = map_sym->addr + obj_section_addr (sec); |
| return map_sym->entry; |
| } |
| } |
| |
| if (idx > 0) |
| { |
| map_sym = VEC_index (arm_exidx_entry_s, map, idx - 1); |
| if (start) |
| *start = map_sym->addr + obj_section_addr (sec); |
| return map_sym->entry; |
| } |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| /* Given the current frame THIS_FRAME, and its associated frame unwinding |
| instruction list from the ARM exception table entry ENTRY, allocate and |
| return a prologue cache structure describing how to unwind this frame. |
| |
| Return NULL if the unwinding instruction list contains a "spare", |
| "reserved" or "refuse to unwind" instruction as defined in section |
| "9.3 Frame unwinding instructions" of the "Exception Handling ABI |
| for the ARM Architecture" document. */ |
| |
| static struct arm_prologue_cache * |
| arm_exidx_fill_cache (struct frame_info *this_frame, gdb_byte *entry) |
| { |
| CORE_ADDR vsp = 0; |
| int vsp_valid = 0; |
| |
| struct arm_prologue_cache *cache; |
| cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache); |
| cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); |
| |
| for (;;) |
| { |
| gdb_byte insn; |
| |
| /* Whenever we reload SP, we actually have to retrieve its |
| actual value in the current frame. */ |
| if (!vsp_valid) |
| { |
| if (trad_frame_realreg_p (cache->saved_regs, ARM_SP_REGNUM)) |
| { |
| int reg = cache->saved_regs[ARM_SP_REGNUM].realreg; |
| vsp = get_frame_register_unsigned (this_frame, reg); |
| } |
| else |
| { |
| CORE_ADDR addr = cache->saved_regs[ARM_SP_REGNUM].addr; |
| vsp = get_frame_memory_unsigned (this_frame, addr, 4); |
| } |
| |
| vsp_valid = 1; |
| } |
| |
| /* Decode next unwind instruction. */ |
| insn = *entry++; |
| |
| if ((insn & 0xc0) == 0) |
| { |
| int offset = insn & 0x3f; |
| vsp += (offset << 2) + 4; |
| } |
| else if ((insn & 0xc0) == 0x40) |
| { |
| int offset = insn & 0x3f; |
| vsp -= (offset << 2) + 4; |
| } |
| else if ((insn & 0xf0) == 0x80) |
| { |
| int mask = ((insn & 0xf) << 8) | *entry++; |
| int i; |
| |
| /* The special case of an all-zero mask identifies |
| "Refuse to unwind". We return NULL to fall back |
| to the prologue analyzer. */ |
| if (mask == 0) |
| return NULL; |
| |
| /* Pop registers r4..r15 under mask. */ |
| for (i = 0; i < 12; i++) |
| if (mask & (1 << i)) |
| { |
| cache->saved_regs[4 + i].addr = vsp; |
| vsp += 4; |
| } |
| |
| /* Special-case popping SP -- we need to reload vsp. */ |
| if (mask & (1 << (ARM_SP_REGNUM - 4))) |
| vsp_valid = 0; |
| } |
| else if ((insn & 0xf0) == 0x90) |
| { |
| int reg = insn & 0xf; |
| |
| /* Reserved cases. */ |
| if (reg == ARM_SP_REGNUM || reg == ARM_PC_REGNUM) |
| return NULL; |
| |
| /* Set SP from another register and mark VSP for reload. */ |
| cache->saved_regs[ARM_SP_REGNUM] = cache->saved_regs[reg]; |
| vsp_valid = 0; |
| } |
| else if ((insn & 0xf0) == 0xa0) |
| { |
| int count = insn & 0x7; |
| int pop_lr = (insn & 0x8) != 0; |
| int i; |
| |
| /* Pop r4..r[4+count]. */ |
| for (i = 0; i <= count; i++) |
| { |
| cache->saved_regs[4 + i].addr = vsp; |
| vsp += 4; |
| } |
| |
| /* If indicated by flag, pop LR as well. */ |
| if (pop_lr) |
| { |
| cache->saved_regs[ARM_LR_REGNUM].addr = vsp; |
| vsp += 4; |
| } |
| } |
| else if (insn == 0xb0) |
| { |
| /* We could only have updated PC by popping into it; if so, it |
| will show up as address. Otherwise, copy LR into PC. */ |
| if (!trad_frame_addr_p (cache->saved_regs, ARM_PC_REGNUM)) |
| cache->saved_regs[ARM_PC_REGNUM] |
| = cache->saved_regs[ARM_LR_REGNUM]; |
| |
| /* We're done. */ |
| break; |
| } |
| else if (insn == 0xb1) |
| { |
| int mask = *entry++; |
| int i; |
| |
| /* All-zero mask and mask >= 16 is "spare". */ |
| if (mask == 0 || mask >= 16) |
| return NULL; |
| |
| /* Pop r0..r3 under mask. */ |
| for (i = 0; i < 4; i++) |
| if (mask & (1 << i)) |
| { |
| cache->saved_regs[i].addr = vsp; |
| vsp += 4; |
| } |
| } |
| else if (insn == 0xb2) |
| { |
| ULONGEST offset = 0; |
| unsigned shift = 0; |
| |
| do |
| { |
| offset |= (*entry & 0x7f) << shift; |
| shift += 7; |
| } |
| while (*entry++ & 0x80); |
| |
| vsp += 0x204 + (offset << 2); |
| } |
| else if (insn == 0xb3) |
| { |
| int start = *entry >> 4; |
| int count = (*entry++) & 0xf; |
| int i; |
| |
| /* Only registers D0..D15 are valid here. */ |
| if (start + count >= 16) |
| return NULL; |
| |
| /* Pop VFP double-precision registers D[start]..D[start+count]. */ |
| for (i = 0; i <= count; i++) |
| { |
| cache->saved_regs[ARM_D0_REGNUM + start + i].addr = vsp; |
| vsp += 8; |
| } |
| |
| /* Add an extra 4 bytes for FSTMFDX-style stack. */ |
| vsp += 4; |
| } |
| else if ((insn & 0xf8) == 0xb8) |
| { |
| int count = insn & 0x7; |
| int i; |
| |
| /* Pop VFP double-precision registers D[8]..D[8+count]. */ |
| for (i = 0; i <= count; i++) |
| { |
| cache->saved_regs[ARM_D0_REGNUM + 8 + i].addr = vsp; |
| vsp += 8; |
| } |
| |
| /* Add an extra 4 bytes for FSTMFDX-style stack. */ |
| vsp += 4; |
| } |
| else if (insn == 0xc6) |
| { |
| int start = *entry >> 4; |
| int count = (*entry++) & 0xf; |
| int i; |
| |
| /* Only registers WR0..WR15 are valid. */ |
| if (start + count >= 16) |
| return NULL; |
| |
| /* Pop iwmmx registers WR[start]..WR[start+count]. */ |
| for (i = 0; i <= count; i++) |
| { |
| cache->saved_regs[ARM_WR0_REGNUM + start + i].addr = vsp; |
| vsp += 8; |
| } |
| } |
| else if (insn == 0xc7) |
| { |
| int mask = *entry++; |
| int i; |
| |
| /* All-zero mask and mask >= 16 is "spare". */ |
| if (mask == 0 || mask >= 16) |
| return NULL; |
| |
| /* Pop iwmmx general-purpose registers WCGR0..WCGR3 under mask. */ |
| for (i = 0; i < 4; i++) |
| if (mask & (1 << i)) |
| { |
| cache->saved_regs[ARM_WCGR0_REGNUM + i].addr = vsp; |
| vsp += 4; |
| } |
| } |
| else if ((insn & 0xf8) == 0xc0) |
| { |
| int count = insn & 0x7; |
| int i; |
| |
| /* Pop iwmmx registers WR[10]..WR[10+count]. */ |
| for (i = 0; i <= count; i++) |
| { |
| cache->saved_regs[ARM_WR0_REGNUM + 10 + i].addr = vsp; |
| vsp += 8; |
| } |
| } |
| else if (insn == 0xc8) |
| { |
| int start = *entry >> 4; |
| int count = (*entry++) & 0xf; |
| int i; |
| |
| /* Only registers D0..D31 are valid. */ |
| if (start + count >= 16) |
| return NULL; |
| |
| /* Pop VFP double-precision registers |
| D[16+start]..D[16+start+count]. */ |
| for (i = 0; i <= count; i++) |
| { |
| cache->saved_regs[ARM_D0_REGNUM + 16 + start + i].addr = vsp; |
| vsp += 8; |
| } |
| } |
| else if (insn == 0xc9) |
| { |
| int start = *entry >> 4; |
| int count = (*entry++) & 0xf; |
| int i; |
| |
| /* Pop VFP double-precision registers D[start]..D[start+count]. */ |
| for (i = 0; i <= count; i++) |
| { |
| cache->saved_regs[ARM_D0_REGNUM + start + i].addr = vsp; |
| vsp += 8; |
| } |
| } |
| else if ((insn & 0xf8) == 0xd0) |
| { |
| int count = insn & 0x7; |
| int i; |
| |
| /* Pop VFP double-precision registers D[8]..D[8+count]. */ |
| for (i = 0; i <= count; i++) |
| { |
| cache->saved_regs[ARM_D0_REGNUM + 8 + i].addr = vsp; |
| vsp += 8; |
| } |
| } |
| else |
| { |
| /* Everything else is "spare". */ |
| return NULL; |
| } |
| } |
| |
| /* If we restore SP from a register, assume this was the frame register. |
| Otherwise just fall back to SP as frame register. */ |
| if (trad_frame_realreg_p (cache->saved_regs, ARM_SP_REGNUM)) |
| cache->framereg = cache->saved_regs[ARM_SP_REGNUM].realreg; |
| else |
| cache->framereg = ARM_SP_REGNUM; |
| |
| /* Determine offset to previous frame. */ |
| cache->framesize |
| = vsp - get_frame_register_unsigned (this_frame, cache->framereg); |
| |
| /* We already got the previous SP. */ |
| cache->prev_sp = vsp; |
| |
| return cache; |
| } |
| |
| /* Unwinding via ARM exception table entries. Note that the sniffer |
| already computes a filled-in prologue cache, which is then used |
| with the same arm_prologue_this_id and arm_prologue_prev_register |
| routines also used for prologue-parsing based unwinding. */ |
| |
| static int |
| arm_exidx_unwind_sniffer (const struct frame_unwind *self, |
| struct frame_info *this_frame, |
| void **this_prologue_cache) |
| { |
| struct gdbarch *gdbarch = get_frame_arch (this_frame); |
| enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); |
| CORE_ADDR addr_in_block, exidx_region, func_start; |
| struct arm_prologue_cache *cache; |
| gdb_byte *entry; |
| |
| /* See if we have an ARM exception table entry covering this address. */ |
| addr_in_block = get_frame_address_in_block (this_frame); |
| entry = arm_find_exidx_entry (addr_in_block, &exidx_region); |
| if (!entry) |
| return 0; |
| |
| /* The ARM exception table does not describe unwind information |
| for arbitrary PC values, but is guaranteed to be correct only |
| at call sites. We have to decide here whether we want to use |
| ARM exception table information for this frame, or fall back |
| to using prologue parsing. (Note that if we have DWARF CFI, |
| this sniffer isn't even called -- CFI is always preferred.) |
| |
| Before we make this decision, however, we check whether we |
| actually have *symbol* information for the current frame. |
| If not, prologue parsing would not work anyway, so we might |
| as well use the exception table and hope for the best. */ |
| if (find_pc_partial_function (addr_in_block, NULL, &func_start, NULL)) |
| { |
| int exc_valid = 0; |
| |
| /* If the next frame is "normal", we are at a call site in this |
| frame, so exception information is guaranteed to be valid. */ |
| if (get_next_frame (this_frame) |
| && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME) |
| exc_valid = 1; |
| |
| /* We also assume exception information is valid if we're currently |
| blocked in a system call. The system library is supposed to |
| ensure this, so that e.g. pthread cancellation works. */ |
| if (arm_frame_is_thumb (this_frame)) |
| { |
| LONGEST insn; |
| |
| if (safe_read_memory_integer (get_frame_pc (this_frame) - 2, 2, |
| byte_order_for_code, &insn) |
| && (insn & 0xff00) == 0xdf00 /* svc */) |
| exc_valid = 1; |
| } |
| else |
| { |
| LONGEST insn; |
| |
| if (safe_read_memory_integer (get_frame_pc (this_frame) - 4, 4, |
| byte_order_for_code, &insn) |
| && (insn & 0x0f000000) == 0x0f000000 /* svc */) |
| exc_valid = 1; |
| } |
| |
| /* Bail out if we don't know that exception information is valid. */ |
| if (!exc_valid) |
| return 0; |
| |
| /* The ARM exception index does not mark the *end* of the region |
| covered by the entry, and some functions will not have any entry. |
| To correctly recognize the end of the covered region, the linker |
| should have inserted dummy records with a CANTUNWIND marker. |
| |
| Unfortunately, current versions of GNU ld do not reliably do |
| this, and thus we may have found an incorrect entry above. |
| As a (temporary) sanity check, we only use the entry if it |
| lies *within* the bounds of the function. Note that this check |
| might reject perfectly valid entries that just happen to cover |
| multiple functions; therefore this check ought to be removed |
| once the linker is fixed. */ |
| if (func_start > exidx_region) |
| return 0; |
| } |
| |
| /* Decode the list of unwinding instructions into a prologue cache. |
| Note that this may fail due to e.g. a "refuse to unwind" code. */ |
| cache = arm_exidx_fill_cache (this_frame, entry); |
| if (!cache) |
| return 0; |
| |
| *this_prologue_cache = cache; |
| return 1; |
| } |
| |
| struct frame_unwind arm_exidx_unwind = { |
| NORMAL_FRAME, |
| default_frame_unwind_stop_reason, |
| arm_prologue_this_id, |
| arm_prologue_prev_register, |
| NULL, |
| arm_exidx_unwind_sniffer |
| }; |
| |
| static struct arm_prologue_cache * |
| arm_make_stub_cache (struct frame_info *this_frame) |
| { |
| struct arm_prologue_cache *cache; |
| |
| cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache); |
| cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); |
| |
| cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); |
| |
| return cache; |
| } |
| |
| /* Our frame ID for a stub frame is the current SP and LR. */ |
| |
| static void |
| arm_stub_this_id (struct frame_info *this_frame, |
| void **this_cache, |
| struct frame_id *this_id) |
| { |
| struct arm_prologue_cache *cache; |
| |
| if (*this_cache == NULL) |
| *this_cache = arm_make_stub_cache (this_frame); |
| cache = *this_cache; |
| |
| *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame)); |
| } |
| |
| static int |
| arm_stub_unwind_sniffer (const struct frame_unwind *self, |
| struct frame_info *this_frame, |
| void **this_prologue_cache) |
| { |
| CORE_ADDR addr_in_block; |
| char dummy[4]; |
| |
| addr_in_block = get_frame_address_in_block (this_frame); |
| if (in_plt_section (addr_in_block, NULL) |
| /* We also use the stub winder if the target memory is unreadable |
| to avoid having the prologue unwinder trying to read it. */ |
| || target_read_memory (get_frame_pc (this_frame), dummy, 4) != 0) |
| return 1; |
| |
| return 0; |
| } |
| |
| struct frame_unwind arm_stub_unwind = { |
| NORMAL_FRAME, |
| default_frame_unwind_stop_reason, |
| arm_stub_this_id, |
| arm_prologue_prev_register, |
| NULL, |
| arm_stub_unwind_sniffer |
| }; |
| |
| static CORE_ADDR |
| arm_normal_frame_base (struct frame_info *this_frame, void **this_cache) |
| { |
| struct arm_prologue_cache *cache; |
| |
| if (*this_cache == NULL) |
| *this_cache = arm_make_prologue_cache (this_frame); |
| cache = *this_cache; |
| |
| return cache->prev_sp - cache->framesize; |
| } |
| |
| struct frame_base arm_normal_base = { |
| &arm_prologue_unwind, |
| arm_normal_frame_base, |
| arm_normal_frame_base, |
| arm_normal_frame_base |
| }; |
| |
| /* Assuming THIS_FRAME is a dummy, return the frame ID of that |
| dummy frame. The frame ID's base needs to match the TOS value |
| saved by save_dummy_frame_tos() and returned from |
| arm_push_dummy_call, and the PC needs to match the dummy frame's |
| breakpoint. */ |
| |
| static struct frame_id |
| arm_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) |
| { |
| return frame_id_build (get_frame_register_unsigned (this_frame, |
| ARM_SP_REGNUM), |
| get_frame_pc (this_frame)); |
| } |
| |
| /* Given THIS_FRAME, find the previous frame's resume PC (which will |
| be used to construct the previous frame's ID, after looking up the |
| containing function). */ |
| |
| static CORE_ADDR |
| arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame) |
| { |
| CORE_ADDR pc; |
| pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM); |
| return arm_addr_bits_remove (gdbarch, pc); |
| } |
| |
| static CORE_ADDR |
| arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame) |
| { |
| return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM); |
| } |
| |
| static struct value * |
| arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache, |
| int regnum) |
| { |
| struct gdbarch * gdbarch = get_frame_arch (this_frame); |
| CORE_ADDR lr, cpsr; |
|