#include "frame.h"
#include "inferior.h"
#include "gdb_assert.h"
+#include "frame-unwind.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+static void dummy_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id);
/* Dummy frame. This saves the processor state just prior to setting
up the inferior function call. Older targets save the registers
CORE_ADDR fp;
CORE_ADDR sp;
CORE_ADDR top;
+ struct frame_id id;
struct regcache *regcache;
/* Address range of the call dummy code. Look for PC in the range
/* Function: find_dummy_frame(pc, fp, sp)
Search the stack of dummy frames for one matching the given PC and
- FP/SP. Unlike PC_IN_CALL_DUMMY, this function doesn't need to
+ FP/SP. Unlike pc_in_dummy_frame(), this function doesn't need to
adjust for DECR_PC_AFTER_BREAK. This is because it is only legal
to call this function after the PC has been adjusted. */
FP against the saved SP and FP. NOTE: If you're trying
to fix a problem with GDB not correctly finding a dummy
frame, check the comments that go with FRAME_ALIGN() and
- SAVE_DUMMY_FRAME_TOS(). */
+ UNWIND_DUMMY_ID(). */
if (fp != dummyframe->fp && fp != dummyframe->sp)
continue;
}
return NULL;
}
-struct dummy_frame *
-cached_find_dummy_frame (struct frame_info *frame, void **cache)
-{
- if ((*cache) == NULL)
- (*cache) = find_dummy_frame (frame->pc, frame->frame);
- return (*cache);
-}
-
struct regcache *
-generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
+deprecated_find_dummy_frame_regcache (CORE_ADDR pc, CORE_ADDR fp)
{
struct dummy_frame *dummy = find_dummy_frame (pc, fp);
if (dummy != NULL)
char *
deprecated_generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
{
- struct regcache *regcache = generic_find_dummy_frame (pc, fp);
+ struct regcache *regcache = deprecated_find_dummy_frame_regcache (pc, fp);
if (regcache == NULL)
return NULL;
return deprecated_grub_regcache_for_registers (regcache);
int
generic_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR fp)
+{
+ return pc_in_dummy_frame (pc);
+}
+
+/* Return non-zero if the PC falls in a dummy frame.
+
+ The code below which allows DECR_PC_AFTER_BREAK is for infrun.c,
+ which may give the function a PC without that subtracted out.
+
+ FIXME: cagney/2002-11-23: This is silly. Surely "infrun.c" can
+ figure out what the real PC (as in the resume address) is BEFORE
+ calling this function (Oh, and I'm not even sure that this function
+ is called with an decremented PC, the call to pc_in_call_dummy() in
+ that file is conditional on
+ !DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET_P yet generic dummy
+ targets set DEPRECATED_CALL_DUMMY_BREAKPOINT_OFFSET. True?). */
+
+int
+pc_in_dummy_frame (CORE_ADDR pc)
{
struct dummy_frame *dummyframe;
for (dummyframe = dummy_frame_stack;
CORE_ADDR
deprecated_read_register_dummy (CORE_ADDR pc, CORE_ADDR fp, int regno)
{
- struct regcache *dummy_regs = generic_find_dummy_frame (pc, fp);
+ struct regcache *dummy_regs = deprecated_find_dummy_frame_regcache (pc, fp);
if (dummy_regs)
{
/* NOTE: cagney/2002-08-12: Replaced a call to
regcache_raw_read_as_address() with a call to
regcache_cooked_read_unsigned(). The old, ...as_address
- function was eventually calling extract_unsigned_integer (via
+ function was eventually calling extract_unsigned_integer (nee
extract_address) to unpack the registers value. The below is
doing an unsigned extract so that it is functionally
equivalent. The read needs to be cooked as, otherwise, it
generic_push_dummy_frame (void)
{
struct dummy_frame *dummy_frame;
- CORE_ADDR fp = (get_current_frame ())->frame;
+ CORE_ADDR fp = get_frame_base (get_current_frame ());
/* check to see if there are stale dummy frames,
perhaps left over from when a longjump took us out of a
dummy_frame->sp = read_sp ();
dummy_frame->top = 0;
dummy_frame->fp = fp;
+ dummy_frame->id = get_frame_id (get_current_frame ());
regcache_cpy (dummy_frame->regcache, current_regcache);
dummy_frame->next = dummy_frame_stack;
dummy_frame_stack = dummy_frame;
generic_pop_current_frame (void (*popper) (struct frame_info * frame))
{
struct frame_info *frame = get_current_frame ();
-
- if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+ if (get_frame_type (frame) == DUMMY_FRAME)
+ /* NOTE: cagney/2002-22-23: Does this ever occure? Surely a dummy
+ frame will have already been poped by the "infrun.c" code. */
generic_pop_dummy_frame ();
else
(*popper) (frame);
}
-/* Function: pop_dummy_frame
- Restore the machine state from a saved dummy stack frame. */
+/* Discard the innermost dummy frame from the dummy frame stack
+ (passed in as a parameter). */
+
+static void
+discard_innermost_dummy (struct dummy_frame **stack)
+{
+ struct dummy_frame *tbd = (*stack);
+ (*stack) = (*stack)->next;
+ regcache_xfree (tbd->regcache);
+ xfree (tbd);
+}
void
generic_pop_dummy_frame (void)
if (!dummy_frame)
error ("Can't pop dummy frame!");
- dummy_frame_stack = dummy_frame->next;
regcache_cpy (current_regcache, dummy_frame->regcache);
flush_cached_frames ();
- regcache_xfree (dummy_frame->regcache);
- xfree (dummy_frame);
-}
-
-/* Function: fix_call_dummy
- Stub function. Generic dummy frames typically do not need to fix
- the frame being created */
-
-void
-generic_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
- struct value **args, struct type *type, int gcc_p)
-{
- return;
+ discard_innermost_dummy (&dummy_frame_stack);
}
/* Given a call-dummy dummy-frame, return the registers. Here the
register value is taken from the local copy of the register buffer. */
-void
-dummy_frame_register_unwind (struct frame_info *frame, void **cache,
- int regnum, int *optimized,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnum, void *bufferp)
+static void
+dummy_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimized,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnum, void *bufferp)
{
- struct dummy_frame *dummy = cached_find_dummy_frame (frame, cache);
+ struct dummy_frame *dummy;
+ struct frame_id id;
+
+ /* Call the ID method which, if at all possible, will set the
+ prologue cache. */
+ dummy_frame_this_id (next_frame, this_prologue_cache, &id);
+ dummy = (*this_prologue_cache);
gdb_assert (dummy != NULL);
/* Describe the register's location. Generic dummy frames always
}
}
-CORE_ADDR
-dummy_frame_pc_unwind (struct frame_info *frame,
- void **cache)
+/* Assuming that THIS frame is a dummy (remember, the NEXT and not
+ THIS frame is passed in), return the ID of THIS frame. That ID is
+ determined by examining the NEXT frame's unwound registers using
+ the method unwind_dummy_id(). As a side effect, THIS dummy frame's
+ dummy cache is located and and saved in THIS_PROLOGUE_CACHE. */
+
+static void
+dummy_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
{
- struct dummy_frame *dummy = cached_find_dummy_frame (frame, cache);
- /* Oops! In a dummy-frame but can't find the stack dummy. Pretend
- that the frame doesn't unwind. Should this function instead
- return a has-no-caller indication? */
- if (dummy == NULL)
- return 0;
- return dummy->pc;
+ struct dummy_frame *dummy = (*this_prologue_cache);
+ if (dummy != NULL)
+ {
+ (*this_id) = dummy->id;
+ return;
+ }
+ /* When unwinding a normal frame, the stack structure is determined
+ by analyzing the frame's function's code (be it using brute force
+ prologue analysis, or the dwarf2 CFI). In the case of a dummy
+ frame, that simply isn't possible. The The PC is either the
+ program entry point, or some random address on the stack. Trying
+ to use that PC to apply standard frame ID unwind techniques is
+ just asking for trouble. */
+ if (gdbarch_unwind_dummy_id_p (current_gdbarch))
+ {
+ /* Use an architecture specific method to extract the prev's
+ dummy ID from the next frame. Note that this method uses
+ frame_register_unwind to obtain the register values needed to
+ determine the dummy frame's ID. */
+ (*this_id) = gdbarch_unwind_dummy_id (current_gdbarch, next_frame);
+ }
+ else if (frame_relative_level (next_frame) < 0)
+ {
+ /* We're unwinding a sentinel frame, the PC of which is pointing
+ at a stack dummy. Fake up the dummy frame's ID using the
+ same sequence as is found a traditional unwinder. Once all
+ architectures supply the unwind_dummy_id method, this code
+ can go away. */
+ (*this_id) = frame_id_build (deprecated_read_fp (), read_pc ());
+ }
+ else if (legacy_frame_p (current_gdbarch)
+ && get_prev_frame (next_frame))
+ {
+ /* Things are looking seriously grim! Assume that the legacy
+ get_prev_frame code has already created THIS frame and linked
+ it in to the frame chain (a pretty bold assumption), extract
+ the ID from THIS base / pc. */
+ (*this_id) = frame_id_build (get_frame_base (get_prev_frame (next_frame)),
+ get_frame_pc (get_prev_frame (next_frame)));
+ }
+ else
+ {
+ /* Outch! We're not trying to find the innermost frame's ID yet
+ we're trying to unwind to a dummy. The architecture must
+ provide the unwind_dummy_id() method. Abandon the unwind
+ process but only after first warning the user. */
+ internal_warning (__FILE__, __LINE__,
+ "Missing unwind_dummy_id architecture method");
+ (*this_id) = null_frame_id;
+ return;
+ }
+ (*this_prologue_cache) = find_dummy_frame ((*this_id).code_addr,
+ (*this_id).stack_addr);
+}
+
+static struct frame_unwind dummy_frame_unwind =
+{
+ DUMMY_FRAME,
+ dummy_frame_this_id,
+ dummy_frame_prev_register
+};
+
+const struct frame_unwind *
+dummy_frame_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
+ ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
+ : pc_in_dummy_frame (pc))
+ return &dummy_frame_unwind;
+ else
+ return NULL;
+}
+
+static void
+fprint_dummy_frames (struct ui_file *file)
+{
+ struct dummy_frame *s;
+ for (s = dummy_frame_stack; s != NULL; s = s->next)
+ {
+ gdb_print_host_address (s, file);
+ fprintf_unfiltered (file, ":");
+ fprintf_unfiltered (file, " pc=0x%s", paddr (s->pc));
+ fprintf_unfiltered (file, " fp=0x%s", paddr (s->fp));
+ fprintf_unfiltered (file, " sp=0x%s", paddr (s->sp));
+ fprintf_unfiltered (file, " top=0x%s", paddr (s->top));
+ fprintf_unfiltered (file, " id=");
+ fprint_frame_id (file, s->id);
+ fprintf_unfiltered (file, " call_lo=0x%s", paddr (s->call_lo));
+ fprintf_unfiltered (file, " call_hi=0x%s", paddr (s->call_hi));
+ fprintf_unfiltered (file, "\n");
+ }
}
+static void
+maintenance_print_dummy_frames (char *args, int from_tty)
+{
+ if (args == NULL)
+ fprint_dummy_frames (gdb_stdout);
+ else
+ {
+ struct ui_file *file = gdb_fopen (args, "w");
+ if (file == NULL)
+ perror_with_name ("maintenance print dummy-frames");
+ fprint_dummy_frames (file);
+ ui_file_delete (file);
+ }
+}
+
+extern void _initialize_dummy_frame (void);
+
+void
+_initialize_dummy_frame (void)
+{
+ add_cmd ("dummy-frames", class_maintenance, maintenance_print_dummy_frames,
+ "Print the contents of the internal dummy-frame stack.",
+ &maintenanceprintlist);
+
+}