Index: gdb/frame.c |
diff --git a/gdb/frame.c b/gdb/frame.c |
index b7698733c2aea38d1a2b0c1329325980c5008521..6a8b5ae58bcf829f8632ecd13907c22029c5833a 100644 |
--- a/gdb/frame.c |
+++ b/gdb/frame.c |
@@ -1,7 +1,6 @@ |
/* Cache and manage frames for GDB, the GNU debugger. |
- Copyright (C) 1986-1987, 1989, 1991, 1994-1996, 1998, 2000-2004, |
- 2007-2012 Free Software Foundation, Inc. |
+ Copyright (C) 1986-2013 Free Software Foundation, Inc. |
This file is part of GDB. |
@@ -25,7 +24,7 @@ |
#include "inferior.h" /* for inferior_ptid */ |
#include "regcache.h" |
#include "gdb_assert.h" |
-#include "gdb_string.h" |
+#include <string.h> |
#include "user-regs.h" |
#include "gdb_obstack.h" |
#include "dummy-frame.h" |
@@ -43,10 +42,30 @@ |
#include "gdbthread.h" |
#include "block.h" |
#include "inline-frame.h" |
-#include "tracepoint.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 |
@@ -94,7 +113,7 @@ struct frame_info |
/* Cached copy of the previous frame's resume address. */ |
struct { |
- int p; |
+ enum cached_copy_status status; |
CORE_ADDR value; |
} prev_pc; |
@@ -129,43 +148,120 @@ struct frame_info |
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. */ |
+ |
+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 = 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; |
-/* We currently only stash one frame at a time, as this seems to be |
- sufficient for now. */ |
-static struct frame_info *frame_stash = NULL; |
+ return frame_id_eq (f_entry->this_id.value, |
+ f_element->this_id.value); |
+} |
-/* Add the following FRAME to the frame stash. */ |
+/* 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) |
{ |
- frame_stash = 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; |
} |
-/* 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) |
@@ -196,7 +292,7 @@ show_backtrace_past_entry (struct ui_file *file, int from_tty, |
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) |
@@ -226,8 +322,8 @@ fprint_frame_id (struct ui_file *file, struct frame_id id) |
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, "}"); |
} |
@@ -245,8 +341,8 @@ fprint_frame_type (struct ui_file *file, enum frame_type type) |
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"); |
@@ -254,6 +350,9 @@ fprint_frame_type (struct ui_file *file, enum frame_type type) |
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; |
@@ -284,10 +383,15 @@ fprint_frame (struct ui_file *file, struct frame_info *fi) |
fprintf_unfiltered (file, "<unknown>"); |
fprintf_unfiltered (file, ","); |
fprintf_unfiltered (file, "pc="); |
- if (fi->next != NULL && fi->next->prev_pc.p) |
- fprintf_unfiltered (file, "%s", hex_string (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) |
@@ -303,11 +407,12 @@ fprint_frame (struct ui_file *file, struct frame_info *fi) |
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 |
|| get_frame_type (frame) == TAILCALL_FRAME) |
@@ -316,6 +421,34 @@ skip_inlined_frames (struct frame_info *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. */ |
@@ -325,37 +458,14 @@ 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) |
- 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"); |
- } |
- } |
- |
- frame_stash_add (fi); |
- |
+ gdb_assert (fi->this_id.p); |
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 |
@@ -368,10 +478,10 @@ frame_unwind_caller_id (struct frame_info *next_frame) |
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; |
} |
@@ -436,12 +546,12 @@ frame_id_p (struct frame_id l) |
} |
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 |
@@ -473,8 +583,8 @@ frame_id_eq (struct frame_id l, struct frame_id r) |
/* 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. */ |
@@ -531,7 +641,7 @@ frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r) |
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 |
@@ -619,10 +729,10 @@ frame_find_by_id (struct frame_id id) |
return NULL; |
} |
-static int |
-frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc) |
+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) |
{ |
if (gdbarch_unwind_pc_p (frame_unwind_arch (this_frame))) |
{ |
@@ -652,24 +762,35 @@ frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc) |
{ |
pc = gdbarch_unwind_pc (prev_gdbarch, this_frame); |
} |
- if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR) |
- { |
- this_frame->prev_pc.p = -1; |
- |
- if (frame_debug) |
- fprintf_unfiltered (gdb_stdlog, |
- "{ frame_unwind_pc (this_frame=%d)" |
- " -> <unavailable> }\n", |
- this_frame->level); |
- } |
- else if (ex.reason < 0) |
+ if (ex.reason < 0) |
{ |
- throw_exception (ex); |
+ 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); |
} |
else |
{ |
this_frame->prev_pc.value = pc; |
- this_frame->prev_pc.p = 1; |
+ this_frame->prev_pc.status = CC_VALUE; |
if (frame_debug) |
fprintf_unfiltered (gdb_stdlog, |
"{ frame_unwind_pc (this_frame=%d) " |
@@ -681,40 +802,23 @@ frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc) |
else |
internal_error (__FILE__, __LINE__, _("No unwind_pc method")); |
} |
- if (this_frame->prev_pc.p < 0) |
- { |
- *pc = -1; |
- return 0; |
- } |
- else |
- { |
- *pc = this_frame->prev_pc.value; |
- return 1; |
- } |
-} |
-static CORE_ADDR |
-frame_unwind_pc (struct frame_info *this_frame) |
-{ |
- CORE_ADDR pc; |
- |
- if (!frame_unwind_pc_if_available (this_frame, &pc)) |
+ 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 |
- return pc; |
+ internal_error (__FILE__, __LINE__, |
+ "unexpected prev_pc status: %d", |
+ (int) this_frame->prev_pc.status); |
} |
CORE_ADDR |
frame_unwind_caller_pc (struct frame_info *this_frame) |
{ |
- return frame_unwind_pc (skip_inlined_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 (skip_artificial_frames (this_frame)); |
} |
int |
@@ -775,7 +879,7 @@ get_frame_func (struct frame_info *this_frame) |
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; |
@@ -919,7 +1023,8 @@ frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf) |
&lval, &addr, &realnum, buf); |
if (optimized) |
- error (_("Register %d was optimized out"), regnum); |
+ throw_error (OPTIMIZED_OUT_ERROR, |
+ _("Register %d was not saved"), regnum); |
if (unavailable) |
throw_error (NOT_AVAILABLE_ERROR, |
_("Register %d is not available"), regnum); |
@@ -961,7 +1066,10 @@ frame_unwind_register_value (struct frame_info *frame, int 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) |
@@ -1071,17 +1179,12 @@ put_frame_register (struct frame_info *frame, int regnum, |
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: |
@@ -1092,7 +1195,8 @@ put_frame_register (struct frame_info *frame, int regnum, |
} |
} |
-/* 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). |
@@ -1100,7 +1204,7 @@ put_frame_register (struct frame_info *frame, int 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; |
@@ -1221,7 +1325,7 @@ put_frame_register_bytes (struct frame_info *frame, int regnum, |
{ |
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); |
} |
@@ -1484,7 +1588,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) |
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; |
@@ -1587,6 +1691,42 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum, |
} |
} |
+/* 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_if_no_cycle (struct frame_info *this_frame) |
+{ |
+ struct frame_info *prev_frame; |
+ |
+ prev_frame = get_prev_frame_raw (this_frame); |
+ if (prev_frame == NULL) |
+ return NULL; |
+ |
+ compute_frame_id (prev_frame); |
+ if (frame_stash_add (prev_frame)) |
+ return 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; |
+ return NULL; |
+} |
+ |
/* Return a "struct frame_info" corresponding to the frame that called |
THIS_FRAME. Returns NULL if there is no such frame. |
@@ -1596,7 +1736,6 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum, |
static struct frame_info * |
get_prev_frame_1 (struct frame_info *this_frame) |
{ |
- struct frame_id this_id; |
struct gdbarch *gdbarch; |
gdb_assert (this_frame != NULL); |
@@ -1640,7 +1779,7 @@ get_prev_frame_1 (struct frame_info *this_frame) |
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_raw (this_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. */ |
@@ -1649,21 +1788,16 @@ get_prev_frame_1 (struct frame_info *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. */ |
- this_id = get_frame_id (this_frame); |
- if (this_frame->level >= 0 && frame_id_eq (this_id, outer_frame_id)) |
{ |
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; |
} |
@@ -1673,7 +1807,8 @@ get_prev_frame_1 (struct frame_info *this_frame) |
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))) |
{ |
CORE_ADDR this_pc_in_block; |
@@ -1682,7 +1817,7 @@ get_prev_frame_1 (struct frame_info *this_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) |
@@ -1699,22 +1834,6 @@ get_prev_frame_1 (struct frame_info *this_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, "-> "); |
- fprint_frame (gdb_stdlog, NULL); |
- fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n"); |
- } |
- this_frame->stop_reason = UNWIND_SAME_ID; |
- return NULL; |
- } |
- |
/* 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 |
@@ -1762,7 +1881,7 @@ get_prev_frame_1 (struct frame_info *this_frame) |
} |
} |
- return get_prev_frame_raw (this_frame); |
+ return get_prev_frame_if_no_cycle (this_frame); |
} |
/* Construct a new "struct frame_info" and link it previous to |
@@ -2332,7 +2451,7 @@ frame_unwind_arch (struct frame_info *next_frame) |
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. */ |
@@ -2389,6 +2508,25 @@ frame_stop_reason_string (enum unwind_stop_reason reason) |
} |
} |
+/* 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 |
+ |
+ default: |
+ internal_error (__FILE__, __LINE__, |
+ "Invalid frame stop reason"); |
+ } |
+} |
+ |
/* Clean up after a failed (wrong unwinder) attempt to unwind past |
FRAME. */ |
@@ -2455,6 +2593,8 @@ _initialize_frame (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, _("\ |
@@ -2494,23 +2634,23 @@ the rest of the stack trace."), |
&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); |
} |