#include "command.h"
#include "gdbcmd.h"
#include "observer.h"
+#include "objfiles.h"
+#include "exceptions.h"
static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
/* Flag to control debugging. */
static int frame_debug;
+static void
+show_frame_debug (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Frame debugging is %s.\n"), value);
+}
/* Flag to indicate whether backtraces should stop at main et.al. */
static int backtrace_past_main;
+static void
+show_backtrace_past_main (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("\
+Whether backtraces should continue past \"main\" is %s.\n"),
+ value);
+}
+
+static int backtrace_past_entry;
+static void
+show_backtrace_past_entry (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("\
+Whether backtraces should continue past the entry point of a program is %s.\n"),
+ value);
+}
+
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)
+{
+ fprintf_filtered (file, _("\
+An upper bound on the number of backtrace levels is %s.\n"),
+ value);
+}
+
static void
fprint_field (struct ui_file *file, const char *name, int p, CORE_ADDR addr)
if (!this_frame->prev_pc.p)
{
CORE_ADDR pc;
- if (gdbarch_unwind_pc_p (current_gdbarch))
+ if (this_frame->unwind == NULL)
+ this_frame->unwind
+ = frame_unwind_find_by_frame (this_frame->next,
+ &this_frame->prologue_cache);
+ if (this_frame->unwind->prev_pc != NULL)
+ /* A per-frame unwinder, prefer it. */
+ pc = this_frame->unwind->prev_pc (this_frame->next,
+ &this_frame->prologue_cache);
+ else if (gdbarch_unwind_pc_p (current_gdbarch))
{
/* The right way. The `pure' way. The one true way. This
method depends solely on the register-unwind code to
different ways that a PC could be unwound. */
pc = gdbarch_unwind_pc (current_gdbarch, this_frame);
}
- else if (this_frame->level < 0)
- {
- /* FIXME: cagney/2003-03-06: Old code and a sentinel
- frame. Do like was always done. Fetch the PC's value
- directly from the global registers array (via read_pc).
- This assumes that this frame belongs to the current
- global register cache. The assumption is dangerous. */
- pc = read_pc ();
- }
else
- internal_error (__FILE__, __LINE__, "No gdbarch_unwind_pc method");
+ internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
this_frame->prev_pc.value = pc;
this_frame->prev_pc.p = 1;
if (frame_debug)
}
static int
-do_frame_unwind_register (void *src, int regnum, void *buf)
+do_frame_register_read (void *src, int regnum, void *buf)
{
- frame_unwind_register (src, regnum, buf);
+ frame_register_read (src, regnum, buf);
return 1;
}
+struct regcache *
+frame_save_as_regcache (struct frame_info *this_frame)
+{
+ struct regcache *regcache = regcache_xmalloc (current_gdbarch);
+ struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
+ regcache_save (regcache, do_frame_register_read, this_frame);
+ discard_cleanups (cleanups);
+ return regcache;
+}
+
void
frame_pop (struct frame_info *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
at the same time writing new values into that same cache. */
- struct regcache *scratch = regcache_xmalloc (current_gdbarch);
+ struct regcache *scratch
+ = frame_save_as_regcache (get_prev_frame_1 (this_frame));
struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch);
- regcache_save (scratch, do_frame_unwind_register, this_frame);
/* FIXME: cagney/2003-03-16: It should be possible to tell the
target's register cache that it is about to be hit with a burst
CORE_ADDR addr;
frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
if (optim)
- error ("Attempt to assign to a value that was optimized out.");
+ error (_("Attempt to assign to a value that was optimized out."));
switch (lval)
{
case lval_memory:
regcache_cooked_write (current_regcache, realnum, buf);
break;
default:
- error ("Attempt to assign to an unmodifiable value.");
+ error (_("Attempt to assign to an unmodifiable value."));
}
}
explicitly checks that ``print $pc'' with no registers prints "No
registers". */
if (!target_has_registers)
- error ("No registers.");
+ error (_("No registers."));
if (!target_has_stack)
- error ("No stack.");
+ error (_("No stack."));
if (!target_has_memory)
- error ("No memory.");
+ error (_("No memory."));
if (current_frame == NULL)
{
struct frame_info *sentinel_frame =
create_sentinel_frame (current_regcache);
if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
- NULL, RETURN_MASK_ERROR) != 0)
+ RETURN_MASK_ERROR) != 0)
{
/* Oops! Fake a current frame? Is this useful? It has a PC
of zero, for instance. */
thrown. */
struct frame_info *
-get_selected_frame (void)
+get_selected_frame (const char *message)
{
if (deprecated_selected_frame == NULL)
- /* Hey! Don't trust this. It should really be re-finding the
- last selected frame of the currently selected thread. This,
- though, is better than nothing. */
- select_frame (get_current_frame ());
+ {
+ if (message != NULL && (!target_has_registers
+ || !target_has_stack
+ || !target_has_memory))
+ error (("%s"), message);
+ /* Hey! Don't trust this. It should really be re-finding the
+ last selected frame of the currently selected thread. This,
+ though, is better than nothing. */
+ select_frame (get_current_frame ());
+ }
/* There is always a frame. */
gdb_assert (deprecated_selected_frame != NULL);
return deprecated_selected_frame;
{
if (!target_has_registers || !target_has_stack || !target_has_memory)
return NULL;
- return get_selected_frame ();
+ return get_selected_frame (NULL);
}
/* Select frame FI (or NULL - to invalidate the current 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?)");
+ error (_("Previous frame inner to this frame (corrupt stack?)"));
/* 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?)");
+ error (_("Previous frame identical to this frame (corrupt stack?)"));
/* 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
}
}
+/* Is this (non-sentinel) frame in the "main"() function? */
+
+static int
+inside_main_func (struct frame_info *this_frame)
+{
+ struct minimal_symbol *msymbol;
+ CORE_ADDR maddr;
+
+ if (symfile_objfile == 0)
+ return 0;
+ msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile);
+ if (msymbol == NULL)
+ return 0;
+ /* Make certain that the code, and not descriptor, address is
+ returned. */
+ maddr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+ SYMBOL_VALUE_ADDRESS (msymbol),
+ ¤t_target);
+ return maddr == get_frame_func (this_frame);
+}
+
+/* Test whether THIS_FRAME is inside the process entry point function. */
+
+static int
+inside_entry_func (struct frame_info *this_frame)
+{
+ return (get_frame_func (this_frame) == entry_point_address ());
+}
+
/* Return a structure containing various interesting information about
the frame that called THIS_FRAME. Returns NULL if there is entier
no such frame or the frame fails any of a set of target-independent
get_current_frame(). */
gdb_assert (this_frame != NULL);
- /* Make sure we pass an address within THIS_FRAME's code block to
- inside_main_func(). Otherwise, we might stop unwinding at a
- function which has a call instruction as its last instruction if
- that function immediately precedes main(). */
+ /* tausq/2004-12-07: Dummy frames are skipped because it doesn't make much
+ sense to stop unwinding at a dummy frame. One place where a dummy
+ frame may have an address "inside_main_func" is on HPUX. On HPUX, the
+ pcsqh register (space register for the instruction at the head of the
+ instruction queue) cannot be written directly; the only way to set it
+ is to branch to code that is in the target space. In order to implement
+ frame dummies on HPUX, the called function is made to jump back to where
+ the inferior was when the user function was called. If gdb was inside
+ the main function when we created the dummy frame, the dummy frame will
+ point inside the main function. */
if (this_frame->level >= 0
+ && get_frame_type (this_frame) != DUMMY_FRAME
&& !backtrace_past_main
- && inside_main_func (get_frame_address_in_block (this_frame)))
- /* Don't unwind past main(), but 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. */
+ && inside_main_func (this_frame))
+ /* Don't unwind past main(). Note, this is done _before_ the
+ frame has been marked as previously unwound. That way if the
+ user later decides to enable unwinds past main(), that will
+ automatically happen. */
{
frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside main func");
return NULL;
if (this_frame->level > backtrace_limit)
{
- error ("Backtrace limit of %d exceeded", backtrace_limit);
+ error (_("Backtrace limit of %d exceeded"), backtrace_limit);
}
/* If we're already inside the entry function for the main objfile,
dummy frame PCs typically land in the entry func. Don't apply
this test to the sentinel frame. Sentinel frames should always
be allowed to unwind. */
- /* NOTE: cagney/2003-02-25: Don't enable until someone has found
- hard evidence that this is needed. */
/* NOTE: cagney/2003-07-07: Fixed a bug in inside_main_func() -
wasn't checking for "main" in the minimal symbols. With that
fixed asm-source tests now stop in "main" instead of halting the
I guess) to determine the address range of the start function.
That should provide a far better stopper than the current
heuristics. */
- /* NOTE: cagney/2003-07-15: Need to add a "set backtrace
- beyond-entry-func" command so that this can be selectively
- disabled. */
- if (0
-#if 0
- && backtrace_beyond_entry_func
-#endif
- && this_frame->unwind->type != DUMMY_FRAME && this_frame->level >= 0
+ /* NOTE: tausq/2004-10-09: this is needed if, for example, the compiler
+ applied tail-call optimizations to main so that a function called
+ from main returns directly to the caller of main. Since we don't
+ stop at main, we should at least stop at the entry point of the
+ application. */
+ if (!backtrace_past_entry
+ && get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0
&& inside_entry_func (this_frame))
{
frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside entry func");
return NULL;
}
+ /* Assume that the only way to get a zero PC is through something
+ like a SIGSEGV or a dummy frame, and hence that NORMAL frames
+ will never unwind a zero PC. */
+ if (this_frame->level > 0
+ && get_frame_type (this_frame) == NORMAL_FRAME
+ && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
+ && get_frame_pc (this_frame) == 0)
+ {
+ frame_debug_got_null_frame (gdb_stdlog, this_frame, "zero PC");
+ return NULL;
+ }
+
return get_prev_frame_1 (this_frame);
}
frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp);
return sp;
}
- internal_error (__FILE__, __LINE__, "Missing unwind SP method");
+ internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
}
extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
observer_attach_target_changed (frame_observer_target_changed);
- add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, "\
+ add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
Set backtrace specific variables.\n\
-Configure backtrace variables such as the backtrace limit",
+Configure backtrace variables such as the backtrace limit"),
&set_backtrace_cmdlist, "set backtrace ",
0/*allow-unknown*/, &setlist);
- add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, "\
+ add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, _("\
Show backtrace specific variables\n\
-Show backtrace variables such as the backtrace limit",
+Show backtrace variables such as the backtrace limit"),
&show_backtrace_cmdlist, "show backtrace ",
0/*allow-unknown*/, &showlist);
add_setshow_boolean_cmd ("past-main", class_obscure,
- &backtrace_past_main, "\
-Set whether backtraces should continue past \"main\".", "\
-Show whether backtraces should continue past \"main\".", "\
+ &backtrace_past_main, _("\
+Set whether backtraces should continue past \"main\"."), _("\
+Show whether backtraces should continue past \"main\"."), _("\
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.", "\
-Whether backtraces should continue past \"main\" is %s.",
- NULL, NULL, &set_backtrace_cmdlist,
+of the stack trace."),
+ NULL,
+ show_backtrace_past_main,
+ &set_backtrace_cmdlist,
+ &show_backtrace_cmdlist);
+
+ add_setshow_boolean_cmd ("past-entry", class_obscure,
+ &backtrace_past_entry, _("\
+Set whether backtraces should continue past the entry point of a program."),
+ _("\
+Show whether backtraces should continue past the entry point of a program."),
+ _("\
+Normally there are no callers beyond the entry point of a program, so GDB\n\
+will terminate the backtrace there. Set this variable if you need to see \n\
+the rest of the stack trace."),
+ NULL,
+ show_backtrace_past_entry,
+ &set_backtrace_cmdlist,
&show_backtrace_cmdlist);
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.", "\
+ &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.", "\
-An upper bound on the number of backtrace levels is %s.",
- NULL, NULL, &set_backtrace_cmdlist,
+Zero is unlimited."),
+ NULL,
+ show_backtrace_limit,
+ &set_backtrace_cmdlist,
&show_backtrace_cmdlist);
/* Debug this files internals. */
- deprecated_add_show_from_set
- (add_set_cmd ("frame", class_maintenance, var_zinteger,
- &frame_debug, "Set frame debugging.\n\
-When non-zero, frame specific internal debugging is enabled.", &setdebuglist),
- &showdebuglist);
+ add_setshow_zinteger_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);
}