* frame.c (struct frame_info): Add stop_reason.

(get_prev_frame_1): Set stop_reason.  Don't call error for
	stop reasons.
	(get_frame_unwind_stop_reason, frame_stop_reason_string): New.
	* frame.h (enum unwind_stop_reason): New.
	(get_frame_unwind_stop_reason, frame_stop_reason_string): New
	prototypes.
	* stack.c (frame_info): Print the stop reason.
	(backtrace_command_1): Print the stop reason for errors.
This commit is contained in:
Daniel Jacobowitz 2006-10-18 19:52:05 +00:00
parent d3f1a42773
commit 55feb68948
4 changed files with 147 additions and 2 deletions

View File

@ -1,3 +1,15 @@
2006-10-18 Daniel Jacobowitz <dan@codesourcery.com>
* frame.c (struct frame_info): Add stop_reason.
(get_prev_frame_1): Set stop_reason. Don't call error for
stop reasons.
(get_frame_unwind_stop_reason, frame_stop_reason_string): New.
* frame.h (enum unwind_stop_reason): New.
(get_frame_unwind_stop_reason, frame_stop_reason_string): New
prototypes.
* stack.c (frame_info): Print the stop reason.
(backtrace_command_1): Print the stop reason for errors.
2006-10-18 Daniel Jacobowitz <dan@codesourcery.com>
* inferior.h (start_remote): Update prototype.

View File

@ -107,6 +107,10 @@ struct frame_info
struct frame_info *next; /* down, inner, younger */
int prev_p;
struct frame_info *prev; /* up, outer, older */
/* The reason why we could not set PREV, or UNWIND_NO_REASON if we
could. Only valid when PREV_P is set. */
enum unwind_stop_reason stop_reason;
};
/* Flag to control debugging. */
@ -1055,6 +1059,7 @@ get_prev_frame_1 (struct frame_info *this_frame)
return this_frame->prev;
}
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
@ -1068,6 +1073,7 @@ get_prev_frame_1 (struct frame_info *this_frame)
fprint_frame (gdb_stdlog, NULL);
fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
}
this_frame->stop_reason = UNWIND_NULL_ID;
return NULL;
}
@ -1078,14 +1084,32 @@ get_prev_frame_1 (struct frame_info *this_frame)
if (this_frame->next->level >= 0
&& this_frame->next->unwind->type != SIGTRAMP_FRAME
&& frame_id_inner (this_id, get_frame_id (this_frame->next)))
error (_("Previous frame inner to this frame (corrupt stack?)"));
{
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)))
error (_("Previous frame identical to this frame (corrupt stack?)"));
{
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;
}
/* 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
@ -1556,6 +1580,45 @@ frame_sp_unwind (struct frame_info *next_frame)
internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
}
/* Return the reason why we can't unwind past FRAME. */
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;
/* 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)
{
switch (reason)
{
case UNWIND_NULL_ID:
return _("unwinder did not report frame ID");
case UNWIND_INNER_ID:
return _("previous frame inner to this frame (corrupt stack?)");
case UNWIND_SAME_ID:
return _("previous frame identical to this frame (corrupt stack?)");
case UNWIND_NO_REASON:
case UNWIND_FIRST_ERROR:
default:
internal_error (__FILE__, __LINE__,
"Invalid frame stop reason");
}
}
extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
static struct cmd_list_element *set_backtrace_cmdlist;

View File

@ -394,6 +394,50 @@ enum frame_type
};
extern enum frame_type get_frame_type (struct frame_info *);
/* For frames where we can not unwind further, describe why. */
enum unwind_stop_reason
{
/* No particular reason; either we haven't tried unwinding yet,
or we didn't fail. */
UNWIND_NO_REASON,
/* The previous frame's analyzer returns an invalid result
from this_id.
FIXME drow/2006-08-16: This is how GDB used to indicate end of
stack. We should migrate to a model where frames always have a
valid ID, and this becomes not just an error but an internal
error. But that's a project for another day. */
UNWIND_NULL_ID,
/* All the conditions after this point are considered errors;
abnormal stack termination. If a backtrace stops for one
of these reasons, we'll let the user know. This marker
is not a valid stop reason. */
UNWIND_FIRST_ERROR,
/* This frame ID looks like it ought to belong to a NEXT frame,
but we got it for a PREV frame. Normally, this is a sign of
unwinder failure. It could also indicate stack corruption. */
UNWIND_INNER_ID,
/* This frame has the same ID as the previous one. That means
that unwinding further would almost certainly give us another
frame with exactly the same ID, so break the chain. Normally,
this is a sign of unwinder failure. It could also indicate
stack corruption. */
UNWIND_SAME_ID,
};
/* Return the reason why we can't unwind past this frame. */
enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
/* Translate a reason code to an informative string. */
const char *frame_stop_reason_string (enum unwind_stop_reason);
/* Unwind the stack frame so that the value of REGNUM, in the previous
(up, older) frame is returned. If VALUEP is NULL, don't
fetch/compute the value. Instead just return the location of the

View File

@ -923,6 +923,16 @@ frame_info (char *addr_exp, int from_tty)
deprecated_print_address_numeric (frame_pc_unwind (fi), 1, gdb_stdout);
printf_filtered ("\n");
if (calling_frame_info == NULL)
{
enum unwind_stop_reason reason;
reason = get_frame_unwind_stop_reason (fi);
if (reason != UNWIND_NO_REASON)
printf_filtered (_(" Outermost frame: %s\n"),
frame_stop_reason_string (reason));
}
if (calling_frame_info)
{
printf_filtered (" called by frame at ");
@ -940,6 +950,7 @@ frame_info (char *addr_exp, int from_tty)
}
if (get_next_frame (fi) || calling_frame_info)
puts_filtered ("\n");
if (s)
printf_filtered (" source language %s.\n",
language_str (s->language));
@ -1163,11 +1174,26 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
print_frame_info (fi, 1, LOCATION, 1);
if (show_locals)
print_frame_local_vars (fi, 1, gdb_stdout);
/* Save the last frame to check for error conditions. */
trailing = fi;
}
/* If we've stopped before the end, mention that. */
if (fi && from_tty)
printf_filtered (_("(More stack frames follow...)\n"));
/* If we've run out of frames, and the reason appears to be an error
condition, print it. */
if (fi == NULL && trailing != NULL)
{
enum unwind_stop_reason reason;
reason = get_frame_unwind_stop_reason (trailing);
if (reason > UNWIND_FIRST_ERROR)
printf_filtered (_("Backtrace stopped: %s\n"),
frame_stop_reason_string (reason));
}
}
struct backtrace_command_args