* 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:
parent
d3f1a42773
commit
55feb68948
4 changed files with 147 additions and 2 deletions
|
@ -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>
|
2006-10-18 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
* inferior.h (start_remote): Update prototype.
|
* inferior.h (start_remote): Update prototype.
|
||||||
|
|
67
gdb/frame.c
67
gdb/frame.c
|
@ -107,6 +107,10 @@ struct frame_info
|
||||||
struct frame_info *next; /* down, inner, younger */
|
struct frame_info *next; /* down, inner, younger */
|
||||||
int prev_p;
|
int prev_p;
|
||||||
struct frame_info *prev; /* up, outer, older */
|
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. */
|
/* Flag to control debugging. */
|
||||||
|
@ -1055,6 +1059,7 @@ get_prev_frame_1 (struct frame_info *this_frame)
|
||||||
return this_frame->prev;
|
return this_frame->prev;
|
||||||
}
|
}
|
||||||
this_frame->prev_p = 1;
|
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
|
/* 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
|
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);
|
fprint_frame (gdb_stdlog, NULL);
|
||||||
fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
|
fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
|
||||||
}
|
}
|
||||||
|
this_frame->stop_reason = UNWIND_NULL_ID;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1078,14 +1084,32 @@ get_prev_frame_1 (struct frame_info *this_frame)
|
||||||
if (this_frame->next->level >= 0
|
if (this_frame->next->level >= 0
|
||||||
&& this_frame->next->unwind->type != SIGTRAMP_FRAME
|
&& this_frame->next->unwind->type != SIGTRAMP_FRAME
|
||||||
&& frame_id_inner (this_id, get_frame_id (this_frame->next)))
|
&& 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
|
/* 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
|
are, there is most likely a stack cycle. As with the inner-than
|
||||||
test above, avoid comparing the inner-most and sentinel frames. */
|
test above, avoid comparing the inner-most and sentinel frames. */
|
||||||
if (this_frame->level > 0
|
if (this_frame->level > 0
|
||||||
&& frame_id_eq (this_id, get_frame_id (this_frame->next)))
|
&& 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.
|
/* 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
|
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"));
|
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 */
|
extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
|
||||||
|
|
||||||
static struct cmd_list_element *set_backtrace_cmdlist;
|
static struct cmd_list_element *set_backtrace_cmdlist;
|
||||||
|
|
44
gdb/frame.h
44
gdb/frame.h
|
@ -394,6 +394,50 @@ enum frame_type
|
||||||
};
|
};
|
||||||
extern enum frame_type get_frame_type (struct frame_info *);
|
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
|
/* Unwind the stack frame so that the value of REGNUM, in the previous
|
||||||
(up, older) frame is returned. If VALUEP is NULL, don't
|
(up, older) frame is returned. If VALUEP is NULL, don't
|
||||||
fetch/compute the value. Instead just return the location of the
|
fetch/compute the value. Instead just return the location of the
|
||||||
|
|
26
gdb/stack.c
26
gdb/stack.c
|
@ -923,6 +923,16 @@ frame_info (char *addr_exp, int from_tty)
|
||||||
deprecated_print_address_numeric (frame_pc_unwind (fi), 1, gdb_stdout);
|
deprecated_print_address_numeric (frame_pc_unwind (fi), 1, gdb_stdout);
|
||||||
printf_filtered ("\n");
|
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)
|
if (calling_frame_info)
|
||||||
{
|
{
|
||||||
printf_filtered (" called by frame at ");
|
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)
|
if (get_next_frame (fi) || calling_frame_info)
|
||||||
puts_filtered ("\n");
|
puts_filtered ("\n");
|
||||||
|
|
||||||
if (s)
|
if (s)
|
||||||
printf_filtered (" source language %s.\n",
|
printf_filtered (" source language %s.\n",
|
||||||
language_str (s->language));
|
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);
|
print_frame_info (fi, 1, LOCATION, 1);
|
||||||
if (show_locals)
|
if (show_locals)
|
||||||
print_frame_local_vars (fi, 1, gdb_stdout);
|
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 we've stopped before the end, mention that. */
|
||||||
if (fi && from_tty)
|
if (fi && from_tty)
|
||||||
printf_filtered (_("(More stack frames follow...)\n"));
|
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
|
struct backtrace_command_args
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue