+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):
(word & 0x1) << 16, 17) << 2;
}
\f
+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;
+}
+\f
+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;
+}
+\f
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;
}
+\f
+/* 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;
+}
+\f
+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);
+}
+\f
/* To see if a frame chain is valid, see if the caller looks like it
was compiled with gcc. */
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 */
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);
&& (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);
+}
/* 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
((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). */
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)