X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gdb%2Fsparc-tdep.c;h=7eb3b18b550a8f4d7476eea3fa74b8429fdce6a2;hb=875896e3e6880ec4c27b4fdfc37ae44881e11ca8;hp=3164ed3c8b47729434d9e8dab5aa893c0daea1e7;hpb=db75c7177045ed2551fe9f8a71bb454f6b71cd5f;p=platform%2Fupstream%2Fbinutils.git diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c index 3164ed3..7eb3b18 100644 --- a/gdb/sparc-tdep.c +++ b/gdb/sparc-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for SPARC. - Copyright (C) 2003-2012 Free Software Foundation, Inc. + Copyright (C) 2003-2014 Free Software Foundation, Inc. This file is part of GDB. @@ -35,10 +35,8 @@ #include "target.h" #include "value.h" -#include "gdb_assert.h" -#include "gdb_string.h" - #include "sparc-tdep.h" +#include "sparc-ravenscar-thread.h" struct regset; @@ -87,6 +85,9 @@ struct regset; #define X_DISP19(i) ((((i) & 0x7ffff) ^ 0x40000) - 0x40000) #define X_DISP10(i) ((((((i) >> 11) && 0x300) | (((i) >> 5) & 0xff)) ^ 0x200) - 0x200) #define X_SIMM13(i) ((((i) & 0x1fff) ^ 0x1000) - 0x1000) +/* Macros to identify some instructions. */ +/* RETURN (RETT in V8) */ +#define X_RETTURN(i) ((X_OP (i) == 0x2) && (X_OP3 (i) == 0x39)) /* Fetch the instruction at PC. Instructions are always big-endian even if the processor operates in little-endian mode. */ @@ -120,6 +121,37 @@ sparc_is_unimp_insn (CORE_ADDR pc) return ((insn & 0xc1c00000) == 0); } +/* Return non-zero if the instruction corresponding to PC is an + "annulled" branch, i.e. the annul bit is set. */ + +int +sparc_is_annulled_branch_insn (CORE_ADDR pc) +{ + /* The branch instructions featuring an annul bit can be identified + by the following bit patterns: + + OP=0 + OP2=1: Branch on Integer Condition Codes with Prediction (BPcc). + OP2=2: Branch on Integer Condition Codes (Bcc). + OP2=5: Branch on FP Condition Codes with Prediction (FBfcc). + OP2=6: Branch on FP Condition Codes (FBcc). + OP2=3 && Bit28=0: + Branch on Integer Register with Prediction (BPr). + + This leaves out ILLTRAP (OP2=0), SETHI/NOP (OP2=4) and the V8 + coprocessor branch instructions (Op2=7). */ + + const unsigned long insn = sparc_fetch_instruction (pc); + const unsigned op2 = X_OP2 (insn); + + if ((X_OP (insn) == 0) + && ((op2 == 1) || (op2 == 2) || (op2 == 5) || (op2 == 6) + || ((op2 == 3) && ((insn & 0x10000000) == 0)))) + return X_A (insn); + else + return 0; +} + /* OpenBSD/sparc includes StackGhost, which according to the author's website http://stackghost.cerias.purdue.edu "... transparently and automatically protects applications' stack frames; more @@ -420,6 +452,29 @@ sparc32_pseudo_register_write (struct gdbarch *gdbarch, regcache_raw_write (regcache, regnum + 1, buf + 4); } +/* Implement "in_function_epilogue_p". */ + +int +sparc_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + /* This function must return true if we are one instruction after an + instruction that destroyed the stack frame of the current + function. The SPARC instructions used to restore the callers + stack frame are RESTORE and RETURN/RETT. + + Of these RETURN/RETT is a branch instruction and thus we return + true if we are in its delay slot. + + RESTORE is almost always found in the delay slot of a branch + instruction that transfers control to the caller, such as JMPL. + Thus the next instruction is in the caller frame and we don't + need to do anything about it. */ + + unsigned int insn = sparc_fetch_instruction (pc - 4); + + return X_RETTURN (insn); +} + static CORE_ADDR sparc32_frame_align (struct gdbarch *gdbarch, CORE_ADDR address) @@ -854,7 +909,7 @@ sparc_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, dynamic linker patches up the first PLT with some code that starts with a SAVE instruction. Patch up PC such that it points at the start of our PLT entry. */ - if (tdep->plt_entry_size > 0 && in_plt_section (current_pc, NULL)) + if (tdep->plt_entry_size > 0 && in_plt_section (current_pc)) pc = current_pc - ((current_pc - pc) % tdep->plt_entry_size); insn = sparc_fetch_instruction (pc); @@ -1369,15 +1424,21 @@ sparc32_return_value (struct gdbarch *gdbarch, struct value *function, if (sparc_structure_or_union_p (type) || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16)) { + ULONGEST sp; + CORE_ADDR addr; + if (readbuf) { - ULONGEST sp; - CORE_ADDR addr; - regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp); addr = read_memory_unsigned_integer (sp + 64, 4, byte_order); read_memory (addr, readbuf, TYPE_LENGTH (type)); } + if (writebuf) + { + regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp); + addr = read_memory_unsigned_integer (sp + 64, 4, byte_order); + write_memory (addr, writebuf, TYPE_LENGTH (type)); + } return RETURN_VALUE_ABI_PRESERVES_ADDRESS; } @@ -1531,7 +1592,6 @@ sparc_analyze_control_transfer (struct frame_info *frame, if (X_A (insn)) *npc = 0; - gdb_assert (offset != 0); return pc + offset; } } @@ -1585,22 +1645,18 @@ sparc_write_pc (struct regcache *regcache, CORE_ADDR pc) } -/* Return the appropriate register set for the core section identified - by SECT_NAME and SECT_SIZE. */ +/* Iterate over core file register note sections. */ -static const struct regset * -sparc_regset_from_core_section (struct gdbarch *gdbarch, - const char *sect_name, size_t sect_size) +static void +sparc_iterate_over_regset_sections (struct gdbarch *gdbarch, + iterate_over_regset_sections_cb *cb, + void *cb_data, + const struct regcache *regcache) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - if (strcmp (sect_name, ".reg") == 0 && sect_size >= tdep->sizeof_gregset) - return tdep->gregset; - - if (strcmp (sect_name, ".reg2") == 0 && sect_size >= tdep->sizeof_fpregset) - return tdep->fpregset; - - return NULL; + cb (".reg", tdep->sizeof_gregset, tdep->gregset, NULL, cb_data); + cb (".reg2", tdep->sizeof_fpregset, tdep->fpregset, NULL, cb_data); } @@ -1616,7 +1672,7 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) return arches->gdbarch; /* Allocate space for the new architecture. */ - tdep = XZALLOC (struct gdbarch_tdep); + tdep = XCNEW (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); tdep->pc_regnum = SPARC32_PC_REGNUM; @@ -1680,8 +1736,10 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* If we have register sets, enable the generic core file support. */ if (tdep->gregset) - set_gdbarch_regset_from_core_section (gdbarch, - sparc_regset_from_core_section); + set_gdbarch_iterate_over_regset_sections + (gdbarch, sparc_iterate_over_regset_sections); + + register_sparc_ravenscar_ops (gdbarch); return gdbarch; } @@ -1833,7 +1891,7 @@ sparc_collect_rwindow (const struct regcache *regcache, /* Helper functions for dealing with register sets. */ void -sparc32_supply_gregset (const struct sparc_gregset *gregset, +sparc32_supply_gregset (const struct sparc_gregmap *gregmap, struct regcache *regcache, int regnum, const void *gregs) { @@ -1843,26 +1901,26 @@ sparc32_supply_gregset (const struct sparc_gregset *gregset, if (regnum == SPARC32_PSR_REGNUM || regnum == -1) regcache_raw_supply (regcache, SPARC32_PSR_REGNUM, - regs + gregset->r_psr_offset); + regs + gregmap->r_psr_offset); if (regnum == SPARC32_PC_REGNUM || regnum == -1) regcache_raw_supply (regcache, SPARC32_PC_REGNUM, - regs + gregset->r_pc_offset); + regs + gregmap->r_pc_offset); if (regnum == SPARC32_NPC_REGNUM || regnum == -1) regcache_raw_supply (regcache, SPARC32_NPC_REGNUM, - regs + gregset->r_npc_offset); + regs + gregmap->r_npc_offset); if (regnum == SPARC32_Y_REGNUM || regnum == -1) regcache_raw_supply (regcache, SPARC32_Y_REGNUM, - regs + gregset->r_y_offset); + regs + gregmap->r_y_offset); if (regnum == SPARC_G0_REGNUM || regnum == -1) regcache_raw_supply (regcache, SPARC_G0_REGNUM, &zero); if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1) { - int offset = gregset->r_g1_offset; + int offset = gregmap->r_g1_offset; for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++) { @@ -1876,7 +1934,7 @@ sparc32_supply_gregset (const struct sparc_gregset *gregset, { /* Not all of the register set variants include Locals and Inputs. For those that don't, we read them off the stack. */ - if (gregset->r_l0_offset == -1) + if (gregmap->r_l0_offset == -1) { ULONGEST sp; @@ -1885,7 +1943,7 @@ sparc32_supply_gregset (const struct sparc_gregset *gregset, } else { - int offset = gregset->r_l0_offset; + int offset = gregmap->r_l0_offset; for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++) { @@ -1898,7 +1956,7 @@ sparc32_supply_gregset (const struct sparc_gregset *gregset, } void -sparc32_collect_gregset (const struct sparc_gregset *gregset, +sparc32_collect_gregset (const struct sparc_gregmap *gregmap, const struct regcache *regcache, int regnum, void *gregs) { @@ -1907,23 +1965,23 @@ sparc32_collect_gregset (const struct sparc_gregset *gregset, if (regnum == SPARC32_PSR_REGNUM || regnum == -1) regcache_raw_collect (regcache, SPARC32_PSR_REGNUM, - regs + gregset->r_psr_offset); + regs + gregmap->r_psr_offset); if (regnum == SPARC32_PC_REGNUM || regnum == -1) regcache_raw_collect (regcache, SPARC32_PC_REGNUM, - regs + gregset->r_pc_offset); + regs + gregmap->r_pc_offset); if (regnum == SPARC32_NPC_REGNUM || regnum == -1) regcache_raw_collect (regcache, SPARC32_NPC_REGNUM, - regs + gregset->r_npc_offset); + regs + gregmap->r_npc_offset); if (regnum == SPARC32_Y_REGNUM || regnum == -1) regcache_raw_collect (regcache, SPARC32_Y_REGNUM, - regs + gregset->r_y_offset); + regs + gregmap->r_y_offset); if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1) { - int offset = gregset->r_g1_offset; + int offset = gregmap->r_g1_offset; /* %g0 is always zero. */ for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++) @@ -1938,9 +1996,9 @@ sparc32_collect_gregset (const struct sparc_gregset *gregset, { /* Not all of the register set variants include Locals and Inputs. For those that don't, we read them off the stack. */ - if (gregset->r_l0_offset != -1) + if (gregmap->r_l0_offset != -1) { - int offset = gregset->r_l0_offset; + int offset = gregmap->r_l0_offset; for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++) { @@ -1953,7 +2011,7 @@ sparc32_collect_gregset (const struct sparc_gregset *gregset, } void -sparc32_supply_fpregset (const struct sparc_fpregset *fpregset, +sparc32_supply_fpregset (const struct sparc_fpregmap *fpregmap, struct regcache *regcache, int regnum, const void *fpregs) { @@ -1964,16 +2022,16 @@ sparc32_supply_fpregset (const struct sparc_fpregset *fpregset, { if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1) regcache_raw_supply (regcache, SPARC_F0_REGNUM + i, - regs + fpregset->r_f0_offset + (i * 4)); + regs + fpregmap->r_f0_offset + (i * 4)); } if (regnum == SPARC32_FSR_REGNUM || regnum == -1) regcache_raw_supply (regcache, SPARC32_FSR_REGNUM, - regs + fpregset->r_fsr_offset); + regs + fpregmap->r_fsr_offset); } void -sparc32_collect_fpregset (const struct sparc_fpregset *fpregset, +sparc32_collect_fpregset (const struct sparc_fpregmap *fpregmap, const struct regcache *regcache, int regnum, void *fpregs) { @@ -1984,19 +2042,19 @@ sparc32_collect_fpregset (const struct sparc_fpregset *fpregset, { if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1) regcache_raw_collect (regcache, SPARC_F0_REGNUM + i, - regs + fpregset->r_f0_offset + (i * 4)); + regs + fpregmap->r_f0_offset + (i * 4)); } if (regnum == SPARC32_FSR_REGNUM || regnum == -1) regcache_raw_collect (regcache, SPARC32_FSR_REGNUM, - regs + fpregset->r_fsr_offset); + regs + fpregmap->r_fsr_offset); } /* SunOS 4. */ /* From . */ -const struct sparc_gregset sparc32_sunos4_gregset = +const struct sparc_gregmap sparc32_sunos4_gregmap = { 0 * 4, /* %psr */ 1 * 4, /* %pc */ @@ -2008,13 +2066,13 @@ const struct sparc_gregset sparc32_sunos4_gregset = -1 /* %l0 */ }; -const struct sparc_fpregset sparc32_sunos4_fpregset = +const struct sparc_fpregmap sparc32_sunos4_fpregmap = { 0 * 4, /* %f0 */ 33 * 4, /* %fsr */ }; -const struct sparc_fpregset sparc32_bsd_fpregset = +const struct sparc_fpregmap sparc32_bsd_fpregmap = { 0 * 4, /* %f0 */ 32 * 4, /* %fsr */