/* 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, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1986-2013 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbthread.h"
#include "block.h"
#include "inline-frame.h"
-#include "tracepoint.h"
+#include "tracepoint.h"
+#include "hashtab.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);
enum unwind_stop_reason stop_reason;
};
-/* A frame stash used to speed up frame lookups. */
+/* 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. */
-/* We currently only stash one frame at a time, as this seems to be
- sufficient for now. */
-static struct frame_info *frame_stash = NULL;
+static htab_t frame_stash;
-/* Add the following FRAME to the 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 = ap;
+ const struct frame_id f_id = frame->this_id.value;
+ hashval_t hash = 0;
+
+ gdb_assert (f_id.stack_addr_p || f_id.code_addr_p
+ || f_id.special_addr_p);
+
+ if (f_id.stack_addr_p)
+ 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 = a;
+ const struct frame_info *f_element = 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. Do
+ not store frames below 0 as they may not have any addresses to
+ calculate a hash. */
static void
frame_stash_add (struct frame_info *frame)
{
- frame_stash = frame;
+ /* Do not stash frames below level 0. */
+ if (frame->level >= 0)
+ {
+ struct frame_info **slot;
+
+ slot = (struct frame_info **) htab_find_slot (frame_stash,
+ frame,
+ INSERT);
+ *slot = frame;
+ }
}
-/* Search the frame stash for an entry with the given frame ID.
- If found, return that frame. Otherwise return NULL. */
+/* 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)
{
- if (frame_stash && frame_id_eq (frame_stash->this_id.value, id))
- return frame_stash;
+ struct frame_info dummy;
+ struct frame_info *frame;
- return NULL;
+ dummy.this_id.value = id;
+ frame = htab_find (frame_stash, &dummy);
+ return frame;
}
-/* Invalidate the frame stash by removing all entries in it. */
+/* 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)
{
- frame_stash = NULL;
+ 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)
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)
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.inline_depth)
- fprintf_unfiltered (file, ",inlined=%d", id.inline_depth);
+ if (id.artificial_depth)
+ fprintf_unfiltered (file, ",artificial=%d", id.artificial_depth);
fprintf_unfiltered (file, "}");
}
case INLINE_FRAME:
fprintf_unfiltered (file, "INLINE_FRAME");
return;
- case SENTINEL_FRAME:
- fprintf_unfiltered (file, "SENTINEL_FRAME");
+ case TAILCALL_FRAME:
+ fprintf_unfiltered (file, "TAILCALL_FRAME");
return;
case SIGTRAMP_FRAME:
fprintf_unfiltered (file, "SIGTRAMP_FRAME");
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, "}");
}
-/* Given FRAME, return the enclosing normal frame for inlined
- function frames. Otherwise return the original frame. */
+/* 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_inlined_frames (struct frame_info *frame)
+skip_artificial_frames (struct frame_info *frame)
{
- while (get_frame_type (frame) == INLINE_FRAME)
+ while (get_frame_type (frame) == INLINE_FRAME
+ || get_frame_type (frame) == TAILCALL_FRAME)
frame = get_prev_frame (frame);
return frame;
fprint_frame_id (gdb_stdlog, fi->this_id.value);
fprintf_unfiltered (gdb_stdlog, " }\n");
}
+ frame_stash_add (fi);
}
- frame_stash_add (fi);
-
return fi->this_id.value;
}
struct frame_id
get_stack_frame_id (struct frame_info *next_frame)
{
- return get_frame_id (skip_inlined_frames (next_frame));
+ return get_frame_id (skip_artificial_frames (next_frame));
}
struct frame_id
returning a null_frame_id (e.g., when a caller requests the frame
ID of "main()"s caller. */
- next_frame = skip_inlined_frames (next_frame);
+ next_frame = skip_artificial_frames (next_frame);
this_frame = get_prev_frame_1 (next_frame);
if (this_frame)
- return get_frame_id (skip_inlined_frames (this_frame));
+ return get_frame_id (skip_artificial_frames (this_frame));
else
return null_frame_id;
}
}
int
-frame_id_inlined_p (struct frame_id l)
+frame_id_artificial_p (struct frame_id l)
{
if (!frame_id_p (l))
return 0;
- return (l.inline_depth != 0);
+ return (l.artificial_depth != 0);
}
int
/* 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.inline_depth != r.inline_depth)
- /* If inline depths are different, the frames must be different. */
+ else if (l.artificial_depth != r.artificial_depth)
+ /* If artifical depths are different, the frames must be different. */
eq = 0;
else
/* Frames are equal. */
if (!l.stack_addr_p || !r.stack_addr_p)
/* Like NaN, any operation involving an invalid ID always fails. */
inner = 0;
- else if (l.inline_depth > r.inline_depth
+ 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
CORE_ADDR
frame_unwind_caller_pc (struct frame_info *this_frame)
{
- return frame_unwind_pc (skip_inlined_frames (this_frame));
+ return frame_unwind_pc (skip_artificial_frames (this_frame));
}
int
frame_unwind_caller_pc_if_available (struct frame_info *this_frame,
CORE_ADDR *pc)
{
- return frame_unwind_pc_if_available (skip_inlined_frames (this_frame), pc);
+ return frame_unwind_pc_if_available (skip_artificial_frames (this_frame), pc);
}
int
static enum register_status
do_frame_register_read (void *src, int regnum, gdb_byte *buf)
{
- if (!frame_register_read (src, regnum, buf))
+ if (!deprecated_frame_register_read (src, regnum, buf))
return REG_UNAVAILABLE;
else
return REG_VALID;
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
frame_register_unwind (frame, regnum, &optimized, &unavailable,
&lval, &addr, &realnum, buf);
+
+ if (optimized)
+ error (_("Register %d was optimized out"), regnum);
+ if (unavailable)
+ throw_error (NOT_AVAILABLE_ERROR,
+ _("Register %d is not available"), regnum);
}
void
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)
{
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;
{
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);
}
{
struct frame_info *sentinel_frame =
create_sentinel_frame (current_program_space, get_current_regcache ());
- if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
- RETURN_MASK_ERROR) != 0)
+ 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;
}
if (get_frame_type (this_frame) == INLINE_FRAME)
return get_prev_frame_raw (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)
+ return NULL;
+
/* 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. */
/* 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);
+ morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block).minsym;
if (morestack_msym)
morestack_name = SYMBOL_LINKAGE_NAME (morestack_msym);
if (!morestack_name || strcmp (morestack_name, "__morestack") != 0)
while (get_frame_type (next_frame) == INLINE_FRAME)
next_frame = next_frame->next;
- if (get_frame_type (next_frame) == NORMAL_FRAME
+ 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;
we can't do much better. */
sal->pc = get_frame_pc (frame);
+ sal->pspace = get_frame_program_space (frame);
+
return;
}
struct gdbarch *
frame_unwind_caller_arch (struct frame_info *next_frame)
{
- return frame_unwind_arch (skip_inlined_frames (next_frame));
+ return frame_unwind_arch (skip_artificial_frames (next_frame));
}
/* Stack pointer methods. */
{
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?)");
+#define SET(name, description) \
+ case name: return _(description);
+#include "unwind_stop_reasons.def"
+#undef SET
- 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");
{
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, _("\
&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, _("\
+ 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);
}