X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fframe.c;h=7df7c43e2967d4ba5815b95692a610127d1fe005;hb=2c0b251b29eeafa90c84a3a938c744bc7ba81aea;hp=bf860fe2ccd03414341a8fbf8b0aaf34653097ac;hpb=6314f104748d0e970aa089d2ba544f81a491b565;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/frame.c b/gdb/frame.c
index bf860fe2cc..dfd6b3d53c 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1,13 +1,13 @@
/* Cache and manage frames for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
- 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001,
+ 2002, 2003, 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@@ -16,9 +16,7 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see . */
#include "defs.h"
#include "frame.h"
@@ -28,7 +26,7 @@
#include "regcache.h"
#include "gdb_assert.h"
#include "gdb_string.h"
-#include "builtin-regs.h"
+#include "user-regs.h"
#include "gdb_obstack.h"
#include "dummy-frame.h"
#include "sentinel-frame.h"
@@ -36,16 +34,210 @@
#include "annotate.h"
#include "language.h"
#include "frame-unwind.h"
+#include "frame-base.h"
#include "command.h"
#include "gdbcmd.h"
+#include "observer.h"
+#include "objfiles.h"
+#include "exceptions.h"
+#include "gdbthread.h"
+
+static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
+
+/* We keep a cache of stack frames, each of which is a "struct
+ frame_info". The innermost one gets allocated (in
+ wait_for_inferior) each time the inferior stops; current_frame
+ points to it. Additional frames get allocated (in get_prev_frame)
+ as needed, and are chained through the next and prev fields. Any
+ time that the frame cache becomes invalid (most notably when we
+ execute something, but also if we change how we interpret the
+ frames (e.g. "set heuristic-fence-post" in mips-tdep.c, or anything
+ which reads new symbols)), we should call reinit_frame_cache. */
+
+struct frame_info
+{
+ /* Level of this frame. The inner-most (youngest) frame is at level
+ 0. As you move towards the outer-most (oldest) frame, the level
+ increases. This is a cached value. It could just as easily be
+ computed by counting back from the selected frame to the inner
+ most frame. */
+ /* NOTE: cagney/2002-04-05: Perhaps a level of ``-1'' should be
+ reserved to indicate a bogus frame - one that has been created
+ just to keep GDB happy (GDB always needs a frame). For the
+ moment leave this as speculation. */
+ int level;
+
+ /* The frame's low-level unwinder and corresponding cache. The
+ low-level unwinder is responsible for unwinding register values
+ for the previous frame. The low-level unwind methods are
+ selected based on the presence, or otherwise, of register unwind
+ information such as CFI. */
+ void *prologue_cache;
+ const struct frame_unwind *unwind;
+
+ /* Cached copy of the previous frame's resume address. */
+ struct {
+ int p;
+ CORE_ADDR value;
+ } prev_pc;
+
+ /* Cached copy of the previous frame's function address. */
+ struct
+ {
+ CORE_ADDR addr;
+ int p;
+ } prev_func;
+
+ /* This frame's ID. */
+ struct
+ {
+ int p;
+ struct frame_id value;
+ } this_id;
+
+ /* The frame's high-level base methods, and corresponding cache.
+ The high level base methods are selected based on the frame's
+ debug info. */
+ const struct frame_base *base;
+ void *base_cache;
+
+ /* Pointers to the next (down, inner, younger) and previous (up,
+ outer, older) frame_info's in the frame cache. */
+ struct frame_info *next; /* down, inner, younger */
+ int prev_p;
+ struct frame_info *prev; /* up, outer, older */
+
+ /* The reason why we could not set PREV, or UNWIND_NO_REASON if we
+ could. Only valid when PREV_P is set. */
+ enum unwind_stop_reason stop_reason;
+};
/* Flag to control debugging. */
-static int frame_debug;
+int frame_debug;
+static void
+show_frame_debug (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Frame debugging is %s.\n"), value);
+}
+
+/* Flag to indicate whether backtraces should stop at main et.al. */
+
+static int backtrace_past_main;
+static void
+show_backtrace_past_main (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("\
+Whether backtraces should continue past \"main\" is %s.\n"),
+ value);
+}
+
+static int backtrace_past_entry;
+static void
+show_backtrace_past_entry (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("\
+Whether backtraces should continue past the entry point of a program is %s.\n"),
+ value);
+}
+
+static int backtrace_limit = INT_MAX;
+static void
+show_backtrace_limit (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("\
+An upper bound on the number of backtrace levels is %s.\n"),
+ value);
+}
+
+
+static void
+fprint_field (struct ui_file *file, const char *name, int p, CORE_ADDR addr)
+{
+ if (p)
+ fprintf_unfiltered (file, "%s=0x%s", name, paddr_nz (addr));
+ else
+ fprintf_unfiltered (file, "!%s", name);
+}
+
+void
+fprint_frame_id (struct ui_file *file, struct frame_id id)
+{
+ fprintf_unfiltered (file, "{");
+ fprint_field (file, "stack", id.stack_addr_p, id.stack_addr);
+ fprintf_unfiltered (file, ",");
+ fprint_field (file, "code", id.code_addr_p, id.code_addr);
+ fprintf_unfiltered (file, ",");
+ fprint_field (file, "special", id.special_addr_p, id.special_addr);
+ fprintf_unfiltered (file, "}");
+}
-/* Flag to indicate whether backtraces should stop at main. */
+static void
+fprint_frame_type (struct ui_file *file, enum frame_type type)
+{
+ switch (type)
+ {
+ case NORMAL_FRAME:
+ fprintf_unfiltered (file, "NORMAL_FRAME");
+ return;
+ case DUMMY_FRAME:
+ fprintf_unfiltered (file, "DUMMY_FRAME");
+ return;
+ case SIGTRAMP_FRAME:
+ fprintf_unfiltered (file, "SIGTRAMP_FRAME");
+ return;
+ default:
+ fprintf_unfiltered (file, "");
+ return;
+ };
+}
-static int backtrace_below_main;
+static void
+fprint_frame (struct ui_file *file, struct frame_info *fi)
+{
+ if (fi == NULL)
+ {
+ fprintf_unfiltered (file, "");
+ return;
+ }
+ fprintf_unfiltered (file, "{");
+ fprintf_unfiltered (file, "level=%d", fi->level);
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "type=");
+ if (fi->unwind != NULL)
+ fprint_frame_type (file, fi->unwind->type);
+ else
+ fprintf_unfiltered (file, "");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "unwind=");
+ if (fi->unwind != NULL)
+ gdb_print_host_address (fi->unwind, file);
+ else
+ fprintf_unfiltered (file, "");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "pc=");
+ if (fi->next != NULL && fi->next->prev_pc.p)
+ fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_pc.value));
+ else
+ fprintf_unfiltered (file, "");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "id=");
+ if (fi->this_id.p)
+ fprint_frame_id (file, fi->this_id.value);
+ else
+ fprintf_unfiltered (file, "");
+ fprintf_unfiltered (file, ",");
+ fprintf_unfiltered (file, "func=");
+ if (fi->next != NULL && fi->next->prev_func.p)
+ fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_func.addr));
+ else
+ fprintf_unfiltered (file, "");
+ fprintf_unfiltered (file, "}");
+}
/* Return a frame uniq ID that can be used to, later, re-find the
frame. */
@@ -57,113 +249,338 @@ get_frame_id (struct frame_info *fi)
{
return null_frame_id;
}
- else
+ if (!fi->this_id.p)
{
- struct frame_id id;
- id.base = fi->frame;
- id.pc = fi->pc;
- return id;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ",
+ fi->level);
+ /* Find the unwinder. */
+ if (fi->unwind == NULL)
+ fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
+ /* Find THIS frame's ID. */
+ fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
+ fi->this_id.p = 1;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame_id (gdb_stdlog, fi->this_id.value);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
}
+ return fi->this_id.value;
+}
+
+struct frame_id
+frame_unwind_id (struct frame_info *next_frame)
+{
+ /* Use prev_frame, and not get_prev_frame. The latter will truncate
+ the frame chain, leading to this function unintentionally
+ returning a null_frame_id (e.g., when a caller requests the frame
+ ID of "main()"s caller. */
+ return get_frame_id (get_prev_frame_1 (next_frame));
}
const struct frame_id null_frame_id; /* All zeros. */
struct frame_id
-frame_id_build (CORE_ADDR base, CORE_ADDR func_or_pc)
+frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
+ CORE_ADDR special_addr)
+{
+ struct frame_id id = null_frame_id;
+ id.stack_addr = stack_addr;
+ id.stack_addr_p = 1;
+ id.code_addr = code_addr;
+ id.code_addr_p = 1;
+ id.special_addr = special_addr;
+ id.special_addr_p = 1;
+ return id;
+}
+
+struct frame_id
+frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
+{
+ struct frame_id id = null_frame_id;
+ id.stack_addr = stack_addr;
+ id.stack_addr_p = 1;
+ id.code_addr = code_addr;
+ id.code_addr_p = 1;
+ return id;
+}
+
+struct frame_id
+frame_id_build_wild (CORE_ADDR stack_addr)
{
- struct frame_id id;
- id.base = base;
- id.pc = func_or_pc;
+ struct frame_id id = null_frame_id;
+ id.stack_addr = stack_addr;
+ id.stack_addr_p = 1;
return id;
}
int
frame_id_p (struct frame_id l)
{
- /* The .func can be NULL but the .base cannot. */
- return (l.base != 0);
+ int p;
+ /* The frame is valid iff it has a valid stack address. */
+ p = l.stack_addr_p;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
+ fprint_frame_id (gdb_stdlog, l);
+ fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", p);
+ }
+ return p;
}
int
frame_id_eq (struct frame_id l, struct frame_id r)
{
- /* If .base is different, the frames are different. */
- if (l.base != r.base)
- return 0;
- /* Add a test to check that the frame ID's are for the same function
- here. */
- return 1;
+ int eq;
+ if (!l.stack_addr_p || !r.stack_addr_p)
+ /* Like a NaN, if either ID is invalid, the result is false.
+ Note that a frame ID is invalid iff it is the null frame ID. */
+ eq = 0;
+ else if (l.stack_addr != r.stack_addr)
+ /* If .stack addresses are different, the frames are different. */
+ eq = 0;
+ else if (!l.code_addr_p || !r.code_addr_p)
+ /* An invalid code addr is a wild card, always succeed. */
+ eq = 1;
+ else if (l.code_addr != r.code_addr)
+ /* If .code addresses are different, the frames are different. */
+ eq = 0;
+ else if (!l.special_addr_p || !r.special_addr_p)
+ /* An invalid special addr is a wild card (or unused), always succeed. */
+ eq = 1;
+ else if (l.special_addr == r.special_addr)
+ /* Frames are equal. */
+ eq = 1;
+ else
+ /* No luck. */
+ eq = 0;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l=");
+ fprint_frame_id (gdb_stdlog, l);
+ fprintf_unfiltered (gdb_stdlog, ",r=");
+ fprint_frame_id (gdb_stdlog, r);
+ fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", eq);
+ }
+ return eq;
}
-int
-frame_id_inner (struct frame_id l, struct frame_id r)
+/* Safety net to check whether frame ID L should be inner to
+ frame ID R, according to their stack addresses.
+
+ This method cannot be used to compare arbitrary frames, as the
+ ranges of valid stack addresses may be discontiguous (e.g. due
+ to sigaltstack).
+
+ However, it can be used as safety net to discover invalid frame
+ IDs in certain circumstances.
+
+ * If frame NEXT is the immediate inner frame to THIS, and NEXT
+ is a NORMAL frame, then the stack address of NEXT must be
+ inner-than-or-equal to the stack address of THIS.
+
+ Therefore, if frame_id_inner (THIS, NEXT) holds, some unwind
+ error has occurred.
+
+ * If frame NEXT is the immediate inner frame to THIS, and NEXT
+ is a NORMAL frame, and NEXT and THIS have different stack
+ addresses, no other frame in the frame chain may have a stack
+ address in between.
+
+ Therefore, if frame_id_inner (TEST, THIS) holds, but
+ frame_id_inner (TEST, NEXT) does not hold, TEST cannot refer
+ to a valid frame in the frame chain. */
+
+static int
+frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
{
- /* Only return non-zero when strictly inner than. Note that, per
- comment in "frame.h", there is some fuzz here. Frameless
- functions are not strictly inner than (same .base but different
- .func). */
- return INNER_THAN (l.base, r.base);
+ int inner;
+ if (!l.stack_addr_p || !r.stack_addr_p)
+ /* Like NaN, any operation involving an invalid ID always fails. */
+ inner = 0;
+ else
+ /* Only return non-zero when strictly inner than. Note that, per
+ comment in "frame.h", there is some fuzz here. Frameless
+ functions are not strictly inner than (same .stack but
+ different .code and/or .special address). */
+ inner = gdbarch_inner_than (gdbarch, l.stack_addr, r.stack_addr);
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ frame_id_inner (l=");
+ fprint_frame_id (gdb_stdlog, l);
+ fprintf_unfiltered (gdb_stdlog, ",r=");
+ fprint_frame_id (gdb_stdlog, r);
+ fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", inner);
+ }
+ return inner;
}
struct frame_info *
frame_find_by_id (struct frame_id id)
{
- struct frame_info *frame;
+ struct frame_info *frame, *prev_frame;
/* ZERO denotes the null frame, let the caller decide what to do
about it. Should it instead return get_current_frame()? */
if (!frame_id_p (id))
return NULL;
- for (frame = get_current_frame ();
- frame != NULL;
- frame = get_prev_frame (frame))
+ for (frame = get_current_frame (); ; frame = prev_frame)
{
struct frame_id this = get_frame_id (frame);
if (frame_id_eq (id, this))
/* An exact match. */
return frame;
- if (frame_id_inner (id, this))
- /* Gone to far. */
+
+ prev_frame = get_prev_frame (frame);
+ if (!prev_frame)
+ return NULL;
+
+ /* As a safety net to avoid unnecessary backtracing while trying
+ to find an invalid ID, we check for a common situation where
+ we can detect from comparing stack addresses that no other
+ frame in the current frame chain can have this ID. See the
+ comment at frame_id_inner for details. */
+ if (get_frame_type (frame) == NORMAL_FRAME
+ && !frame_id_inner (get_frame_arch (frame), id, this)
+ && frame_id_inner (get_frame_arch (prev_frame), id,
+ get_frame_id (prev_frame)))
return NULL;
- /* Either, we're not yet gone far enough out along the frame
- chain (inner(this,id), or we're comparing frameless functions
- (same .base, different .func, no test available). Struggle
- on until we've definitly gone to far. */
}
return NULL;
}
CORE_ADDR
-frame_pc_unwind (struct frame_info *frame)
+frame_pc_unwind (struct frame_info *this_frame)
+{
+ if (!this_frame->prev_pc.p)
+ {
+ CORE_ADDR pc;
+ if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
+ {
+ /* The right way. The `pure' way. The one true way. This
+ method depends solely on the register-unwind code to
+ determine the value of registers in THIS frame, and hence
+ the value of this frame's PC (resume address). A typical
+ implementation is no more than:
+
+ frame_unwind_register (this_frame, ISA_PC_REGNUM, buf);
+ return extract_unsigned_integer (buf, size of ISA_PC_REGNUM);
+
+ Note: this method is very heavily dependent on a correct
+ register-unwind implementation, it pays to fix that
+ method first; this method is frame type agnostic, since
+ it only deals with register values, it works with any
+ frame. This is all in stark contrast to the old
+ FRAME_SAVED_PC which would try to directly handle all the
+ different ways that a PC could be unwound. */
+ pc = gdbarch_unwind_pc (get_frame_arch (this_frame), this_frame);
+ }
+ else
+ internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
+ this_frame->prev_pc.value = pc;
+ this_frame->prev_pc.p = 1;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_pc_unwind (this_frame=%d) -> 0x%s }\n",
+ this_frame->level,
+ paddr_nz (this_frame->prev_pc.value));
+ }
+ return this_frame->prev_pc.value;
+}
+
+CORE_ADDR
+get_frame_func (struct frame_info *this_frame)
{
- if (!frame->pc_unwind_cache_p)
+ struct frame_info *next_frame = this_frame->next;
+
+ if (!next_frame->prev_func.p)
{
- frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache);
- frame->pc_unwind_cache_p = 1;
+ /* Make certain that this, and not the adjacent, function is
+ found. */
+ CORE_ADDR addr_in_block = get_frame_address_in_block (this_frame);
+ next_frame->prev_func.p = 1;
+ next_frame->prev_func.addr = get_pc_function_start (addr_in_block);
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ get_frame_func (this_frame=%d) -> 0x%s }\n",
+ this_frame->level,
+ paddr_nz (next_frame->prev_func.addr));
}
- return frame->pc_unwind_cache;
+ return next_frame->prev_func.addr;
+}
+
+static int
+do_frame_register_read (void *src, int regnum, gdb_byte *buf)
+{
+ return frame_register_read (src, regnum, buf);
+}
+
+struct regcache *
+frame_save_as_regcache (struct frame_info *this_frame)
+{
+ struct regcache *regcache = regcache_xmalloc (get_frame_arch (this_frame));
+ struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
+ regcache_save (regcache, do_frame_register_read, this_frame);
+ discard_cleanups (cleanups);
+ return regcache;
}
void
-frame_pop (struct frame_info *frame)
+frame_pop (struct frame_info *this_frame)
{
- /* FIXME: cagney/2003-01-18: There is probably a chicken-egg problem
- with passing in current_regcache. The pop function needs to be
- written carefully so as to not overwrite registers whose [old]
- values are needed to restore other registers. Instead, this code
- should pass in a scratch cache and, as a second step, restore the
- registers using that. */
- frame->unwind->pop (frame, &frame->unwind_cache, current_regcache);
- flush_cached_frames ();
+ struct frame_info *prev_frame;
+ struct regcache *scratch;
+ struct cleanup *cleanups;
+
+ if (get_frame_type (this_frame) == DUMMY_FRAME)
+ {
+ /* Popping a dummy frame involves restoring more than just registers.
+ dummy_frame_pop does all the work. */
+ dummy_frame_pop (get_frame_id (this_frame));
+ return;
+ }
+
+ /* Ensure that we have a frame to pop to. */
+ prev_frame = get_prev_frame_1 (this_frame);
+
+ if (!prev_frame)
+ error (_("Cannot pop the initial frame."));
+
+ /* Make a copy of all the register values unwound from this frame.
+ Save them in a scratch buffer so that there isn't a race between
+ trying to extract the old values from the current regcache while
+ at the same time writing new values into that same cache. */
+ scratch = frame_save_as_regcache (prev_frame);
+ cleanups = make_cleanup_regcache_xfree (scratch);
+
+ /* FIXME: cagney/2003-03-16: It should be possible to tell the
+ target's register cache that it is about to be hit with a burst
+ register transfer and that the sequence of register writes should
+ be batched. The pair target_prepare_to_store() and
+ target_store_registers() kind of suggest this functionality.
+ Unfortunately, they don't implement it. Their lack of a formal
+ definition can lead to targets writing back bogus values
+ (arguably a bug in the target code mind). */
+ /* Now copy those saved registers into the current regcache.
+ Here, regcache_cpy() calls regcache_restore(). */
+ regcache_cpy (get_current_regcache (), scratch);
+ do_cleanups (cleanups);
+
+ /* We've made right mess of GDB's local state, just discard
+ everything. */
+ reinit_frame_cache ();
}
void
frame_register_unwind (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
- CORE_ADDR *addrp, int *realnump, void *bufferp)
+ CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
{
- struct frame_unwind_cache *cache;
+ struct value *value;
/* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
that the value proper does not need to be fetched. */
@@ -173,21 +590,29 @@ frame_register_unwind (struct frame_info *frame, int regnum,
gdb_assert (realnump != NULL);
/* gdb_assert (bufferp != NULL); */
- /* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame
- is broken. There is always a frame. If there, for some reason,
- isn't, there is some pretty busted code as it should have
- detected the problem before calling here. */
- gdb_assert (frame != NULL);
+ value = frame_unwind_register_value (frame, regnum);
- /* Ask this frame to unwind its register. */
- frame->unwind->reg (frame, &frame->unwind_cache, regnum,
- optimizedp, lvalp, addrp, realnump, bufferp);
+ gdb_assert (value != NULL);
+
+ *optimizedp = value_optimized_out (value);
+ *lvalp = VALUE_LVAL (value);
+ *addrp = VALUE_ADDRESS (value);
+ *realnump = VALUE_REGNUM (value);
+
+ if (bufferp)
+ memcpy (bufferp, value_contents_all (value),
+ TYPE_LENGTH (value_type (value)));
+
+ /* Dispose of the new value. This prevents watchpoints from
+ trying to watch the saved frame pointer. */
+ release_value (value);
+ value_free (value);
}
void
frame_register (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
- CORE_ADDR *addrp, int *realnump, void *bufferp)
+ CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
{
/* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
that the value proper does not need to be fetched. */
@@ -197,32 +622,6 @@ frame_register (struct frame_info *frame, int regnum,
gdb_assert (realnump != NULL);
/* gdb_assert (bufferp != NULL); */
- /* Ulgh! Old code that, for lval_register, sets ADDRP to the offset
- of the register in the register cache. It should instead return
- the REGNUM corresponding to that register. Translate the . */
- if (GET_SAVED_REGISTER_P ())
- {
- GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame, regnum, lvalp);
- /* Compute the REALNUM if the caller wants it. */
- if (*lvalp == lval_register)
- {
- int regnum;
- for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
- {
- if (*addrp == register_offset_hack (current_gdbarch, regnum))
- {
- *realnump = regnum;
- return;
- }
- }
- internal_error (__FILE__, __LINE__,
- "Failed to compute the register number corresponding"
- " to 0x%s", paddr_d (*addrp));
- }
- *realnump = -1;
- return;
- }
-
/* Obtain the register value by unwinding the register from the next
(more inner frame). */
gdb_assert (frame != NULL && frame->next != NULL);
@@ -231,7 +630,7 @@ frame_register (struct frame_info *frame, int regnum,
}
void
-frame_unwind_register (struct frame_info *frame, int regnum, void *buf)
+frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf)
{
int optimized;
CORE_ADDR addr;
@@ -242,120 +641,149 @@ frame_unwind_register (struct frame_info *frame, int regnum, void *buf)
}
void
-frame_unwind_signed_register (struct frame_info *frame, int regnum,
- LONGEST *val)
+get_frame_register (struct frame_info *frame,
+ int regnum, gdb_byte *buf)
{
- void *buf = alloca (MAX_REGISTER_RAW_SIZE);
- frame_unwind_register (frame, regnum, buf);
- (*val) = extract_signed_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
+ frame_unwind_register (frame->next, regnum, buf);
}
-void
-frame_unwind_unsigned_register (struct frame_info *frame, int regnum,
- ULONGEST *val)
+struct value *
+frame_unwind_register_value (struct frame_info *frame, int regnum)
{
- void *buf = alloca (MAX_REGISTER_RAW_SIZE);
- frame_unwind_register (frame, regnum, buf);
- (*val) = extract_unsigned_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
+ struct value *value;
+
+ gdb_assert (frame != NULL);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "\
+{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
+ frame->level, regnum,
+ user_reg_map_regnum_to_name
+ (get_frame_arch (frame), regnum));
+ }
+
+ /* Find the unwinder. */
+ if (frame->unwind == NULL)
+ frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
+
+ /* Ask this frame to unwind its register. */
+ value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "->");
+ if (value_optimized_out (value))
+ fprintf_unfiltered (gdb_stdlog, " optimized out");
+ else
+ {
+ if (VALUE_LVAL (value) == lval_register)
+ fprintf_unfiltered (gdb_stdlog, " register=%d",
+ VALUE_REGNUM (value));
+ else if (VALUE_LVAL (value) == lval_memory)
+ fprintf_unfiltered (gdb_stdlog, " address=0x%s",
+ paddr_nz (VALUE_ADDRESS (value)));
+ else
+ fprintf_unfiltered (gdb_stdlog, " computed");
+
+ if (value_lazy (value))
+ fprintf_unfiltered (gdb_stdlog, " lazy");
+ else
+ {
+ int i;
+ const gdb_byte *buf = value_contents (value);
+
+ fprintf_unfiltered (gdb_stdlog, " bytes=");
+ fprintf_unfiltered (gdb_stdlog, "[");
+ for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
+ fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+ fprintf_unfiltered (gdb_stdlog, "]");
+ }
+ }
+
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+
+ return value;
}
-void
-frame_read_register (struct frame_info *frame, int regnum, void *buf)
+struct value *
+get_frame_register_value (struct frame_info *frame, int regnum)
{
- gdb_assert (frame != NULL && frame->next != NULL);
- frame_unwind_register (frame->next, regnum, buf);
+ return frame_unwind_register_value (frame->next, regnum);
}
-void
-frame_read_unsigned_register (struct frame_info *frame, int regnum,
- ULONGEST *val)
-{
- /* NOTE: cagney/2002-10-31: There is a bit of dogma here - there is
- always a frame. Both this, and the equivalent
- frame_read_signed_register() function, can only be called with a
- valid frame. If, for some reason, this function is called
- without a frame then the problem isn't here, but rather in the
- caller. It should of first created a frame and then passed that
- in. */
- /* NOTE: cagney/2002-10-31: As a side bar, keep in mind that the
- ``current_frame'' should not be treated as a special case. While
- ``get_next_frame (current_frame) == NULL'' currently holds, it
- should, as far as possible, not be relied upon. In the future,
- ``get_next_frame (current_frame)'' may instead simply return a
- normal frame object that simply always gets register values from
- the register cache. Consequently, frame code should try to avoid
- tests like ``if get_next_frame() == NULL'' and instead just rely
- on recursive frame calls (like the below code) when manipulating
- a frame chain. */
- gdb_assert (frame != NULL && frame->next != NULL);
- frame_unwind_unsigned_register (frame->next, regnum, val);
+LONGEST
+frame_unwind_register_signed (struct frame_info *frame, int regnum)
+{
+ gdb_byte buf[MAX_REGISTER_SIZE];
+ frame_unwind_register (frame, regnum, buf);
+ return extract_signed_integer (buf, register_size (get_frame_arch (frame),
+ regnum));
}
-void
-frame_read_signed_register (struct frame_info *frame, int regnum,
- LONGEST *val)
+LONGEST
+get_frame_register_signed (struct frame_info *frame, int regnum)
{
- /* See note above in frame_read_unsigned_register(). */
- gdb_assert (frame != NULL && frame->next != NULL);
- frame_unwind_signed_register (frame->next, regnum, val);
+ return frame_unwind_register_signed (frame->next, regnum);
}
-void
-generic_unwind_get_saved_register (char *raw_buffer,
- int *optimizedp,
- CORE_ADDR *addrp,
- struct frame_info *frame,
- int regnum,
- enum lval_type *lvalp)
-{
- int optimizedx;
- CORE_ADDR addrx;
- int realnumx;
- enum lval_type lvalx;
-
- if (!target_has_registers)
- error ("No registers.");
-
- /* Keep things simple, ensure that all the pointers (except valuep)
- are non NULL. */
- if (optimizedp == NULL)
- optimizedp = &optimizedx;
- if (lvalp == NULL)
- lvalp = &lvalx;
- if (addrp == NULL)
- addrp = &addrx;
+ULONGEST
+frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
+{
+ gdb_byte buf[MAX_REGISTER_SIZE];
+ frame_unwind_register (frame, regnum, buf);
+ return extract_unsigned_integer (buf, register_size (get_frame_arch (frame),
+ regnum));
+}
- gdb_assert (frame != NULL && frame->next != NULL);
- frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
- &realnumx, raw_buffer);
+ULONGEST
+get_frame_register_unsigned (struct frame_info *frame, int regnum)
+{
+ return frame_unwind_register_unsigned (frame->next, regnum);
}
void
-get_saved_register (char *raw_buffer,
- int *optimized,
- CORE_ADDR *addrp,
- struct frame_info *frame,
- int regnum,
- enum lval_type *lval)
-{
- if (GET_SAVED_REGISTER_P ())
+put_frame_register (struct frame_info *frame, int regnum,
+ const gdb_byte *buf)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ int realnum;
+ int optim;
+ enum lval_type lval;
+ CORE_ADDR addr;
+ frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
+ if (optim)
+ error (_("Attempt to assign to a value that was optimized out."));
+ switch (lval)
{
- GET_SAVED_REGISTER (raw_buffer, optimized, addrp, frame, regnum, lval);
- return;
+ case lval_memory:
+ {
+ /* FIXME: write_memory doesn't yet take constant buffers.
+ Arrrg! */
+ gdb_byte tmp[MAX_REGISTER_SIZE];
+ memcpy (tmp, buf, register_size (gdbarch, regnum));
+ write_memory (addr, tmp, register_size (gdbarch, regnum));
+ break;
+ }
+ case lval_register:
+ regcache_cooked_write (get_current_regcache (), realnum, buf);
+ break;
+ default:
+ error (_("Attempt to assign to an unmodifiable value."));
}
- generic_unwind_get_saved_register (raw_buffer, optimized, addrp, frame,
- regnum, lval);
}
/* frame_register_read ()
Find and return the value of REGNUM for the specified stack frame.
- The number of bytes copied is REGISTER_RAW_SIZE (REGNUM).
+ The number of bytes copied is REGISTER_SIZE (REGNUM).
Returns 0 if the register value could not be found. */
int
-frame_register_read (struct frame_info *frame, int regnum, void *myaddr)
+frame_register_read (struct frame_info *frame, int regnum,
+ gdb_byte *myaddr)
{
int optimized;
enum lval_type lval;
@@ -363,86 +791,137 @@ frame_register_read (struct frame_info *frame, int regnum, void *myaddr)
int realnum;
frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr);
- /* FIXME: cagney/2002-05-15: This test, is just bogus.
-
- It indicates that the target failed to supply a value for a
- register because it was "not available" at this time. Problem
- is, the target still has the register and so get saved_register()
- may be returning a value saved on the stack. */
-
- if (register_cached (regnum) < 0)
- return 0; /* register value not available */
-
return !optimized;
}
-
-/* Map between a frame register number and its name. A frame register
- space is a superset of the cooked register space --- it also
- includes builtin registers. */
-
int
-frame_map_name_to_regnum (const char *name, int len)
+get_frame_register_bytes (struct frame_info *frame, int regnum,
+ CORE_ADDR offset, int len, gdb_byte *myaddr)
{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
int i;
+ int maxsize;
+ int numregs;
- if (len < 0)
- len = strlen (name);
+ /* Skip registers wholly inside of OFFSET. */
+ while (offset >= register_size (gdbarch, regnum))
+ {
+ offset -= register_size (gdbarch, regnum);
+ regnum++;
+ }
- /* Search register name space. */
- for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
- if (REGISTER_NAME (i) && len == strlen (REGISTER_NAME (i))
- && strncmp (name, REGISTER_NAME (i), len) == 0)
- {
- return i;
- }
+ /* Ensure that we will not read beyond the end of the register file.
+ This can only ever happen if the debug information is bad. */
+ maxsize = -offset;
+ numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+ for (i = regnum; i < numregs; i++)
+ {
+ int thissize = register_size (gdbarch, i);
+ if (thissize == 0)
+ break; /* This register is not available on this architecture. */
+ maxsize += thissize;
+ }
+ if (len > maxsize)
+ {
+ warning (_("Bad debug information detected: "
+ "Attempt to read %d bytes from registers."), len);
+ return 0;
+ }
- /* Try builtin registers. */
- i = builtin_reg_map_name_to_regnum (name, len);
- if (i >= 0)
+ /* Copy the data. */
+ while (len > 0)
{
- /* A builtin register doesn't fall into the architecture's
- register range. */
- gdb_assert (i >= NUM_REGS + NUM_PSEUDO_REGS);
- return i;
+ int curr_len = register_size (gdbarch, regnum) - offset;
+ if (curr_len > len)
+ curr_len = len;
+
+ if (curr_len == register_size (gdbarch, regnum))
+ {
+ if (!frame_register_read (frame, regnum, myaddr))
+ return 0;
+ }
+ else
+ {
+ gdb_byte buf[MAX_REGISTER_SIZE];
+ if (!frame_register_read (frame, regnum, buf))
+ return 0;
+ memcpy (myaddr, buf + offset, curr_len);
+ }
+
+ myaddr += curr_len;
+ len -= curr_len;
+ offset = 0;
+ regnum++;
}
- return -1;
+ return 1;
}
-const char *
-frame_map_regnum_to_name (int regnum)
+void
+put_frame_register_bytes (struct frame_info *frame, int regnum,
+ CORE_ADDR offset, int len, const gdb_byte *myaddr)
{
- if (regnum < 0)
- return NULL;
- if (regnum < NUM_REGS + NUM_PSEUDO_REGS)
- return REGISTER_NAME (regnum);
- return builtin_reg_map_regnum_to_name (regnum);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+
+ /* Skip registers wholly inside of OFFSET. */
+ while (offset >= register_size (gdbarch, regnum))
+ {
+ offset -= register_size (gdbarch, regnum);
+ regnum++;
+ }
+
+ /* Copy the data. */
+ while (len > 0)
+ {
+ int curr_len = register_size (gdbarch, regnum) - offset;
+ if (curr_len > len)
+ curr_len = len;
+
+ if (curr_len == register_size (gdbarch, regnum))
+ {
+ put_frame_register (frame, regnum, myaddr);
+ }
+ else
+ {
+ gdb_byte buf[MAX_REGISTER_SIZE];
+ frame_register_read (frame, regnum, buf);
+ memcpy (buf + offset, myaddr, curr_len);
+ put_frame_register (frame, regnum, buf);
+ }
+
+ myaddr += curr_len;
+ len -= curr_len;
+ offset = 0;
+ regnum++;
+ }
}
/* Create a sentinel frame. */
-struct frame_info *
+static struct frame_info *
create_sentinel_frame (struct regcache *regcache)
{
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
- frame->type = NORMAL_FRAME;
frame->level = -1;
/* Explicitly initialize the sentinel frame's cache. Provide it
with the underlying regcache. In the future additional
information, such as the frame's thread will be added. */
- frame->unwind_cache = sentinel_frame_cache (regcache);
+ frame->prologue_cache = sentinel_frame_cache (regcache);
/* For the moment there is only one sentinel frame implementation. */
frame->unwind = sentinel_frame_unwind;
/* Link this frame back to itself. The frame is self referential
(the unwound PC is the same as the pc), so make it so. */
frame->next = frame;
- /* Always unwind the PC as part of creating this frame. This
- ensures that the frame's PC points at something valid. */
- /* FIXME: cagney/2003-01-10: Problem here. Unwinding a sentinel
- frame's PC may require information such as the frame's thread's
- stop reason. Is it possible to get to that? */
- frame->pc = frame_pc_unwind (frame);
+ /* Make the sentinel frame's ID valid, but invalid. That way all
+ comparisons with it should fail. */
+ frame->this_id.p = 1;
+ frame->this_id.value = null_frame_id;
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "{ create_sentinel_frame (...) -> ");
+ fprint_frame (gdb_stdlog, frame);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
return frame;
}
@@ -464,20 +943,6 @@ frame_obstack_zalloc (unsigned long size)
return data;
}
-CORE_ADDR *
-frame_saved_regs_zalloc (struct frame_info *fi)
-{
- fi->saved_regs = (CORE_ADDR *)
- frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
- return fi->saved_regs;
-}
-
-CORE_ADDR *
-get_frame_saved_regs (struct frame_info *fi)
-{
- return fi->saved_regs;
-}
-
/* Return the innermost (currently executing) stack frame. This is
split into two functions. The function unwind_to_current_frame()
is wrapped in catch exceptions so that, even when the unwind of the
@@ -487,7 +952,7 @@ static int
unwind_to_current_frame (struct ui_out *ui_out, void *args)
{
struct frame_info *frame = get_prev_frame (args);
- /* A sentinel frame can fail to unwind, eg, because it's PC value
+ /* A sentinel frame can fail to unwind, e.g., because its PC value
lands in somewhere like start. */
if (frame == NULL)
return 1;
@@ -498,18 +963,26 @@ unwind_to_current_frame (struct ui_out *ui_out, void *args)
struct frame_info *
get_current_frame (void)
{
- if (!target_has_stack)
- error ("No stack.");
+ /* First check, and report, the lack of registers. Having GDB
+ report "No stack!" or "No memory" when the target doesn't even
+ have registers is very confusing. Besides, "printcmd.exp"
+ explicitly checks that ``print $pc'' with no registers prints "No
+ registers". */
if (!target_has_registers)
- error ("No registers.");
+ error (_("No registers."));
+ if (!target_has_stack)
+ error (_("No stack."));
if (!target_has_memory)
- error ("No memory.");
+ error (_("No memory."));
+ if (is_executing (inferior_ptid))
+ error (_("Target is executing."));
+
if (current_frame == NULL)
{
struct frame_info *sentinel_frame =
- create_sentinel_frame (current_regcache);
+ create_sentinel_frame (get_current_regcache ());
if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
- NULL, RETURN_MASK_ERROR) != 0)
+ RETURN_MASK_ERROR) != 0)
{
/* Oops! Fake a current frame? Is this useful? It has a PC
of zero, for instance. */
@@ -522,23 +995,53 @@ get_current_frame (void)
/* The "selected" stack frame is used by default for local and arg
access. May be zero, for no selected frame. */
-struct frame_info *deprecated_selected_frame;
+static struct frame_info *selected_frame;
+
+int
+has_stack_frames (void)
+{
+ if (!target_has_registers || !target_has_stack || !target_has_memory)
+ return 0;
+
+ /* If the current thread is executing, don't try to read from
+ it. */
+ if (is_executing (inferior_ptid))
+ return 0;
+
+ return 1;
+}
-/* Return the selected frame. Always non-null (unless there isn't an
+/* Return the selected frame. Always non-NULL (unless there isn't an
inferior sufficient for creating a frame) in which case an error is
thrown. */
struct frame_info *
-get_selected_frame (void)
+get_selected_frame (const char *message)
{
- if (deprecated_selected_frame == NULL)
- /* Hey! Don't trust this. It should really be re-finding the
- last selected frame of the currently selected thread. This,
- though, is better than nothing. */
- select_frame (get_current_frame ());
+ if (selected_frame == NULL)
+ {
+ if (message != NULL && !has_stack_frames ())
+ error (("%s"), message);
+ /* Hey! Don't trust this. It should really be re-finding the
+ last selected frame of the currently selected thread. This,
+ though, is better than nothing. */
+ select_frame (get_current_frame ());
+ }
/* There is always a frame. */
- gdb_assert (deprecated_selected_frame != NULL);
- return deprecated_selected_frame;
+ gdb_assert (selected_frame != NULL);
+ return selected_frame;
+}
+
+/* This is a variant of get_selected_frame() which can be called when
+ the inferior does not have a frame; in that case it will return
+ NULL instead of calling error(). */
+
+struct frame_info *
+deprecated_safe_get_selected_frame (void)
+{
+ if (!has_stack_frames ())
+ return NULL;
+ return get_selected_frame (NULL);
}
/* Select frame FI (or NULL - to invalidate the current frame). */
@@ -546,28 +1049,34 @@ get_selected_frame (void)
void
select_frame (struct frame_info *fi)
{
- register struct symtab *s;
+ struct symtab *s;
- deprecated_selected_frame = fi;
- /* NOTE: cagney/2002-05-04: FI can be NULL. This occures when the
+ selected_frame = fi;
+ /* NOTE: cagney/2002-05-04: FI can be NULL. This occurs when the
frame is being invalidated. */
- if (selected_frame_level_changed_hook)
- selected_frame_level_changed_hook (frame_relative_level (fi));
+ if (deprecated_selected_frame_level_changed_hook)
+ deprecated_selected_frame_level_changed_hook (frame_relative_level (fi));
/* FIXME: kseitz/2002-08-28: It would be nice to call
- selected_frame_level_changed_event right here, but due to limitations
+ selected_frame_level_changed_event() right here, but due to limitations
in the current interfaces, we would end up flooding UIs with events
- because select_frame is used extensively internally.
+ because select_frame() is used extensively internally.
Once we have frame-parameterized frame (and frame-related) commands,
the event notification can be moved here, since this function will only
- be called when the users selected frame is being changed. */
+ be called when the user's selected frame is being changed. */
/* Ensure that symbols for this frame are read in. Also, determine the
source language of this frame, and switch to it if desired. */
if (fi)
{
- s = find_pc_symtab (fi->pc);
+ /* We retrieve the frame's symtab by using the frame PC. However
+ we cannot use the frame PC as-is, because it usually points to
+ the instruction following the "call", which is sometimes the
+ first instruction of another function. So we rely on
+ get_frame_address_in_block() which provides us with a PC which
+ is guaranteed to be inside the frame's code block. */
+ s = find_pc_symtab (get_frame_address_in_block (fi));
if (s
&& s->language != current_language->la_language
&& s->language != language_unknown
@@ -577,711 +1086,270 @@ select_frame (struct frame_info *fi)
}
}
}
+
+/* Create an arbitrary (i.e. address specified by user) or innermost frame.
+ Always returns a non-NULL value. */
-/* Return the register saved in the simplistic ``saved_regs'' cache.
- If the value isn't here AND a value is needed, try the next inner
- most frame. */
-
-static void
-frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *bufferp)
+struct frame_info *
+create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
{
- /* There is always a frame at this point. And THIS is the frame
- we're interested in. */
- gdb_assert (frame != NULL);
- /* If we're using generic dummy frames, we'd better not be in a call
- dummy. (generic_call_dummy_register_unwind ought to have been called
- instead.) */
- gdb_assert (!(DEPRECATED_USE_GENERIC_DUMMY_FRAMES
- && (get_frame_type (frame) == DUMMY_FRAME)));
-
- /* Only (older) architectures that implement the
- DEPRECATED_FRAME_INIT_SAVED_REGS method should be using this
- function. */
- gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
-
- /* Load the saved_regs register cache. */
- if (get_frame_saved_regs (frame) == NULL)
- DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
-
- if (get_frame_saved_regs (frame) != NULL
- && get_frame_saved_regs (frame)[regnum] != 0)
- {
- if (regnum == SP_REGNUM)
- {
- /* SP register treated specially. */
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (bufferp != NULL)
- store_address (bufferp, REGISTER_RAW_SIZE (regnum),
- get_frame_saved_regs (frame)[regnum]);
- }
- else
- {
- /* Any other register is saved in memory, fetch it but cache
- a local copy of its value. */
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = get_frame_saved_regs (frame)[regnum];
- *realnump = -1;
- if (bufferp != NULL)
- {
-#if 1
- /* Save each register value, as it is read in, in a
- frame based cache. */
- void **regs = (*cache);
- if (regs == NULL)
- {
- int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS)
- * sizeof (void *));
- regs = frame_obstack_zalloc (sizeof_cache);
- (*cache) = regs;
- }
- if (regs[regnum] == NULL)
- {
- regs[regnum]
- = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum));
- read_memory (get_frame_saved_regs (frame)[regnum], regs[regnum],
- REGISTER_RAW_SIZE (regnum));
- }
- memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum));
-#else
- /* Read the value in from memory. */
- read_memory (get_frame_saved_regs (frame)[regnum], bufferp,
- REGISTER_RAW_SIZE (regnum));
-#endif
- }
- }
- return;
- }
-
- /* No luck, assume this and the next frame have the same register
- value. Pass the request down the frame chain to the next frame.
- Hopefully that will find the register's location, either in a
- register or in memory. */
- frame_register (frame, regnum, optimizedp, lvalp, addrp, realnump,
- bufferp);
-}
+ struct frame_info *fi;
-static CORE_ADDR
-frame_saved_regs_pc_unwind (struct frame_info *frame, void **cache)
-{
- gdb_assert (FRAME_SAVED_PC_P ());
- return FRAME_SAVED_PC (frame);
-}
-
-static void
-frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache,
- struct frame_id *id)
-{
- int fromleaf;
- CORE_ADDR base;
- CORE_ADDR pc;
-
- /* Start out by assuming it's NULL. */
- (*id) = null_frame_id;
-
- if (frame_relative_level (next_frame) <= 0)
- /* FIXME: 2002-11-09: Frameless functions can occure anywhere in
- the frame chain, not just the inner most frame! The generic,
- per-architecture, frame code should handle this and the below
- should simply be removed. */
- fromleaf = FRAMELESS_FUNCTION_INVOCATION (next_frame);
- else
- fromleaf = 0;
-
- if (fromleaf)
- /* A frameless inner-most frame. The `FP' (which isn't an
- architecture frame-pointer register!) of the caller is the same
- as the callee. */
- /* FIXME: 2002-11-09: There isn't any reason to special case this
- edge condition. Instead the per-architecture code should hande
- it locally. */
- base = get_frame_base (next_frame);
- else
+ if (frame_debug)
{
- /* Two macros defined in tm.h specify the machine-dependent
- actions to be performed here.
-
- First, get the frame's chain-pointer.
-
- If that is zero, the frame is the outermost frame or a leaf
- called by the outermost frame. This means that if start
- calls main without a frame, we'll return 0 (which is fine
- anyway).
-
- Nope; there's a problem. This also returns when the current
- routine is a leaf of main. This is unacceptable. We move
- this to after the ffi test; I'd rather have backtraces from
- start go curfluy than have an abort called from main not show
- main. */
- gdb_assert (FRAME_CHAIN_P ());
- base = FRAME_CHAIN (next_frame);
-
- if (!frame_chain_valid (base, next_frame))
- return;
+ fprintf_unfiltered (gdb_stdlog,
+ "{ create_new_frame (addr=0x%s, pc=0x%s) ",
+ paddr_nz (addr), paddr_nz (pc));
}
- if (base == 0)
- return;
-
- /* FIXME: cagney/2002-06-08: This should probably return the frame's
- function and not the PC (a.k.a. resume address). */
- pc = frame_pc_unwind (next_frame);
- id->pc = pc;
- id->base = base;
-}
-
-static void
-frame_saved_regs_pop (struct frame_info *fi, void **cache,
- struct regcache *regcache)
-{
- gdb_assert (POP_FRAME_P ());
- POP_FRAME;
-}
-
-const struct frame_unwind trad_frame_unwinder = {
- frame_saved_regs_pop,
- frame_saved_regs_pc_unwind,
- frame_saved_regs_id_unwind,
- frame_saved_regs_register_unwind
-};
-const struct frame_unwind *trad_frame_unwind = &trad_frame_unwinder;
-
-
-/* Function: get_saved_register
- Find register number REGNUM relative to FRAME and put its (raw,
- target format) contents in *RAW_BUFFER.
-
- Set *OPTIMIZED if the variable was optimized out (and thus can't be
- fetched). Note that this is never set to anything other than zero
- in this implementation.
-
- Set *LVAL to lval_memory, lval_register, or not_lval, depending on
- whether the value was fetched from memory, from a register, or in a
- strange and non-modifiable way (e.g. a frame pointer which was
- calculated rather than fetched). We will use not_lval for values
- fetched from generic dummy frames.
-
- Set *ADDRP to the address, either in memory or as a REGISTER_BYTE
- offset into the registers array. If the value is stored in a dummy
- frame, set *ADDRP to zero.
-
- To use this implementation, define a function called
- "get_saved_register" in your target code, which simply passes all
- of its arguments to this function.
-
- The argument RAW_BUFFER must point to aligned memory. */
-void
-deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
- CORE_ADDR *addrp,
- struct frame_info *frame, int regnum,
- enum lval_type *lval)
-{
- if (!target_has_registers)
- error ("No registers.");
+ fi = FRAME_OBSTACK_ZALLOC (struct frame_info);
- gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
+ fi->next = create_sentinel_frame (get_current_regcache ());
- /* Normal systems don't optimize out things with register numbers. */
- if (optimized != NULL)
- *optimized = 0;
+ /* Set/update this frame's cached PC value, found in the next frame.
+ Do this before looking for this frame's unwinder. A sniffer is
+ very likely to read this, and the corresponding unwinder is
+ entitled to rely that the PC doesn't magically change. */
+ fi->next->prev_pc.value = pc;
+ fi->next->prev_pc.p = 1;
- if (addrp) /* default assumption: not found in memory */
- *addrp = 0;
+ /* Select/initialize both the unwind function and the frame's type
+ based on the PC. */
+ fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
- /* Note: since the current frame's registers could only have been
- saved by frames INTERIOR TO the current frame, we skip examining
- the current frame itself: otherwise, we would be getting the
- previous frame's registers which were saved by the current frame. */
+ fi->this_id.p = 1;
+ fi->this_id.value = frame_id_build (addr, pc);
- if (frame != NULL)
+ if (frame_debug)
{
- for (frame = get_next_frame (frame);
- frame_relative_level (frame) >= 0;
- frame = get_next_frame (frame))
- {
- if (get_frame_type (frame) == DUMMY_FRAME)
- {
- if (lval) /* found it in a CALL_DUMMY frame */
- *lval = not_lval;
- if (raw_buffer)
- /* FIXME: cagney/2002-06-26: This should be via the
- gdbarch_register_read() method so that it, on the
- fly, constructs either a raw or pseudo register
- from the raw register cache. */
- regcache_raw_read
- (generic_find_dummy_frame (get_frame_pc (frame),
- get_frame_base (frame)),
- regnum, raw_buffer);
- return;
- }
-
- DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
- if (get_frame_saved_regs (frame) != NULL
- && get_frame_saved_regs (frame)[regnum] != 0)
- {
- if (lval) /* found it saved on the stack */
- *lval = lval_memory;
- if (regnum == SP_REGNUM)
- {
- if (raw_buffer) /* SP register treated specially */
- store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
- get_frame_saved_regs (frame)[regnum]);
- }
- else
- {
- if (addrp) /* any other register */
- *addrp = get_frame_saved_regs (frame)[regnum];
- if (raw_buffer)
- read_memory (get_frame_saved_regs (frame)[regnum], raw_buffer,
- REGISTER_RAW_SIZE (regnum));
- }
- return;
- }
- }
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, fi);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
}
- /* If we get thru the loop to this point, it means the register was
- not saved in any frame. Return the actual live-register value. */
-
- if (lval) /* found it in a live register */
- *lval = lval_register;
- if (addrp)
- *addrp = REGISTER_BYTE (regnum);
- if (raw_buffer)
- deprecated_read_register_gen (regnum, raw_buffer);
-}
-
-/* Determine the frame's type based on its PC. */
-
-static enum frame_type
-frame_type_from_pc (CORE_ADDR pc)
-{
- /* FIXME: cagney/2002-11-24: Can't yet directly call
- pc_in_dummy_frame() as some architectures don't set
- PC_IN_CALL_DUMMY() to generic_pc_in_call_dummy() (remember the
- latter is implemented by simply calling pc_in_dummy_frame). */
- if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
- && DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
- return DUMMY_FRAME;
- else
- {
- char *name;
- find_pc_partial_function (pc, &name, NULL, NULL);
- if (PC_IN_SIGTRAMP (pc, name))
- return SIGTRAMP_FRAME;
- else
- return NORMAL_FRAME;
- }
+ return fi;
}
-/* Create an arbitrary (i.e. address specified by user) or innermost frame.
- Always returns a non-NULL value. */
+/* Return the frame that THIS_FRAME calls (NULL if THIS_FRAME is the
+ innermost frame). Be careful to not fall off the bottom of the
+ frame chain and onto the sentinel frame. */
struct frame_info *
-create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
+get_next_frame (struct frame_info *this_frame)
{
- struct frame_info *fi;
-
- fi = frame_obstack_zalloc (sizeof (struct frame_info));
-
- fi->frame = addr;
- fi->pc = pc;
- fi->next = create_sentinel_frame (current_regcache);
- fi->type = frame_type_from_pc (pc);
-
- if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
- DEPRECATED_INIT_EXTRA_FRAME_INFO (0, fi);
-
- /* Select/initialize an unwind function. */
- fi->unwind = frame_unwind_find_by_pc (current_gdbarch, fi->pc);
-
- return fi;
+ if (this_frame->level > 0)
+ return this_frame->next;
+ else
+ return NULL;
}
-/* Return the frame that FRAME calls (NULL if FRAME is the innermost
- frame). Be careful to not fall off the bottom of the frame chain
- and onto the sentinel frame. */
+/* Observer for the target_changed event. */
-struct frame_info *
-get_next_frame (struct frame_info *frame)
+static void
+frame_observer_target_changed (struct target_ops *target)
{
- if (frame->level > 0)
- return frame->next;
- else
- return NULL;
+ reinit_frame_cache ();
}
/* Flush the entire frame cache. */
void
-flush_cached_frames (void)
+reinit_frame_cache (void)
{
+ struct frame_info *fi;
+
+ /* Tear down all frame caches. */
+ for (fi = current_frame; fi != NULL; fi = fi->prev)
+ {
+ if (fi->prologue_cache && fi->unwind->dealloc_cache)
+ fi->unwind->dealloc_cache (fi, fi->prologue_cache);
+ if (fi->base_cache && fi->base->unwind->dealloc_cache)
+ fi->base->unwind->dealloc_cache (fi, fi->base_cache);
+ }
+
/* Since we can't really be sure what the first object allocated was */
obstack_free (&frame_cache_obstack, 0);
obstack_init (&frame_cache_obstack);
+ if (current_frame != NULL)
+ annotate_frames_invalid ();
+
current_frame = NULL; /* Invalidate cache */
select_frame (NULL);
- annotate_frames_invalid ();
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ reinit_frame_cache () }\n");
}
-/* Flush the frame cache, and start a new one if necessary. */
+/* Find where a register is saved (in memory or another register).
+ The result of frame_register_unwind is just where it is saved
+ relative to this particular frame. */
-void
-reinit_frame_cache (void)
+static void
+frame_register_unwind_location (struct frame_info *this_frame, int regnum,
+ int *optimizedp, enum lval_type *lvalp,
+ CORE_ADDR *addrp, int *realnump)
{
- flush_cached_frames ();
+ gdb_assert (this_frame == NULL || this_frame->level >= 0);
- /* FIXME: The inferior_ptid test is wrong if there is a corefile. */
- if (PIDGET (inferior_ptid) != 0)
+ while (this_frame != NULL)
{
- select_frame (get_current_frame ());
- }
-}
-
-/* Create the previous frame using the deprecated methods
- INIT_EXTRA_INFO, INIT_FRAME_PC and INIT_FRAME_PC_FIRST. */
+ frame_register_unwind (this_frame, regnum, optimizedp, lvalp,
+ addrp, realnump, NULL);
-static struct frame_info *
-legacy_get_prev_frame (struct frame_info *next_frame)
-{
- CORE_ADDR address = 0;
- struct frame_info *prev;
- int fromleaf;
-
- /* This code only works on normal frames. A sentinel frame, where
- the level is -1, should never reach this code. */
- gdb_assert (next_frame->level >= 0);
-
- /* On some machines it is possible to call a function without
- setting up a stack frame for it. On these machines, we
- define this macro to take two args; a frameinfo pointer
- identifying a frame and a variable to set or clear if it is
- or isn't leafless. */
-
- /* Still don't want to worry about this except on the innermost
- frame. This macro will set FROMLEAF if NEXT_FRAME is a frameless
- function invocation. */
- if (next_frame->level == 0)
- /* FIXME: 2002-11-09: Frameless functions can occure anywhere in
- the frame chain, not just the inner most frame! The generic,
- per-architecture, frame code should handle this and the below
- should simply be removed. */
- fromleaf = FRAMELESS_FUNCTION_INVOCATION (next_frame);
- else
- fromleaf = 0;
-
- if (fromleaf)
- /* A frameless inner-most frame. The `FP' (which isn't an
- architecture frame-pointer register!) of the caller is the same
- as the callee. */
- /* FIXME: 2002-11-09: There isn't any reason to special case this
- edge condition. Instead the per-architecture code should hande
- it locally. */
- address = get_frame_base (next_frame);
- else
- {
- /* Two macros defined in tm.h specify the machine-dependent
- actions to be performed here.
-
- First, get the frame's chain-pointer.
-
- If that is zero, the frame is the outermost frame or a leaf
- called by the outermost frame. This means that if start
- calls main without a frame, we'll return 0 (which is fine
- anyway).
-
- Nope; there's a problem. This also returns when the current
- routine is a leaf of main. This is unacceptable. We move
- this to after the ffi test; I'd rather have backtraces from
- start go curfluy than have an abort called from main not show
- main. */
- gdb_assert (FRAME_CHAIN_P ());
- address = FRAME_CHAIN (next_frame);
-
- if (!frame_chain_valid (address, next_frame))
- return 0;
- }
- if (address == 0)
- return 0;
+ if (*optimizedp)
+ break;
- /* Create an initially zero previous frame. */
- prev = frame_obstack_zalloc (sizeof (struct frame_info));
+ if (*lvalp != lval_register)
+ break;
- /* Link it in. */
- next_frame->prev = prev;
- prev->next = next_frame;
- prev->frame = address;
- prev->level = next_frame->level + 1;
- /* FIXME: cagney/2002-11-18: Should be setting the frame's type
- here, before anything else, and not last. Various INIT functions
- are full of work-arounds for the frames type not being set
- correctly from the word go. Ulgh! */
- prev->type = NORMAL_FRAME;
-
- /* This change should not be needed, FIXME! We should determine
- whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen
- after DEPRECATED_INIT_EXTRA_FRAME_INFO and come up with a simple
- way to express what goes on here.
-
- DEPRECATED_INIT_EXTRA_FRAME_INFO is called from two places:
- create_new_frame (where the PC is already set up) and here (where
- it isn't). DEPRECATED_INIT_FRAME_PC is only called from here,
- always after DEPRECATED_INIT_EXTRA_FRAME_INFO.
-
- The catch is the MIPS, where DEPRECATED_INIT_EXTRA_FRAME_INFO
- requires the PC value (which hasn't been set yet). Some other
- machines appear to require DEPRECATED_INIT_EXTRA_FRAME_INFO
- before they can do DEPRECATED_INIT_FRAME_PC. Phoo.
-
- We shouldn't need DEPRECATED_INIT_FRAME_PC_FIRST to add more
- complication to an already overcomplicated part of GDB.
- gnu@cygnus.com, 15Sep92.
-
- Assuming that some machines need DEPRECATED_INIT_FRAME_PC after
- DEPRECATED_INIT_EXTRA_FRAME_INFO, one possible scheme:
-
- SETUP_INNERMOST_FRAME(): Default version is just create_new_frame
- (read_fp ()), read_pc ()). Machines with extra frame info would
- do that (or the local equivalent) and then set the extra fields.
-
- SETUP_ARBITRARY_FRAME(argc, argv): Only change here is that
- create_new_frame would no longer init extra frame info;
- SETUP_ARBITRARY_FRAME would have to do that.
-
- INIT_PREV_FRAME(fromleaf, prev) Replace
- DEPRECATED_INIT_EXTRA_FRAME_INFO and DEPRECATED_INIT_FRAME_PC.
- This should also return a flag saying whether to keep the new
- frame, or whether to discard it, because on some machines (e.g.
- mips) it is really awkward to have FRAME_CHAIN_VALID called
- BEFORE DEPRECATED_INIT_EXTRA_FRAME_INFO (there is no good way to
- get information deduced in FRAME_CHAIN_VALID into the extra
- fields of the new frame). std_frame_pc(fromleaf, prev)
-
- This is the default setting for INIT_PREV_FRAME. It just does
- what the default DEPRECATED_INIT_FRAME_PC does. Some machines
- will call it from INIT_PREV_FRAME (either at the beginning, the
- end, or in the middle). Some machines won't use it.
-
- kingdon@cygnus.com, 13Apr93, 31Jan94, 14Dec94. */
-
- /* NOTE: cagney/2002-11-09: Just ignore the above! There is no
- reason for things to be this complicated.
-
- The trick is to assume that there is always a frame. Instead of
- special casing the inner-most frame, create fake frame
- (containing the hardware registers) that is inner to the
- user-visible inner-most frame (...) and then unwind from that.
- That way architecture code can use use the standard
- frame_XX_unwind() functions and not differentiate between the
- inner most and any other case.
-
- Since there is always a frame to unwind from, there is always
- somewhere (NEXT_FRAME) to store all the info needed to construct
- a new (previous) frame without having to first create it. This
- means that the convolution below - needing to carefully order a
- frame's initialization - isn't needed.
-
- The irony here though, is that FRAME_CHAIN(), at least for a more
- up-to-date architecture, always calls FRAME_SAVED_PC(), and
- FRAME_SAVED_PC() computes the PC but without first needing the
- frame! Instead of the convolution below, we could have simply
- called FRAME_SAVED_PC() and been done with it! Note that
- FRAME_SAVED_PC() is being superseed by frame_pc_unwind() and that
- function does have somewhere to cache that PC value. */
-
- if (DEPRECATED_INIT_FRAME_PC_FIRST_P ())
- prev->pc = (DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf, prev));
-
- if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
- DEPRECATED_INIT_EXTRA_FRAME_INFO (fromleaf, prev);
-
- /* This entry is in the frame queue now, which is good since
- FRAME_SAVED_PC may use that queue to figure out its value (see
- tm-sparc.h). We want the pc saved in the inferior frame. */
- if (DEPRECATED_INIT_FRAME_PC_P ())
- prev->pc = DEPRECATED_INIT_FRAME_PC (fromleaf, prev);
-
- /* If ->frame and ->pc are unchanged, we are in the process of
- getting ourselves into an infinite backtrace. Some architectures
- check this in FRAME_CHAIN or thereabouts, but it seems like there
- is no reason this can't be an architecture-independent check. */
- if (prev->frame == next_frame->frame
- && prev->pc == next_frame->pc)
- {
- next_frame->prev = NULL;
- obstack_free (&frame_cache_obstack, prev);
- return NULL;
+ regnum = *realnump;
+ this_frame = get_next_frame (this_frame);
}
-
- /* Initialize the code used to unwind the frame PREV based on the PC
- (and probably other architectural information). The PC lets you
- check things like the debug info at that point (dwarf2cfi?) and
- use that to decide how the frame should be unwound. */
- prev->unwind = frame_unwind_find_by_pc (current_gdbarch, prev->pc);
-
- /* NOTE: cagney/2002-11-18: The code segments, found in
- create_new_frame and get_prev_frame(), that initializes the
- frames type is subtly different. The latter only updates ->type
- when it encounters a SIGTRAMP_FRAME or DUMMY_FRAME. This stops
- get_prev_frame() overriding the frame's type when the INIT code
- has previously set it. This is really somewhat bogus. The
- initialization, as seen in create_new_frame(), should occur
- before the INIT function has been called. */
- if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
- && (DEPRECATED_PC_IN_CALL_DUMMY_P ()
- ? DEPRECATED_PC_IN_CALL_DUMMY (prev->pc, 0, 0)
- : pc_in_dummy_frame (prev->pc)))
- prev->type = DUMMY_FRAME;
- else
- {
- /* FIXME: cagney/2002-11-10: This should be moved to before the
- INIT code above so that the INIT code knows what the frame's
- type is (in fact, for a [generic] dummy-frame, the type can
- be set and then the entire initialization can be skipped.
- Unforunatly, its the INIT code that sets the PC (Hmm, catch
- 22). */
- char *name;
- find_pc_partial_function (prev->pc, &name, NULL, NULL);
- if (PC_IN_SIGTRAMP (prev->pc, name))
- prev->type = SIGTRAMP_FRAME;
- /* FIXME: cagney/2002-11-11: Leave prev->type alone. Some
- architectures are forcing the frame's type in INIT so we
- don't want to override it here. Remember, NORMAL_FRAME == 0,
- so it all works (just :-/). Once this initialization is
- moved to the start of this function, all this nastness will
- go away. */
- }
-
- return prev;
}
-/* Return a structure containing various interesting information
- about the frame that called NEXT_FRAME. Returns NULL
- if there is no such frame. */
+/* Return a "struct frame_info" corresponding to the frame that called
+ THIS_FRAME. Returns NULL if there is no such frame.
-struct frame_info *
-get_prev_frame (struct frame_info *next_frame)
+ Unlike get_prev_frame, this function always tries to unwind the
+ frame. */
+
+static struct frame_info *
+get_prev_frame_1 (struct frame_info *this_frame)
{
struct frame_info *prev_frame;
+ struct frame_id this_id;
+ struct gdbarch *gdbarch;
- /* Return the inner-most frame, when the caller passes in NULL. */
- /* NOTE: cagney/2002-11-09: Not sure how this would happen. The
- caller should have previously obtained a valid frame using
- get_selected_frame() and then called this code - only possibility
- I can think of is code behaving badly.
-
- NOTE: cagney/2003-01-10: Talk about code behaving badly. Check
- block_innermost_frame(). It does the sequence: frame = NULL;
- while (1) { frame = get_prev_frame (frame); .... }. Ulgh! Why
- it couldn't be written better, I don't know.
-
- NOTE: cagney/2003-01-11: I suspect what is happening is
- block_innermost_frame() is, when the target has no state
- (registers, memory, ...), still calling this function. The
- assumption being that this function will return NULL indicating
- that a frame isn't possible, rather than checking that the target
- has state and then calling get_current_frame() and
- get_prev_frame(). This is a guess mind. */
- if (next_frame == NULL)
+ gdb_assert (this_frame != NULL);
+ gdbarch = get_frame_arch (this_frame);
+
+ if (frame_debug)
{
- /* NOTE: cagney/2002-11-09: There was a code segment here that
- would error out when CURRENT_FRAME was NULL. The comment
- that went with it made the claim ...
-
- ``This screws value_of_variable, which just wants a nice
- clean NULL return from block_innermost_frame if there are no
- frames. I don't think I've ever seen this message happen
- otherwise. And returning NULL here is a perfectly legitimate
- thing to do.''
-
- Per the above, this code shouldn't even be called with a NULL
- NEXT_FRAME. */
- return current_frame;
+ fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_1 (this_frame=");
+ if (this_frame != NULL)
+ fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
+ else
+ fprintf_unfiltered (gdb_stdlog, "");
+ fprintf_unfiltered (gdb_stdlog, ") ");
}
- /* There is always a frame. If this assertion fails, suspect that
- something should be calling get_selected_frame() or
- get_current_frame(). */
- gdb_assert (next_frame != NULL);
-
- if (next_frame->level >= 0
- && !backtrace_below_main
- && inside_main_func (get_frame_pc (next_frame)))
- /* Don't unwind past main(), bug always unwind the sentinel frame.
- Note, this is done _before_ the frame has been marked as
- previously unwound. That way if the user later decides to
- allow unwinds past main(), that just happens. */
+ /* Only try to do the unwind once. */
+ if (this_frame->prev_p)
{
if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - inside main func.\n");
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, this_frame->prev);
+ fprintf_unfiltered (gdb_stdlog, " // cached \n");
+ }
+ return this_frame->prev;
+ }
+
+ /* If the frame unwinder hasn't been selected yet, we must do so
+ before setting prev_p; otherwise the check for misbehaved
+ sniffers will think that this frame's sniffer tried to unwind
+ further (see frame_cleanup_after_sniffer). */
+ if (this_frame->unwind == NULL)
+ this_frame->unwind
+ = frame_unwind_find_by_frame (this_frame, &this_frame->prologue_cache);
+
+ this_frame->prev_p = 1;
+ this_frame->stop_reason = UNWIND_NO_REASON;
+
+ /* Check that this frame's ID was valid. If it wasn't, don't try to
+ unwind to the prev frame. Be careful to not apply this test to
+ the sentinel frame. */
+ this_id = get_frame_id (this_frame);
+ if (this_frame->level >= 0 && !frame_id_p (this_id))
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
+ }
+ this_frame->stop_reason = UNWIND_NULL_ID;
return NULL;
}
- /* Only try to do the unwind once. */
- if (next_frame->prev_p)
- return next_frame->prev;
- next_frame->prev_p = 1;
-
- /* If we're inside the entry file, it isn't valid. Don't apply this
- test to a dummy frame - dummy frame PC's typically land in the
- entry file. Don't apply this test to the sentinel frame.
- Sentinel frames should always be allowed to unwind. */
- /* NOTE: drow/2002-12-25: should there be a way to disable this
- check? It assumes a single small entry file, and the way some
- debug readers (e.g. dbxread) figure out which object is the
- entry file is somewhat hokey. */
- /* NOTE: cagney/2003-01-10: If there is a way of disabling this test
- then it should probably be moved to before the ->prev_p test,
- above. */
- if (next_frame->type != DUMMY_FRAME && next_frame->level >= 0
- && inside_entry_file (get_frame_pc (next_frame)))
+ /* Check that this frame's ID isn't inner to (younger, below, next)
+ the next frame. This happens when a frame unwind goes backwards.
+ This check is valid only if the next frame is NORMAL. See the
+ comment at frame_id_inner for details. */
+ if (this_frame->next->unwind->type == NORMAL_FRAME
+ && frame_id_inner (get_frame_arch (this_frame->next), this_id,
+ get_frame_id (this_frame->next)))
{
if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - inside entry file\n");
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // this frame ID is inner }\n");
+ }
+ this_frame->stop_reason = UNWIND_INNER_ID;
return NULL;
}
- /* If we're already inside the entry function for the main objfile,
- then it isn't valid. Don't apply this test to a dummy frame -
- dummy frame PC's typically land in the entry func. Don't apply
- this test to the sentinel frame. Sentinel frames should always
- be allowed to unwind. */
- /* NOTE: cagney/2003-02-25: Don't enable until someone has found
- hard evidence that this is needed. */
- if (0
- && next_frame->type != DUMMY_FRAME && next_frame->level >= 0
- && inside_entry_func (get_frame_pc (next_frame)))
+ /* Check that this and the next frame are not identical. If they
+ are, there is most likely a stack cycle. As with the inner-than
+ test above, avoid comparing the inner-most and sentinel frames. */
+ if (this_frame->level > 0
+ && frame_id_eq (this_id, get_frame_id (this_frame->next)))
{
if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - inside entry func\n");
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+ }
+ this_frame->stop_reason = UNWIND_SAME_ID;
return NULL;
}
- /* If any of the old frame initialization methods are around, use
- the legacy get_prev_frame method. Just don't try to unwind a
- sentinel frame using that method - it doesn't work. All sentinal
- frames use the new unwind code. */
- if ((DEPRECATED_INIT_FRAME_PC_P ()
- || DEPRECATED_INIT_FRAME_PC_FIRST_P ()
- || DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()
- || FRAME_CHAIN_P ())
- && next_frame->level >= 0)
+ /* Check that this and the next frame do not unwind the PC register
+ to the same memory location. If they do, then even though they
+ have different frame IDs, the new frame will be bogus; two
+ functions can't share a register save slot for the PC. This can
+ happen when the prologue analyzer finds a stack adjustment, but
+ no PC save.
+
+ This check does assume that the "PC register" is roughly a
+ traditional PC, even if the gdbarch_unwind_pc method adjusts
+ it (we do not rely on the value, only on the unwound PC being
+ dependent on this value). A potential improvement would be
+ to have the frame prev_pc method and the gdbarch unwind_pc
+ method set the same lval and location information as
+ frame_register_unwind. */
+ if (this_frame->level > 0
+ && gdbarch_pc_regnum (gdbarch) >= 0
+ && get_frame_type (this_frame) == NORMAL_FRAME
+ && get_frame_type (this_frame->next) == NORMAL_FRAME)
{
- prev_frame = legacy_get_prev_frame (next_frame);
- if (frame_debug && prev_frame == NULL)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - legacy_get_prev_frame NULL.\n");
- return prev_frame;
+ int optimized, realnum, nrealnum;
+ enum lval_type lval, nlval;
+ CORE_ADDR addr, naddr;
+
+ frame_register_unwind_location (this_frame,
+ gdbarch_pc_regnum (gdbarch),
+ &optimized, &lval, &addr, &realnum);
+ frame_register_unwind_location (get_next_frame (this_frame),
+ gdbarch_pc_regnum (gdbarch),
+ &optimized, &nlval, &naddr, &nrealnum);
+
+ if ((lval == lval_memory && lval == nlval && addr == naddr)
+ || (lval == lval_register && lval == nlval && realnum == nrealnum))
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // no saved PC }\n");
+ }
+
+ this_frame->stop_reason = UNWIND_NO_SAVED_PC;
+ this_frame->prev = NULL;
+ return NULL;
+ }
}
/* Allocate the new frame but do not wire it in to the frame chain.
@@ -1295,153 +1363,240 @@ get_prev_frame (struct frame_info *next_frame)
been here before' check above will stop repeated memory
allocation calls. */
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
- prev_frame->level = next_frame->level + 1;
-
- /* Try to unwind the PC. If that doesn't work, assume we've reached
- the oldest frame and simply return. Is there a better sentinal
- value? The unwound PC value is then used to initialize the new
- previous frame's type.
-
- Note that the pc-unwind is intentionally performed before the
- frame chain. This is ok since, for old targets, both
- frame_pc_unwind (nee, FRAME_SAVED_PC) and FRAME_CHAIN()) assume
- NEXT_FRAME's data structures have already been initialized (using
- DEPRECATED_INIT_EXTRA_FRAME_INFO) and hence the call order
- doesn't matter.
-
- By unwinding the PC first, it becomes possible to, in the case of
- a dummy frame, avoid also unwinding the frame ID. This is
- because (well ignoring the PPC) a dummy frame can be located
- using NEXT_FRAME's frame ID. */
-
- prev_frame->pc = frame_pc_unwind (next_frame);
- if (prev_frame->pc == 0)
+ prev_frame->level = this_frame->level + 1;
+
+ /* Don't yet compute ->unwind (and hence ->type). It is computed
+ on-demand in get_frame_type, frame_register_unwind, and
+ get_frame_id. */
+
+ /* Don't yet compute the frame's ID. It is computed on-demand by
+ get_frame_id(). */
+
+ /* The unwound frame ID is validate at the start of this function,
+ as part of the logic to decide if that frame should be further
+ unwound, and not here while the prev frame is being created.
+ Doing this makes it possible for the user to examine a frame that
+ has an invalid frame ID.
+
+ Some very old VAX code noted: [...] For the sake of argument,
+ suppose that the stack is somewhat trashed (which is one reason
+ that "info frame" exists). So, return 0 (indicating we don't
+ know the address of the arglist) if we don't know what frame this
+ frame calls. */
+
+ /* Link it in. */
+ this_frame->prev = prev_frame;
+ prev_frame->next = this_frame;
+
+ if (frame_debug)
{
- /* The allocated PREV_FRAME will be reclaimed when the frame
- obstack is next purged. */
- if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - unwound PC zero\n");
- return NULL;
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, prev_frame);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
}
- prev_frame->type = frame_type_from_pc (prev_frame->pc);
- /* Set the unwind functions based on that identified PC. */
- prev_frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
- prev_frame->pc);
+ return prev_frame;
+}
+
+/* Debug routine to print a NULL frame being returned. */
- /* Find the prev's frame's ID. */
- switch (prev_frame->type)
+static void
+frame_debug_got_null_frame (struct frame_info *this_frame,
+ const char *reason)
+{
+ if (frame_debug)
{
- case DUMMY_FRAME:
- /* 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))
- {
- /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS,
- previously saved the dummy frame's ID. Things only work
- if the two return the same value. */
- gdb_assert (SAVE_DUMMY_FRAME_TOS_P ());
- /* 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. */
- prev_frame->id = gdbarch_unwind_dummy_id (current_gdbarch,
- next_frame);
- }
- else if (next_frame->level < 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. */
- prev_frame->id.base = read_fp ();
- prev_frame->id.pc = read_pc ();
- }
+ fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame (this_frame=");
+ if (this_frame != NULL)
+ fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
else
- {
- /* Outch! We're not on the innermost frame 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");
- return NULL;
- }
- break;
- case NORMAL_FRAME:
- case SIGTRAMP_FRAME:
- /* FIXME: cagney/2003-03-04: The below call isn't right. It
- should instead be doing something like "prev_frame -> unwind
- -> id (next_frame, & prev_frame -> unwind_cache, & prev_frame
- -> id)" but that requires more extensive (pending) changes. */
- next_frame->unwind->id (next_frame, &next_frame->unwind_cache,
- &prev_frame->id);
- /* Check that the unwound ID is valid. */
- if (!frame_id_p (prev_frame->id))
- {
- if (frame_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Outermost frame - unwound frame ID invalid\n");
- return NULL;
- }
- /* Check that the new frame isn't inner to (younger, below,
- next) the old frame. If that happens the frame unwind is
- going backwards. */
- /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since
- that doesn't have a valid frame ID. Should instead set the
- sentinel frame's frame ID to a `sentinel'. Leave it until
- after the switch to storing the frame ID, instead of the
- frame base, in the frame object. */
- if (next_frame->level >= 0
- && frame_id_inner (prev_frame->id, get_frame_id (next_frame)))
- error ("Unwound frame inner-to selected frame (corrupt stack?)");
- /* Note that, due to frameless functions, the stronger test of
- the new frame being outer to the old frame can't be used -
- frameless functions differ by only their PC value. */
- break;
- default:
- internal_error (__FILE__, __LINE__, "bad switch");
+ fprintf_unfiltered (gdb_stdlog, "");
+ fprintf_unfiltered (gdb_stdlog, ") -> // %s}\n", reason);
}
+}
- /* FIXME: cagney/2002-12-18: Instead of this hack, should only store
- the frame ID in PREV_FRAME. Unfortunatly, some architectures
- (HP/UX) still reply on EXTRA_FRAME_INFO and, hence, still poke at
- the "struct frame_info" object directly. */
- prev_frame->frame = prev_frame->id.base;
+/* Is this (non-sentinel) frame in the "main"() function? */
- /* Link it in. */
- next_frame->prev = prev_frame;
- prev_frame->next = next_frame;
-
- /* FIXME: cagney/2002-01-19: This call will go away. Instead of
- initializing extra info, all frames will use the frame_cache
- (passed to the unwind functions) to store additional frame info.
- Unfortunatly legacy targets can't use legacy_get_prev_frame() to
- unwind the sentinel frame and, consequently, are forced to take
- this code path and rely on the below call to
- DEPRECATED_INIT_EXTRA_FRAME_INFO to initialize the inner-most
+static int
+inside_main_func (struct frame_info *this_frame)
+{
+ struct minimal_symbol *msymbol;
+ CORE_ADDR maddr;
+
+ if (symfile_objfile == 0)
+ return 0;
+ msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile);
+ if (msymbol == NULL)
+ return 0;
+ /* Make certain that the code, and not descriptor, address is
+ returned. */
+ maddr = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame),
+ SYMBOL_VALUE_ADDRESS (msymbol),
+ ¤t_target);
+ return maddr == get_frame_func (this_frame);
+}
+
+/* Test whether THIS_FRAME is inside the process entry point function. */
+
+static int
+inside_entry_func (struct frame_info *this_frame)
+{
+ return (get_frame_func (this_frame) == entry_point_address ());
+}
+
+/* Return a structure containing various interesting information about
+ the frame that called THIS_FRAME. Returns NULL if there is entier
+ no such frame or the frame fails any of a set of target-independent
+ condition that should terminate the frame chain (e.g., as unwinding
+ past main()).
+
+ This function should not contain target-dependent tests, such as
+ checking whether the program-counter is zero. */
+
+struct frame_info *
+get_prev_frame (struct frame_info *this_frame)
+{
+ struct frame_info *prev_frame;
+
+ /* There is always a frame. If this assertion fails, suspect that
+ something should be calling get_selected_frame() or
+ get_current_frame(). */
+ gdb_assert (this_frame != NULL);
+
+ /* tausq/2004-12-07: Dummy frames are skipped because it doesn't make much
+ sense to stop unwinding at a dummy frame. One place where a dummy
+ frame may have an address "inside_main_func" is on HPUX. On HPUX, the
+ pcsqh register (space register for the instruction at the head of the
+ instruction queue) cannot be written directly; the only way to set it
+ is to branch to code that is in the target space. In order to implement
+ frame dummies on HPUX, the called function is made to jump back to where
+ the inferior was when the user function was called. If gdb was inside
+ the main function when we created the dummy frame, the dummy frame will
+ point inside the main function. */
+ if (this_frame->level >= 0
+ && get_frame_type (this_frame) != DUMMY_FRAME
+ && !backtrace_past_main
+ && inside_main_func (this_frame))
+ /* Don't unwind past main(). Note, this is done _before_ the
+ frame has been marked as previously unwound. That way if the
+ user later decides to enable unwinds past main(), that will
+ automatically happen. */
+ {
+ frame_debug_got_null_frame (this_frame, "inside main func");
+ return NULL;
+ }
+
+ /* If the user's backtrace limit has been exceeded, stop. We must
+ add two to the current level; one of those accounts for backtrace_limit
+ being 1-based and the level being 0-based, and the other accounts for
+ the level of the new frame instead of the level of the current
frame. */
- if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
+ if (this_frame->level + 2 > backtrace_limit)
{
- gdb_assert (prev_frame->level == 0);
- DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev_frame);
+ frame_debug_got_null_frame (this_frame, "backtrace limit exceeded");
+ return NULL;
}
- return prev_frame;
+ /* If we're already inside the entry function for the main objfile,
+ then it isn't valid. Don't apply this test to a dummy frame -
+ dummy frame PCs typically land in the entry func. Don't apply
+ this test to the sentinel frame. Sentinel frames should always
+ be allowed to unwind. */
+ /* NOTE: cagney/2003-07-07: Fixed a bug in inside_main_func() -
+ wasn't checking for "main" in the minimal symbols. With that
+ fixed asm-source tests now stop in "main" instead of halting the
+ backtrace in weird and wonderful ways somewhere inside the entry
+ file. Suspect that tests for inside the entry file/func were
+ added to work around that (now fixed) case. */
+ /* NOTE: cagney/2003-07-15: danielj (if I'm reading it right)
+ suggested having the inside_entry_func test use the
+ inside_main_func() msymbol trick (along with entry_point_address()
+ I guess) to determine the address range of the start function.
+ That should provide a far better stopper than the current
+ heuristics. */
+ /* NOTE: tausq/2004-10-09: this is needed if, for example, the compiler
+ applied tail-call optimizations to main so that a function called
+ from main returns directly to the caller of main. Since we don't
+ stop at main, we should at least stop at the entry point of the
+ application. */
+ if (!backtrace_past_entry
+ && get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0
+ && inside_entry_func (this_frame))
+ {
+ frame_debug_got_null_frame (this_frame, "inside entry func");
+ return NULL;
+ }
+
+ /* Assume that the only way to get a zero PC is through something
+ like a SIGSEGV or a dummy frame, and hence that NORMAL frames
+ will never unwind a zero PC. */
+ if (this_frame->level > 0
+ && get_frame_type (this_frame) == NORMAL_FRAME
+ && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
+ && get_frame_pc (this_frame) == 0)
+ {
+ frame_debug_got_null_frame (this_frame, "zero PC");
+ return NULL;
+ }
+
+ return get_prev_frame_1 (this_frame);
}
CORE_ADDR
get_frame_pc (struct frame_info *frame)
{
- return frame->pc;
+ gdb_assert (frame->next != NULL);
+ return frame_pc_unwind (frame->next);
+}
+
+/* Return an address that falls within THIS_FRAME's code block. */
+
+CORE_ADDR
+get_frame_address_in_block (struct frame_info *this_frame)
+{
+ /* A draft address. */
+ CORE_ADDR pc = get_frame_pc (this_frame);
+
+ struct frame_info *next_frame = this_frame->next;
+
+ /* Calling get_frame_pc returns the resume address for THIS_FRAME.
+ Normally the resume address is inside the body of the function
+ associated with THIS_FRAME, but there is a special case: when
+ calling a function which the compiler knows will never return
+ (for instance abort), the call may be the very last instruction
+ in the calling function. The resume address will point after the
+ call and may be at the beginning of a different function
+ entirely.
+
+ If THIS_FRAME is a signal frame or dummy frame, then we should
+ not adjust the unwound PC. For a dummy frame, GDB pushed the
+ resume address manually onto the stack. For a signal frame, the
+ OS may have pushed the resume address manually and invoked the
+ handler (e.g. GNU/Linux), or invoked the trampoline which called
+ the signal handler - but in either case the signal handler is
+ expected to return to the trampoline. So in both of these
+ cases we know that the resume address is executable and
+ related. So we only need to adjust the PC if THIS_FRAME
+ is a normal function.
+
+ If the program has been interrupted while THIS_FRAME is current,
+ then clearly the resume address is inside the associated
+ function. There are three kinds of interruption: debugger stop
+ (next frame will be SENTINEL_FRAME), operating system
+ signal or exception (next frame will be SIGTRAMP_FRAME),
+ or debugger-induced function call (next frame will be
+ DUMMY_FRAME). So we only need to adjust the PC if
+ NEXT_FRAME is a normal function.
+
+ We check the type of NEXT_FRAME first, since it is already
+ known; frame type is determined by the unwinder, and since
+ we have THIS_FRAME we've already selected an unwinder for
+ NEXT_FRAME. */
+ if (get_frame_type (next_frame) == NORMAL_FRAME
+ && get_frame_type (this_frame) == NORMAL_FRAME)
+ return pc - 1;
+
+ return pc;
}
static int
@@ -1464,7 +1619,7 @@ pc_notcurrent (struct frame_info *frame)
void
find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
{
- (*sal) = find_pc_line (frame->pc, pc_notcurrent (frame));
+ (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
}
/* Per "frame.h", return the ``address'' of the frame. Code should
@@ -1472,7 +1627,55 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
CORE_ADDR
get_frame_base (struct frame_info *fi)
{
- return fi->frame;
+ return get_frame_id (fi).stack_addr;
+}
+
+/* High-level offsets into the frame. Used by the debug info. */
+
+CORE_ADDR
+get_frame_base_address (struct frame_info *fi)
+{
+ if (get_frame_type (fi) != NORMAL_FRAME)
+ return 0;
+ if (fi->base == NULL)
+ fi->base = frame_base_find_by_frame (fi);
+ /* Sneaky: If the low-level unwind and high-level base code share a
+ common unwinder, let them share the prologue cache. */
+ if (fi->base->unwind == fi->unwind)
+ return fi->base->this_base (fi, &fi->prologue_cache);
+ return fi->base->this_base (fi, &fi->base_cache);
+}
+
+CORE_ADDR
+get_frame_locals_address (struct frame_info *fi)
+{
+ void **cache;
+ if (get_frame_type (fi) != NORMAL_FRAME)
+ return 0;
+ /* If there isn't a frame address method, find it. */
+ if (fi->base == NULL)
+ fi->base = frame_base_find_by_frame (fi);
+ /* Sneaky: If the low-level unwind and high-level base code share a
+ common unwinder, let them share the prologue cache. */
+ if (fi->base->unwind == fi->unwind)
+ return fi->base->this_locals (fi, &fi->prologue_cache);
+ return fi->base->this_locals (fi, &fi->base_cache);
+}
+
+CORE_ADDR
+get_frame_args_address (struct frame_info *fi)
+{
+ void **cache;
+ if (get_frame_type (fi) != NORMAL_FRAME)
+ return 0;
+ /* If there isn't a frame address method, find it. */
+ if (fi->base == NULL)
+ fi->base = frame_base_find_by_frame (fi);
+ /* Sneaky: If the low-level unwind and high-level base code share a
+ common unwinder, let them share the prologue cache. */
+ if (fi->base->unwind == fi->unwind)
+ return fi->base->this_args (fi, &fi->prologue_cache);
+ return fi->base->this_args (fi, &fi->base_cache);
}
/* Level of the selected frame: 0 for innermost, 1 for its caller, ...
@@ -1490,148 +1693,178 @@ frame_relative_level (struct frame_info *fi)
enum frame_type
get_frame_type (struct frame_info *frame)
{
- /* Some targets still don't use [generic] dummy frames. Catch them
- here. */
- if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES
- && deprecated_frame_in_dummy (frame))
- return DUMMY_FRAME;
- return frame->type;
+ if (frame->unwind == NULL)
+ /* Initialize the frame's unwinder because that's what
+ provides the frame's type. */
+ frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
+ return frame->unwind->type;
}
-void
-deprecated_set_frame_type (struct frame_info *frame, enum frame_type type)
-{
- /* Arrrg! See comment in "frame.h". */
- frame->type = type;
-}
-
-#ifdef FRAME_FIND_SAVED_REGS
-/* XXX - deprecated. This is a compatibility function for targets
- that do not yet implement DEPRECATED_FRAME_INIT_SAVED_REGS. */
-/* Find the addresses in which registers are saved in FRAME. */
+/* Memory access methods. */
void
-deprecated_get_frame_saved_regs (struct frame_info *frame,
- struct frame_saved_regs *saved_regs_addr)
+get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr,
+ gdb_byte *buf, int len)
{
- if (frame->saved_regs == NULL)
- {
- frame->saved_regs = (CORE_ADDR *)
- frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
- }
- if (saved_regs_addr == NULL)
- {
- struct frame_saved_regs saved_regs;
- FRAME_FIND_SAVED_REGS (frame, saved_regs);
- memcpy (frame->saved_regs, &saved_regs, SIZEOF_FRAME_SAVED_REGS);
- }
- else
- {
- FRAME_FIND_SAVED_REGS (frame, *saved_regs_addr);
- memcpy (frame->saved_regs, saved_regs_addr, SIZEOF_FRAME_SAVED_REGS);
- }
+ read_memory (addr, buf, len);
}
-#endif
-struct frame_extra_info *
-get_frame_extra_info (struct frame_info *fi)
+LONGEST
+get_frame_memory_signed (struct frame_info *this_frame, CORE_ADDR addr,
+ int len)
{
- return fi->extra_info;
+ return read_memory_integer (addr, len);
}
-struct frame_extra_info *
-frame_extra_info_zalloc (struct frame_info *fi, long size)
+ULONGEST
+get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr,
+ int len)
{
- fi->extra_info = frame_obstack_zalloc (size);
- return fi->extra_info;
+ return read_memory_unsigned_integer (addr, len);
}
-void
-deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
+int
+safe_frame_unwind_memory (struct frame_info *this_frame,
+ CORE_ADDR addr, gdb_byte *buf, int len)
{
- /* See comment in "frame.h". */
- frame->pc = pc;
- /* While we're at it, update this frame's cached PC value, found in
- the next frame. Oh, for the day when "struct frame_info" is
- opaque and this hack on hack can go. */
- gdb_assert (frame->next != NULL);
- frame->next->pc_unwind_cache = pc;
- frame->next->pc_unwind_cache_p = 1;
+ /* NOTE: target_read_memory returns zero on success! */
+ return !target_read_memory (addr, buf, len);
}
-void
-deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base)
-{
- /* See comment in "frame.h". */
- frame->frame = base;
-}
+/* Architecture method. */
-void
-deprecated_set_frame_saved_regs_hack (struct frame_info *frame,
- CORE_ADDR *saved_regs)
+struct gdbarch *
+get_frame_arch (struct frame_info *this_frame)
{
- frame->saved_regs = saved_regs;
+ /* In the future, this function will return a per-frame
+ architecture instead of current_gdbarch. Calling the
+ routine with a NULL value of this_frame is a bug! */
+ gdb_assert (this_frame);
+
+ return current_gdbarch;
}
-void
-deprecated_set_frame_extra_info_hack (struct frame_info *frame,
- struct frame_extra_info *extra_info)
+/* Stack pointer methods. */
+
+CORE_ADDR
+get_frame_sp (struct frame_info *this_frame)
{
- frame->extra_info = extra_info;
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ /* Normality - an architecture that provides a way of obtaining any
+ frame inner-most address. */
+ if (gdbarch_unwind_sp_p (gdbarch))
+ /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to
+ operate on THIS_FRAME now. */
+ return gdbarch_unwind_sp (gdbarch, this_frame->next);
+ /* Now things are really are grim. Hope that the value returned by
+ the gdbarch_sp_regnum register is meaningful. */
+ if (gdbarch_sp_regnum (gdbarch) >= 0)
+ return get_frame_register_unsigned (this_frame,
+ gdbarch_sp_regnum (gdbarch));
+ internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
}
-void
-deprecated_set_frame_next_hack (struct frame_info *fi,
- struct frame_info *next)
+/* Return the reason why we can't unwind past FRAME. */
+
+enum unwind_stop_reason
+get_frame_unwind_stop_reason (struct frame_info *frame)
{
- fi->next = next;
+ /* If we haven't tried to unwind past this point yet, then assume
+ that unwinding would succeed. */
+ if (frame->prev_p == 0)
+ return UNWIND_NO_REASON;
+
+ /* Otherwise, we set a reason when we succeeded (or failed) to
+ unwind. */
+ return frame->stop_reason;
}
-void
-deprecated_set_frame_prev_hack (struct frame_info *fi,
- struct frame_info *prev)
+/* Return a string explaining REASON. */
+
+const char *
+frame_stop_reason_string (enum unwind_stop_reason reason)
{
- fi->prev = prev;
+ switch (reason)
+ {
+ case UNWIND_NULL_ID:
+ return _("unwinder did not report frame ID");
+
+ case UNWIND_INNER_ID:
+ return _("previous frame inner to this frame (corrupt stack?)");
+
+ case UNWIND_SAME_ID:
+ return _("previous frame identical to this frame (corrupt stack?)");
+
+ case UNWIND_NO_SAVED_PC:
+ return _("frame did not save the PC");
+
+ case UNWIND_NO_REASON:
+ case UNWIND_FIRST_ERROR:
+ default:
+ internal_error (__FILE__, __LINE__,
+ "Invalid frame stop reason");
+ }
}
-struct context *
-deprecated_get_frame_context (struct frame_info *fi)
+/* Clean up after a failed (wrong unwinder) attempt to unwind past
+ FRAME. */
+
+static void
+frame_cleanup_after_sniffer (void *arg)
{
- return fi->context;
+ struct frame_info *frame = arg;
+
+ /* The sniffer should not allocate a prologue cache if it did not
+ match this frame. */
+ gdb_assert (frame->prologue_cache == NULL);
+
+ /* No sniffer should extend the frame chain; sniff based on what is
+ already certain. */
+ gdb_assert (!frame->prev_p);
+
+ /* The sniffer should not check the frame's ID; that's circular. */
+ gdb_assert (!frame->this_id.p);
+
+ /* Clear cached fields dependent on the unwinder.
+
+ The previous PC is independent of the unwinder, but the previous
+ function is not (see get_frame_address_in_block). */
+ frame->prev_func.p = 0;
+ frame->prev_func.addr = 0;
+
+ /* Discard the unwinder last, so that we can easily find it if an assertion
+ in this function triggers. */
+ frame->unwind = NULL;
}
-void
-deprecated_set_frame_context (struct frame_info *fi,
- struct context *context)
+/* Set FRAME's unwinder temporarily, so that we can call a sniffer.
+ Return a cleanup which should be called if unwinding fails, and
+ discarded if it succeeds. */
+
+struct cleanup *
+frame_prepare_for_sniffer (struct frame_info *frame,
+ const struct frame_unwind *unwind)
{
- fi->context = context;
+ gdb_assert (frame->unwind == NULL);
+ frame->unwind = unwind;
+ return make_cleanup (frame_cleanup_after_sniffer, frame);
}
-struct frame_info *
-deprecated_frame_xmalloc (void)
+extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
+
+static struct cmd_list_element *set_backtrace_cmdlist;
+static struct cmd_list_element *show_backtrace_cmdlist;
+
+static void
+set_backtrace_cmd (char *args, int from_tty)
{
- struct frame_info *frame = XMALLOC (struct frame_info);
- memset (frame, 0, sizeof (struct frame_info));
- return frame;
+ help_list (set_backtrace_cmdlist, "set backtrace ", -1, gdb_stdout);
}
-struct frame_info *
-deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs,
- long sizeof_extra_info)
+static void
+show_backtrace_cmd (char *args, int from_tty)
{
- struct frame_info *frame = deprecated_frame_xmalloc ();
- make_cleanup (xfree, frame);
- if (sizeof_saved_regs > 0)
- {
- frame->saved_regs = xcalloc (1, sizeof_saved_regs);
- make_cleanup (xfree, frame->saved_regs);
- }
- if (sizeof_extra_info > 0)
- {
- frame->extra_info = xcalloc (1, sizeof_extra_info);
- make_cleanup (xfree, frame->extra_info);
- }
- return frame;
+ cmd_show_list (show_backtrace_cmdlist, from_tty, "");
}
void
@@ -1639,27 +1872,62 @@ _initialize_frame (void)
{
obstack_init (&frame_cache_obstack);
- /* FIXME: cagney/2003-01-19: This command needs a rename. Suggest
- `set backtrace {past,beyond,...}-main'. Also suggest adding `set
- backtrace ...-start' to control backtraces past start. The
- problem with `below' is that it stops the `up' command. */
-
- add_setshow_boolean_cmd ("backtrace-below-main", class_obscure,
- &backtrace_below_main, "\
-Set whether backtraces should continue past \"main\".\n\
-Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
-the backtrace at \"main\". Set this variable if you need to see the rest\n\
-of the stack trace.", "\
-Show whether backtraces should continue past \"main\".\n\
+ observer_attach_target_changed (frame_observer_target_changed);
+
+ add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
+Set backtrace specific variables.\n\
+Configure backtrace variables such as the backtrace limit"),
+ &set_backtrace_cmdlist, "set backtrace ",
+ 0/*allow-unknown*/, &setlist);
+ add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, _("\
+Show backtrace specific variables\n\
+Show backtrace variables such as the backtrace limit"),
+ &show_backtrace_cmdlist, "show backtrace ",
+ 0/*allow-unknown*/, &showlist);
+
+ add_setshow_boolean_cmd ("past-main", class_obscure,
+ &backtrace_past_main, _("\
+Set whether backtraces should continue past \"main\"."), _("\
+Show whether backtraces should continue past \"main\"."), _("\
Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
the backtrace at \"main\". Set this variable if you need to see the rest\n\
-of the stack trace.",
- NULL, NULL, &setlist, &showlist);
-
+of the stack trace."),
+ NULL,
+ show_backtrace_past_main,
+ &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
+
+ add_setshow_boolean_cmd ("past-entry", class_obscure,
+ &backtrace_past_entry, _("\
+Set whether backtraces should continue past the entry point of a program."),
+ _("\
+Show whether backtraces should continue past the entry point of a program."),
+ _("\
+Normally there are no callers beyond the entry point of a program, so GDB\n\
+will terminate the backtrace there. Set this variable if you need to see \n\
+the rest of the stack trace."),
+ NULL,
+ show_backtrace_past_entry,
+ &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
+
+ add_setshow_integer_cmd ("limit", class_obscure,
+ &backtrace_limit, _("\
+Set an upper bound on the number of backtrace levels."), _("\
+Show the upper bound on the number of backtrace levels."), _("\
+No more than the specified number of frames can be displayed or examined.\n\
+Zero is unlimited."),
+ NULL,
+ show_backtrace_limit,
+ &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
/* Debug this files internals. */
- add_show_from_set (add_set_cmd ("frame", class_maintenance, var_zinteger,
- &frame_debug, "Set frame debugging.\n\
-When non-zero, frame specific internal debugging is enabled.", &setdebuglist),
- &showdebuglist);
+ add_setshow_zinteger_cmd ("frame", class_maintenance, &frame_debug, _("\
+Set frame debugging."), _("\
+Show frame debugging."), _("\
+When non-zero, frame specific internal debugging is enabled."),
+ NULL,
+ show_frame_debug,
+ &setdebuglist, &showdebuglist);
}