X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fframe.c;h=a3599e8af6968a85a6054a3a8907980a2e863c52;hb=e7bc9db8f447e056f4faa11702230239b4075c2c;hp=89f48aea696f78a5004f605e25be3364f555dca7;hpb=b66f5587de2a096f357124b20376b2bab980238b;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/frame.c b/gdb/frame.c index 89f48aea69..a3599e8af6 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1,6 +1,6 @@ /* Cache and manage frames for GDB, the GNU debugger. - Copyright (C) 1986-2018 Free Software Foundation, Inc. + Copyright (C) 1986-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -42,6 +42,7 @@ #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 @@ -52,6 +53,20 @@ static struct frame_info *sentinel_frame; +/* Number of calls to reinit_frame_cache. */ +static unsigned int frame_cache_generation = 0; + +/* See frame.h. */ + +unsigned int +get_frame_cache_generation () +{ + return frame_cache_generation; +} + +/* 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); @@ -119,6 +134,8 @@ struct frame_info /* 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; @@ -157,6 +174,25 @@ struct frame_info 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 @@ -295,9 +331,8 @@ show_frame_debug (struct ui_file *file, int from_tty, 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) @@ -308,7 +343,8 @@ show_backtrace_past_main (struct ui_file *file, int from_tty, 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) @@ -318,7 +354,8 @@ show_backtrace_past_entry (struct ui_file *file, int from_tty, 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) @@ -424,8 +461,11 @@ fprint_frame (struct ui_file *file, struct frame_info *fi) if (fi->next == NULL || fi->next->prev_pc.status == CC_UNKNOWN) fprintf_unfiltered (file, ""); 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) @@ -717,7 +757,7 @@ frame_id_eq (struct frame_id l, struct frame_id r) 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. */ @@ -872,76 +912,70 @@ frame_unwind_pc (struct frame_info *this_frame) { 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)" + " -> }\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)" - " -> }\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)" - " -> }\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)" + " -> }\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) @@ -1024,21 +1058,19 @@ get_frame_func (struct frame_info *this_frame) 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 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 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; } @@ -1052,7 +1084,7 @@ frame_pop (struct frame_info *this_frame) { /* 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; } @@ -1093,7 +1125,7 @@ frame_pop (struct frame_info *this_frame) } 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) @@ -1108,7 +1140,7 @@ frame_register_unwind (struct frame_info *frame, int regnum, 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); @@ -1156,7 +1188,7 @@ frame_register (struct frame_info *frame, int regnum, } 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; @@ -1164,7 +1196,7 @@ frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf) 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) @@ -1183,29 +1215,31 @@ get_frame_register (struct frame_info *frame, } 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) { @@ -1255,12 +1289,12 @@ get_frame_register_value (struct frame_info *frame, int regnum) } 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); @@ -1289,12 +1323,12 @@ get_frame_register_signed (struct frame_info *frame, int regnum) } 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); @@ -1416,7 +1450,7 @@ get_frame_register_bytes (struct frame_info *frame, int regnum, /* 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); @@ -1624,15 +1658,16 @@ has_stack_frames (void) 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; } @@ -1819,6 +1854,8 @@ reinit_frame_cache (void) { struct frame_info *fi; + ++frame_cache_generation; + /* Tear down all frame caches. */ for (fi = sentinel_frame; fi != NULL; fi = fi->prev) { @@ -1898,7 +1935,9 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame) if (prev_frame->level == 0) return prev_frame; - TRY + unsigned int entry_generation = get_frame_cache_generation (); + + try { compute_frame_id (prev_frame); if (!frame_stash_add (prev_frame)) @@ -1918,14 +1957,16 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame) prev_frame = NULL; } } - CATCH (ex, RETURN_MASK_ALL) + catch (const gdb_exception &ex) { - prev_frame->next = NULL; - this_frame->prev = NULL; + if (get_frame_cache_generation () == entry_generation) + { + prev_frame->next = NULL; + this_frame->prev = NULL; + } - throw_exception (ex); + throw; } - END_CATCH return prev_frame; } @@ -2020,7 +2061,7 @@ get_prev_frame_always_1 (struct frame_info *this_frame) this_pc_in_block = get_frame_address_in_block (this_frame); morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block).minsym; if (morestack_msym) - morestack_name = MSYMBOL_LINKAGE_NAME (morestack_msym); + morestack_name = morestack_msym->linkage_name (); if (!morestack_name || strcmp (morestack_name, "__morestack") != 0) { if (frame_debug) @@ -2096,11 +2137,11 @@ get_prev_frame_always (struct frame_info *this_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) { @@ -2114,17 +2155,16 @@ get_prev_frame_always (struct frame_info *this_frame) 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; } @@ -2222,7 +2262,7 @@ inside_main_func (struct frame_info *this_frame) returned. */ maddr = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame), BMSYMBOL_VALUE_ADDRESS (msymbol), - target_stack); + current_top_target ()); return maddr == get_frame_func (this_frame); } @@ -2283,7 +2323,7 @@ get_prev_frame (struct frame_info *this_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 @@ -2300,7 +2340,7 @@ get_prev_frame (struct frame_info *this_frame) 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; @@ -2330,7 +2370,7 @@ get_prev_frame (struct frame_info *this_frame) 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)) { @@ -2383,18 +2423,17 @@ get_frame_pc_if_available (struct frame_info *frame, CORE_ADDR *pc) 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; } @@ -2466,17 +2505,16 @@ get_frame_address_in_block_if_available (struct frame_info *this_frame, 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; } @@ -2488,18 +2526,19 @@ find_frame_sal (frame_info *frame) int notcurrent; CORE_ADDR pc; - /* If the next frame represents an inlined function call, this frame's - sal is the "call site" of that inlined function, which can not - be inferred from get_frame_pc. */ - next_frame = get_next_frame (frame); if (frame_inlined_callees (frame) > 0) { struct symbol *sym; + /* If the current frame has some inlined callees, and we have a next + frame, then that frame must be an inlined frame. In this case + this frame's sal is the "call site" of the next frame's inlined + function, which can not be inferred from get_frame_pc. */ + next_frame = get_next_frame (frame); 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); @@ -2751,17 +2790,16 @@ get_frame_language (struct frame_info *frame) 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) { @@ -2781,18 +2819,9 @@ get_frame_sp (struct frame_info *this_frame) { 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. */ @@ -2902,21 +2931,42 @@ frame_prepare_for_sniffer (struct frame_info *frame, static struct cmd_list_element *set_backtrace_cmdlist; static struct cmd_list_element *show_backtrace_cmdlist; -static void -set_backtrace_cmd (const char *args, int from_tty) -{ - help_list (set_backtrace_cmdlist, "set backtrace ", all_commands, - gdb_stdout); -} +/* Definition of the "set backtrace" settings that are exposed as + "backtrace" command options. */ -static void -show_backtrace_cmd (const char *args, int from_tty) -{ - cmd_show_list (show_backtrace_cmdlist, from_tty, ""); -} +using boolean_option_def + = gdb::option::boolean_option_def; +using uinteger_option_def + = gdb::option::uinteger_option_def; +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 -_initialize_frame (void) +_initialize_frame () { obstack_init (&frame_cache_obstack); @@ -2924,45 +2974,19 @@ _initialize_frame (void) gdb::observers::target_changed.attach (frame_observer_target_changed); - add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\ + add_basic_prefix_cmd ("backtrace", class_maintenance, _("\ Set backtrace specific variables.\n\ 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, _("\ -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); + &set_backtrace_cmdlist, "set backtrace ", + 0/*allow-unknown*/, &setlist); + add_show_prefix_cmd ("backtrace", class_maintenance, _("\ +Show backtrace specific variables.\n\ +Show backtrace variables such as the backtrace limit."), + &show_backtrace_cmdlist, "show backtrace ", + 0/*allow-unknown*/, &showlist); 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\ @@ -2972,6 +2996,10 @@ Literal \"unlimited\" or zero means no limit."), &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."), _("\