/* Cache and manage frames for GDB, the GNU debugger.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "tracepoint.h"
#include "hashtab.h"
#include "valprint.h"
+#include "cli/cli-option.h"
/* The sentinel frame terminates the innermost end of the frame chain.
If unwound, it returns the information needed to construct an
static struct frame_info *sentinel_frame;
+/* The values behind the global "set backtrace ..." settings. */
+set_backtrace_options user_set_backtrace_options;
+
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);
/* Cached copy of the previous frame's resume address. */
struct {
enum cached_copy_status status;
+ /* Did VALUE require unmasking when being read. */
+ bool masked;
CORE_ADDR value;
} prev_pc;
const char *stop_string;
};
+/* See frame.h. */
+
+void
+set_frame_previous_pc_masked (struct frame_info *frame)
+{
+ frame->prev_pc.masked = true;
+}
+
+/* See frame.h. */
+
+bool
+get_frame_pc_masked (const struct frame_info *frame)
+{
+ gdb_assert (frame->next != nullptr);
+ gdb_assert (frame->next->prev_pc.status == CC_VALUE);
+
+ return frame->next->prev_pc.masked;
+}
+
/* 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
fprintf_filtered (file, _("Frame debugging is %s.\n"), value);
}
-/* Flag to indicate whether backtraces should stop at main et.al. */
+/* Implementation of "show backtrace past-main". */
-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)
value);
}
-static int backtrace_past_entry;
+/* Implementation of "show backtrace past-entry". */
+
static void
show_backtrace_past_entry (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
value);
}
-static unsigned int backtrace_limit = UINT_MAX;
+/* Implementation of "show backtrace limit". */
+
static void
show_backtrace_limit (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
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));
+ {
+ fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_pc.value));
+ if (fi->next->prev_pc.masked)
+ fprintf_unfiltered (file, "[PAC]");
+ }
else if (fi->next->prev_pc.status == CC_NOT_SAVED)
val_print_not_saved (file);
else if (fi->next->prev_pc.status == CC_UNAVAILABLE)
if special addresses are different, the frames are different. */
eq = 0;
else if (l.artificial_depth != r.artificial_depth)
- /* If artifical depths are different, the frames must be different. */
+ /* If artificial depths are different, the frames must be different. */
eq = 0;
else
/* Frames are equal. */
{
if (this_frame->prev_pc.status == CC_UNKNOWN)
{
- if (gdbarch_unwind_pc_p (frame_unwind_arch (this_frame)))
+ struct gdbarch *prev_gdbarch;
+ CORE_ADDR pc = 0;
+ int pc_p = 0;
+
+ /* The right way. The `pure' way. The one true way. This
+ method depends solely on the register-unwind code to
+ determine the value of registers in THIS frame, and hence
+ the value of this frame's PC (resume address). A typical
+ implementation is no more than:
+
+ frame_unwind_register (this_frame, ISA_PC_REGNUM, buf);
+ return extract_unsigned_integer (buf, size of ISA_PC_REGNUM);
+
+ Note: this method is very heavily dependent on a correct
+ register-unwind implementation, it pays to fix that
+ method first; this method is frame type agnostic, since
+ it only deals with register values, it works with any
+ frame. This is all in stark contrast to the old
+ FRAME_SAVED_PC which would try to directly handle all the
+ different ways that a PC could be unwound. */
+ prev_gdbarch = frame_unwind_arch (this_frame);
+
+ try
{
- struct gdbarch *prev_gdbarch;
- CORE_ADDR pc = 0;
- int pc_p = 0;
-
- /* The right way. The `pure' way. The one true way. This
- method depends solely on the register-unwind code to
- determine the value of registers in THIS frame, and hence
- the value of this frame's PC (resume address). A typical
- implementation is no more than:
-
- frame_unwind_register (this_frame, ISA_PC_REGNUM, buf);
- return extract_unsigned_integer (buf, size of ISA_PC_REGNUM);
-
- Note: this method is very heavily dependent on a correct
- register-unwind implementation, it pays to fix that
- method first; this method is frame type agnostic, since
- it only deals with register values, it works with any
- frame. This is all in stark contrast to the old
- FRAME_SAVED_PC which would try to directly handle all the
- different ways that a PC could be unwound. */
- prev_gdbarch = frame_unwind_arch (this_frame);
-
- TRY
+ pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
+ pc_p = 1;
+ }
+ catch (const gdb_exception_error &ex)
+ {
+ if (ex.error == NOT_AVAILABLE_ERROR)
{
- pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
- pc_p = 1;
+ 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);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ else if (ex.error == OPTIMIZED_OUT_ERROR)
{
- 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);
- }
- END_CATCH
+ this_frame->prev_pc.status = CC_NOT_SAVED;
- if (pc_p)
- {
- this_frame->prev_pc.value = pc;
- this_frame->prev_pc.status = CC_VALUE;
if (frame_debug)
fprintf_unfiltered (gdb_stdlog,
- "{ frame_unwind_pc (this_frame=%d) "
- "-> %s }\n",
- this_frame->level,
- hex_string (this_frame->prev_pc.value));
+ "{ frame_unwind_pc (this_frame=%d)"
+ " -> <not saved> }\n",
+ this_frame->level);
}
+ else
+ throw;
+ }
+
+ if (pc_p)
+ {
+ this_frame->prev_pc.value = pc;
+ this_frame->prev_pc.status = CC_VALUE;
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ frame_unwind_pc (this_frame=%d) "
+ "-> %s }\n",
+ this_frame->level,
+ hex_string (this_frame->prev_pc.value));
}
- else
- internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
}
if (this_frame->prev_pc.status == CC_VALUE)
return pc;
}
-static enum register_status
-do_frame_register_read (void *src, int regnum, gdb_byte *buf)
-{
- if (!deprecated_frame_register_read ((struct frame_info *) src, regnum, buf))
- return REG_UNAVAILABLE;
- else
- return REG_VALID;
-}
-
std::unique_ptr<readonly_detached_regcache>
frame_save_as_regcache (struct frame_info *this_frame)
{
+ auto cooked_read = [this_frame] (int regnum, gdb_byte *buf)
+ {
+ if (!deprecated_frame_register_read (this_frame, regnum, buf))
+ return REG_UNAVAILABLE;
+ else
+ return REG_VALID;
+ };
+
std::unique_ptr<readonly_detached_regcache> regcache
- (new readonly_detached_regcache (get_frame_arch (this_frame),
- do_frame_register_read, this_frame));
+ (new readonly_detached_regcache (get_frame_arch (this_frame), cooked_read));
return regcache;
}
{
/* Popping a dummy frame involves restoring more than just registers.
dummy_frame_pop does all the work. */
- dummy_frame_pop (get_frame_id (this_frame), inferior_ptid);
+ dummy_frame_pop (get_frame_id (this_frame), inferior_thread ());
return;
}
}
void
-frame_register_unwind (struct frame_info *frame, int regnum,
+frame_register_unwind (frame_info *next_frame, int regnum,
int *optimizedp, int *unavailablep,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *bufferp)
gdb_assert (realnump != NULL);
/* gdb_assert (bufferp != NULL); */
- value = frame_unwind_register_value (frame, regnum);
+ value = frame_unwind_register_value (next_frame, regnum);
gdb_assert (value != NULL);
}
void
-frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf)
+frame_unwind_register (frame_info *next_frame, int regnum, gdb_byte *buf)
{
int optimized;
int unavailable;
int realnum;
enum lval_type lval;
- frame_register_unwind (frame, regnum, &optimized, &unavailable,
+ frame_register_unwind (next_frame, regnum, &optimized, &unavailable,
&lval, &addr, &realnum, buf);
if (optimized)
}
struct value *
-frame_unwind_register_value (struct frame_info *frame, int regnum)
+frame_unwind_register_value (frame_info *next_frame, int regnum)
{
struct gdbarch *gdbarch;
struct value *value;
- gdb_assert (frame != NULL);
- gdbarch = frame_unwind_arch (frame);
+ gdb_assert (next_frame != NULL);
+ gdbarch = frame_unwind_arch (next_frame);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog,
"{ frame_unwind_register_value "
"(frame=%d,regnum=%d(%s),...) ",
- frame->level, regnum,
+ next_frame->level, regnum,
user_reg_map_regnum_to_name (gdbarch, regnum));
}
/* Find the unwinder. */
- if (frame->unwind == NULL)
- frame_unwind_find_by_frame (frame, &frame->prologue_cache);
+ if (next_frame->unwind == NULL)
+ frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache);
/* Ask this frame to unwind its register. */
- value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum);
+ value = next_frame->unwind->prev_register (next_frame,
+ &next_frame->prologue_cache,
+ regnum);
if (frame_debug)
{
}
LONGEST
-frame_unwind_register_signed (struct frame_info *frame, int regnum)
+frame_unwind_register_signed (frame_info *next_frame, int regnum)
{
- struct gdbarch *gdbarch = frame_unwind_arch (frame);
+ struct gdbarch *gdbarch = frame_unwind_arch (next_frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int size = register_size (gdbarch, regnum);
- struct value *value = frame_unwind_register_value (frame, regnum);
+ struct value *value = frame_unwind_register_value (next_frame, regnum);
gdb_assert (value != NULL);
}
ULONGEST
-frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
+frame_unwind_register_unsigned (frame_info *next_frame, int regnum)
{
- struct gdbarch *gdbarch = frame_unwind_arch (frame);
+ struct gdbarch *gdbarch = frame_unwind_arch (next_frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int size = register_size (gdbarch, regnum);
- struct value *value = frame_unwind_register_value (frame, regnum);
+ struct value *value = frame_unwind_register_value (next_frame, regnum);
gdb_assert (value != NULL);
/* Ensure that we will not read beyond the end of the register file.
This can only ever happen if the debug information is bad. */
maxsize = -offset;
- numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+ numregs = gdbarch_num_cooked_regs (gdbarch);
for (i = regnum; i < numregs; i++)
{
int thissize = register_size (gdbarch, i);
if (get_traceframe_number () < 0)
{
/* No current inferior, no frame. */
- if (ptid_equal (inferior_ptid, null_ptid))
+ if (inferior_ptid == null_ptid)
return 0;
+ thread_info *tp = inferior_thread ();
/* Don't try to read from a dead thread. */
- if (is_exited (inferior_ptid))
+ if (tp->state == THREAD_EXITED)
return 0;
/* ... or from a spinning thread. */
- if (is_executing (inferior_ptid))
+ if (tp->executing)
return 0;
}
if (prev_frame->level == 0)
return prev_frame;
- TRY
+ try
{
compute_frame_id (prev_frame);
if (!frame_stash_add (prev_frame))
prev_frame = NULL;
}
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (const gdb_exception &ex)
{
prev_frame->next = NULL;
this_frame->prev = NULL;
- throw_exception (ex);
+ throw;
}
- END_CATCH
return prev_frame;
}
{
struct frame_info *prev_frame = NULL;
- TRY
+ try
{
prev_frame = get_prev_frame_always_1 (this_frame);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error == MEMORY_ERROR)
{
Allocate using stack local STOP_STRING then assign the
pointer to the frame, this allows the STOP_STRING on the
frame to be of type 'const char *'. */
- size = strlen (ex.message) + 1;
+ size = ex.message->size () + 1;
stop_string = (char *) frame_obstack_zalloc (size);
- memcpy (stop_string, ex.message, size);
+ memcpy (stop_string, ex.what (), size);
this_frame->stop_string = stop_string;
}
prev_frame = NULL;
}
else
- throw_exception (ex);
+ throw;
}
- END_CATCH
return prev_frame;
}
point inside the main function. */
if (this_frame->level >= 0
&& get_frame_type (this_frame) == NORMAL_FRAME
- && !backtrace_past_main
+ && !user_set_backtrace_options.backtrace_past_main
&& frame_pc_p
&& inside_main_func (this_frame))
/* Don't unwind past main(). Note, this is done _before_ the
being 1-based and the level being 0-based, and the other accounts for
the level of the new frame instead of the level of the current
frame. */
- if (this_frame->level + 2 > backtrace_limit)
+ if (this_frame->level + 2 > user_set_backtrace_options.backtrace_limit)
{
frame_debug_got_null_frame (this_frame, "backtrace limit exceeded");
return NULL;
application. */
if (this_frame->level >= 0
&& get_frame_type (this_frame) == NORMAL_FRAME
- && !backtrace_past_entry
+ && !user_set_backtrace_options.backtrace_past_entry
&& frame_pc_p
&& inside_entry_func (this_frame))
{
gdb_assert (frame->next != NULL);
- TRY
+ try
{
*pc = frame_unwind_pc (frame->next);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error == NOT_AVAILABLE_ERROR)
return 0;
else
- throw_exception (ex);
+ throw;
}
- END_CATCH
return 1;
}
CORE_ADDR *pc)
{
- TRY
+ try
{
*pc = get_frame_address_in_block (this_frame);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error == NOT_AVAILABLE_ERROR)
return 0;
- throw_exception (ex);
+ throw;
}
- END_CATCH
return 1;
}
if (next_frame)
sym = get_frame_function (next_frame);
else
- sym = inline_skipped_symbol (inferior_ptid);
+ sym = inline_skipped_symbol (inferior_thread ());
/* If frame is inline, it certainly has symbols. */
gdb_assert (sym);
a PC that is guaranteed to be inside the frame's code
block. */
- TRY
+ try
{
pc = get_frame_address_in_block (frame);
pc_p = 1;
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ throw;
}
- END_CATCH
if (pc_p)
{
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
- /* Normality - an architecture that provides a way of obtaining any
- frame inner-most address. */
- if (gdbarch_unwind_sp_p (gdbarch))
- /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to
- operate on THIS_FRAME now. */
- return gdbarch_unwind_sp (gdbarch, this_frame->next);
- /* Now things are really are grim. Hope that the value returned by
- the gdbarch_sp_regnum register is meaningful. */
- if (gdbarch_sp_regnum (gdbarch) >= 0)
- return get_frame_register_unsigned (this_frame,
- gdbarch_sp_regnum (gdbarch));
- internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
+ /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to
+ operate on THIS_FRAME now. */
+ return gdbarch_unwind_sp (gdbarch, this_frame->next);
}
/* Return the reason why we can't unwind past FRAME. */
cmd_show_list (show_backtrace_cmdlist, from_tty, "");
}
+/* Definition of the "set backtrace" settings that are exposed as
+ "backtrace" command options. */
+
+using boolean_option_def
+ = gdb::option::boolean_option_def<set_backtrace_options>;
+using uinteger_option_def
+ = gdb::option::uinteger_option_def<set_backtrace_options>;
+
+const gdb::option::option_def set_backtrace_option_defs[] = {
+
+ boolean_option_def {
+ "past-main",
+ [] (set_backtrace_options *opt) { return &opt->backtrace_past_main; },
+ show_backtrace_past_main, /* show_cmd_cb */
+ N_("Set whether backtraces should continue past \"main\"."),
+ N_("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 if you need to see the rest\n\
+of the stack trace."),
+ },
+
+ boolean_option_def {
+ "past-entry",
+ [] (set_backtrace_options *opt) { return &opt->backtrace_past_entry; },
+ show_backtrace_past_entry, /* show_cmd_cb */
+ N_("Set whether backtraces should continue past the entry point of a program."),
+ N_("Show whether backtraces should continue past the entry point of a program."),
+ N_("Normally there are no callers beyond the entry point of a program, so GDB\n\
+will terminate the backtrace there. Set this if you need to see\n\
+the rest of the stack trace."),
+ },
+};
+
void
_initialize_frame (void)
{
&set_backtrace_cmdlist, "set backtrace ",
0/*allow-unknown*/, &setlist);
add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, _("\
-Show backtrace specific variables\n\
-Show backtrace variables such as the backtrace limit"),
+Show backtrace specific variables.\n\
+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\"."), _("\
-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,
- 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, _("\
+ &user_set_backtrace_options.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\
&set_backtrace_cmdlist,
&show_backtrace_cmdlist);
+ gdb::option::add_setshow_cmds_for_options
+ (class_stack, &user_set_backtrace_options,
+ set_backtrace_option_defs, &set_backtrace_cmdlist, &show_backtrace_cmdlist);
+
/* Debug this files internals. */
add_setshow_zuinteger_cmd ("frame", class_maintenance, &frame_debug, _("\
Set frame debugging."), _("\