From b5c10493e9666be2c7413ffcf712160d35246966 Mon Sep 17 00:00:00 2001 From: Stu Grossman Date: Mon, 28 Dec 1992 23:19:51 +0000 Subject: [PATCH] * hppah-tdep.c (frame_saved_pc): Use better test for outermost frame. Use find_return_regnum to find the caller. * (find_unwind_entry): New routine to locate stack frame info associated with a procedure. This looks in the $UNWIND_START$ section in the SOM file. * (find_return_regnum): New routine. Uses find_unwind_entry() to figure out where the caller's return address is stored. * (find_proc_framesize): New routine. Uses find_unwind_entry() to figure out the frame size for a procedure. * (saved_pc_after_call): New routine, moved from tm-hppa.h. * (init_extra_frame_info): New routine. Corrects PC and FP for outermost frame if necessary. * (frame_chain): New routine, moved from tm-hppa.h. * (skip_trampoline_code): Handle computed function calls (ie: calls from $$dyncall). * (unwind_command): Temporary support function to allow user to control/observe aspects of the unwind (stack frame) info. * infcmd.c (read_pc): (Temporary), put a hack in to see if the PC was in a system call, if so, then read the PC from r31. * tm-hppah.h (SKIP_TRAMPOLINE_CODE, IN_SOLIB_TRAMPOLINE): Deal with extra arg for skip_trampoline_code(). * (INIT_EXTRA_FRAME_INFO): Define to point at subr (see above). * (FRAME_CHAIN, FRAME_CHAIN_VALID): Turn into real subroutines. * tm-hppa.h (SAVED_PC_AFTER_CALL): Turn into real subroutine. --- gdb/ChangeLog | 27 +++++++ gdb/hppah-tdep.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++----- gdb/infcmd.c | 7 ++ gdb/tm-hppa.h | 17 ++--- gdb/tm-hppah.h | 6 +- 5 files changed, 239 insertions(+), 33 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d062e41..690b59a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,30 @@ +Mon Dec 28 15:00:01 1992 Stu Grossman (grossman at cygnus.com) + + * hppah-tdep.c (frame_saved_pc): Use better test for outermost + frame. Use find_return_regnum to find the caller. + * (find_unwind_entry): New routine to locate stack frame info + associated with a procedure. This looks in the $UNWIND_START$ + section in the SOM file. + * (find_return_regnum): New routine. Uses find_unwind_entry() to + figure out where the caller's return address is stored. + * (find_proc_framesize): New routine. Uses find_unwind_entry() + to figure out the frame size for a procedure. + * (saved_pc_after_call): New routine, moved from tm-hppa.h. + * (init_extra_frame_info): New routine. Corrects PC and FP for + outermost frame if necessary. + * (frame_chain): New routine, moved from tm-hppa.h. + * (skip_trampoline_code): Handle computed function calls (ie: + calls from $$dyncall). + * (unwind_command): Temporary support function to allow user + to control/observe aspects of the unwind (stack frame) info. + * infcmd.c (read_pc): (Temporary), put a hack in to see if the PC + was in a system call, if so, then read the PC from r31. + * tm-hppah.h (SKIP_TRAMPOLINE_CODE, IN_SOLIB_TRAMPOLINE): Deal + with extra arg for skip_trampoline_code(). + * (INIT_EXTRA_FRAME_INFO): Define to point at subr (see above). + * (FRAME_CHAIN, FRAME_CHAIN_VALID): Turn into real subroutines. + * tm-hppa.h (SAVED_PC_AFTER_CALL): Turn into real subroutine. + Sun Dec 27 17:34:15 1992 Fred Fish (fnf@cygnus.com) * dbxread.c (dbx_symfile_init, elfstab_build_psymtabs): diff --git a/gdb/hppah-tdep.c b/gdb/hppah-tdep.c index 67aae83..51608ee 100644 --- a/gdb/hppah-tdep.c +++ b/gdb/hppah-tdep.c @@ -260,29 +260,150 @@ extract_17 (word) (word & 0x1) << 16, 17) << 2; } +int use_unwind = 0; + +static struct unwind_table_entry * +find_unwind_entry(pc) + CORE_ADDR pc; +{ + static struct unwind_table_entry *unwind = NULL, *unwind_end; + struct unwind_table_entry *u; + + if (!use_unwind) + return NULL; + + if (!unwind) + { + asection *unwind_sec; + + unwind_sec = bfd_get_section_by_name (exec_bfd, "$UNWIND_START$"); + if (unwind_sec) + { + int size; + + size = bfd_section_size (exec_bfd, unwind_sec); + unwind = malloc (size); + unwind_end = unwind + size/sizeof (struct unwind_table_entry); + + bfd_get_section_contents (exec_bfd, unwind_sec, unwind, 0, size); + } + } + + for (u = unwind; u < unwind_end; u++) + { + if (pc >= u->region_start + && pc <= u->region_end) + return u; + } + return NULL; +} + +static int +find_return_regnum(pc) + CORE_ADDR pc; +{ + struct unwind_table_entry *u; + + u = find_unwind_entry (pc); + + if (!u) + return RP_REGNUM; + + if (u->Millicode) + return 31; + + return RP_REGNUM; +} + +int +find_proc_framesize(pc) + CORE_ADDR pc; +{ + struct unwind_table_entry *u; + + u = find_unwind_entry (pc); + + if (!u) + return -1; + + return u->Total_frame_size << 3; +} + +CORE_ADDR +saved_pc_after_call (frame) + FRAME frame; +{ + int ret_regnum; + + ret_regnum = find_return_regnum (get_frame_pc (frame)); + + return read_register (ret_regnum) & ~0x3; +} + CORE_ADDR frame_saved_pc (frame) FRAME frame; { - if (get_current_frame () == frame) + if (!frame->next) { - struct frame_saved_regs saved_regs; CORE_ADDR pc = get_frame_pc (frame); - int flags; - - flags = read_register (FLAGS_REGNUM); - get_frame_saved_regs (frame, &saved_regs); - if (pc >= millicode_start && pc < millicode_end - || (flags & 2)) /* In system call? */ - return read_register (31) & ~3; - else if (saved_regs.regs[RP_REGNUM]) - return read_memory_integer (saved_regs.regs[RP_REGNUM], 4) & ~3; - else - return read_register (RP_REGNUM) & ~3; + int ret_regnum; + + ret_regnum = find_return_regnum (pc); + + return read_register (ret_regnum) & ~0x3; } return read_memory_integer (frame->frame - 20, 4) & ~0x3; } + +/* We need to correct the PC and the FP for the outermost frame when we are + in a system call. */ + +void +init_extra_frame_info (fromleaf, frame) + int fromleaf; + struct frame_info *frame; +{ + int flags; + int framesize; + + if (frame->next) /* Only do this for outermost frame */ + return; + flags = read_register (FLAGS_REGNUM); + if (flags & 2) /* In system call? */ + frame->pc = read_register (31) & ~0x3; + + /* The outermost frame is always derived from PC-framesize */ + framesize = find_proc_framesize(frame->pc); + if (framesize == -1) + frame->frame = read_register (FP_REGNUM); + else + frame->frame = read_register (SP_REGNUM) - framesize; + + if (framesize != 0) /* Frameless? */ + return; + + /* For frameless functions, we need to look at the caller's frame */ + framesize = find_proc_framesize(FRAME_SAVED_PC(frame)); + if (framesize != -1) + frame->frame -= framesize; +} + +FRAME_ADDR +frame_chain (frame) + struct frame_info *frame; +{ + int framesize; + + framesize = find_proc_framesize(FRAME_SAVED_PC(frame)); + + if (framesize != -1) + return frame->frame - framesize; + + return read_memory_integer (frame->frame, 4); +} + /* To see if a frame chain is valid, see if the caller looks like it was compiled with gcc. */ @@ -293,7 +414,6 @@ int frame_chain_valid (chain, thisframe) if (chain && (chain > 0x60000000)) { CORE_ADDR pc = get_pc_function_start (FRAME_SAVED_PC (thisframe)); - if (inside_entry_file (pc)) return 0; /* look for stw rp, -20(0,sp); copy 4,1; copy sp, 4 */ @@ -629,13 +749,32 @@ pa_print_fp_reg (i) small piece of code that does long format (`external' in HPPA parlance) jumps. We figure out where the trampoline is going to end up, and return the PC of the final destination. If we aren't in a trampoline, we just - return NULL. */ + return NULL. + + For computed calls, we just extract the new PC from r22. */ CORE_ADDR -skip_trampoline_code (pc) +skip_trampoline_code (pc, name) CORE_ADDR pc; + char *name; { long inst0, inst1; + static CORE_ADDR dyncall = 0; + struct minimal_symbol *msym; + +/* FIXME XXX - dyncall must be initialized whenever we get a new exec file */ + + if (!dyncall) + { + msym = lookup_minimal_symbol ("$$dyncall", NULL); + if (msym) + dyncall = msym->address; + else + dyncall = -1; + } + + if (pc == dyncall) + return (CORE_ADDR)(read_register (22) & ~0x3); inst0 = read_memory_integer (pc, 4); inst1 = read_memory_integer (pc+4, 4); @@ -644,7 +783,49 @@ skip_trampoline_code (pc) && (inst1 & 0xffe0e002) == 0xe0202002) /* be,n yyy(sr4, r1) */ pc = extract_21 (inst0) + extract_17 (inst1); else - pc = NULL; + pc = (CORE_ADDR)NULL; return pc; } + +static void +unwind_command (exp, from_tty) + char *exp; + int from_tty; +{ + CORE_ADDR address; + union + { + int *foo; + struct unwind_table_entry *u; + } xxx; + + /* If we have an expression, evaluate it and use it as the address. */ + + if (exp != 0 && *exp != 0) + address = parse_and_eval_address (exp); + else + return; + + xxx.u = find_unwind_entry (address); + + if (!xxx.u) + { + printf ("Can't find unwind table entry for PC 0x%x\n", address); + return; + } + + printf ("%08x\n%08X\n%08X\n%08X\n", xxx.foo[0], xxx.foo[1], xxx.foo[2], + xxx.foo[3]); +} + +void +_initialize_hppah_tdep () +{ + add_com ("unwind", class_obscure, unwind_command, "Print unwind info\n"); + add_show_from_set + (add_set_cmd ("use_unwind", class_obscure, var_boolean, + (char *)&use_unwind, + "Control the useage of unwind info.\n", &setlist), + &showlist); +} diff --git a/gdb/infcmd.c b/gdb/infcmd.c index c190ffe..05d2214 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -877,6 +877,13 @@ path_command (dirname, from_tty) CORE_ADDR read_pc () { +#if GDB_TARGET_IS_HPPA + int flags = read_register(FLAGS_REGNUM); + + if (flags & 2) + return read_register(31) & ~0x3; +#endif + return ADDR_BITS_REMOVE ((CORE_ADDR) read_register (PC_REGNUM)); } diff --git a/gdb/tm-hppa.h b/gdb/tm-hppa.h index 285e932..97cf7b4 100644 --- a/gdb/tm-hppa.h +++ b/gdb/tm-hppa.h @@ -75,11 +75,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* If PC is in some function-call trampoline code, return the PC where the function itself actually starts. If not, return NULL. */ -#define SKIP_TRAMPOLINE_CODE(pc) skip_trampoline_code (pc) +#define SKIP_TRAMPOLINE_CODE(pc) skip_trampoline_code (pc, NULL) /* Return non-zero if we are in some sort of a trampoline. */ -#define IN_SOLIB_TRAMPOLINE(pc,name) skip_trampoline_code (pc) +#define IN_SOLIB_TRAMPOLINE(pc, name) skip_trampoline_code (pc, name) /* Immediately after a function call, return the saved pc. Can't go through the frames for this because on some machines @@ -290,11 +290,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ((regno) >= PCSQ_TAIL_REGNUM && (regno) < IPSW_REGNUM) || \ ((regno) > IPSW_REGNUM && (regno) < FP4_REGNUM) -/* This is a piece of magic that is given a register number REGNO - and as BLOCKEND the address in the system of the end of the user structure - and stores in ADDR the address in the kernel or core dump - of that register. */ - +#define INIT_EXTRA_FRAME_INFO(fromleaf, frame) init_extra_frame_info (fromleaf, frame) /* Describe the pointer in each stack frame to the previous stack frame (its caller). */ @@ -313,13 +309,12 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ is the address of a 4-byte word containing the calling frame's address (previous FP). */ -#define FRAME_CHAIN(thisframe) \ - (!inside_entry_file ((thisframe)->pc) ? \ - read_memory_integer ((thisframe)->frame, 4) :\ - 0) +#define FRAME_CHAIN(thisframe) frame_chain (thisframe) +#if 0 #define FRAME_CHAIN_VALID(chain, thisframe) \ frame_chain_valid (chain, thisframe) +#endif #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) diff --git a/gdb/tm-hppah.h b/gdb/tm-hppah.h index 42632ef..05720cd 100644 --- a/gdb/tm-hppah.h +++ b/gdb/tm-hppah.h @@ -32,11 +32,7 @@ extern CORE_ADDR millicode_start, millicode_end; some instructions. */ #undef SAVED_PC_AFTER_CALL -#define SAVED_PC_AFTER_CALL(frame) \ - ((get_frame_pc (frame) >= millicode_start \ - && get_frame_pc (frame) < millicode_end) ? \ - read_register (31) & ~3 \ - : read_register (RP_REGNUM) & ~3) +#define SAVED_PC_AFTER_CALL(frame) saved_pc_after_call (frame) /* We need to figure out where the text region is so that we use the appropriate ptrace operator to manipulate text. Simply reading/writing -- 2.7.4