2003-01-21 Andrew Cagney <ac131313@redhat.com>

* frame.h (FRAME_OBSTACK_ZALLOC): Define.
	* blockframe.c (backtrace_below_main): Move to "frame.c".
	(frame_chain_valid): Delete check for backtrace_below_main.
	(_initialize_blockframe): Delete initialization, move ``set
	backtrace-below-main'' command to "frame.c".
	(do_flush_frames_sfunc): Delete function.
	* frame.c: Include "command.h" and "gdbcmd.h".
	(frame_type_from_pc): New function.
	(create_new_frame): Use frame_type_from_pc.
	(legacy_get_prev_frame): New function.
	(get_prev_frame): Rewrite.  When an old style frame, call
	legacy_get_prev_frame.  Otherwize, unwind the PC first.
	(_initialize_frame): Add ``set backtrace-below-main'' command.
	* Makefile.in (frame.o): Update dependencies.
This commit is contained in:
Andrew Cagney 2003-01-21 19:32:42 +00:00
parent dd1e43b69f
commit eb4f72c5f9
5 changed files with 230 additions and 106 deletions

View file

@ -1,3 +1,20 @@
2003-01-21 Andrew Cagney <ac131313@redhat.com>
* frame.h (FRAME_OBSTACK_ZALLOC): Define.
* blockframe.c (backtrace_below_main): Move to "frame.c".
(frame_chain_valid): Delete check for backtrace_below_main.
(_initialize_blockframe): Delete initialization, move ``set
backtrace-below-main'' command to "frame.c".
(do_flush_frames_sfunc): Delete function.
* frame.c: Include "command.h" and "gdbcmd.h".
(frame_type_from_pc): New function.
(create_new_frame): Use frame_type_from_pc.
(legacy_get_prev_frame): New function.
(get_prev_frame): Rewrite. When an old style frame, call
legacy_get_prev_frame. Otherwize, unwind the PC first.
(_initialize_frame): Add ``set backtrace-below-main'' command.
* Makefile.in (frame.o): Update dependencies.
2003-01-19 Andrew Cagney <ac131313@redhat.com>
* config/pa/tm-hppa.h (DEPRECATED_DO_REGISTERS_INFO): Rename

View file

@ -1690,7 +1690,7 @@ fork-child.o: fork-child.c $(defs_h) $(gdb_string_h) $(frame_h) \
frame.o: frame.c $(defs_h) $(frame_h) $(target_h) $(value_h) $(inferior_h) \
$(regcache_h) $(gdb_assert_h) $(gdb_string_h) $(builtin_regs_h) \
$(gdb_obstack_h) $(dummy_frame_h) $(gdbcore_h) $(annotate_h) \
$(language_h) $(frame_unwind_h)
$(language_h) $(frame_unwind_h) $(command_h) $(gdbcmd_h)
frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_h) \
$(gdb_assert_h) $(dummy_frame_h) $(legacy_frame_h)
frv-tdep.o: frv-tdep.c $(defs_h) $(inferior_h) $(symfile_h) $(gdbcore_h) \

View file

@ -39,10 +39,6 @@
#include "command.h"
#include "gdbcmd.h"
/* Flag to indicate whether backtraces should stop at main. */
static int backtrace_below_main;
/* Prototypes for exported functions. */
void _initialize_blockframe (void);
@ -697,53 +693,9 @@ frame_chain_valid (CORE_ADDR fp, struct frame_info *fi)
if (inside_entry_file (frame_pc_unwind (fi)))
return 0;
/* If we want backtraces to stop at main, and we're inside main, then it
isn't valid. */
if (!backtrace_below_main && inside_main_func (get_frame_pc (fi)))
return 0;
/* If the architecture has a custom FRAME_CHAIN_VALID, call it now. */
if (FRAME_CHAIN_VALID_P ())
return FRAME_CHAIN_VALID (fp, fi);
return 1;
}
void
do_flush_frames_sfunc (char *args, int from_tty, struct cmd_list_element *c)
{
int saved_level;
struct frame_info *cur_frame;
if (! target_has_stack)
return;
saved_level = frame_relative_level (get_selected_frame ());
flush_cached_frames ();
cur_frame = find_relative_frame (get_current_frame (), &saved_level);
select_frame (cur_frame);
/* If we were below main and backtrace-below-main was turned off,
SAVED_LEVEL will be non-zero. CUR_FRAME will point to main.
Accept this but print the new frame. */
if (saved_level != 0)
print_stack_frame (get_selected_frame (), -1, 0);
}
void
_initialize_blockframe (void)
{
add_setshow_boolean_cmd ("backtrace-below-main", class_obscure,
&backtrace_below_main,
"Set whether backtraces should continue past \"main\".\n"
"Normally the caller of \"main\" is not of interest, so GDB will terminate\n"
"the backtrace at \"main\". Set this variable if you need to see the rest\n"
"of the stack trace.",
"Show whether backtraces should continue past \"main\".\n"
"Normally the caller of \"main\" is not of interest, so GDB will terminate\n"
"the backtrace at \"main\". Set this variable if you need to see the rest\n"
"of the stack trace.",
do_flush_frames_sfunc, NULL, &setlist, &showlist);
}

View file

@ -35,6 +35,12 @@
#include "annotate.h"
#include "language.h"
#include "frame-unwind.h"
#include "command.h"
#include "gdbcmd.h"
/* Flag to indicate whether backtraces should stop at main. */
static int backtrace_below_main;
/* Return a frame uniq ID that can be used to, later, re-find the
frame. */
@ -843,6 +849,29 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
deprecated_read_register_gen (regnum, raw_buffer);
}
/* Determine the frame's type based on its PC. */
static enum frame_type
frame_type_from_pc (CORE_ADDR pc)
{
/* FIXME: cagney/2002-11-24: Can't yet directly call
pc_in_dummy_frame() as some architectures don't set
PC_IN_CALL_DUMMY() to generic_pc_in_call_dummy() (remember the
latter is implemented by simply calling pc_in_dummy_frame). */
if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
&& DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
return DUMMY_FRAME;
else
{
char *name;
find_pc_partial_function (pc, &name, NULL, NULL);
if (PC_IN_SIGTRAMP (pc, name))
return SIGTRAMP_FRAME;
else
return NORMAL_FRAME;
}
}
/* Create an arbitrary (i.e. address specified by user) or innermost frame.
Always returns a non-NULL value. */
@ -850,36 +879,12 @@ struct frame_info *
create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
{
struct frame_info *fi;
enum frame_type type;
fi = frame_obstack_zalloc (sizeof (struct frame_info));
fi->frame = addr;
fi->pc = pc;
/* NOTE: cagney/2002-11-18: The code segments, found in
create_new_frame and get_prev_frame(), that initializes the
frames type is subtly different. The latter only updates ->type
when it encounters a SIGTRAMP_FRAME or DUMMY_FRAME. This stops
get_prev_frame() overriding the frame's type when the INIT code
has previously set it. This is really somewhat bogus. The
initialization, as seen in create_new_frame(), should occur
before the INIT function has been called. */
if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
&& (DEPRECATED_PC_IN_CALL_DUMMY_P ()
? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
: pc_in_dummy_frame (pc)))
/* NOTE: cagney/2002-11-11: Does this even occure? */
type = DUMMY_FRAME;
else
{
char *name;
find_pc_partial_function (pc, &name, NULL, NULL);
if (PC_IN_SIGTRAMP (fi->pc, name))
type = SIGTRAMP_FRAME;
else
type = NORMAL_FRAME;
}
fi->type = type;
fi->type = frame_type_from_pc (pc);
if (INIT_EXTRA_FRAME_INFO_P ())
INIT_EXTRA_FRAME_INFO (0, fi);
@ -927,43 +932,19 @@ reinit_frame_cache (void)
}
}
/* Return a structure containing various interesting information
about the frame that called NEXT_FRAME. Returns NULL
if there is no such frame. */
/* Create the previous frame using the deprecated methods
INIT_EXTRA_INFO, INIT_FRAME_PC and INIT_FRAME_PC_FIRST. */
struct frame_info *
get_prev_frame (struct frame_info *next_frame)
static struct frame_info *
legacy_get_prev_frame (struct frame_info *next_frame)
{
CORE_ADDR address = 0;
struct frame_info *prev;
int fromleaf;
/* Return the inner-most frame, when the caller passes in NULL. */
/* NOTE: cagney/2002-11-09: Not sure how this would happen. The
caller should have previously obtained a valid frame using
get_selected_frame() and then called this code - only possibility
I can think of is code behaving badly. */
if (next_frame == NULL)
{
/* NOTE: cagney/2002-11-09: There was a code segment here that
would error out when CURRENT_FRAME was NULL. The comment
that went with it made the claim ...
``This screws value_of_variable, which just wants a nice
clean NULL return from block_innermost_frame if there are no
frames. I don't think I've ever seen this message happen
otherwise. And returning NULL here is a perfectly legitimate
thing to do.''
Per the above, this code shouldn't even be called with a NULL
NEXT_FRAME. */
return current_frame;
}
/* Only try to do the unwind once. */
if (next_frame->prev_p)
return next_frame->prev;
next_frame->prev_p = 1;
/* This code only works on normal frames. A sentinel frame, where
the level is -1, should never reach this code. */
gdb_assert (next_frame->level >= 0);
/* On some machines it is possible to call a function without
setting up a stack frame for it. On these machines, we
@ -974,7 +955,7 @@ get_prev_frame (struct frame_info *next_frame)
/* Still don't want to worry about this except on the innermost
frame. This macro will set FROMLEAF if NEXT_FRAME is a frameless
function invocation. */
if (next_frame->next == NULL)
if (next_frame->level == 0)
/* FIXME: 2002-11-09: Frameless functions can occure anywhere in
the frame chain, not just the inner most frame! The generic,
per-architecture, frame code should handle this and the below
@ -1166,6 +1147,162 @@ get_prev_frame (struct frame_info *next_frame)
return prev;
}
/* Return a structure containing various interesting information
about the frame that called NEXT_FRAME. Returns NULL
if there is no such frame. */
struct frame_info *
get_prev_frame (struct frame_info *next_frame)
{
struct frame_info *prev_frame;
/* Return the inner-most frame, when the caller passes in NULL. */
/* NOTE: cagney/2002-11-09: Not sure how this would happen. The
caller should have previously obtained a valid frame using
get_selected_frame() and then called this code - only possibility
I can think of is code behaving badly.
NOTE: cagney/2003-01-10: Talk about code behaving badly. Check
block_innermost_frame(). It does the sequence: frame = NULL;
while (1) { frame = get_prev_frame (frame); .... }. Ulgh! Why
it couldn't be written better, I don't know.
NOTE: cagney/2003-01-11: I suspect what is happening is
block_innermost_frame() is, when the target has no state
(registers, memory, ...), still calling this function. The
assumption being that this function will return NULL indicating
that a frame isn't possible, rather than checking that the target
has state and then calling get_current_frame() and
get_prev_frame(). This is a guess mind. */
if (next_frame == NULL)
{
/* NOTE: cagney/2002-11-09: There was a code segment here that
would error out when CURRENT_FRAME was NULL. The comment
that went with it made the claim ...
``This screws value_of_variable, which just wants a nice
clean NULL return from block_innermost_frame if there are no
frames. I don't think I've ever seen this message happen
otherwise. And returning NULL here is a perfectly legitimate
thing to do.''
Per the above, this code shouldn't even be called with a NULL
NEXT_FRAME. */
return current_frame;
}
/* There is always a frame. If this assertion fails, suspect that
something should be calling get_selected_frame() or
get_current_frame(). */
gdb_assert (next_frame != NULL);
if (next_frame->level >= 0
&& !backtrace_below_main
&& inside_main_func (get_frame_pc (next_frame)))
/* Don't unwind past main(), bug always unwind the sentinel frame.
Note, this is done _before_ the frame has been marked as
previously unwound. That way if the user later decides to
allow unwinds past main(), that just happens. */
return NULL;
/* Only try to do the unwind once. */
if (next_frame->prev_p)
return next_frame->prev;
next_frame->prev_p = 1;
/* If we're inside the entry file, it isn't valid. */
/* NOTE: drow/2002-12-25: should there be a way to disable this
check? It assumes a single small entry file, and the way some
debug readers (e.g. dbxread) figure out which object is the
entry file is somewhat hokey. */
/* NOTE: cagney/2003-01-10: If there is a way of disabling this test
then it should probably be moved to before the ->prev_p test,
above. */
if (inside_entry_file (get_frame_pc (next_frame)))
return NULL;
/* If any of the old frame initialization methods are around, use
the legacy get_prev_frame method. Just don't try to unwind a
sentinel frame using that method - it doesn't work. All sentinal
frames use the new unwind code. */
if ((DEPRECATED_INIT_FRAME_PC_P ()
|| DEPRECATED_INIT_FRAME_PC_FIRST_P ()
|| INIT_EXTRA_FRAME_INFO_P ())
&& next_frame->level >= 0)
return legacy_get_prev_frame (next_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
definition, recursive). Try to prevent it.
There is no reason to worry about memory leaks, should the
remainder of the function fail. The allocated memory will be
quickly reclaimed when the frame cache is flushed, and the `we've
been here before' check above will stop repeated memory
allocation calls. */
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev_frame->level = next_frame->level + 1;
/* Try to unwind the PC. If that doesn't work, assume we've reached
the oldest frame and simply return. Is there a better sentinal
value? The unwound PC value is then used to initialize the new
previous frame's type.
Note that the pc-unwind is intentionally performed before the
frame chain. This is ok since, for old targets, both
frame_pc_unwind (nee, FRAME_SAVED_PC) and FRAME_CHAIN()) assume
NEXT_FRAME's data structures have already been initialized (using
INIT_EXTRA_FRAME_INFO) and hence the call order doesn't matter.
By unwinding the PC first, it becomes possible to, in the case of
a dummy frame, avoid also unwinding the frame ID. This is
because (well ignoring the PPC) a dummy frame can be located
using NEXT_FRAME's frame ID. */
prev_frame->pc = frame_pc_unwind (next_frame);
if (prev_frame->pc == 0)
/* The allocated PREV_FRAME will be reclaimed when the frame
obstack is next purged. */
return NULL;
prev_frame->type = frame_type_from_pc (prev_frame->pc);
/* Set the unwind functions based on that identified PC. */
prev_frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
prev_frame->pc);
/* FIXME: cagney/2003-01-13: A dummy frame doesn't need to unwind
the frame ID because the frame ID comes from the previous frame.
The other frames do though. True? */
{
/* FIXME: cagney/2002-12-18: Instead of this hack, should just
save the frame ID directly. */
struct frame_id id = frame_id_unwind (next_frame);
if (!frame_id_p (id))
return NULL;
prev_frame->frame = id.base;
}
/* Link it in. */
next_frame->prev = prev_frame;
prev_frame->next = next_frame;
/* FIXME: cagney/2002-01-19: This call will go away. Instead of
initializing extra info, all frames will use the frame_cache
(passed to the unwind functions) to store additional frame info.
Unfortunatly legacy targets can't use legacy_get_prev_frame() to
unwind the sentinel frame and, consequently, are forced to take
this code path and rely on the below call to INIT_EXTR_FRAME_INFO
to initialize the inner-most frame. */
if (INIT_EXTRA_FRAME_INFO_P ())
{
gdb_assert (prev_frame->level == 0);
INIT_EXTRA_FRAME_INFO (0, prev_frame);
}
return prev_frame;
}
CORE_ADDR
get_frame_pc (struct frame_info *frame)
{
@ -1360,4 +1497,21 @@ void
_initialize_frame (void)
{
obstack_init (&frame_cache_obstack);
/* FIXME: cagney/2003-01-19: This command needs a rename. Suggest
`set backtrace {past,beyond,...}-main'. Also suggest adding `set
backtrace ...-start' to control backtraces past start. The
problem with `below' is that it stops the `up' command. */
add_setshow_boolean_cmd ("backtrace-below-main", class_obscure,
&backtrace_below_main, "\
Set whether backtraces should continue past \"main\".\n\
Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
the backtrace at \"main\". Set this variable if you need to see the rest\n\
of the stack trace.", "\
Show whether backtraces should continue past \"main\".\n\
Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
the backtrace at \"main\". Set this variable if you need to see the rest\n\
of the stack trace.",
NULL, NULL, &setlist, &showlist);
}

View file

@ -445,6 +445,7 @@ enum print_what
allocate memory using this method. */
extern void *frame_obstack_zalloc (unsigned long size);
#define FRAME_OBSTACK_ZALLOC(TYPE) ((TYPE *) frame_obstack_zalloc (sizeof (TYPE)))
/* If FRAME_CHAIN_VALID returns zero it means that the given frame
is the outermost one and has no caller. */