X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/18ea5ba4f05d572ec1513a37c22544c6037b21fa..5378adc435ea0bce3ecb56bf0f1bc42deb1406f1:/gdb/frame.c diff --git a/gdb/frame.c b/gdb/frame.c index 29ebfbee40..d252d8a7df 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1,7 +1,7 @@ /* Cache and manage frames for GDB, the GNU debugger. Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, - 2001, 2002 Free Software Foundation, Inc. + 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GDB. @@ -34,6 +34,13 @@ #include "gdbcore.h" #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. */ @@ -127,12 +134,36 @@ frame_pc_unwind (struct frame_info *frame) { if (!frame->pc_unwind_cache_p) { - frame->pc_unwind_cache = frame->pc_unwind (frame, &frame->unwind_cache); + frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache); frame->pc_unwind_cache_p = 1; } return frame->pc_unwind_cache; } +struct frame_id +frame_id_unwind (struct frame_info *frame) +{ + if (!frame->id_unwind_cache_p) + { + frame->unwind->id (frame, &frame->unwind_cache, &frame->id_unwind_cache); + frame->id_unwind_cache_p = 1; + } + return frame->id_unwind_cache; +} + +void +frame_pop (struct frame_info *frame) +{ + /* FIXME: cagney/2003-01-18: There is probably a chicken-egg problem + with passing in current_regcache. The pop function needs to be + written carefully so as to not overwrite registers whose [old] + values are needed to restore other registers. Instead, this code + should pass in a scratch cache and, as a second step, restore the + registers using that. */ + frame->unwind->pop (frame, &frame->unwind_cache, current_regcache); + flush_cached_frames (); +} + void frame_register_unwind (struct frame_info *frame, int regnum, int *optimizedp, enum lval_type *lvalp, @@ -173,8 +204,8 @@ frame_register_unwind (struct frame_info *frame, int regnum, } /* Ask this frame to unwind its register. */ - frame->register_unwind (frame, &frame->unwind_cache, regnum, - optimizedp, lvalp, addrp, realnump, bufferp); + frame->unwind->reg (frame, &frame->unwind_cache, regnum, + optimizedp, lvalp, addrp, realnump, bufferp); } void @@ -443,19 +474,26 @@ static struct frame_info *current_frame; static struct obstack frame_cache_obstack; void * -frame_obstack_alloc (unsigned long size) +frame_obstack_zalloc (unsigned long size) { - return obstack_alloc (&frame_cache_obstack, size); + void *data = obstack_alloc (&frame_cache_obstack, size); + memset (data, 0, size); + return data; } -void +CORE_ADDR * frame_saved_regs_zalloc (struct frame_info *fi) { fi->saved_regs = (CORE_ADDR *) - frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS); - memset (fi->saved_regs, 0, SIZEOF_FRAME_SAVED_REGS); + frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS); + return fi->saved_regs; } +CORE_ADDR * +get_frame_saved_regs (struct frame_info *fi) +{ + return fi->saved_regs; +} /* Return the innermost (currently executing) stack frame. */ @@ -550,6 +588,10 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, gdb_assert (!(DEPRECATED_USE_GENERIC_DUMMY_FRAMES && (get_frame_type (frame) == DUMMY_FRAME))); + /* Only (older) architectures that implement the + FRAME_INIT_SAVED_REGS method should be using this function. */ + gdb_assert (FRAME_INIT_SAVED_REGS_P ()); + /* Load the saved_regs register cache. */ if (frame->saved_regs == NULL) FRAME_INIT_SAVED_REGS (frame); @@ -586,14 +628,13 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, { int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS) * sizeof (void *)); - regs = frame_obstack_alloc (sizeof_cache); - memset (regs, 0, sizeof_cache); + regs = frame_obstack_zalloc (sizeof_cache); (*cache) = regs; } if (regs[regnum] == NULL) { regs[regnum] - = frame_obstack_alloc (REGISTER_RAW_SIZE (regnum)); + = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum)); read_memory (frame->saved_regs[regnum], regs[regnum], REGISTER_RAW_SIZE (regnum)); } @@ -632,6 +673,83 @@ frame_saved_regs_pc_unwind (struct frame_info *frame, void **cache) return FRAME_SAVED_PC (frame); } +static void +frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache, + struct frame_id *id) +{ + int fromleaf; + CORE_ADDR base; + CORE_ADDR pc; + + /* Start out by assuming it's NULL. */ + (*id) = null_frame_id; + + if (next_frame->next == NULL) + /* 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 + should simply be removed. */ + fromleaf = FRAMELESS_FUNCTION_INVOCATION (next_frame); + else + fromleaf = 0; + + if (fromleaf) + /* A frameless inner-most frame. The `FP' (which isn't an + architecture frame-pointer register!) of the caller is the same + as the callee. */ + /* FIXME: 2002-11-09: There isn't any reason to special case this + edge condition. Instead the per-architecture code should hande + it locally. */ + base = get_frame_base (next_frame); + else + { + /* Two macros defined in tm.h specify the machine-dependent + actions to be performed here. + + First, get the frame's chain-pointer. + + If that is zero, the frame is the outermost frame or a leaf + called by the outermost frame. This means that if start + calls main without a frame, we'll return 0 (which is fine + anyway). + + Nope; there's a problem. This also returns when the current + routine is a leaf of main. This is unacceptable. We move + this to after the ffi test; I'd rather have backtraces from + start go curfluy than have an abort called from main not show + main. */ + base = FRAME_CHAIN (next_frame); + + if (!frame_chain_valid (base, next_frame)) + return; + } + if (base == 0) + return; + + /* FIXME: cagney/2002-06-08: This should probably return the frame's + function and not the PC (a.k.a. resume address). */ + pc = frame_pc_unwind (next_frame); + id->pc = pc; + id->base = base; +} + +static void +frame_saved_regs_pop (struct frame_info *fi, void **cache, + struct regcache *regcache) +{ + gdb_assert (POP_FRAME_P ()); + POP_FRAME; +} + +const struct frame_unwind trad_frame_unwinder = { + frame_saved_regs_pop, + frame_saved_regs_pc_unwind, + frame_saved_regs_id_unwind, + frame_saved_regs_register_unwind +}; +const struct frame_unwind *trad_frame_unwind = &trad_frame_unwinder; + + /* Function: get_saved_register Find register number REGNUM relative to FRAME and put its (raw, target format) contents in *RAW_BUFFER. @@ -665,6 +783,8 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized, if (!target_has_registers) error ("No registers."); + gdb_assert (FRAME_INIT_SAVED_REGS_P ()); + /* Normal systems don't optimize out things with register numbers. */ if (optimized != NULL) *optimized = 0; @@ -729,35 +849,26 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized, deprecated_read_register_gen (regnum, raw_buffer); } -/* Using the PC, select a mechanism for unwinding a frame returning - the previous frame. The register unwind function should, on - demand, initialize the ->context object. */ +/* Determine the frame's type based on its PC. */ -static void -set_unwind_by_pc (CORE_ADDR pc, CORE_ADDR fp, - frame_register_unwind_ftype **unwind_register, - frame_pc_unwind_ftype **unwind_pc) +static enum frame_type +frame_type_from_pc (CORE_ADDR pc) { - if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES) - { - /* Still need to set this to something. The ``info frame'' code - calls this function to find out where the saved registers are. - Hopefully this is robust enough to stop any core dumps and - return vaguely correct values.. */ - *unwind_register = frame_saved_regs_register_unwind; - *unwind_pc = frame_saved_regs_pc_unwind; - } - else if (DEPRECATED_PC_IN_CALL_DUMMY_P () - ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0) - : pc_in_dummy_frame (pc)) - { - *unwind_register = dummy_frame_register_unwind; - *unwind_pc = dummy_frame_pc_unwind; - } + /* 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 { - *unwind_register = frame_saved_regs_register_unwind; - *unwind_pc = frame_saved_regs_pc_unwind; + char *name; + find_pc_partial_function (pc, &name, NULL, NULL); + if (PC_IN_SIGTRAMP (pc, name)) + return SIGTRAMP_FRAME; + else + return NORMAL_FRAME; } } @@ -768,48 +879,18 @@ struct frame_info * create_new_frame (CORE_ADDR addr, CORE_ADDR pc) { struct frame_info *fi; - enum frame_type type; - - fi = (struct frame_info *) - obstack_alloc (&frame_cache_obstack, - sizeof (struct frame_info)); - /* Zero all fields by default. */ - memset (fi, 0, sizeof (struct frame_info)); + 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); /* Select/initialize an unwind function. */ - set_unwind_by_pc (fi->pc, fi->frame, &fi->register_unwind, - &fi->pc_unwind); + fi->unwind = frame_unwind_find_by_pc (current_gdbarch, fi->pc); return fi; } @@ -851,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 @@ -898,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 @@ -934,25 +991,14 @@ get_prev_frame (struct frame_info *next_frame) main. */ address = FRAME_CHAIN (next_frame); - /* FIXME: cagney/2002-06-08: There should be two tests here. - The first would check for a valid frame chain based on a user - selectable policy. The default being ``stop at main'' (as - implemented by generic_func_frame_chain_valid()). Other - policies would be available - stop at NULL, .... The second - test, if provided by the target architecture, would check for - more exotic cases - most target architectures wouldn't bother - with this second case. */ - if (!FRAME_CHAIN_VALID (address, next_frame)) + if (!frame_chain_valid (address, next_frame)) return 0; } if (address == 0) return 0; /* Create an initially zero previous frame. */ - prev = (struct frame_info *) - obstack_alloc (&frame_cache_obstack, - sizeof (struct frame_info)); - memset (prev, 0, sizeof (struct frame_info)); + prev = frame_obstack_zalloc (sizeof (struct frame_info)); /* Link it in. */ next_frame->prev = prev; @@ -1063,8 +1109,7 @@ get_prev_frame (struct frame_info *next_frame) (and probably other architectural information). The PC lets you check things like the debug info at that point (dwarf2cfi?) and use that to decide how the frame should be unwound. */ - set_unwind_by_pc (prev->pc, prev->frame, &prev->register_unwind, - &prev->pc_unwind); + prev->unwind = frame_unwind_find_by_pc (current_gdbarch, prev->pc); /* NOTE: cagney/2002-11-18: The code segments, found in create_new_frame and get_prev_frame(), that initializes the @@ -1102,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) { @@ -1181,7 +1382,7 @@ deprecated_get_frame_saved_regs (struct frame_info *frame, if (frame->saved_regs == NULL) { frame->saved_regs = (CORE_ADDR *) - frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS); + frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS); } if (saved_regs_addr == NULL) { @@ -1206,13 +1407,111 @@ get_frame_extra_info (struct frame_info *fi) struct frame_extra_info * frame_extra_info_zalloc (struct frame_info *fi, long size) { - fi->extra_info = frame_obstack_alloc (size); - memset (fi->extra_info, 0, size); + fi->extra_info = frame_obstack_zalloc (size); return fi->extra_info; } +void +deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc) +{ + /* See comment in "frame.h". */ + frame->pc = pc; +} + +void +deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base) +{ + /* See comment in "frame.h". */ + frame->frame = base; +} + +void +deprecated_set_frame_saved_regs_hack (struct frame_info *frame, + CORE_ADDR *saved_regs) +{ + frame->saved_regs = saved_regs; +} + +void +deprecated_set_frame_extra_info_hack (struct frame_info *frame, + struct frame_extra_info *extra_info) +{ + frame->extra_info = extra_info; +} + +void +deprecated_set_frame_next_hack (struct frame_info *fi, + struct frame_info *next) +{ + fi->next = next; +} + +void +deprecated_set_frame_prev_hack (struct frame_info *fi, + struct frame_info *prev) +{ + fi->prev = prev; +} + +struct context * +deprecated_get_frame_context (struct frame_info *fi) +{ + return fi->context; +} + +void +deprecated_set_frame_context (struct frame_info *fi, + struct context *context) +{ + fi->context = context; +} + +struct frame_info * +deprecated_frame_xmalloc (void) +{ + struct frame_info *frame = XMALLOC (struct frame_info); + memset (frame, 0, sizeof (struct frame_info)); + return frame; +} + +struct frame_info * +deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs, + long sizeof_extra_info) +{ + struct frame_info *frame = deprecated_frame_xmalloc (); + make_cleanup (xfree, frame); + if (sizeof_saved_regs > 0) + { + frame->saved_regs = xcalloc (1, sizeof_saved_regs); + make_cleanup (xfree, frame->saved_regs); + } + if (sizeof_extra_info > 0) + { + frame->extra_info = xcalloc (1, sizeof_extra_info); + make_cleanup (xfree, frame->extra_info); + } + return frame; +} + 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); }