X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fsparc-tdep.c;h=1f08865f9aaf08a4b41a7d3cbf09f89702a47962;hb=7755ddb77d227d1d5c1b211e989fafb17e26765d;hp=c98de3a94332952deb81327b24f4d3d068a81938;hpb=fe10a582b69fc09ce4775071aa619b0a6fc5dd1a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c index c98de3a943..1f08865f9a 100644 --- a/gdb/sparc-tdep.c +++ b/gdb/sparc-tdep.c @@ -1,7 +1,6 @@ /* Target-dependent code for SPARC. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright (C) 2003-2017 Free Software Foundation, Inc. This file is part of GDB. @@ -21,6 +20,7 @@ #include "defs.h" #include "arch-utils.h" #include "dis-asm.h" +#include "dwarf2.h" #include "dwarf2-frame.h" #include "floatformat.h" #include "frame.h" @@ -34,12 +34,12 @@ #include "osabi.h" #include "regcache.h" #include "target.h" +#include "target-descriptions.h" #include "value.h" -#include "gdb_assert.h" -#include "gdb_string.h" - #include "sparc-tdep.h" +#include "sparc-ravenscar-thread.h" +#include struct regset; @@ -86,7 +86,11 @@ struct regset; /* Sign extension macros. */ #define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000) #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 +124,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 @@ -193,6 +228,7 @@ sparc_integral_or_pointer_p (const struct type *type) return (len == 1 || len == 2 || len == 4 || len == 8); case TYPE_CODE_PTR: case TYPE_CODE_REF: + case TYPE_CODE_RVALUE_REF: /* Allow either 32-bit or 64-bit pointers. */ return (len == 4 || len == 8); default: @@ -262,21 +298,61 @@ sparc_structure_or_union_p (const struct type *type) return 0; } -/* Register information. */ +/* Check whether TYPE is returned on registers. */ -static const char *sparc32_register_names[] = +static bool +sparc_structure_return_p (const struct type *type) +{ + if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_LENGTH (type) <= 8) + { + struct type *t = check_typedef (TYPE_TARGET_TYPE (type)); + + if (sparc_floating_p (t) && TYPE_LENGTH (t) == 8) + return true; + return false; + } + if (sparc_floating_p (type) && TYPE_LENGTH (type) == 16) + return true; + return sparc_structure_or_union_p (type); +} + +/* Check whether TYPE is passed on registers. */ + +static bool +sparc_arg_on_registers_p (const struct type *type) { - "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", - "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", - "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", - "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", + if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_LENGTH (type) <= 8) + { + struct type *t = check_typedef (TYPE_TARGET_TYPE (type)); - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + if (sparc_floating_p (t) && TYPE_LENGTH (t) == 8) + return false; + return true; + } + if (sparc_structure_or_union_p (type) || sparc_complex_floating_p (type) + || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16)) + return false; + return true; +} +/* Register information. */ +#define SPARC32_FPU_REGISTERS \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \ + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" +#define SPARC32_CP0_REGISTERS \ "y", "psr", "wim", "tbr", "pc", "npc", "fsr", "csr" + +static const char *sparc_core_register_names[] = { SPARC_CORE_REGISTERS }; +static const char *sparc32_fpu_register_names[] = { SPARC32_FPU_REGISTERS }; +static const char *sparc32_cp0_register_names[] = { SPARC32_CP0_REGISTERS }; + +static const char *sparc32_register_names[] = +{ + SPARC_CORE_REGISTERS, + SPARC32_FPU_REGISTERS, + SPARC32_CP0_REGISTERS }; /* Total number of registers. */ @@ -294,18 +370,33 @@ static const char *sparc32_pseudo_register_names[] = /* Total number of pseudo registers. */ #define SPARC32_NUM_PSEUDO_REGS ARRAY_SIZE (sparc32_pseudo_register_names) +/* Return the name of pseudo register REGNUM. */ + +static const char * +sparc32_pseudo_register_name (struct gdbarch *gdbarch, int regnum) +{ + regnum -= gdbarch_num_regs (gdbarch); + + if (regnum < SPARC32_NUM_PSEUDO_REGS) + return sparc32_pseudo_register_names[regnum]; + + internal_error (__FILE__, __LINE__, + _("sparc32_pseudo_register_name: bad register number %d"), + regnum); +} + /* Return the name of register REGNUM. */ static const char * sparc32_register_name (struct gdbarch *gdbarch, int regnum) { - if (regnum >= 0 && regnum < SPARC32_NUM_REGS) - return sparc32_register_names[regnum]; + if (tdesc_has_registers (gdbarch_target_desc (gdbarch))) + return tdesc_register_name (gdbarch, regnum); - if (regnum < SPARC32_NUM_REGS + SPARC32_NUM_PSEUDO_REGS) - return sparc32_pseudo_register_names[regnum - SPARC32_NUM_REGS]; + if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch)) + return sparc32_register_names[regnum]; - return NULL; + return sparc32_pseudo_register_name (gdbarch, regnum); } /* Construct types for ISA-specific registers. */ @@ -365,18 +456,34 @@ sparc_fsr_type (struct gdbarch *gdbarch) return tdep->sparc_fsr_type; } +/* Return the GDB type object for the "standard" data type of data in + pseudo register REGNUM. */ + +static struct type * +sparc32_pseudo_register_type (struct gdbarch *gdbarch, int regnum) +{ + regnum -= gdbarch_num_regs (gdbarch); + + if (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM) + return builtin_type (gdbarch)->builtin_double; + + internal_error (__FILE__, __LINE__, + _("sparc32_pseudo_register_type: bad register number %d"), + regnum); +} + /* Return the GDB type object for the "standard" data type of data in register REGNUM. */ static struct type * sparc32_register_type (struct gdbarch *gdbarch, int regnum) { + if (tdesc_has_registers (gdbarch_target_desc (gdbarch))) + return tdesc_register_type (gdbarch, regnum); + if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM) return builtin_type (gdbarch)->builtin_float; - if (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM) - return builtin_type (gdbarch)->builtin_double; - if (regnum == SPARC_SP_REGNUM || regnum == SPARC_FP_REGNUM) return builtin_type (gdbarch)->builtin_data_ptr; @@ -389,6 +496,9 @@ sparc32_register_type (struct gdbarch *gdbarch, int regnum) if (regnum == SPARC32_FSR_REGNUM) return sparc_fsr_type (gdbarch); + if (regnum >= gdbarch_num_regs (gdbarch)) + return sparc32_pseudo_register_type (gdbarch, regnum); + return builtin_type (gdbarch)->builtin_int32; } @@ -399,6 +509,7 @@ sparc32_pseudo_register_read (struct gdbarch *gdbarch, { enum register_status status; + regnum -= gdbarch_num_regs (gdbarch); gdb_assert (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM); regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC32_D0_REGNUM); @@ -413,6 +524,7 @@ sparc32_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int regnum, const gdb_byte *buf) { + regnum -= gdbarch_num_regs (gdbarch); gdb_assert (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM); regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC32_D0_REGNUM); @@ -420,6 +532,29 @@ sparc32_pseudo_register_write (struct gdbarch *gdbarch, regcache_raw_write (regcache, regnum + 1, buf + 4); } +/* Implement the stack_frame_destroyed_p gdbarch method. */ + +int +sparc_stack_frame_destroyed_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) @@ -472,9 +607,7 @@ sparc32_store_arguments (struct regcache *regcache, int nargs, struct type *type = value_type (args[i]); int len = TYPE_LENGTH (type); - if (sparc_structure_or_union_p (type) - || (sparc_floating_p (type) && len == 16) - || sparc_complex_floating_p (type)) + if (!sparc_arg_on_registers_p (type)) { /* Structure, Union and Quad-Precision Arguments. */ sp -= len; @@ -496,17 +629,14 @@ sparc32_store_arguments (struct regcache *regcache, int nargs, else { /* Integral and pointer arguments. */ - gdb_assert (sparc_integral_or_pointer_p (type)); - - if (len < 4) - args[i] = value_cast (builtin_type (gdbarch)->builtin_int32, - args[i]); + gdb_assert (sparc_integral_or_pointer_p (type) + || (TYPE_CODE (type) == TYPE_CODE_ARRAY && len <= 8)); num_elements += ((len + 3) / 4); } } /* Always allocate at least six words. */ - sp -= max (6, num_elements) * 4; + sp -= std::max (6, num_elements) * 4; /* The psABI says that "Software convention requires space for the struct/union return value pointer, even if the word is unused." */ @@ -522,6 +652,15 @@ sparc32_store_arguments (struct regcache *regcache, int nargs, const bfd_byte *valbuf = value_contents (args[i]); struct type *type = value_type (args[i]); int len = TYPE_LENGTH (type); + gdb_byte buf[4]; + + if (len < 4) + { + memset (buf, 0, 4 - len); + memcpy (buf + 4 - len, valbuf, len); + valbuf = buf; + len = 4; + } gdb_assert (len == 4 || len == 8); @@ -585,15 +724,9 @@ sparc32_push_dummy_call (struct gdbarch *gdbarch, struct value *function, encode a breakpoint instruction, store the length of the string in *LEN and optionally adjust *PC to point to the correct memory location for inserting the breakpoint. */ - -static const gdb_byte * -sparc_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc, int *len) -{ - static const gdb_byte break_insn[] = { 0x91, 0xd0, 0x20, 0x01 }; +constexpr gdb_byte sparc_break_insn[] = { 0x91, 0xd0, 0x20, 0x01 }; - *len = sizeof (break_insn); - return break_insn; -} +typedef BP_MANIPULATION (sparc_break_insn) sparc_breakpoint; /* Allocate and initialize a frame cache. */ @@ -602,7 +735,6 @@ static struct sparc_frame_cache * sparc_alloc_frame_cache (void) { struct sparc_frame_cache *cache; - int i; cache = FRAME_OBSTACK_ZALLOC (struct sparc_frame_cache); @@ -630,7 +762,6 @@ sparc_skip_stack_check (const CORE_ADDR start_pc) { CORE_ADDR pc = start_pc; unsigned long insn; - int offset_stack_checking_sequence = 0; int probing_loop = 0; /* With GCC, all stack checking sequences begin with the same two @@ -855,7 +986,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); @@ -1046,7 +1177,7 @@ sparc_frame_cache (struct frame_info *this_frame, void **this_cache) struct sparc_frame_cache *cache; if (*this_cache) - return *this_cache; + return (struct sparc_frame_cache *) *this_cache; cache = sparc_alloc_frame_cache (); *this_cache = cache; @@ -1104,7 +1235,7 @@ sparc32_frame_cache (struct frame_info *this_frame, void **this_cache) struct symbol *sym; if (*this_cache) - return *this_cache; + return (struct sparc_frame_cache *) *this_cache; cache = sparc_frame_cache (this_frame, this_cache); @@ -1255,10 +1386,10 @@ sparc32_extract_return_value (struct type *type, struct regcache *regcache, int len = TYPE_LENGTH (type); gdb_byte buf[32]; - gdb_assert (!sparc_structure_or_union_p (type)); - gdb_assert (!(sparc_floating_p (type) && len == 16)); + gdb_assert (!sparc_structure_return_p (type)); - if (sparc_floating_p (type) || sparc_complex_floating_p (type)) + if (sparc_floating_p (type) || sparc_complex_floating_p (type) + || TYPE_CODE (type) == TYPE_CODE_ARRAY) { /* Floating return values. */ regcache_cooked_read (regcache, SPARC_F0_REGNUM, buf); @@ -1307,11 +1438,9 @@ sparc32_store_return_value (struct type *type, struct regcache *regcache, const gdb_byte *valbuf) { int len = TYPE_LENGTH (type); - gdb_byte buf[8]; + gdb_byte buf[32]; - gdb_assert (!sparc_structure_or_union_p (type)); - gdb_assert (!(sparc_floating_p (type) && len == 16)); - gdb_assert (len <= 8); + gdb_assert (!sparc_structure_return_p (type)); if (sparc_floating_p (type) || sparc_complex_floating_p (type)) { @@ -1354,7 +1483,7 @@ sparc32_store_return_value (struct type *type, struct regcache *regcache, } static enum return_value_convention -sparc32_return_value (struct gdbarch *gdbarch, struct type *func_type, +sparc32_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { @@ -1367,18 +1496,23 @@ sparc32_return_value (struct gdbarch *gdbarch, struct type *func_type, guarantees that we can always find the return value, not just before the function returns. */ - if (sparc_structure_or_union_p (type) - || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16)) + if (sparc_structure_return_p (type)) { + 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; } @@ -1441,25 +1575,63 @@ sparc32_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, } } +/* Implement the execute_dwarf_cfa_vendor_op method. */ + +static bool +sparc_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op, + struct dwarf2_frame_state *fs) +{ + /* Only DW_CFA_GNU_window_save is expected on SPARC. */ + if (op != DW_CFA_GNU_window_save) + return false; + + uint64_t reg; + int size = register_size (gdbarch, 0); + + fs->regs.alloc_regs (32); + for (reg = 8; reg < 16; reg++) + { + fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG; + fs->regs.reg[reg].loc.reg = reg + 16; + } + for (reg = 16; reg < 32; reg++) + { + fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET; + fs->regs.reg[reg].loc.offset = (reg - 16) * size; + } + + return true; +} + /* The SPARC Architecture doesn't have hardware single-step support, and most operating systems don't implement it either, so we provide software single-step mechanism. */ static CORE_ADDR -sparc_analyze_control_transfer (struct frame_info *frame, +sparc_analyze_control_transfer (struct regcache *regcache, CORE_ADDR pc, CORE_ADDR *npc) { unsigned long insn = sparc_fetch_instruction (pc); int conditional_p = X_COND (insn) & 0x7; - int branch_p = 0; + int branch_p = 0, fused_p = 0; long offset = 0; /* Must be signed for sign-extend. */ - if (X_OP (insn) == 0 && X_OP2 (insn) == 3 && (insn & 0x1000000) == 0) + if (X_OP (insn) == 0 && X_OP2 (insn) == 3) { - /* Branch on Integer Register with Prediction (BPr). */ - branch_p = 1; - conditional_p = 1; + if ((insn & 0x10000000) == 0) + { + /* Branch on Integer Register with Prediction (BPr). */ + branch_p = 1; + conditional_p = 1; + } + else + { + /* Compare and Branch */ + branch_p = 1; + fused_p = 1; + offset = 4 * X_DISP10 (insn); + } } else if (X_OP (insn) == 0 && X_OP2 (insn) == 6) { @@ -1488,15 +1660,27 @@ sparc_analyze_control_transfer (struct frame_info *frame, } else if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3a) { + struct frame_info *frame = get_current_frame (); + /* Trap instruction (TRAP). */ - return gdbarch_tdep (get_frame_arch (frame))->step_trap (frame, insn); + return gdbarch_tdep (get_regcache_arch (regcache))->step_trap (frame, + insn); } /* FIXME: Handle DONE and RETRY instructions. */ if (branch_p) { - if (conditional_p) + if (fused_p) + { + /* Fused compare-and-branch instructions are non-delayed, + and do not have an annuling capability. So we need to + always set a breakpoint on both the NPC and the branch + target address. */ + gdb_assert (offset != 0); + return pc + offset; + } + else if (conditional_p) { /* For conditional branches, return nPC + 4 iff the annul bit is 1. */ @@ -1513,7 +1697,6 @@ sparc_analyze_control_transfer (struct frame_info *frame, if (X_A (insn)) *npc = 0; - gdb_assert (offset != 0); return pc + offset; } } @@ -1527,26 +1710,26 @@ sparc_step_trap (struct frame_info *frame, unsigned long insn) return 0; } -int -sparc_software_single_step (struct frame_info *frame) +static std::vector +sparc_software_single_step (struct regcache *regcache) { - struct gdbarch *arch = get_frame_arch (frame); + struct gdbarch *arch = get_regcache_arch (regcache); struct gdbarch_tdep *tdep = gdbarch_tdep (arch); - struct address_space *aspace = get_frame_address_space (frame); CORE_ADDR npc, nnpc; CORE_ADDR pc, orig_npc; + std::vector next_pcs; - pc = get_frame_register_unsigned (frame, tdep->pc_regnum); - orig_npc = npc = get_frame_register_unsigned (frame, tdep->npc_regnum); + pc = regcache_raw_get_unsigned (regcache, tdep->pc_regnum); + orig_npc = npc = regcache_raw_get_unsigned (regcache, tdep->npc_regnum); /* Analyze the instruction at PC. */ - nnpc = sparc_analyze_control_transfer (frame, pc, &npc); + nnpc = sparc_analyze_control_transfer (regcache, pc, &npc); if (npc != 0) - insert_single_step_breakpoint (arch, aspace, npc); + next_pcs.push_back (npc); if (nnpc != 0) - insert_single_step_breakpoint (arch, aspace, nnpc); + next_pcs.push_back (nnpc); /* Assert that we have set at least one breakpoint, and that they're not set at the same spot - unless we're going @@ -1554,7 +1737,7 @@ sparc_software_single_step (struct frame_info *frame) gdb_assert (npc != 0 || nnpc != 0 || orig_npc == 0); gdb_assert (nnpc != npc || orig_npc == 0); - return 1; + return next_pcs; } static void @@ -1567,30 +1750,51 @@ 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; + cb (".reg", tdep->sizeof_gregset, tdep->gregset, NULL, cb_data); + cb (".reg2", tdep->sizeof_fpregset, tdep->fpregset, NULL, cb_data); +} + + +static int +validate_tdesc_registers (const struct target_desc *tdesc, + struct tdesc_arch_data *tdesc_data, + const char *feature_name, + const char *register_names[], + unsigned int registers_num, + unsigned int reg_start) +{ + int valid_p = 1; + const struct tdesc_feature *feature; + + feature = tdesc_find_feature (tdesc, feature_name); + if (feature == NULL) + return 0; - if (strcmp (sect_name, ".reg2") == 0 && sect_size >= tdep->sizeof_fpregset) - return tdep->fpregset; + for (unsigned int i = 0; i < registers_num; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + reg_start + i, + register_names[i]); - return NULL; + return valid_p; } - static struct gdbarch * sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { struct gdbarch_tdep *tdep; + const struct target_desc *tdesc = info.target_desc; struct gdbarch *gdbarch; + int valid_p = 1; /* If there is already a candidate, use it. */ arches = gdbarch_list_lookup_by_info (arches, &info); @@ -1598,20 +1802,29 @@ 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; tdep->npc_regnum = SPARC32_NPC_REGNUM; tdep->step_trap = sparc_step_trap; + tdep->fpu_register_names = sparc32_fpu_register_names; + tdep->fpu_registers_num = ARRAY_SIZE (sparc32_fpu_register_names); + tdep->cp0_register_names = sparc32_cp0_register_names; + tdep->cp0_registers_num = ARRAY_SIZE (sparc32_cp0_register_names); set_gdbarch_long_double_bit (gdbarch, 128); set_gdbarch_long_double_format (gdbarch, floatformats_sparc_quad); + set_gdbarch_wchar_bit (gdbarch, 16); + set_gdbarch_wchar_signed (gdbarch, 1); + set_gdbarch_num_regs (gdbarch, SPARC32_NUM_REGS); set_gdbarch_register_name (gdbarch, sparc32_register_name); set_gdbarch_register_type (gdbarch, sparc32_register_type); set_gdbarch_num_pseudo_regs (gdbarch, SPARC32_NUM_PSEUDO_REGS); + set_tdesc_pseudo_register_name (gdbarch, sparc32_pseudo_register_name); + set_tdesc_pseudo_register_type (gdbarch, sparc32_pseudo_register_type); set_gdbarch_pseudo_register_read (gdbarch, sparc32_pseudo_register_read); set_gdbarch_pseudo_register_write (gdbarch, sparc32_pseudo_register_write); @@ -1635,12 +1848,13 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Stack grows downward. */ set_gdbarch_inner_than (gdbarch, core_addr_lessthan); - set_gdbarch_breakpoint_from_pc (gdbarch, sparc_breakpoint_from_pc); + set_gdbarch_breakpoint_kind_from_pc (gdbarch, + sparc_breakpoint::kind_from_pc); + set_gdbarch_sw_breakpoint_from_kind (gdbarch, + sparc_breakpoint::bp_from_kind); set_gdbarch_frame_args_skip (gdbarch, 8); - set_gdbarch_print_insn (gdbarch, print_insn_sparc); - set_gdbarch_software_single_step (gdbarch, sparc_software_single_step); set_gdbarch_write_pc (gdbarch, sparc_write_pc); @@ -1652,6 +1866,9 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Hook in the DWARF CFI frame unwinder. */ dwarf2_frame_set_init_reg (gdbarch, sparc32_dwarf2_frame_init_reg); + /* Register DWARF vendor CFI handler. */ + set_gdbarch_execute_dwarf_cfa_vendor_op (gdbarch, + sparc_execute_dwarf_cfa_vendor_op); /* FIXME: kettenis/20050423: Don't enable the unwinder until the StackGhost issues have been resolved. */ @@ -1660,10 +1877,45 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) frame_unwind_append_unwinder (gdbarch, &sparc32_frame_unwind); + if (tdesc_has_registers (tdesc)) + { + struct tdesc_arch_data *tdesc_data = tdesc_data_alloc (); + + /* Validate that the descriptor provides the mandatory registers + and allocate their numbers. */ + valid_p &= validate_tdesc_registers (tdesc, tdesc_data, + "org.gnu.gdb.sparc.cpu", + sparc_core_register_names, + ARRAY_SIZE (sparc_core_register_names), + SPARC_G0_REGNUM); + valid_p &= validate_tdesc_registers (tdesc, tdesc_data, + "org.gnu.gdb.sparc.fpu", + tdep->fpu_register_names, + tdep->fpu_registers_num, + SPARC_F0_REGNUM); + valid_p &= validate_tdesc_registers (tdesc, tdesc_data, + "org.gnu.gdb.sparc.cp0", + tdep->cp0_register_names, + tdep->cp0_registers_num, + SPARC_F0_REGNUM + + tdep->fpu_registers_num); + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + + /* Target description may have changed. */ + info.tdesc_data = tdesc_data; + tdesc_use_registers (gdbarch, tdesc, tdesc_data); + } + /* 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; } @@ -1815,36 +2067,36 @@ 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) { - const gdb_byte *regs = gregs; + const gdb_byte *regs = (const gdb_byte *) gregs; gdb_byte zero[4] = { 0 }; int i; 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++) { @@ -1858,7 +2110,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; @@ -1867,7 +2119,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++) { @@ -1880,32 +2132,32 @@ 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) { - gdb_byte *regs = gregs; + gdb_byte *regs = (gdb_byte *) gregs; int i; 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++) @@ -1920,9 +2172,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++) { @@ -1935,44 +2187,50 @@ sparc32_collect_gregset (const struct sparc_gregset *gregset, } void -sparc32_supply_fpregset (struct regcache *regcache, +sparc32_supply_fpregset (const struct sparc_fpregmap *fpregmap, + struct regcache *regcache, int regnum, const void *fpregs) { - const gdb_byte *regs = fpregs; + const gdb_byte *regs = (const gdb_byte *) fpregs; int i; for (i = 0; i < 32; i++) { if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1) - regcache_raw_supply (regcache, SPARC_F0_REGNUM + i, regs + (i * 4)); + regcache_raw_supply (regcache, SPARC_F0_REGNUM + i, + regs + fpregmap->r_f0_offset + (i * 4)); } if (regnum == SPARC32_FSR_REGNUM || regnum == -1) - regcache_raw_supply (regcache, SPARC32_FSR_REGNUM, regs + (32 * 4) + 4); + regcache_raw_supply (regcache, SPARC32_FSR_REGNUM, + regs + fpregmap->r_fsr_offset); } void -sparc32_collect_fpregset (const struct regcache *regcache, +sparc32_collect_fpregset (const struct sparc_fpregmap *fpregmap, + const struct regcache *regcache, int regnum, void *fpregs) { - gdb_byte *regs = fpregs; + gdb_byte *regs = (gdb_byte *) fpregs; int i; for (i = 0; i < 32; i++) { if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1) - regcache_raw_collect (regcache, SPARC_F0_REGNUM + i, regs + (i * 4)); + regcache_raw_collect (regcache, SPARC_F0_REGNUM + i, + regs + fpregmap->r_f0_offset + (i * 4)); } if (regnum == SPARC32_FSR_REGNUM || regnum == -1) - regcache_raw_collect (regcache, SPARC32_FSR_REGNUM, regs + (32 * 4) + 4); + regcache_raw_collect (regcache, SPARC32_FSR_REGNUM, + 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 */ @@ -1983,6 +2241,18 @@ const struct sparc_gregset sparc32_sunos4_gregset = 4 * 4, /* %g1 */ -1 /* %l0 */ }; + +const struct sparc_fpregmap sparc32_sunos4_fpregmap = +{ + 0 * 4, /* %f0 */ + 33 * 4, /* %fsr */ +}; + +const struct sparc_fpregmap sparc32_bsd_fpregmap = +{ + 0 * 4, /* %f0 */ + 32 * 4, /* %fsr */ +}; /* Provide a prototype to silence -Wmissing-prototypes. */