/* Code dealing with dummy stack frames, for GDB, the GNU debugger.
Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software
- Foundation, Inc.
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
+ Software Foundation, Inc.
This file is part of GDB.
#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);
+
+static int pc_in_dummy_frame (CORE_ADDR pc);
/* Dummy frame. This saves the processor state just prior to setting
up the inferior function call. Older targets save the registers
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 (get_frame_pc (frame), get_frame_base (frame));
- return (*cache);
-}
-
-struct regcache *
-generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
+static struct regcache *
+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);
}
-/* Function: pc_in_call_dummy (pc, sp, fp)
+/* Function: pc_in_call_dummy (pc)
Return true if the PC falls in a dummy frame created by gdb for an
inferior call. The code below which allows DECR_PC_AFTER_BREAK is
subtracted out. */
int
-generic_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR fp)
+deprecated_pc_in_call_dummy (CORE_ADDR pc)
{
return pc_in_dummy_frame (pc);
}
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 !CALL_DUMMY_BREAKPOINT_OFFSET_P yet
- generic dummy targets set CALL_DUMMY_BREAKPOINT_OFFSET. True?). */
+ calling this function. */
-int
+static int
pc_in_dummy_frame (CORE_ADDR pc)
{
struct dummy_frame *dummyframe;
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
dummy_frame_stack->call_hi = hi;
}
-/* Restore the machine state from either the saved dummy stack or a
- real stack frame. */
-
-void
-generic_pop_current_frame (void (*popper) (struct frame_info * frame))
-{
- struct frame_info *frame = get_current_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);
-}
-
/* Discard the innermost dummy frame from the dummy frame stack
(passed in as a parameter). */
xfree (tbd);
}
-/* Function: dummy_frame_pop. Restore the machine state from a saved
- dummy stack frame. */
-
-static void
-dummy_frame_pop (struct frame_info *fi, void **cache,
- struct regcache *regcache)
-{
- struct dummy_frame *dummy = cached_find_dummy_frame (fi, cache);
-
- /* If it isn't, what are we even doing here? */
- gdb_assert (get_frame_type (fi) == DUMMY_FRAME);
-
- if (dummy == NULL)
- error ("Can't pop dummy frame!");
-
- /* Discard all dummy frames up-to but not including this one. */
- while (dummy_frame_stack != dummy)
- discard_innermost_dummy (&dummy_frame_stack);
-
- /* Restore this one. */
- regcache_cpy (regcache, dummy->regcache);
- flush_cached_frames ();
-
- /* Now discard it. */
- discard_innermost_dummy (&dummy_frame_stack);
-
- /* Note: target changed would be better. Registers, memory and
- frame are all invalid. */
- flush_cached_frames ();
-}
-
void
-generic_pop_dummy_frame (void)
+deprecated_pop_dummy_frame (void)
{
struct dummy_frame *dummy_frame = dummy_frame_stack;
discard_innermost_dummy (&dummy_frame_stack);
}
-/* 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;
-}
-
/* Given a call-dummy dummy-frame, return the registers. Here the
register value is taken from the local copy of the register buffer. */
static 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)
+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
}
}
-/* Assuming that FRAME is a dummy, return the ID of the calling frame
- (the frame that the dummy has the saved state of). */
+/* 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_id_unwind (struct frame_info *frame,
- void **cache,
- struct frame_id *id)
+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)
- (*id) = null_frame_id;
+ 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 (get_frame_type (next_frame) == SENTINEL_FRAME)
+ {
+ /* 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
- (*id) = dummy->id;
+ {
+ /* Ouch! 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_pop,
- dummy_frame_id_unwind,
- dummy_frame_register_unwind
+ DUMMY_FRAME,
+ dummy_frame_this_id,
+ dummy_frame_prev_register
};
const struct frame_unwind *
-dummy_frame_p (CORE_ADDR pc)
+dummy_frame_sniffer (struct frame_info *next_frame)
{
- if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
- ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
- : pc_in_dummy_frame (pc))
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ if (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);
+
+}