/* Cache and manage frames for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001,
- 2002, 2003, 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1986-2015 Free Software Foundation, Inc.
This file is part of GDB.
#include "value.h"
#include "inferior.h" /* for inferior_ptid */
#include "regcache.h"
-#include "gdb_assert.h"
-#include "gdb_string.h"
#include "user-regs.h"
#include "gdb_obstack.h"
#include "dummy-frame.h"
#include "gdbcmd.h"
#include "observer.h"
#include "objfiles.h"
-#include "exceptions.h"
#include "gdbthread.h"
+#include "block.h"
+#include "inline-frame.h"
+#include "tracepoint.h"
+#include "hashtab.h"
+#include "valprint.h"
-static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
+static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame);
+static const char *frame_stop_reason_symbol_string (enum unwind_stop_reason reason);
+
+/* Status of some values cached in the frame_info object. */
+
+enum cached_copy_status
+{
+ /* Value is unknown. */
+ CC_UNKNOWN,
+
+ /* We have a value. */
+ CC_VALUE,
+
+ /* Value was not saved. */
+ CC_NOT_SAVED,
+
+ /* Value is unavailable. */
+ CC_UNAVAILABLE
+};
/* We keep a cache of stack frames, each of which is a "struct
frame_info". The innermost one gets allocated (in
moment leave this as speculation. */
int level;
+ /* The frame's program space. */
+ struct program_space *pspace;
+
+ /* The frame's address space. */
+ struct address_space *aspace;
+
/* 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
void *prologue_cache;
const struct frame_unwind *unwind;
+ /* Cached copy of the previous frame's architecture. */
+ struct
+ {
+ int p;
+ struct gdbarch *arch;
+ } prev_arch;
+
/* Cached copy of the previous frame's resume address. */
struct {
- int p;
+ enum cached_copy_status status;
CORE_ADDR value;
} prev_pc;
/* 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;
+
+ /* A frame specific string describing the STOP_REASON in more detail.
+ Only valid when PREV_P is set, but even then may still be NULL. */
+ const char *stop_string;
};
+/* A frame stash used to speed up frame lookups. Create a hash table
+ to stash frames previously accessed from the frame cache for
+ quicker subsequent retrieval. The hash table is emptied whenever
+ the frame cache is invalidated. */
+
+static htab_t frame_stash;
+
+/* Internal function to calculate a hash from the frame_id addresses,
+ using as many valid addresses as possible. Frames below level 0
+ are not stored in the hash table. */
+
+static hashval_t
+frame_addr_hash (const void *ap)
+{
+ const struct frame_info *frame = (const struct frame_info *) ap;
+ const struct frame_id f_id = frame->this_id.value;
+ hashval_t hash = 0;
+
+ gdb_assert (f_id.stack_status != FID_STACK_INVALID
+ || f_id.code_addr_p
+ || f_id.special_addr_p);
+
+ if (f_id.stack_status == FID_STACK_VALID)
+ hash = iterative_hash (&f_id.stack_addr,
+ sizeof (f_id.stack_addr), hash);
+ if (f_id.code_addr_p)
+ hash = iterative_hash (&f_id.code_addr,
+ sizeof (f_id.code_addr), hash);
+ if (f_id.special_addr_p)
+ hash = iterative_hash (&f_id.special_addr,
+ sizeof (f_id.special_addr), hash);
+
+ return hash;
+}
+
+/* Internal equality function for the hash table. This function
+ defers equality operations to frame_id_eq. */
+
+static int
+frame_addr_hash_eq (const void *a, const void *b)
+{
+ const struct frame_info *f_entry = (const struct frame_info *) a;
+ const struct frame_info *f_element = (const struct frame_info *) b;
+
+ return frame_id_eq (f_entry->this_id.value,
+ f_element->this_id.value);
+}
+
+/* Internal function to create the frame_stash hash table. 100 seems
+ to be a good compromise to start the hash table at. */
+
+static void
+frame_stash_create (void)
+{
+ frame_stash = htab_create (100,
+ frame_addr_hash,
+ frame_addr_hash_eq,
+ NULL);
+}
+
+/* Internal function to add a frame to the frame_stash hash table.
+ Returns false if a frame with the same ID was already stashed, true
+ otherwise. */
+
+static int
+frame_stash_add (struct frame_info *frame)
+{
+ struct frame_info **slot;
+
+ /* Do not try to stash the sentinel frame. */
+ gdb_assert (frame->level >= 0);
+
+ slot = (struct frame_info **) htab_find_slot (frame_stash,
+ frame,
+ INSERT);
+
+ /* If we already have a frame in the stack with the same id, we
+ either have a stack cycle (corrupted stack?), or some bug
+ elsewhere in GDB. In any case, ignore the duplicate and return
+ an indication to the caller. */
+ if (*slot != NULL)
+ return 0;
+
+ *slot = frame;
+ return 1;
+}
+
+/* Internal function to search the frame stash for an entry with the
+ given frame ID. If found, return that frame. Otherwise return
+ NULL. */
+
+static struct frame_info *
+frame_stash_find (struct frame_id id)
+{
+ struct frame_info dummy;
+ struct frame_info *frame;
+
+ dummy.this_id.value = id;
+ frame = (struct frame_info *) htab_find (frame_stash, &dummy);
+ return frame;
+}
+
+/* Internal function to invalidate the frame stash by removing all
+ entries in it. This only occurs when the frame cache is
+ invalidated. */
+
+static void
+frame_stash_invalidate (void)
+{
+ htab_empty (frame_stash);
+}
+
/* Flag to control debugging. */
-int frame_debug;
+unsigned int frame_debug;
static void
show_frame_debug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
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"),
+ fprintf_filtered (file,
+ _("Whether backtraces should "
+ "continue past \"main\" is %s.\n"),
value);
}
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"),
+ 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 unsigned int backtrace_limit = UINT_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"),
+ fprintf_filtered (file,
+ _("An upper bound on the number "
+ "of backtrace levels is %s.\n"),
value);
}
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));
+ fprintf_unfiltered (file, "%s=%s", name, hex_string (addr));
else
fprintf_unfiltered (file, "!%s", name);
}
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);
+
+ if (id.stack_status == FID_STACK_INVALID)
+ fprintf_unfiltered (file, "!stack");
+ else if (id.stack_status == FID_STACK_UNAVAILABLE)
+ fprintf_unfiltered (file, "stack=<unavailable>");
+ else
+ fprintf_unfiltered (file, "stack=%s", hex_string (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);
+
+ if (id.artificial_depth)
+ fprintf_unfiltered (file, ",artificial=%d", id.artificial_depth);
+
fprintf_unfiltered (file, "}");
}
case DUMMY_FRAME:
fprintf_unfiltered (file, "DUMMY_FRAME");
return;
+ case INLINE_FRAME:
+ fprintf_unfiltered (file, "INLINE_FRAME");
+ return;
+ case TAILCALL_FRAME:
+ fprintf_unfiltered (file, "TAILCALL_FRAME");
+ return;
case SIGTRAMP_FRAME:
fprintf_unfiltered (file, "SIGTRAMP_FRAME");
return;
+ case ARCH_FRAME:
+ fprintf_unfiltered (file, "ARCH_FRAME");
+ return;
+ case SENTINEL_FRAME:
+ fprintf_unfiltered (file, "SENTINEL_FRAME");
+ return;
default:
fprintf_unfiltered (file, "<unknown type>");
return;
fprintf_unfiltered (file, "<unknown>");
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
+ if (fi->next == NULL || fi->next->prev_pc.status == CC_UNKNOWN)
fprintf_unfiltered (file, "<unknown>");
+ else if (fi->next->prev_pc.status == CC_VALUE)
+ fprintf_unfiltered (file, "%s",
+ hex_string (fi->next->prev_pc.value));
+ else if (fi->next->prev_pc.status == CC_NOT_SAVED)
+ val_print_not_saved (file);
+ else if (fi->next->prev_pc.status == CC_UNAVAILABLE)
+ val_print_unavailable (file);
fprintf_unfiltered (file, ",");
fprintf_unfiltered (file, "id=");
if (fi->this_id.p)
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));
+ fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_func.addr));
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, "}");
}
+/* Given FRAME, return the enclosing frame as found in real frames read-in from
+ inferior memory. Skip any previous frames which were made up by GDB.
+ Return the original frame if no immediate previous frames exist. */
+
+static struct frame_info *
+skip_artificial_frames (struct frame_info *frame)
+{
+ /* Note we use get_prev_frame_always, 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 the user
+ sets a backtrace limit). This is safe, because as these frames
+ are made up by GDB, there must be a real frame in the chain
+ below. */
+ while (get_frame_type (frame) == INLINE_FRAME
+ || get_frame_type (frame) == TAILCALL_FRAME)
+ frame = get_prev_frame_always (frame);
+
+ return frame;
+}
+
+/* Compute the frame's uniq ID that can be used to, later, re-find the
+ frame. */
+
+static void
+compute_frame_id (struct frame_info *fi)
+{
+ gdb_assert (!fi->this_id.p);
+
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ compute_frame_id (fi=%d) ",
+ fi->level);
+ /* Find the unwinder. */
+ if (fi->unwind == NULL)
+ frame_unwind_find_by_frame (fi, &fi->prologue_cache);
+ /* Find THIS frame's ID. */
+ /* Default to outermost if no ID is found. */
+ fi->this_id.value = outer_frame_id;
+ fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
+ gdb_assert (frame_id_p (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 a frame uniq ID that can be used to, later, re-find the
frame. */
get_frame_id (struct frame_info *fi)
{
if (fi == NULL)
- {
- return null_frame_id;
- }
- if (!fi->this_id.p)
- {
- 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 null_frame_id;
+
+ gdb_assert (fi->this_id.p);
return fi->this_id.value;
}
struct frame_id
-frame_unwind_id (struct frame_info *next_frame)
+get_stack_frame_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));
+ return get_frame_id (skip_artificial_frames (next_frame));
+}
+
+struct frame_id
+frame_unwind_caller_id (struct frame_info *next_frame)
+{
+ struct frame_info *this_frame;
+
+ /* Use get_prev_frame_always, 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. */
+
+ next_frame = skip_artificial_frames (next_frame);
+ this_frame = get_prev_frame_always (next_frame);
+ if (this_frame)
+ return get_frame_id (skip_artificial_frames (this_frame));
+ else
+ return null_frame_id;
}
-const struct frame_id null_frame_id; /* All zeros. */
+const struct frame_id null_frame_id = { 0 }; /* All zeros. */
+const struct frame_id outer_frame_id = { 0, 0, 0, FID_STACK_INVALID, 0, 1, 0 };
struct frame_id
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.stack_status = FID_STACK_VALID;
+ id.code_addr = code_addr;
+ id.code_addr_p = 1;
+ id.special_addr = special_addr;
+ id.special_addr_p = 1;
+ return id;
+}
+
+/* See frame.h. */
+
+struct frame_id
+frame_id_build_unavailable_stack (CORE_ADDR code_addr)
+{
+ struct frame_id id = null_frame_id;
+
+ id.stack_status = FID_STACK_UNAVAILABLE;
+ id.code_addr = code_addr;
+ id.code_addr_p = 1;
+ return id;
+}
+
+/* See frame.h. */
+
+struct frame_id
+frame_id_build_unavailable_stack_special (CORE_ADDR code_addr,
+ CORE_ADDR special_addr)
+{
+ struct frame_id id = null_frame_id;
+
+ id.stack_status = FID_STACK_UNAVAILABLE;
id.code_addr = code_addr;
id.code_addr_p = 1;
id.special_addr = special_addr;
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.stack_status = FID_STACK_VALID;
id.code_addr = code_addr;
id.code_addr_p = 1;
return id;
frame_id_build_wild (CORE_ADDR stack_addr)
{
struct frame_id id = null_frame_id;
+
id.stack_addr = stack_addr;
- id.stack_addr_p = 1;
+ id.stack_status = FID_STACK_VALID;
return id;
}
frame_id_p (struct frame_id l)
{
int p;
+
/* The frame is valid iff it has a valid stack address. */
- p = l.stack_addr_p;
+ p = l.stack_status != FID_STACK_INVALID;
+ /* outer_frame_id is also valid. */
+ if (!p && memcmp (&l, &outer_frame_id, sizeof (l)) == 0)
+ p = 1;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
return p;
}
+int
+frame_id_artificial_p (struct frame_id l)
+{
+ if (!frame_id_p (l))
+ return 0;
+
+ return (l.artificial_depth != 0);
+}
+
int
frame_id_eq (struct frame_id l, struct frame_id r)
{
int eq;
- if (!l.stack_addr_p || !r.stack_addr_p)
+
+ if (l.stack_status == FID_STACK_INVALID && l.special_addr_p
+ && r.stack_status == FID_STACK_INVALID && r.special_addr_p)
+ /* The outermost frame marker is equal to itself. This is the
+ dodgy thing about outer_frame_id, since between execution steps
+ we might step into another function - from which we can't
+ unwind either. More thought required to get rid of
+ outer_frame_id. */
+ eq = 1;
+ else if (l.stack_status == FID_STACK_INVALID
+ || r.stack_status == FID_STACK_INVALID)
/* 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)
+ else if (l.stack_status != r.stack_status || 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. */
+ else if (l.code_addr_p && r.code_addr_p && l.code_addr != r.code_addr)
+ /* An invalid code addr is a wild card. 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)
+ else if (l.special_addr_p && r.special_addr_p
+ && l.special_addr != r.special_addr)
+ /* An invalid special addr is a wild card (or unused). Otherwise
+ if special addresses are different, the frames are different. */
+ eq = 0;
+ else if (l.artificial_depth != r.artificial_depth)
+ /* If artifical depths are different, the frames must be different. */
+ eq = 0;
+ else
/* Frames are equal. */
eq = 1;
- else
- /* No luck. */
- eq = 0;
+
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l=");
to sigaltstack).
However, it can be used as safety net to discover invalid frame
- IDs in certain circumstances. Assuming that NEXT is the immediate
+ IDs in certain circumstances. Assuming that NEXT is the immediate
inner frame to THIS and that NEXT and THIS are both NORMAL frames:
* The stack address of NEXT must be inner-than-or-equal to the stack
is involved, because signal handlers might be executed on a different
stack than the stack used by the routine that caused the signal
to be raised. This can happen for instance when a thread exceeds
- its maximum stack size. In this case, certain compilers implement
+ its maximum stack size. In this case, certain compilers implement
a stack overflow strategy that cause the handler to be run on a
different stack. */
frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
{
int inner;
- if (!l.stack_addr_p || !r.stack_addr_p)
- /* Like NaN, any operation involving an invalid ID always fails. */
+
+ if (l.stack_status != FID_STACK_VALID || r.stack_status != FID_STACK_VALID)
+ /* Like NaN, any operation involving an invalid ID always fails.
+ Likewise if either ID has an unavailable stack address. */
inner = 0;
+ else if (l.artificial_depth > r.artificial_depth
+ && l.stack_addr == r.stack_addr
+ && l.code_addr_p == r.code_addr_p
+ && l.special_addr_p == r.special_addr_p
+ && l.special_addr == r.special_addr)
+ {
+ /* Same function, different inlined functions. */
+ const struct block *lb, *rb;
+
+ gdb_assert (l.code_addr_p && r.code_addr_p);
+
+ lb = block_for_pc (l.code_addr);
+ rb = block_for_pc (r.code_addr);
+
+ if (lb == NULL || rb == NULL)
+ /* Something's gone wrong. */
+ inner = 0;
+ else
+ /* This will return true if LB and RB are the same block, or
+ if the block with the smaller depth lexically encloses the
+ block with the greater depth. */
+ inner = contained_in (lb, rb);
+ }
else
/* Only return non-zero when strictly inner than. Note that, per
comment in "frame.h", there is some fuzz here. Frameless
if (!frame_id_p (id))
return NULL;
+ /* Try using the frame stash first. Finding it there removes the need
+ to perform the search by looping over all frames, which can be very
+ CPU-intensive if the number of frames is very high (the loop is O(n)
+ and get_prev_frame performs a series of checks that are relatively
+ expensive). This optimization is particularly useful when this function
+ is called from another function (such as value_fetch_lazy, case
+ VALUE_LVAL (val) == lval_register) which already loops over all frames,
+ making the overall behavior O(n^2). */
+ frame = frame_stash_find (id);
+ if (frame)
+ return frame;
+
for (frame = get_current_frame (); ; frame = prev_frame)
{
- struct frame_id this = get_frame_id (frame);
- if (frame_id_eq (id, this))
+ struct frame_id self = get_frame_id (frame);
+
+ if (frame_id_eq (id, self))
/* An exact match. */
return frame;
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 (frame), id, self)
&& frame_id_inner (get_frame_arch (prev_frame), id,
get_frame_id (prev_frame)))
return NULL;
return NULL;
}
-CORE_ADDR
-frame_pc_unwind (struct frame_info *this_frame)
+static CORE_ADDR
+frame_unwind_pc (struct frame_info *this_frame)
{
- if (!this_frame->prev_pc.p)
+ if (this_frame->prev_pc.status == CC_UNKNOWN)
{
- CORE_ADDR pc;
- if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
+ if (gdbarch_unwind_pc_p (frame_unwind_arch (this_frame)))
{
+ struct gdbarch *prev_gdbarch;
+ CORE_ADDR pc = 0;
+ int pc_p = 0;
+
/* 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
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);
+ prev_gdbarch = frame_unwind_arch (this_frame);
+
+ TRY
+ {
+ pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
+ pc_p = 1;
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error == NOT_AVAILABLE_ERROR)
+ {
+ this_frame->prev_pc.status = CC_UNAVAILABLE;
+
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_unwind_pc (this_frame=%d)"
+ " -> <unavailable> }\n",
+ this_frame->level);
+ }
+ else if (ex.error == OPTIMIZED_OUT_ERROR)
+ {
+ this_frame->prev_pc.status = CC_NOT_SAVED;
+
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_unwind_pc (this_frame=%d)"
+ " -> <not saved> }\n",
+ this_frame->level);
+ }
+ else
+ throw_exception (ex);
+ }
+ END_CATCH
+
+ if (pc_p)
+ {
+ this_frame->prev_pc.value = pc;
+ this_frame->prev_pc.status = CC_VALUE;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_unwind_pc (this_frame=%d) "
+ "-> %s }\n",
+ this_frame->level,
+ hex_string (this_frame->prev_pc.value));
+ }
}
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;
+
+ if (this_frame->prev_pc.status == CC_VALUE)
+ return this_frame->prev_pc.value;
+ else if (this_frame->prev_pc.status == CC_UNAVAILABLE)
+ throw_error (NOT_AVAILABLE_ERROR, _("PC not available"));
+ else if (this_frame->prev_pc.status == CC_NOT_SAVED)
+ throw_error (OPTIMIZED_OUT_ERROR, _("PC not saved"));
+ else
+ internal_error (__FILE__, __LINE__,
+ "unexpected prev_pc status: %d",
+ (int) this_frame->prev_pc.status);
}
CORE_ADDR
-get_frame_func (struct frame_info *this_frame)
+frame_unwind_caller_pc (struct frame_info *this_frame)
+{
+ return frame_unwind_pc (skip_artificial_frames (this_frame));
+}
+
+int
+get_frame_func_if_available (struct frame_info *this_frame, CORE_ADDR *pc)
{
struct frame_info *next_frame = this_frame->next;
if (!next_frame->prev_func.p)
{
+ CORE_ADDR addr_in_block;
+
/* 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));
+ if (!get_frame_address_in_block_if_available (this_frame, &addr_in_block))
+ {
+ next_frame->prev_func.p = -1;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ get_frame_func (this_frame=%d)"
+ " -> unavailable }\n",
+ this_frame->level);
+ }
+ else
+ {
+ 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) -> %s }\n",
+ this_frame->level,
+ hex_string (next_frame->prev_func.addr));
+ }
+ }
+
+ if (next_frame->prev_func.p < 0)
+ {
+ *pc = -1;
+ return 0;
+ }
+ else
+ {
+ *pc = next_frame->prev_func.addr;
+ return 1;
}
- return next_frame->prev_func.addr;
}
-static int
+CORE_ADDR
+get_frame_func (struct frame_info *this_frame)
+{
+ CORE_ADDR pc;
+
+ if (!get_frame_func_if_available (this_frame, &pc))
+ throw_error (NOT_AVAILABLE_ERROR, _("PC not available"));
+
+ return pc;
+}
+
+static enum register_status
do_frame_register_read (void *src, int regnum, gdb_byte *buf)
{
- return frame_register_read (src, regnum, buf);
+ if (!deprecated_frame_register_read ((struct frame_info *) src, regnum, buf))
+ return REG_UNAVAILABLE;
+ else
+ return REG_VALID;
}
struct regcache *
frame_save_as_regcache (struct frame_info *this_frame)
{
- struct regcache *regcache = regcache_xmalloc (get_frame_arch (this_frame));
+ struct address_space *aspace = get_frame_address_space (this_frame);
+ struct regcache *regcache = regcache_xmalloc (get_frame_arch (this_frame),
+ aspace);
struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
+
regcache_save (regcache, do_frame_register_read, this_frame);
discard_cleanups (cleanups);
return regcache;
{
/* 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));
+ dummy_frame_pop (get_frame_id (this_frame), inferior_ptid);
return;
}
/* Ensure that we have a frame to pop to. */
- prev_frame = get_prev_frame_1 (this_frame);
+ prev_frame = get_prev_frame_always (this_frame);
if (!prev_frame)
error (_("Cannot pop the initial frame."));
+ /* Ignore TAILCALL_FRAME type frames, they were executed already before
+ entering THISFRAME. */
+ while (get_frame_type (prev_frame) == TAILCALL_FRAME)
+ prev_frame = get_prev_frame (prev_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
void
frame_register_unwind (struct frame_info *frame, int regnum,
- int *optimizedp, enum lval_type *lvalp,
- CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
+ int *optimizedp, int *unavailablep,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, gdb_byte *bufferp)
{
struct value *value;
gdb_assert (value != NULL);
*optimizedp = value_optimized_out (value);
+ *unavailablep = !value_entirely_available (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)));
+ {
+ if (!*optimizedp && !*unavailablep)
+ memcpy (bufferp, value_contents_all (value),
+ TYPE_LENGTH (value_type (value)));
+ else
+ memset (bufferp, 0, TYPE_LENGTH (value_type (value)));
+ }
/* Dispose of the new value. This prevents watchpoints from
trying to watch the saved frame pointer. */
void
frame_register (struct frame_info *frame, int regnum,
- int *optimizedp, enum lval_type *lvalp,
+ int *optimizedp, int *unavailablep, enum lval_type *lvalp,
CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
{
/* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
/* Obtain the register value by unwinding the register from the next
(more inner frame). */
gdb_assert (frame != NULL && frame->next != NULL);
- frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
- realnump, bufferp);
+ frame_register_unwind (frame->next, regnum, optimizedp, unavailablep,
+ lvalp, addrp, realnump, bufferp);
}
void
frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf)
{
int optimized;
+ int unavailable;
CORE_ADDR addr;
int realnum;
enum lval_type lval;
- frame_register_unwind (frame, regnum, &optimized, &lval, &addr,
- &realnum, buf);
+
+ frame_register_unwind (frame, regnum, &optimized, &unavailable,
+ &lval, &addr, &realnum, buf);
+
+ if (optimized)
+ throw_error (OPTIMIZED_OUT_ERROR,
+ _("Register %d was not saved"), regnum);
+ if (unavailable)
+ throw_error (NOT_AVAILABLE_ERROR,
+ _("Register %d is not available"), regnum);
}
void
struct value *
frame_unwind_register_value (struct frame_info *frame, int regnum)
{
+ struct gdbarch *gdbarch;
struct value *value;
gdb_assert (frame != NULL);
+ gdbarch = frame_unwind_arch (frame);
if (frame_debug)
{
- fprintf_unfiltered (gdb_stdlog, "\
-{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
+ 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));
+ user_reg_map_regnum_to_name (gdbarch, regnum));
}
/* Find the unwinder. */
if (frame->unwind == NULL)
- frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
+ 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);
{
fprintf_unfiltered (gdb_stdlog, "->");
if (value_optimized_out (value))
- fprintf_unfiltered (gdb_stdlog, " optimized out");
+ {
+ fprintf_unfiltered (gdb_stdlog, " ");
+ val_print_optimized_out (value, gdb_stdlog);
+ }
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)));
+ fprintf_unfiltered (gdb_stdlog, " address=%s",
+ paddress (gdbarch,
+ value_address (value)));
else
fprintf_unfiltered (gdb_stdlog, " computed");
fprintf_unfiltered (gdb_stdlog, " bytes=");
fprintf_unfiltered (gdb_stdlog, "[");
- for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
+ for (i = 0; i < register_size (gdbarch, regnum); i++)
fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
fprintf_unfiltered (gdb_stdlog, "]");
}
LONGEST
frame_unwind_register_signed (struct frame_info *frame, int regnum)
{
+ struct gdbarch *gdbarch = frame_unwind_arch (frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int size = register_size (gdbarch, 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));
+ return extract_signed_integer (buf, size, byte_order);
}
LONGEST
ULONGEST
frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
{
+ struct gdbarch *gdbarch = frame_unwind_arch (frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int size = register_size (gdbarch, 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));
+ return extract_unsigned_integer (buf, size, byte_order);
}
ULONGEST
return frame_unwind_register_unsigned (frame->next, regnum);
}
+int
+read_frame_register_unsigned (struct frame_info *frame, int regnum,
+ ULONGEST *val)
+{
+ struct value *regval = get_frame_register_value (frame, regnum);
+
+ if (!value_optimized_out (regval)
+ && value_entirely_available (regval))
+ {
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int size = register_size (gdbarch, VALUE_REGNUM (regval));
+
+ *val = extract_unsigned_integer (value_contents (regval), size, byte_order);
+ return 1;
+ }
+
+ return 0;
+}
+
void
put_frame_register (struct frame_info *frame, int regnum,
const gdb_byte *buf)
struct gdbarch *gdbarch = get_frame_arch (frame);
int realnum;
int optim;
+ int unavail;
enum lval_type lval;
CORE_ADDR addr;
- frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
+
+ frame_register (frame, regnum, &optim, &unavail,
+ &lval, &addr, &realnum, NULL);
if (optim)
- error (_("Attempt to assign to a value that was optimized out."));
+ error (_("Attempt to assign to a register that was not saved."));
switch (lval)
{
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));
+ write_memory (addr, buf, register_size (gdbarch, regnum));
break;
}
case lval_register:
}
}
-/* frame_register_read ()
+/* This function is deprecated. Use get_frame_register_value instead,
+ which provides more accurate information.
Find and return the value of REGNUM for the specified stack frame.
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,
+deprecated_frame_register_read (struct frame_info *frame, int regnum,
gdb_byte *myaddr)
{
int optimized;
+ int unavailable;
enum lval_type lval;
CORE_ADDR addr;
int realnum;
- frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr);
- return !optimized;
+ frame_register (frame, regnum, &optimized, &unavailable,
+ &lval, &addr, &realnum, myaddr);
+
+ return !optimized && !unavailable;
}
int
get_frame_register_bytes (struct frame_info *frame, int regnum,
- CORE_ADDR offset, int len, gdb_byte *myaddr)
+ CORE_ADDR offset, int len, gdb_byte *myaddr,
+ int *optimizedp, int *unavailablep)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
int i;
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;
- }
+ error (_("Bad debug information detected: "
+ "Attempt to read %d bytes from registers."), len);
/* 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))
{
- if (!frame_register_read (frame, regnum, myaddr))
+ enum lval_type lval;
+ CORE_ADDR addr;
+ int realnum;
+
+ frame_register (frame, regnum, optimizedp, unavailablep,
+ &lval, &addr, &realnum, myaddr);
+ if (*optimizedp || *unavailablep)
return 0;
}
else
{
gdb_byte buf[MAX_REGISTER_SIZE];
- if (!frame_register_read (frame, regnum, buf))
+ enum lval_type lval;
+ CORE_ADDR addr;
+ int realnum;
+
+ frame_register (frame, regnum, optimizedp, unavailablep,
+ &lval, &addr, &realnum, buf);
+ if (*optimizedp || *unavailablep)
return 0;
memcpy (myaddr, buf + offset, curr_len);
}
regnum++;
}
+ *optimizedp = 0;
+ *unavailablep = 0;
return 1;
}
while (len > 0)
{
int curr_len = register_size (gdbarch, regnum) - offset;
+
if (curr_len > len)
curr_len = len;
else
{
gdb_byte buf[MAX_REGISTER_SIZE];
- frame_register_read (frame, regnum, buf);
+
+ deprecated_frame_register_read (frame, regnum, buf);
memcpy (buf + offset, myaddr, curr_len);
put_frame_register (frame, regnum, buf);
}
/* Create a sentinel frame. */
static struct frame_info *
-create_sentinel_frame (struct regcache *regcache)
+create_sentinel_frame (struct program_space *pspace, struct regcache *regcache)
{
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+
frame->level = -1;
+ frame->pspace = pspace;
+ frame->aspace = get_regcache_aspace (regcache);
/* 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->prologue_cache = sentinel_frame_cache (regcache);
/* For the moment there is only one sentinel frame implementation. */
- frame->unwind = sentinel_frame_unwind;
+ 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;
return frame;
}
-/* Info about the innermost stack frame (contents of FP register) */
+/* Info about the innermost stack frame (contents of FP register). */
static struct frame_info *current_frame;
frame_obstack_zalloc (unsigned long size)
{
void *data = obstack_alloc (&frame_cache_obstack, size);
+
memset (data, 0, size);
return data;
}
static int
unwind_to_current_frame (struct ui_out *ui_out, void *args)
{
- struct frame_info *frame = get_prev_frame (args);
+ struct frame_info *frame = get_prev_frame ((struct frame_info *) args);
+
/* A sentinel frame can fail to unwind, e.g., because its PC value
lands in somewhere like start. */
if (frame == NULL)
error (_("No stack."));
if (!target_has_memory)
error (_("No memory."));
- if (ptid_equal (inferior_ptid, null_ptid))
- error (_("No selected thread."));
- if (is_exited (inferior_ptid))
- error (_("Invalid selected thread."));
- if (is_executing (inferior_ptid))
- error (_("Target is executing."));
+ /* Traceframes are effectively a substitute for the live inferior. */
+ if (get_traceframe_number () < 0)
+ {
+ if (ptid_equal (inferior_ptid, null_ptid))
+ error (_("No selected thread."));
+ if (is_exited (inferior_ptid))
+ error (_("Invalid selected thread."));
+ if (is_executing (inferior_ptid))
+ error (_("Target is executing."));
+ }
if (current_frame == NULL)
{
struct frame_info *sentinel_frame =
- create_sentinel_frame (get_current_regcache ());
- if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
- RETURN_MASK_ERROR) != 0)
+ create_sentinel_frame (current_program_space, get_current_regcache ());
+ if (catch_exceptions (current_uiout, unwind_to_current_frame,
+ sentinel_frame, RETURN_MASK_ERROR) != 0)
{
/* Oops! Fake a current frame? Is this useful? It has a PC
of zero, for instance. */
if (!target_has_registers || !target_has_stack || !target_has_memory)
return 0;
- /* No current inferior, no frame. */
- if (ptid_equal (inferior_ptid, null_ptid))
- return 0;
+ /* Traceframes are effectively a substitute for the live inferior. */
+ if (get_traceframe_number () < 0)
+ {
+ /* No current inferior, no frame. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return 0;
- /* Don't try to read from a dead thread. */
- if (is_exited (inferior_ptid))
- return 0;
+ /* Don't try to read from a dead thread. */
+ if (is_exited (inferior_ptid))
+ return 0;
- /* ... or from a spinning thread. */
- if (is_executing (inferior_ptid))
- return 0;
+ /* ... or from a spinning thread. */
+ if (is_executing (inferior_ptid))
+ return 0;
+ }
return 1;
}
return selected_frame;
}
+/* If there is a selected frame, return it. Otherwise, return NULL. */
+
+struct frame_info *
+get_selected_frame_if_set (void)
+{
+ 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(). */
void
select_frame (struct frame_info *fi)
{
- struct symtab *s;
-
selected_frame = fi;
/* NOTE: cagney/2002-05-04: FI can be NULL. This occurs when the
frame is being invalidated. */
- 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
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 user's 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)
{
- /* 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
- && language_mode == language_mode_auto)
+ CORE_ADDR 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. */
+ if (get_frame_address_in_block_if_available (fi, &pc))
{
- set_language (s->language);
+ struct compunit_symtab *cust = find_pc_compunit_symtab (pc);
+
+ if (cust != NULL
+ && compunit_language (cust) != current_language->la_language
+ && compunit_language (cust) != language_unknown
+ && language_mode == language_mode_auto)
+ set_language (compunit_language (cust));
}
}
}
-
+
/* Create an arbitrary (i.e. address specified by user) or innermost frame.
Always returns a non-NULL value. */
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog,
- "{ create_new_frame (addr=0x%s, pc=0x%s) ",
- paddr_nz (addr), paddr_nz (pc));
+ "{ create_new_frame (addr=%s, pc=%s) ",
+ hex_string (addr), hex_string (pc));
}
fi = FRAME_OBSTACK_ZALLOC (struct frame_info);
- fi->next = create_sentinel_frame (get_current_regcache ());
+ fi->next = create_sentinel_frame (current_program_space,
+ get_current_regcache ());
/* 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;
+ fi->next->prev_pc.status = CC_VALUE;
+
+ /* We currently assume that frame chain's can't cross spaces. */
+ fi->pspace = fi->next->pspace;
+ fi->aspace = fi->next->aspace;
/* 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);
+ frame_unwind_find_by_frame (fi, &fi->prologue_cache);
fi->this_id.p = 1;
fi->this_id.value = frame_id_build (addr, pc);
fi->base->unwind->dealloc_cache (fi, fi->base_cache);
}
- /* Since we can't really be sure what the first object allocated was */
+ /* Since we can't really be sure what the first object allocated was. */
obstack_free (&frame_cache_obstack, 0);
obstack_init (&frame_cache_obstack);
current_frame = NULL; /* Invalidate cache */
select_frame (NULL);
+ frame_stash_invalidate ();
if (frame_debug)
fprintf_unfiltered (gdb_stdlog, "{ reinit_frame_cache () }\n");
}
while (this_frame != NULL)
{
- frame_register_unwind (this_frame, regnum, optimizedp, lvalp,
- addrp, realnump, NULL);
+ int unavailable;
+
+ frame_register_unwind (this_frame, regnum, optimizedp, &unavailable,
+ lvalp, addrp, realnump, NULL);
if (*optimizedp)
break;
}
}
-/* Return a "struct frame_info" corresponding to the frame that called
- THIS_FRAME. Returns NULL if there is no such frame.
+/* Called during frame unwinding to remove a previous frame pointer from a
+ frame passed in ARG. */
- Unlike get_prev_frame, this function always tries to unwind the
- frame. */
+static void
+remove_prev_frame (void *arg)
+{
+ struct frame_info *this_frame, *prev_frame;
+
+ this_frame = (struct frame_info *) arg;
+ prev_frame = this_frame->prev;
+ gdb_assert (prev_frame != NULL);
+
+ prev_frame->next = NULL;
+ this_frame->prev = NULL;
+}
+
+/* Get the previous raw frame, and check that it is not identical to
+ same other frame frame already in the chain. If it is, there is
+ most likely a stack cycle, so we discard it, and mark THIS_FRAME as
+ outermost, with UNWIND_SAME_ID stop reason. Unlike the other
+ validity tests, that compare THIS_FRAME and the next frame, we do
+ this right after creating the previous frame, to avoid ever ending
+ up with two frames with the same id in the frame chain. */
static struct frame_info *
-get_prev_frame_1 (struct frame_info *this_frame)
+get_prev_frame_if_no_cycle (struct frame_info *this_frame)
{
struct frame_info *prev_frame;
- struct frame_id this_id;
+ struct cleanup *prev_frame_cleanup;
+
+ prev_frame = get_prev_frame_raw (this_frame);
+ if (prev_frame == NULL)
+ return NULL;
+
+ /* The cleanup will remove the previous frame that get_prev_frame_raw
+ linked onto THIS_FRAME. */
+ prev_frame_cleanup = make_cleanup (remove_prev_frame, this_frame);
+
+ compute_frame_id (prev_frame);
+ if (!frame_stash_add (prev_frame))
+ {
+ /* Another frame with the same id was already in the stash. We just
+ detected a cycle. */
+ if (frame_debug)
+ {
+ 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;
+ /* Unlink. */
+ prev_frame->next = NULL;
+ this_frame->prev = NULL;
+ prev_frame = NULL;
+ }
+
+ discard_cleanups (prev_frame_cleanup);
+ return prev_frame;
+}
+
+/* Helper function for get_prev_frame_always, this is called inside a
+ TRY_CATCH block. Return the frame that called THIS_FRAME or NULL if
+ there is no such frame. This may throw an exception. */
+
+static struct frame_info *
+get_prev_frame_always_1 (struct frame_info *this_frame)
+{
struct gdbarch *gdbarch;
gdb_assert (this_frame != NULL);
if (frame_debug)
{
- fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_1 (this_frame=");
+ fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_always (this_frame=");
if (this_frame != NULL)
fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
else
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);
+ 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 we are unwinding from an inline frame, all of the below tests
+ were already performed when we unwound from the next non-inline
+ frame. We must skip them, since we can not get THIS_FRAME's ID
+ until we have unwound all the way down to the previous non-inline
+ frame. */
+ if (get_frame_type (this_frame) == INLINE_FRAME)
+ return get_prev_frame_if_no_cycle (this_frame);
+
+ /* Check that this frame is unwindable. If it isn't, don't try to
+ unwind to the prev frame. */
+ this_frame->stop_reason
+ = this_frame->unwind->stop_reason (this_frame,
+ &this_frame->prologue_cache);
+
+ if (this_frame->stop_reason != UNWIND_NO_REASON)
{
if (frame_debug)
{
+ enum unwind_stop_reason reason = this_frame->stop_reason;
+
fprintf_unfiltered (gdb_stdlog, "-> ");
fprint_frame (gdb_stdlog, NULL);
- fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
+ fprintf_unfiltered (gdb_stdlog, " // %s }\n",
+ frame_stop_reason_symbol_string (reason));
}
- this_frame->stop_reason = UNWIND_NULL_ID;
return NULL;
}
See the comment at frame_id_inner for details. */
if (get_frame_type (this_frame) == NORMAL_FRAME
&& this_frame->next->unwind->type == NORMAL_FRAME
- && frame_id_inner (get_frame_arch (this_frame->next), this_id,
+ && frame_id_inner (get_frame_arch (this_frame->next),
+ get_frame_id (this_frame),
get_frame_id (this_frame->next)))
{
- if (frame_debug)
- {
- 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;
- }
-
- /* 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)
+ CORE_ADDR this_pc_in_block;
+ struct minimal_symbol *morestack_msym;
+ const char *morestack_name = NULL;
+
+ /* gcc -fsplit-stack __morestack can continue the stack anywhere. */
+ this_pc_in_block = get_frame_address_in_block (this_frame);
+ morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block).minsym;
+ if (morestack_msym)
+ morestack_name = MSYMBOL_LINKAGE_NAME (morestack_msym);
+ if (!morestack_name || strcmp (morestack_name, "__morestack") != 0)
{
- fprintf_unfiltered (gdb_stdlog, "-> ");
- fprint_frame (gdb_stdlog, NULL);
- fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+ if (frame_debug)
+ {
+ 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;
}
- this_frame->stop_reason = UNWIND_SAME_ID;
- return NULL;
}
/* Check that this and the next frame do not unwind the PC register
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)
+ && (get_frame_type (this_frame->next) == NORMAL_FRAME
+ || get_frame_type (this_frame->next) == INLINE_FRAME))
{
int optimized, realnum, nrealnum;
enum lval_type lval, nlval;
}
}
+ return get_prev_frame_if_no_cycle (this_frame);
+}
+
+/* Return a "struct frame_info" corresponding to the frame that called
+ THIS_FRAME. Returns NULL if there is no such frame.
+
+ Unlike get_prev_frame, this function always tries to unwind the
+ frame. */
+
+struct frame_info *
+get_prev_frame_always (struct frame_info *this_frame)
+{
+ struct frame_info *prev_frame = NULL;
+
+ TRY
+ {
+ prev_frame = get_prev_frame_always_1 (this_frame);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error == MEMORY_ERROR)
+ {
+ this_frame->stop_reason = UNWIND_MEMORY_ERROR;
+ if (ex.message != NULL)
+ {
+ char *stop_string;
+ size_t size;
+
+ /* The error needs to live as long as the frame does.
+ Allocate using stack local STOP_STRING then assign the
+ pointer to the frame, this allows the STOP_STRING on the
+ frame to be of type 'const char *'. */
+ size = strlen (ex.message) + 1;
+ stop_string = (char *) frame_obstack_zalloc (size);
+ memcpy (stop_string, ex.message, size);
+ this_frame->stop_string = stop_string;
+ }
+ prev_frame = NULL;
+ }
+ else
+ throw_exception (ex);
+ }
+ END_CATCH
+
+ return prev_frame;
+}
+
+/* Construct a new "struct frame_info" and link it previous to
+ this_frame. */
+
+static struct frame_info *
+get_prev_frame_raw (struct frame_info *this_frame)
+{
+ struct frame_info *prev_frame;
+
/* Allocate the new frame but do not wire it in to the frame chain.
Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along
frame->next to pull some fancy tricks (of course such code is, by
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev_frame->level = this_frame->level + 1;
+ /* For now, assume we don't have frame chains crossing address
+ spaces. */
+ prev_frame->pspace = this_frame->pspace;
+ prev_frame->aspace = this_frame->aspace;
+
/* Don't yet compute ->unwind (and hence ->type). It is computed
on-demand in get_frame_type, frame_register_unwind, and
get_frame_id. */
static int
inside_main_func (struct frame_info *this_frame)
{
- struct minimal_symbol *msymbol;
+ struct bound_minimal_symbol msymbol;
CORE_ADDR maddr;
if (symfile_objfile == 0)
return 0;
msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile);
- if (msymbol == NULL)
+ if (msymbol.minsym == 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),
+ BMSYMBOL_VALUE_ADDRESS (msymbol),
¤t_target);
return maddr == get_frame_func (this_frame);
}
static int
inside_entry_func (struct frame_info *this_frame)
{
- return (get_frame_func (this_frame) == entry_point_address ());
+ CORE_ADDR entry_point;
+
+ if (!entry_point_address_query (&entry_point))
+ return 0;
+
+ return get_frame_func (this_frame) == entry_point;
}
/* Return a structure containing various interesting information about
struct frame_info *
get_prev_frame (struct frame_info *this_frame)
{
- struct frame_info *prev_frame;
+ CORE_ADDR frame_pc;
+ int frame_pc_p;
/* 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);
+ frame_pc_p = get_frame_pc_if_available (this_frame, &frame_pc);
/* 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
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
+ && get_frame_type (this_frame) == NORMAL_FRAME
&& !backtrace_past_main
+ && frame_pc_p
&& 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
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
+ if (this_frame->level >= 0
+ && get_frame_type (this_frame) == NORMAL_FRAME
+ && !backtrace_past_entry
+ && frame_pc_p
&& inside_entry_func (this_frame))
{
frame_debug_got_null_frame (this_frame, "inside entry func");
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 (this_frame) == NORMAL_FRAME
+ || get_frame_type (this_frame) == INLINE_FRAME)
&& get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
- && get_frame_pc (this_frame) == 0)
+ && frame_pc_p && frame_pc == 0)
{
frame_debug_got_null_frame (this_frame, "zero PC");
return NULL;
}
- return get_prev_frame_1 (this_frame);
+ return get_prev_frame_always (this_frame);
}
CORE_ADDR
get_frame_pc (struct frame_info *frame)
{
gdb_assert (frame->next != NULL);
- return frame_pc_unwind (frame->next);
+ return frame_unwind_pc (frame->next);
+}
+
+int
+get_frame_pc_if_available (struct frame_info *frame, CORE_ADDR *pc)
+{
+
+ gdb_assert (frame->next != NULL);
+
+ TRY
+ {
+ *pc = frame_unwind_pc (frame->next);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error == NOT_AVAILABLE_ERROR)
+ return 0;
+ else
+ throw_exception (ex);
+ }
+ END_CATCH
+
+ return 1;
}
/* Return an address that falls within THIS_FRAME's code block. */
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)
+ NEXT_FRAME.
+
+ If the next frame is inlined, we need to keep going until we find
+ the real function - for instance, if a signal handler is invoked
+ while in an inlined function, then the code address of the
+ "calling" normal function should not be adjusted either. */
+
+ while (get_frame_type (next_frame) == INLINE_FRAME)
+ next_frame = next_frame->next;
+
+ if ((get_frame_type (next_frame) == NORMAL_FRAME
+ || get_frame_type (next_frame) == TAILCALL_FRAME)
+ && (get_frame_type (this_frame) == NORMAL_FRAME
+ || get_frame_type (this_frame) == TAILCALL_FRAME
+ || get_frame_type (this_frame) == INLINE_FRAME))
return pc - 1;
return pc;
}
-static int
-pc_notcurrent (struct frame_info *frame)
+int
+get_frame_address_in_block_if_available (struct frame_info *this_frame,
+ CORE_ADDR *pc)
+{
+
+ TRY
+ {
+ *pc = get_frame_address_in_block (this_frame);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error == NOT_AVAILABLE_ERROR)
+ return 0;
+ throw_exception (ex);
+ }
+ END_CATCH
+
+ return 1;
+}
+
+void
+find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
{
+ struct frame_info *next_frame;
+ int notcurrent;
+ CORE_ADDR pc;
+
+ /* If the next frame represents an inlined function call, this frame's
+ sal is the "call site" of that inlined function, which can not
+ be inferred from get_frame_pc. */
+ next_frame = get_next_frame (frame);
+ if (frame_inlined_callees (frame) > 0)
+ {
+ struct symbol *sym;
+
+ if (next_frame)
+ sym = get_frame_function (next_frame);
+ else
+ sym = inline_skipped_symbol (inferior_ptid);
+
+ /* If frame is inline, it certainly has symbols. */
+ gdb_assert (sym);
+ init_sal (sal);
+ if (SYMBOL_LINE (sym) != 0)
+ {
+ sal->symtab = symbol_symtab (sym);
+ sal->line = SYMBOL_LINE (sym);
+ }
+ else
+ /* If the symbol does not have a location, we don't know where
+ the call site is. Do not pretend to. This is jarring, but
+ we can't do much better. */
+ sal->pc = get_frame_pc (frame);
+
+ sal->pspace = get_frame_program_space (frame);
+
+ return;
+ }
+
/* If FRAME is not the innermost frame, that normally means that
FRAME->pc points at the return instruction (which is *after* the
call instruction), and we want to get the line containing the
PC and such a PC indicates the current (rather than next)
instruction/line, consequently, for such cases, want to get the
line containing fi->pc. */
- struct frame_info *next = get_next_frame (frame);
- int notcurrent = (next != NULL && get_frame_type (next) == NORMAL_FRAME);
- return notcurrent;
-}
+ if (!get_frame_pc_if_available (frame, &pc))
+ {
+ init_sal (sal);
+ return;
+ }
-void
-find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
-{
- (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
+ notcurrent = (pc != get_frame_address_in_block (frame));
+ (*sal) = find_pc_line (pc, notcurrent);
}
/* Per "frame.h", return the ``address'' of the frame. Code should
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. */
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. */
return fi->base->this_args (fi, &fi->base_cache);
}
+/* Return true if the frame unwinder for frame FI is UNWINDER; false
+ otherwise. */
+
+int
+frame_unwinder_is (struct frame_info *fi, const struct frame_unwind *unwinder)
+{
+ if (fi->unwind == NULL)
+ frame_unwind_find_by_frame (fi, &fi->prologue_cache);
+ return fi->unwind == unwinder;
+}
+
/* Level of the selected frame: 0 for innermost, 1 for its caller, ...
or -1 for a NULL frame. */
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);
+ frame_unwind_find_by_frame (frame, &frame->prologue_cache);
return frame->unwind->type;
}
+struct program_space *
+get_frame_program_space (struct frame_info *frame)
+{
+ return frame->pspace;
+}
+
+struct program_space *
+frame_unwind_program_space (struct frame_info *this_frame)
+{
+ gdb_assert (this_frame);
+
+ /* This is really a placeholder to keep the API consistent --- we
+ assume for now that we don't have frame chains crossing
+ spaces. */
+ return this_frame->pspace;
+}
+
+struct address_space *
+get_frame_address_space (struct frame_info *frame)
+{
+ return frame->aspace;
+}
+
/* Memory access methods. */
void
get_frame_memory_signed (struct frame_info *this_frame, CORE_ADDR addr,
int len)
{
- return read_memory_integer (addr, len);
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ return read_memory_integer (addr, len, byte_order);
}
ULONGEST
get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr,
int len)
{
- return read_memory_unsigned_integer (addr, len);
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ return read_memory_unsigned_integer (addr, len, byte_order);
}
int
return !target_read_memory (addr, buf, len);
}
-/* Architecture method. */
+/* Architecture methods. */
struct gdbarch *
get_frame_arch (struct frame_info *this_frame)
{
- /* 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 frame_unwind_arch (this_frame->next);
+}
+
+struct gdbarch *
+frame_unwind_arch (struct frame_info *next_frame)
+{
+ if (!next_frame->prev_arch.p)
+ {
+ struct gdbarch *arch;
+
+ if (next_frame->unwind == NULL)
+ frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache);
+
+ if (next_frame->unwind->prev_arch != NULL)
+ arch = next_frame->unwind->prev_arch (next_frame,
+ &next_frame->prologue_cache);
+ else
+ arch = get_frame_arch (next_frame);
+
+ next_frame->prev_arch.arch = arch;
+ next_frame->prev_arch.p = 1;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_unwind_arch (next_frame=%d) -> %s }\n",
+ next_frame->level,
+ gdbarch_bfd_arch_info (arch)->printable_name);
+ }
+
+ return next_frame->prev_arch.arch;
+}
+
+struct gdbarch *
+frame_unwind_caller_arch (struct frame_info *next_frame)
+{
+ return frame_unwind_arch (skip_artificial_frames (next_frame));
+}
+
+/* Gets the language of FRAME. */
+
+enum language
+get_frame_language (struct frame_info *frame)
+{
+ CORE_ADDR pc = 0;
+ int pc_p = 0;
+
+ gdb_assert (frame!= NULL);
+
+ /* We determine the current frame language by looking up its
+ associated symtab. To retrieve this symtab, we use 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(), it provides us with
+ a PC that is guaranteed to be inside the frame's code
+ block. */
- return current_gdbarch;
+ TRY
+ {
+ pc = get_frame_address_in_block (frame);
+ pc_p = 1;
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error != NOT_AVAILABLE_ERROR)
+ throw_exception (ex);
+ }
+ END_CATCH
+
+ if (pc_p)
+ {
+ struct compunit_symtab *cust = find_pc_compunit_symtab (pc);
+
+ if (cust != NULL)
+ return compunit_language (cust);
+ }
+
+ return language_unknown;
}
/* Stack pointer methods. */
get_frame_sp (struct frame_info *this_frame)
{
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))
enum unwind_stop_reason
get_frame_unwind_stop_reason (struct frame_info *frame)
{
- /* 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;
+ /* Fill-in STOP_REASON. */
+ get_prev_frame_always (frame);
+ gdb_assert (frame->prev_p);
- /* Otherwise, we set a reason when we succeeded (or failed) to
- unwind. */
return frame->stop_reason;
}
/* Return a string explaining REASON. */
const char *
-frame_stop_reason_string (enum unwind_stop_reason reason)
+unwind_stop_reason_to_string (enum unwind_stop_reason reason)
{
switch (reason)
{
- case UNWIND_NULL_ID:
- return _("unwinder did not report frame ID");
+#define SET(name, description) \
+ case name: return _(description);
+#include "unwind_stop_reasons.def"
+#undef SET
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ "Invalid frame stop reason");
+ }
+}
+
+const char *
+frame_stop_reason_string (struct frame_info *fi)
+{
+ gdb_assert (fi->prev_p);
+ gdb_assert (fi->prev == NULL);
- case UNWIND_INNER_ID:
- return _("previous frame inner to this frame (corrupt stack?)");
+ /* Return the specific string if we have one. */
+ if (fi->stop_string != NULL)
+ return fi->stop_string;
- case UNWIND_SAME_ID:
- return _("previous frame identical to this frame (corrupt stack?)");
+ /* Return the generic string if we have nothing better. */
+ return unwind_stop_reason_to_string (fi->stop_reason);
+}
- case UNWIND_NO_SAVED_PC:
- return _("frame did not save the PC");
+/* Return the enum symbol name of REASON as a string, to use in debug
+ output. */
+
+static const char *
+frame_stop_reason_symbol_string (enum unwind_stop_reason reason)
+{
+ switch (reason)
+ {
+#define SET(name, description) \
+ case name: return #name;
+#include "unwind_stop_reasons.def"
+#undef SET
- case UNWIND_NO_REASON:
- case UNWIND_FIRST_ERROR:
default:
internal_error (__FILE__, __LINE__,
"Invalid frame stop reason");
static void
frame_cleanup_after_sniffer (void *arg)
{
- struct frame_info *frame = arg;
+ struct frame_info *frame = (struct frame_info *) arg;
/* The sniffer should not allocate a prologue cache if it did not
match this frame. */
static void
set_backtrace_cmd (char *args, int from_tty)
{
- help_list (set_backtrace_cmdlist, "set backtrace ", -1, gdb_stdout);
+ help_list (set_backtrace_cmdlist, "set backtrace ", all_commands,
+ gdb_stdout);
}
static void
{
obstack_init (&frame_cache_obstack);
+ frame_stash_create ();
+
observer_attach_target_changed (frame_observer_target_changed);
add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
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\
+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, _("\
+ add_setshow_uinteger_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);
+Literal \"unlimited\" or zero means no limit."),
+ NULL,
+ show_backtrace_limit,
+ &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
- /* Debug this files internals. */
- add_setshow_zinteger_cmd ("frame", class_maintenance, &frame_debug, _("\
+ /* Debug this files internals. */
+ add_setshow_zuinteger_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);
+ NULL,
+ show_frame_debug,
+ &setdebuglist, &showdebuglist);
}