diff options
-rw-r--r-- | gdb/ChangeLog | 22 | ||||
-rw-r--r-- | gdb/ppc-linux-tdep.c | 110 | ||||
-rw-r--r-- | gdb/rs6000-tdep.c | 259 |
3 files changed, 377 insertions, 14 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index dfc5524..c0d7178 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,25 @@ +2004-03-19 Andrew Cagney <cagney@redhat.com> + + Committed by Kevin Buettner <kevinb@redhat.com>. + + * ppc-linux-tdep.c: Include "trad-frame.h", and "frame-unwind.h". + Update copyright. + (struct ppc_linux_sigtramp_cache, ppc_linux_sigtramp_cache) + (ppc_linux_sigtramp_this_id, ppc_linux_sigtramp_prev_register) + (ppc_linux_sigtramp_unwind, ppc_linux_sigtramp_sniffer) + (ppc_linux_init_abi): Add both 32- and 64-bit signal trampoline + unwinders. #ifdef legacy frame code. + * rs6000-tdep.c: Include "trad-frame.h", "frame-unwind.h", and + "frame-base.h". + (rs6000_unwind_pc, rs6000_unwind_dummy_id) + (struct rs6000_frame_cache, rs6000_frame_cache) + (rs6000_frame_this_id, rs6000_frame_prev_register) + (rs6000_frame_sniffer, rs6000_frame_unwind) + (rs6000_frame_base_address, rs6000_frame_base_sniffer) + (rs6000_frame_base): Implement a traditional frame unwinder. + (rs6000_gdbarch_init): When unknown, NetBSD, or GNU/Linux use the + frame unwinder. + 2004-03-19 Kevin Buettner <kevinb@redhat.com> * breakpoint.c (adjust_breakpoint_address): Don't adjust diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index a8173ea..901ae5c 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -35,6 +35,8 @@ #include "regset.h" #include "solib-svr4.h" #include "ppc-tdep.h" +#include "trad-frame.h" +#include "frame-unwind.h" /* The following instructions are used in the signal trampoline code on GNU/Linux PPC. The kernel used to use magic syscalls 0x6666 and @@ -1017,6 +1019,110 @@ static struct regset ppc32_linux_gregset = { NULL, ppc32_linux_supply_gregset }; +struct ppc_linux_sigtramp_cache +{ + CORE_ADDR base; + struct trad_frame_saved_reg *saved_regs; +}; + +static struct ppc_linux_sigtramp_cache * +ppc_linux_sigtramp_cache (struct frame_info *next_frame, void **this_cache) +{ + CORE_ADDR regs; + CORE_ADDR gpregs; + CORE_ADDR fpregs; + int i; + struct ppc_linux_sigtramp_cache *cache; + struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if ((*this_cache) != NULL) + return (*this_cache); + cache = FRAME_OBSTACK_ZALLOC (struct ppc_linux_sigtramp_cache); + (*this_cache) = cache; + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM); + + /* Find the register pointer, which gives the address of the + register buffers. */ + if (tdep->wordsize == 4) + regs = (cache->base + + 0xd0 /* Offset to ucontext_t. */ + + 0x30 /* Offset to .reg. */); + else + regs = (cache->base + + 0x80 /* Offset to ucontext_t. */ + + 0xe0 /* Offset to .reg. */); + /* And the corresponding register buffers. */ + gpregs = read_memory_unsigned_integer (regs, tdep->wordsize); + fpregs = gpregs + 48 * tdep->wordsize; + + /* General purpose. */ + for (i = 0; i < 32; i++) + { + int regnum = i + tdep->ppc_gp0_regnum; + cache->saved_regs[regnum].addr = gpregs + i * tdep->wordsize; + } + cache->saved_regs[PC_REGNUM].addr = gpregs + 32 * tdep->wordsize; + cache->saved_regs[tdep->ppc_ctr_regnum].addr = gpregs + 35 * tdep->wordsize; + cache->saved_regs[tdep->ppc_lr_regnum].addr = gpregs + 36 * tdep->wordsize; + cache->saved_regs[tdep->ppc_xer_regnum].addr = gpregs + 37 * tdep->wordsize; + cache->saved_regs[tdep->ppc_cr_regnum].addr = gpregs + 38 * tdep->wordsize; + + /* Floating point registers. */ + for (i = 0; i < 32; i++) + { + int regnum = i + FP0_REGNUM; + cache->saved_regs[regnum].addr = fpregs + i * tdep->wordsize; + } + cache->saved_regs[tdep->ppc_fpscr_regnum].addr = fpregs + 32 * tdep->wordsize; + + return cache; +} + +static void +ppc_linux_sigtramp_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct ppc_linux_sigtramp_cache *info + = ppc_linux_sigtramp_cache (next_frame, this_cache); + (*this_id) = frame_id_build (info->base, frame_pc_unwind (next_frame)); +} + +static void +ppc_linux_sigtramp_prev_register (struct frame_info *next_frame, + void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct ppc_linux_sigtramp_cache *info + = ppc_linux_sigtramp_cache (next_frame, this_cache); + trad_frame_prev_register (next_frame, info->saved_regs, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind ppc_linux_sigtramp_unwind = +{ + SIGTRAMP_FRAME, + ppc_linux_sigtramp_this_id, + ppc_linux_sigtramp_prev_register +}; + +static const struct frame_unwind * +ppc_linux_sigtramp_sniffer (struct frame_info *next_frame) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame)); + if (frame_pc_unwind (next_frame) + > frame_unwind_register_unsigned (next_frame, SP_REGNUM)) + /* Assume anything that is vaguely on the stack is a signal + trampoline. */ + return &ppc_linux_sigtramp_unwind; + else + return NULL; +} + static void ppc64_linux_supply_gregset (const struct regset *regset, struct regcache * regcache, @@ -1084,6 +1190,7 @@ ppc_linux_init_abi (struct gdbarch_info info, PowerOpen struct convention. */ set_gdbarch_return_value (gdbarch, ppc_linux_return_value); +#if 0 /* Note: kevinb/2002-04-12: See note in rs6000_gdbarch_init regarding *_push_arguments(). The same remarks hold for the methods below. */ set_gdbarch_deprecated_frameless_function_invocation (gdbarch, ppc_linux_frameless_function_invocation); @@ -1094,9 +1201,11 @@ ppc_linux_init_abi (struct gdbarch_info info, ppc_linux_frame_init_saved_regs); set_gdbarch_deprecated_init_extra_frame_info (gdbarch, ppc_linux_init_extra_frame_info); +#endif set_gdbarch_memory_remove_breakpoint (gdbarch, ppc_linux_memory_remove_breakpoint); + /* Shared library handling. */ set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section); set_gdbarch_skip_trampoline_code (gdbarch, @@ -1120,6 +1229,7 @@ ppc_linux_init_abi (struct gdbarch_info info, set_gdbarch_name_of_malloc (gdbarch, ".malloc"); } set_gdbarch_regset_from_core_section (gdbarch, ppc_linux_regset_from_core_section); + frame_unwind_append_sniffer (gdbarch, ppc_linux_sigtramp_sniffer); } void diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index 934b5d3..aefa629 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -50,6 +50,10 @@ #include "gdb_assert.h" #include "dis-asm.h" +#include "trad-frame.h" +#include "frame-unwind.h" +#include "frame-base.h" + /* If the kernel has to deliver a signal, it pushes a sigcontext structure on the stack and then calls the signal handler, passing the address of the sigcontext in an argument register. Usually @@ -2639,6 +2643,221 @@ gdb_print_insn_powerpc (bfd_vma memaddr, disassemble_info *info) return print_insn_little_powerpc (memaddr, info); } +static CORE_ADDR +rs6000_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + return frame_unwind_register_unsigned (next_frame, PC_REGNUM); +} + +static struct frame_id +rs6000_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + return frame_id_build (frame_unwind_register_unsigned (next_frame, + SP_REGNUM), + frame_pc_unwind (next_frame)); +} + +struct rs6000_frame_cache +{ + CORE_ADDR base; + CORE_ADDR initial_sp; + struct trad_frame_saved_reg *saved_regs; +}; + +static struct rs6000_frame_cache * +rs6000_frame_cache (struct frame_info *next_frame, void **this_cache) +{ + struct rs6000_frame_cache *cache; + struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct rs6000_framedata fdata; + int wordsize = tdep->wordsize; + + if ((*this_cache) != NULL) + return (*this_cache); + cache = FRAME_OBSTACK_ZALLOC (struct rs6000_frame_cache); + (*this_cache) = cache; + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + skip_prologue (frame_func_unwind (next_frame), frame_pc_unwind (next_frame), + &fdata); + + /* If there were any saved registers, figure out parent's stack + pointer. */ + /* The following is true only if the frame doesn't have a call to + alloca(), FIXME. */ + + if (fdata.saved_fpr == 0 + && fdata.saved_gpr == 0 + && fdata.saved_vr == 0 + && fdata.saved_ev == 0 + && fdata.lr_offset == 0 + && fdata.cr_offset == 0 + && fdata.vr_offset == 0 + && fdata.ev_offset == 0) + cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM); + else + { + /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most + address of the current frame. Things might be easier if the + ->frame pointed to the outer-most address of the frame. In + the mean time, the address of the prev frame is used as the + base address of this frame. */ + cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM); + if (!fdata.frameless) + /* Frameless really means stackless. */ + cache->base = read_memory_addr (cache->base, wordsize); + } + trad_frame_set_value (cache->saved_regs, SP_REGNUM, cache->base); + + /* if != -1, fdata.saved_fpr is the smallest number of saved_fpr. + All fpr's from saved_fpr to fp31 are saved. */ + + if (fdata.saved_fpr >= 0) + { + int i; + CORE_ADDR fpr_addr = cache->base + fdata.fpr_offset; + for (i = fdata.saved_fpr; i < 32; i++) + { + cache->saved_regs[FP0_REGNUM + i].addr = fpr_addr; + fpr_addr += 8; + } + } + + /* if != -1, fdata.saved_gpr is the smallest number of saved_gpr. + All gpr's from saved_gpr to gpr31 are saved. */ + + if (fdata.saved_gpr >= 0) + { + int i; + CORE_ADDR gpr_addr = cache->base + fdata.gpr_offset; + for (i = fdata.saved_gpr; i < 32; i++) + { + cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = gpr_addr; + gpr_addr += wordsize; + } + } + + /* if != -1, fdata.saved_vr is the smallest number of saved_vr. + All vr's from saved_vr to vr31 are saved. */ + if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) + { + if (fdata.saved_vr >= 0) + { + int i; + CORE_ADDR vr_addr = cache->base + fdata.vr_offset; + for (i = fdata.saved_vr; i < 32; i++) + { + cache->saved_regs[tdep->ppc_vr0_regnum + i].addr = vr_addr; + vr_addr += register_size (gdbarch, tdep->ppc_vr0_regnum); + } + } + } + + /* if != -1, fdata.saved_ev is the smallest number of saved_ev. + All vr's from saved_ev to ev31 are saved. ????? */ + if (tdep->ppc_ev0_regnum != -1 && tdep->ppc_ev31_regnum != -1) + { + if (fdata.saved_ev >= 0) + { + int i; + CORE_ADDR ev_addr = cache->base + fdata.ev_offset; + for (i = fdata.saved_ev; i < 32; i++) + { + cache->saved_regs[tdep->ppc_ev0_regnum + i].addr = ev_addr; + cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = ev_addr + 4; + ev_addr += register_size (gdbarch, tdep->ppc_ev0_regnum); + } + } + } + + /* If != 0, fdata.cr_offset is the offset from the frame that + holds the CR. */ + if (fdata.cr_offset != 0) + cache->saved_regs[tdep->ppc_cr_regnum].addr = cache->base + fdata.cr_offset; + + /* If != 0, fdata.lr_offset is the offset from the frame that + holds the LR. */ + if (fdata.lr_offset != 0) + cache->saved_regs[tdep->ppc_lr_regnum].addr = cache->base + fdata.lr_offset; + /* The PC is found in the link register. */ + cache->saved_regs[PC_REGNUM] = cache->saved_regs[tdep->ppc_lr_regnum]; + + /* If != 0, fdata.vrsave_offset is the offset from the frame that + holds the VRSAVE. */ + if (fdata.vrsave_offset != 0) + cache->saved_regs[tdep->ppc_vrsave_regnum].addr = cache->base + fdata.vrsave_offset; + + if (fdata.alloca_reg < 0) + /* If no alloca register used, then fi->frame is the value of the + %sp for this frame, and it is good enough. */ + cache->initial_sp = frame_unwind_register_unsigned (next_frame, SP_REGNUM); + else + cache->initial_sp = frame_unwind_register_unsigned (next_frame, + fdata.alloca_reg); + + return cache; +} + +static void +rs6000_frame_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct rs6000_frame_cache *info = rs6000_frame_cache (next_frame, + this_cache); + (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame)); +} + +static void +rs6000_frame_prev_register (struct frame_info *next_frame, + void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct rs6000_frame_cache *info = rs6000_frame_cache (next_frame, + this_cache); + trad_frame_prev_register (next_frame, info->saved_regs, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind rs6000_frame_unwind = +{ + NORMAL_FRAME, + rs6000_frame_this_id, + rs6000_frame_prev_register +}; + +static const struct frame_unwind * +rs6000_frame_sniffer (struct frame_info *next_frame) +{ + return &rs6000_frame_unwind; +} + + + +static CORE_ADDR +rs6000_frame_base_address (struct frame_info *next_frame, + void **this_cache) +{ + struct rs6000_frame_cache *info = rs6000_frame_cache (next_frame, + this_cache); + return info->initial_sp; +} + +static const struct frame_base rs6000_frame_base = { + &rs6000_frame_unwind, + rs6000_frame_base_address, + rs6000_frame_base_address, + rs6000_frame_base_address +}; + +static const struct frame_base * +rs6000_frame_base_sniffer (struct frame_info *next_frame) +{ + return &rs6000_frame_base; +} + /* Initialize the current architecture based on INFO. If possible, re-use an architecture from ARCHES, which is a list of architectures already created during this debugging session. @@ -2891,8 +3110,6 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) Problem is, 220 isn't frame (16 byte) aligned. Round it up to 224. */ set_gdbarch_frame_red_zone_size (gdbarch, 224); - set_gdbarch_deprecated_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos); - set_gdbarch_believe_pcc_promotion (gdbarch, 1); set_gdbarch_deprecated_register_convertible (gdbarch, rs6000_register_convertible); set_gdbarch_deprecated_register_convert_to_virtual (gdbarch, rs6000_register_convert_to_virtual); @@ -2913,7 +3130,6 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call); set_gdbarch_deprecated_extract_struct_value_address (gdbarch, rs6000_extract_struct_value_address); - set_gdbarch_deprecated_pop_frame (gdbarch, rs6000_pop_frame); set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue); set_gdbarch_inner_than (gdbarch, core_addr_lessthan); @@ -2935,14 +3151,6 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_use_struct_convention (gdbarch, rs6000_use_struct_convention); - set_gdbarch_deprecated_frameless_function_invocation (gdbarch, rs6000_frameless_function_invocation); - set_gdbarch_deprecated_frame_chain (gdbarch, rs6000_frame_chain); - set_gdbarch_deprecated_frame_saved_pc (gdbarch, rs6000_frame_saved_pc); - - set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, rs6000_frame_init_saved_regs); - set_gdbarch_deprecated_init_extra_frame_info (gdbarch, rs6000_init_extra_frame_info); - set_gdbarch_deprecated_init_frame_pc_first (gdbarch, rs6000_init_frame_pc_first); - if (!sysv_abi) { /* Handle RS/6000 function pointers (which are really function @@ -2950,9 +3158,6 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_convert_from_func_ptr_addr (gdbarch, rs6000_convert_from_func_ptr_addr); } - set_gdbarch_deprecated_frame_args_address (gdbarch, rs6000_frame_args_address); - set_gdbarch_deprecated_frame_locals_address (gdbarch, rs6000_frame_args_address); - set_gdbarch_deprecated_saved_pc_after_call (gdbarch, rs6000_saved_pc_after_call); /* Helpers for function argument information. */ set_gdbarch_fetch_pointer_argument (gdbarch, rs6000_fetch_pointer_argument); @@ -2960,6 +3165,32 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Hook in ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); + switch (info.osabi) + { + case GDB_OSABI_NETBSD_AOUT: + case GDB_OSABI_NETBSD_ELF: + case GDB_OSABI_UNKNOWN: + case GDB_OSABI_LINUX: + set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc); + frame_unwind_append_sniffer (gdbarch, rs6000_frame_sniffer); + set_gdbarch_unwind_dummy_id (gdbarch, rs6000_unwind_dummy_id); + frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer); + break; + default: + set_gdbarch_deprecated_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos); + set_gdbarch_believe_pcc_promotion (gdbarch, 1); + set_gdbarch_deprecated_pop_frame (gdbarch, rs6000_pop_frame); + set_gdbarch_deprecated_frame_args_address (gdbarch, rs6000_frame_args_address); + set_gdbarch_deprecated_frame_locals_address (gdbarch, rs6000_frame_args_address); + set_gdbarch_deprecated_saved_pc_after_call (gdbarch, rs6000_saved_pc_after_call); + set_gdbarch_deprecated_frameless_function_invocation (gdbarch, rs6000_frameless_function_invocation); + set_gdbarch_deprecated_frame_chain (gdbarch, rs6000_frame_chain); + set_gdbarch_deprecated_frame_saved_pc (gdbarch, rs6000_frame_saved_pc); + set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, rs6000_frame_init_saved_regs); + set_gdbarch_deprecated_init_extra_frame_info (gdbarch, rs6000_init_extra_frame_info); + set_gdbarch_deprecated_init_frame_pc_first (gdbarch, rs6000_init_frame_pc_first); + } + if (from_xcoff_exec) { /* NOTE: jimix/2003-06-09: This test should really check for |