X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fframe.c;h=ff27b9f00e9f73bef6fe0a7a946b716f180ce5dc;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=013d602feca7d922f3f99225de9b47cf0d48ec46;hpb=51d481464ec03be1f5479ed648cc38fb944d7fc0;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/frame.c b/gdb/frame.c index 013d602fec..ff27b9f00e 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-2014 Free Software Foundation, Inc. + Copyright (C) 1986-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -23,8 +23,6 @@ #include "value.h" #include "inferior.h" /* for inferior_ptid */ #include "regcache.h" -#include "gdb_assert.h" -#include #include "user-regs.h" #include "gdb_obstack.h" #include "dummy-frame.h" @@ -36,15 +34,27 @@ #include "frame-base.h" #include "command.h" #include "gdbcmd.h" -#include "observer.h" +#include "observable.h" #include "objfiles.h" -#include "exceptions.h" #include "gdbthread.h" #include "block.h" #include "inline-frame.h" #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 + innermost frame. + + The current frame, which is the innermost frame, can be found at + sentinel_frame->prev. */ + +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); @@ -68,7 +78,7 @@ enum cached_copy_status /* We keep a cache of stack frames, each of which is a "struct frame_info". The innermost one gets allocated (in - wait_for_inferior) each time the inferior stops; current_frame + wait_for_inferior) each time the inferior stops; sentinel_frame points to it. Additional frames get allocated (in get_prev_frame) as needed, and are chained through the next and prev fields. Any time that the frame cache becomes invalid (most notably when we @@ -93,7 +103,7 @@ struct frame_info struct program_space *pspace; /* The frame's address space. */ - struct address_space *aspace; + const address_space *aspace; /* The frame's low-level unwinder and corresponding cache. The low-level unwinder is responsible for unwinding register values @@ -113,6 +123,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; @@ -145,8 +157,31 @@ struct frame_info /* The reason why we could not set PREV, or UNWIND_NO_REASON if we could. Only valid when PREV_P is set. */ enum unwind_stop_reason stop_reason; + + /* A frame specific string describing the STOP_REASON in more detail. + Only valid when PREV_P is set, but even then may still be NULL. */ + 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 @@ -161,7 +196,7 @@ static htab_t frame_stash; static hashval_t frame_addr_hash (const void *ap) { - const struct frame_info *frame = ap; + const struct frame_info *frame = (const struct frame_info *) ap; const struct frame_id f_id = frame->this_id.value; hashval_t hash = 0; @@ -188,8 +223,8 @@ frame_addr_hash (const void *ap) static int frame_addr_hash_eq (const void *a, const void *b) { - const struct frame_info *f_entry = a; - const struct frame_info *f_element = b; + const struct frame_info *f_entry = (const struct frame_info *) a; + const struct frame_info *f_element = (const struct frame_info *) b; return frame_id_eq (f_entry->this_id.value, f_element->this_id.value); @@ -245,7 +280,7 @@ frame_stash_find (struct frame_id id) struct frame_info *frame; dummy.this_id.value = id; - frame = htab_find (frame_stash, &dummy); + frame = (struct frame_info *) htab_find (frame_stash, &dummy); return frame; } @@ -259,6 +294,22 @@ frame_stash_invalidate (void) htab_empty (frame_stash); } +/* See frame.h */ +scoped_restore_selected_frame::scoped_restore_selected_frame () +{ + m_fid = get_frame_id (get_selected_frame (NULL)); +} + +/* See frame.h */ +scoped_restore_selected_frame::~scoped_restore_selected_frame () +{ + frame_info *frame = frame_find_by_id (m_fid); + if (frame == NULL) + warning (_("Unable to restore previously selected frame.")); + else + select_frame (frame); +} + /* Flag to control debugging. */ unsigned int frame_debug; @@ -269,9 +320,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) @@ -282,7 +332,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) @@ -292,7 +343,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) @@ -322,6 +374,8 @@ fprint_frame_id (struct ui_file *file, struct frame_id id) fprintf_unfiltered (file, "!stack"); else if (id.stack_status == FID_STACK_UNAVAILABLE) fprintf_unfiltered (file, "stack="); + else if (id.stack_status == FID_STACK_SENTINEL) + fprintf_unfiltered (file, "stack="); else fprintf_unfiltered (file, "stack=%s", hex_string (id.stack_addr)); fprintf_unfiltered (file, ","); @@ -396,8 +450,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) @@ -419,7 +476,8 @@ fprint_frame (struct ui_file *file, struct frame_info *fi) /* Given FRAME, return the enclosing frame as found in real frames read-in from inferior memory. Skip any previous frames which were made up by GDB. - Return the original frame if no immediate previous frames exist. */ + Return FRAME if FRAME is a non-artificial frame. + Return NULL if FRAME is the start of an artificial-only chain. */ static struct frame_info * skip_artificial_frames (struct frame_info *frame) @@ -427,12 +485,47 @@ skip_artificial_frames (struct frame_info *frame) /* Note we use get_prev_frame_always, and not get_prev_frame. The latter will truncate the frame chain, leading to this function unintentionally returning a null_frame_id (e.g., when the user - sets a backtrace limit). This is safe, because as these frames - are made up by GDB, there must be a real frame in the chain - below. */ + sets a backtrace limit). + + Note that for record targets we may get a frame chain that consists + of artificial frames only. */ while (get_frame_type (frame) == INLINE_FRAME || get_frame_type (frame) == TAILCALL_FRAME) - frame = get_prev_frame_always (frame); + { + frame = get_prev_frame_always (frame); + if (frame == NULL) + break; + } + + return frame; +} + +struct frame_info * +skip_unwritable_frames (struct frame_info *frame) +{ + while (gdbarch_code_of_frame_writable (get_frame_arch (frame), frame) == 0) + { + frame = get_prev_frame (frame); + if (frame == NULL) + break; + } + + return frame; +} + +/* See frame.h. */ + +struct frame_info * +skip_tailcall_frames (struct frame_info *frame) +{ + while (get_frame_type (frame) == TAILCALL_FRAME) + { + /* Note that for record targets we may get a frame chain that consists of + tailcall frames only. */ + frame = get_prev_frame (frame); + if (frame == NULL) + break; + } return frame; } @@ -474,7 +567,26 @@ get_frame_id (struct frame_info *fi) if (fi == NULL) return null_frame_id; - gdb_assert (fi->this_id.p); + if (!fi->this_id.p) + { + int stashed; + + /* If we haven't computed the frame id yet, then it must be that + this is the current frame. Compute it now, and stash the + result. The IDs of other frames are computed as soon as + they're created, in order to detect cycles. See + get_prev_frame_if_no_cycle. */ + gdb_assert (fi->level == 0); + + /* Compute. */ + compute_frame_id (fi); + + /* Since this is the first frame in the chain, this should + always succeed. */ + stashed = frame_stash_add (fi); + gdb_assert (stashed); + } + return fi->this_id.value; } @@ -495,6 +607,9 @@ frame_unwind_caller_id (struct frame_info *next_frame) requests the frame ID of "main()"s caller. */ next_frame = skip_artificial_frames (next_frame); + if (next_frame == NULL) + return null_frame_id; + this_frame = get_prev_frame_always (next_frame); if (this_frame) return get_frame_id (skip_artificial_frames (this_frame)); @@ -502,7 +617,8 @@ frame_unwind_caller_id (struct frame_info *next_frame) return null_frame_id; } -const struct frame_id null_frame_id; /* All zeros. */ +const struct frame_id null_frame_id = { 0 }; /* All zeros. */ +const struct frame_id sentinel_frame_id = { 0, 0, 0, FID_STACK_SENTINEL, 0, 1, 0 }; const struct frame_id outer_frame_id = { 0, 0, 0, FID_STACK_INVALID, 0, 1, 0 }; struct frame_id @@ -571,6 +687,14 @@ frame_id_build_wild (CORE_ADDR stack_addr) return id; } +bool +frame_id_computed_p (struct frame_info *frame) +{ + gdb_assert (frame != nullptr); + + return frame->this_id.p != 0; +} + int frame_id_p (struct frame_id l) { @@ -613,7 +737,7 @@ frame_id_eq (struct frame_id l, struct frame_id r) outer_frame_id. */ eq = 1; else if (l.stack_status == FID_STACK_INVALID - || l.stack_status == FID_STACK_INVALID) + || r.stack_status == FID_STACK_INVALID) /* Like a NaN, if either ID is invalid, the result is false. Note that a frame ID is invalid iff it is the null frame ID. */ eq = 0; @@ -630,7 +754,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. */ @@ -695,7 +819,7 @@ frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r) && l.special_addr == r.special_addr) { /* Same function, different inlined functions. */ - struct block *lb, *rb; + const struct block *lb, *rb; gdb_assert (l.code_addr_p && r.code_addr_p); @@ -738,6 +862,10 @@ frame_find_by_id (struct frame_id id) if (!frame_id_p (id)) return NULL; + /* Check for the sentinel frame. */ + if (frame_id_eq (id, sentinel_frame_id)) + return sentinel_frame; + /* Try using the frame stash first. Finding it there removes the need to perform the search by looping over all frames, which can be very CPU-intensive if the number of frames is very high (the loop is O(n) @@ -752,9 +880,9 @@ frame_find_by_id (struct frame_id id) for (frame = get_current_frame (); ; frame = prev_frame) { - struct frame_id this = get_frame_id (frame); + struct frame_id self = get_frame_id (frame); - if (frame_id_eq (id, this)) + if (frame_id_eq (id, self)) /* An exact match. */ return frame; @@ -768,7 +896,7 @@ frame_find_by_id (struct frame_id id) frame in the current frame chain can have this ID. See the comment at frame_id_inner for details. */ if (get_frame_type (frame) == NORMAL_FRAME - && !frame_id_inner (get_frame_arch (frame), id, this) + && !frame_id_inner (get_frame_arch (frame), id, self) && frame_id_inner (get_frame_arch (prev_frame), id, get_frame_id (prev_frame))) return NULL; @@ -781,73 +909,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 { - volatile struct gdb_exception ex; - struct gdbarch *prev_gdbarch; - CORE_ADDR pc = 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_CATCH (ex, RETURN_MASK_ERROR) - { - pc = gdbarch_unwind_pc (prev_gdbarch, this_frame); - } - if (ex.reason < 0) + pc = gdbarch_unwind_pc (prev_gdbarch, this_frame); + pc_p = 1; + } + catch (const gdb_exception_error &ex) + { + if (ex.error == NOT_AVAILABLE_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); + 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 + else if (ex.error == OPTIMIZED_OUT_ERROR) { - this_frame->prev_pc.value = pc; - this_frame->prev_pc.status = CC_VALUE; + this_frame->prev_pc.status = CC_NOT_SAVED; + 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) @@ -865,7 +990,14 @@ frame_unwind_pc (struct frame_info *this_frame) CORE_ADDR frame_unwind_caller_pc (struct frame_info *this_frame) { - return frame_unwind_pc (skip_artificial_frames (this_frame)); + this_frame = skip_artificial_frames (this_frame); + + /* We must have a non-artificial frame. The caller is supposed to check + the result of frame_unwind_caller_id (), which returns NULL_FRAME_ID + in this case. */ + gdb_assert (this_frame != NULL); + + return frame_unwind_pc (this_frame); } int @@ -923,25 +1055,20 @@ 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 (src, regnum, buf)) - return REG_UNAVAILABLE; - else - return REG_VALID; -} - -struct regcache * +std::unique_ptr frame_save_as_regcache (struct frame_info *this_frame) { - struct address_space *aspace = get_frame_address_space (this_frame); - struct regcache *regcache = regcache_xmalloc (get_frame_arch (this_frame), - aspace); - struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache); + 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), cooked_read)); - regcache_save (regcache, do_frame_register_read, this_frame); - discard_cleanups (cleanups); return regcache; } @@ -949,14 +1076,12 @@ void frame_pop (struct frame_info *this_frame) { struct frame_info *prev_frame; - struct regcache *scratch; - struct cleanup *cleanups; if (get_frame_type (this_frame) == DUMMY_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)); + dummy_frame_pop (get_frame_id (this_frame), inferior_thread ()); return; } @@ -968,15 +1093,17 @@ frame_pop (struct frame_info *this_frame) /* Ignore TAILCALL_FRAME type frames, they were executed already before entering THISFRAME. */ - while (get_frame_type (prev_frame) == TAILCALL_FRAME) - prev_frame = get_prev_frame (prev_frame); + prev_frame = skip_tailcall_frames (prev_frame); + + if (prev_frame == NULL) + error (_("Cannot find the caller frame.")); /* Make a copy of all the register values unwound from 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. */ - scratch = frame_save_as_regcache (prev_frame); - cleanups = make_cleanup_regcache_xfree (scratch); + std::unique_ptr scratch + = frame_save_as_regcache (prev_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 @@ -986,10 +1113,8 @@ frame_pop (struct frame_info *this_frame) Unfortunately, they don't implement it. Their lack of a formal definition can lead to targets writing back bogus values (arguably a bug in the target code mind). */ - /* Now copy those saved registers into the current regcache. - Here, regcache_cpy() calls regcache_restore(). */ - regcache_cpy (get_current_regcache (), scratch); - do_cleanups (cleanups); + /* Now copy those saved registers into the current regcache. */ + get_current_regcache ()->restore (scratch.get ()); /* We've made right mess of GDB's local state, just discard everything. */ @@ -997,7 +1122,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) @@ -1012,7 +1137,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); @@ -1020,7 +1145,10 @@ frame_register_unwind (struct frame_info *frame, int regnum, *unavailablep = !value_entirely_available (value); *lvalp = VALUE_LVAL (value); *addrp = value_address (value); - *realnump = VALUE_REGNUM (value); + if (*lvalp == lval_register) + *realnump = VALUE_REGNUM (value); + else + *realnump = -1; if (bufferp) { @@ -1034,7 +1162,6 @@ frame_register_unwind (struct frame_info *frame, int regnum, /* Dispose of the new value. This prevents watchpoints from trying to watch the saved frame pointer. */ release_value (value); - value_free (value); } void @@ -1058,7 +1185,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; @@ -1066,7 +1193,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) @@ -1085,29 +1212,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) { @@ -1157,15 +1286,31 @@ 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); - gdb_byte buf[MAX_REGISTER_SIZE]; + struct value *value = frame_unwind_register_value (next_frame, regnum); + + gdb_assert (value != NULL); + + if (value_optimized_out (value)) + { + throw_error (OPTIMIZED_OUT_ERROR, + _("Register %d was not saved"), regnum); + } + if (!value_entirely_available (value)) + { + throw_error (NOT_AVAILABLE_ERROR, + _("Register %d is not available"), regnum); + } - frame_unwind_register (frame, regnum, buf); - return extract_signed_integer (buf, size, byte_order); + LONGEST r = extract_signed_integer (value_contents_all (value), size, + byte_order); + + release_value (value); + return r; } LONGEST @@ -1175,15 +1320,31 @@ 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); - gdb_byte buf[MAX_REGISTER_SIZE]; + struct value *value = frame_unwind_register_value (next_frame, regnum); - frame_unwind_register (frame, regnum, buf); - return extract_unsigned_integer (buf, size, byte_order); + gdb_assert (value != NULL); + + if (value_optimized_out (value)) + { + throw_error (OPTIMIZED_OUT_ERROR, + _("Register %d was not saved"), regnum); + } + if (!value_entirely_available (value)) + { + throw_error (NOT_AVAILABLE_ERROR, + _("Register %d is not available"), regnum); + } + + ULONGEST r = extract_unsigned_integer (value_contents_all (value), size, + byte_order); + + release_value (value); + return r; } ULONGEST @@ -1235,7 +1396,7 @@ put_frame_register (struct frame_info *frame, int regnum, break; } case lval_register: - regcache_cooked_write (get_current_regcache (), realnum, buf); + get_current_regcache ()->cooked_write (realnum, buf); break; default: error (_("Attempt to assign to an unmodifiable value.")); @@ -1286,7 +1447,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); @@ -1320,16 +1481,19 @@ get_frame_register_bytes (struct frame_info *frame, int regnum, } else { - gdb_byte buf[MAX_REGISTER_SIZE]; - enum lval_type lval; - CORE_ADDR addr; - int realnum; + struct value *value = frame_unwind_register_value (frame->next, + regnum); + gdb_assert (value != NULL); + *optimizedp = value_optimized_out (value); + *unavailablep = !value_entirely_available (value); - frame_register (frame, regnum, optimizedp, unavailablep, - &lval, &addr, &realnum, buf); if (*optimizedp || *unavailablep) - return 0; - memcpy (myaddr, buf + offset, curr_len); + { + release_value (value); + return 0; + } + memcpy (myaddr, value_contents_all (value) + offset, curr_len); + release_value (value); } myaddr += curr_len; @@ -1370,11 +1534,14 @@ put_frame_register_bytes (struct frame_info *frame, int regnum, } else { - gdb_byte buf[MAX_REGISTER_SIZE]; - - deprecated_frame_register_read (frame, regnum, buf); - memcpy (buf + offset, myaddr, curr_len); - put_frame_register (frame, regnum, buf); + struct value *value = frame_unwind_register_value (frame->next, + regnum); + gdb_assert (value != NULL); + + memcpy ((char *) value_contents_writeable (value) + offset, myaddr, + curr_len); + put_frame_register (frame, regnum, value_contents_raw (value)); + release_value (value); } myaddr += curr_len; @@ -1393,7 +1560,7 @@ create_sentinel_frame (struct program_space *pspace, struct regcache *regcache) frame->level = -1; frame->pspace = pspace; - frame->aspace = get_regcache_aspace (regcache); + frame->aspace = regcache->aspace (); /* Explicitly initialize the sentinel frame's cache. Provide it with the underlying regcache. In the future additional information, such as the frame's thread will be added. */ @@ -1403,10 +1570,9 @@ create_sentinel_frame (struct program_space *pspace, struct regcache *regcache) /* Link this frame back to itself. The frame is self referential (the unwound PC is the same as the pc), so make it so. */ frame->next = frame; - /* Make the sentinel frame's ID valid, but invalid. That way all - comparisons with it should fail. */ + /* The sentinel frame has a special ID. */ frame->this_id.p = 1; - frame->this_id.value = null_frame_id; + frame->this_id.value = sentinel_frame_id; if (frame_debug) { fprintf_unfiltered (gdb_stdlog, "{ create_sentinel_frame (...) -> "); @@ -1416,10 +1582,6 @@ create_sentinel_frame (struct program_space *pspace, struct regcache *regcache) return frame; } -/* Info about the innermost stack frame (contents of FP register). */ - -static struct frame_info *current_frame; - /* Cache for frame addresses already read by gdb. Valid only while inferior is stopped. Control variables for the frame cache should be local to this module. */ @@ -1435,27 +1597,13 @@ frame_obstack_zalloc (unsigned long size) return data; } -/* Return the innermost (currently executing) stack frame. This is - split into two functions. The function unwind_to_current_frame() - is wrapped in catch exceptions so that, even when the unwind of the - sentinel frame fails, the function still returns a stack frame. */ - -static int -unwind_to_current_frame (struct ui_out *ui_out, void *args) -{ - struct frame_info *frame = get_prev_frame (args); - - /* A sentinel frame can fail to unwind, e.g., because its PC value - lands in somewhere like start. */ - if (frame == NULL) - return 1; - current_frame = frame; - return 0; -} +static struct frame_info *get_prev_frame_always_1 (struct frame_info *this_frame); struct frame_info * get_current_frame (void) { + struct frame_info *current_frame; + /* First check, and report, the lack of registers. Having GDB report "No stack!" or "No memory" when the target doesn't even have registers is very confusing. Besides, "printcmd.exp" @@ -1469,27 +1617,26 @@ get_current_frame (void) error (_("No memory.")); /* Traceframes are effectively a substitute for the live inferior. */ if (get_traceframe_number () < 0) - { - if (ptid_equal (inferior_ptid, null_ptid)) - error (_("No selected thread.")); - if (is_exited (inferior_ptid)) - error (_("Invalid selected thread.")); - if (is_executing (inferior_ptid)) - error (_("Target is executing.")); - } + validate_registers_access (); + + if (sentinel_frame == NULL) + sentinel_frame = + create_sentinel_frame (current_program_space, get_current_regcache ()); + + /* Set the current frame before computing the frame id, to avoid + recursion inside compute_frame_id, in case the frame's + unwinder decides to do a symbol lookup (which depends on the + selected frame's block). + + This call must always succeed. In particular, nothing inside + get_prev_frame_always_1 should try to unwind from the + sentinel frame, because that could fail/throw, and we always + want to leave with the current frame created and linked in -- + we should never end up with the sentinel frame as outermost + frame. */ + current_frame = get_prev_frame_always_1 (sentinel_frame); + gdb_assert (current_frame != NULL); - if (current_frame == NULL) - { - struct frame_info *sentinel_frame = - create_sentinel_frame (current_program_space, get_current_regcache ()); - if (catch_exceptions (current_uiout, unwind_to_current_frame, - sentinel_frame, RETURN_MASK_ERROR) != 0) - { - /* Oops! Fake a current frame? Is this useful? It has a PC - of zero, for instance. */ - current_frame = sentinel_frame; - } - } return current_frame; } @@ -1508,15 +1655,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; } @@ -1572,8 +1720,6 @@ select_frame (struct frame_info *fi) selected_frame = fi; /* NOTE: cagney/2002-05-04: FI can be NULL. This occurs when the frame is being invalidated. */ - if (deprecated_selected_frame_level_changed_hook) - deprecated_selected_frame_level_changed_hook (frame_relative_level (fi)); /* FIXME: kseitz/2002-08-28: It would be nice to call selected_frame_level_changed_event() right here, but due to limitations @@ -1599,13 +1745,13 @@ select_frame (struct frame_info *fi) block. */ if (get_frame_address_in_block_if_available (fi, &pc)) { - struct symtab *s = find_pc_symtab (pc); + struct compunit_symtab *cust = find_pc_compunit_symtab (pc); - if (s - && s->language != current_language->la_language - && s->language != language_unknown + if (cust != NULL + && compunit_language (cust) != current_language->la_language + && compunit_language (cust) != language_unknown && language_mode == language_mode_auto) - set_language (s->language); + set_language (compunit_language (cust)); } } } @@ -1671,6 +1817,25 @@ get_next_frame (struct frame_info *this_frame) return NULL; } +/* Return the frame that THIS_FRAME calls. If THIS_FRAME is the + innermost (i.e. current) frame, return the sentinel frame. Thus, + unlike get_next_frame(), NULL will never be returned. */ + +struct frame_info * +get_next_frame_sentinel_okay (struct frame_info *this_frame) +{ + gdb_assert (this_frame != NULL); + + /* Note that, due to the manner in which the sentinel frame is + constructed, this_frame->next still works even when this_frame + is the sentinel frame. But we disallow it here anyway because + calling get_next_frame_sentinel_okay() on the sentinel frame + is likely a coding error. */ + gdb_assert (this_frame != sentinel_frame); + + return this_frame->next; +} + /* Observer for the target_changed event. */ static void @@ -1687,7 +1852,7 @@ reinit_frame_cache (void) struct frame_info *fi; /* Tear down all frame caches. */ - for (fi = current_frame; fi != NULL; fi = fi->prev) + for (fi = sentinel_frame; fi != NULL; fi = fi->prev) { if (fi->prologue_cache && fi->unwind->dealloc_cache) fi->unwind->dealloc_cache (fi, fi->prologue_cache); @@ -1699,10 +1864,10 @@ reinit_frame_cache (void) obstack_free (&frame_cache_obstack, 0); obstack_init (&frame_cache_obstack); - if (current_frame != NULL) + if (sentinel_frame != NULL) annotate_frames_invalid (); - current_frame = NULL; /* Invalidate cache */ + sentinel_frame = NULL; /* Invalidate cache */ select_frame (NULL); frame_stash_invalidate (); if (frame_debug) @@ -1752,36 +1917,56 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame) struct frame_info *prev_frame; prev_frame = get_prev_frame_raw (this_frame); - if (prev_frame == NULL) - return NULL; - compute_frame_id (prev_frame); - if (frame_stash_add (prev_frame)) + /* Don't compute the frame id of the current frame yet. Unwinding + the sentinel frame can fail (e.g., if the thread is gone and we + can't thus read its registers). If we let the cycle detection + code below try to compute a frame ID, then an error thrown from + within the frame ID computation would result in the sentinel + frame as outermost frame, which is bogus. Instead, we'll compute + the current frame's ID lazily in get_frame_id. Note that there's + no point in doing cycle detection when there's only one frame, so + nothing is lost here. */ + if (prev_frame->level == 0) return prev_frame; - /* Another frame with the same id was already in the stash. We just - detected a cycle. */ - if (frame_debug) + try { - fprintf_unfiltered (gdb_stdlog, "-> "); - fprint_frame (gdb_stdlog, NULL); - fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n"); + compute_frame_id (prev_frame); + if (!frame_stash_add (prev_frame)) + { + /* Another frame with the same id was already in the stash. We just + detected a cycle. */ + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n"); + } + this_frame->stop_reason = UNWIND_SAME_ID; + /* Unlink. */ + prev_frame->next = NULL; + this_frame->prev = NULL; + prev_frame = NULL; + } } - this_frame->stop_reason = UNWIND_SAME_ID; - /* Unlink. */ - prev_frame->next = NULL; - this_frame->prev = NULL; - return NULL; -} + catch (const gdb_exception &ex) + { + prev_frame->next = NULL; + this_frame->prev = NULL; -/* Return a "struct frame_info" corresponding to the frame that called - THIS_FRAME. Returns NULL if there is no such frame. + throw; + } - Unlike get_prev_frame, this function always tries to unwind the - frame. */ + return prev_frame; +} -struct frame_info * -get_prev_frame_always (struct frame_info *this_frame) +/* Helper function for get_prev_frame_always, this is called inside a + TRY_CATCH block. Return the frame that called THIS_FRAME or NULL if + there is no such frame. This may throw an exception. */ + +static struct frame_info * +get_prev_frame_always_1 (struct frame_info *this_frame) { struct gdbarch *gdbarch; @@ -1866,7 +2051,7 @@ get_prev_frame_always (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) @@ -1931,6 +2116,49 @@ get_prev_frame_always (struct frame_info *this_frame) return get_prev_frame_if_no_cycle (this_frame); } +/* Return a "struct frame_info" corresponding to the frame that called + THIS_FRAME. Returns NULL if there is no such frame. + + Unlike get_prev_frame, this function always tries to unwind the + frame. */ + +struct frame_info * +get_prev_frame_always (struct frame_info *this_frame) +{ + struct frame_info *prev_frame = NULL; + + try + { + prev_frame = get_prev_frame_always_1 (this_frame); + } + catch (const gdb_exception_error &ex) + { + if (ex.error == MEMORY_ERROR) + { + this_frame->stop_reason = UNWIND_MEMORY_ERROR; + if (ex.message != NULL) + { + char *stop_string; + size_t size; + + /* The error needs to live as long as the frame does. + 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 = ex.message->size () + 1; + stop_string = (char *) frame_obstack_zalloc (size); + memcpy (stop_string, ex.what (), size); + this_frame->stop_string = stop_string; + } + prev_frame = NULL; + } + else + throw; + } + + return prev_frame; +} + /* Construct a new "struct frame_info" and link it previous to this_frame. */ @@ -2024,7 +2252,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), - ¤t_target); + current_top_target ()); return maddr == get_frame_func (this_frame); } @@ -2060,6 +2288,17 @@ get_prev_frame (struct frame_info *this_frame) something should be calling get_selected_frame() or get_current_frame(). */ gdb_assert (this_frame != NULL); + + /* If this_frame is the current frame, then compute and stash + its frame id prior to fetching and computing the frame id of the + previous frame. Otherwise, the cycle detection code in + get_prev_frame_if_no_cycle() will not work correctly. When + get_frame_id() is called later on, an assertion error will + be triggered in the event of a cycle between the current + frame and its previous frame. */ + if (this_frame->level == 0) + get_frame_id (this_frame); + frame_pc_p = get_frame_pc_if_available (this_frame, &frame_pc); /* tausq/2004-12-07: Dummy frames are skipped because it doesn't make much @@ -2074,7 +2313,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 @@ -2091,7 +2330,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; @@ -2121,7 +2360,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)) { @@ -2145,6 +2384,22 @@ get_prev_frame (struct frame_info *this_frame) return get_prev_frame_always (this_frame); } +struct frame_id +get_prev_frame_id_by_id (struct frame_id id) +{ + struct frame_id prev_id; + struct frame_info *frame; + + frame = frame_find_by_id (id); + + if (frame != NULL) + prev_id = get_frame_id (get_prev_frame (frame)); + else + prev_id = null_frame_id; + + return prev_id; +} + CORE_ADDR get_frame_pc (struct frame_info *frame) { @@ -2155,20 +2410,19 @@ get_frame_pc (struct frame_info *frame) int get_frame_pc_if_available (struct frame_info *frame, CORE_ADDR *pc) { - volatile struct gdb_exception ex; gdb_assert (frame->next != NULL); - TRY_CATCH (ex, RETURN_MASK_ERROR) + try { *pc = frame_unwind_pc (frame->next); } - if (ex.reason < 0) + catch (const gdb_exception_error &ex) { if (ex.error == NOT_AVAILABLE_ERROR) return 0; else - throw_exception (ex); + throw; } return 1; @@ -2240,57 +2494,59 @@ int get_frame_address_in_block_if_available (struct frame_info *this_frame, CORE_ADDR *pc) { - volatile struct gdb_exception ex; - TRY_CATCH (ex, RETURN_MASK_ERROR) + try { *pc = get_frame_address_in_block (this_frame); } - if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR) - return 0; - else if (ex.reason < 0) - throw_exception (ex); - else - return 1; + catch (const gdb_exception_error &ex) + { + if (ex.error == NOT_AVAILABLE_ERROR) + return 0; + throw; + } + + return 1; } -void -find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) +symtab_and_line +find_frame_sal (frame_info *frame) { struct frame_info *next_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); - init_sal (sal); + + symtab_and_line sal; if (SYMBOL_LINE (sym) != 0) { - sal->symtab = SYMBOL_SYMTAB (sym); - sal->line = SYMBOL_LINE (sym); + sal.symtab = symbol_symtab (sym); + sal.line = SYMBOL_LINE (sym); } else /* If the symbol does not have a location, we don't know where the call site is. Do not pretend to. This is jarring, but we can't do much better. */ - sal->pc = get_frame_pc (frame); + sal.pc = get_frame_pc (frame); - sal->pspace = get_frame_program_space (frame); - - return; + sal.pspace = get_frame_program_space (frame); + return sal; } /* If FRAME is not the innermost frame, that normally means that @@ -2303,13 +2559,10 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) instruction/line, consequently, for such cases, want to get the line containing fi->pc. */ if (!get_frame_pc_if_available (frame, &pc)) - { - init_sal (sal); - return; - } + return {}; notcurrent = (pc != get_frame_address_in_block (frame)); - (*sal) = find_pc_line (pc, notcurrent); + return find_pc_line (pc, notcurrent); } /* Per "frame.h", return the ``address'' of the frame. Code should @@ -2416,7 +2669,7 @@ frame_unwind_program_space (struct frame_info *this_frame) return this_frame->pspace; } -struct address_space * +const address_space * get_frame_address_space (struct frame_info *frame) { return frame->aspace; @@ -2498,7 +2751,55 @@ frame_unwind_arch (struct frame_info *next_frame) struct gdbarch * frame_unwind_caller_arch (struct frame_info *next_frame) { - return frame_unwind_arch (skip_artificial_frames (next_frame)); + next_frame = skip_artificial_frames (next_frame); + + /* We must have a non-artificial frame. The caller is supposed to check + the result of frame_unwind_caller_id (), which returns NULL_FRAME_ID + in this case. */ + gdb_assert (next_frame != NULL); + + return frame_unwind_arch (next_frame); +} + +/* Gets the language of FRAME. */ + +enum language +get_frame_language (struct frame_info *frame) +{ + CORE_ADDR pc = 0; + int pc_p = 0; + + gdb_assert (frame!= NULL); + + /* We determine the current frame language by looking up its + associated symtab. To retrieve this symtab, we use the frame + PC. However we cannot use the frame PC as is, because it + usually points to the instruction following the "call", which + is sometimes the first instruction of another function. So + we rely on get_frame_address_in_block(), it provides us with + a PC that is guaranteed to be inside the frame's code + block. */ + + try + { + pc = get_frame_address_in_block (frame); + pc_p = 1; + } + catch (const gdb_exception_error &ex) + { + if (ex.error != NOT_AVAILABLE_ERROR) + throw; + } + + if (pc_p) + { + struct compunit_symtab *cust = find_pc_compunit_symtab (pc); + + if (cust != NULL) + return compunit_language (cust); + } + + return language_unknown; } /* Stack pointer methods. */ @@ -2508,18 +2809,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. */ @@ -2537,7 +2829,7 @@ get_frame_unwind_stop_reason (struct frame_info *frame) /* Return a string explaining REASON. */ const char * -frame_stop_reason_string (enum unwind_stop_reason reason) +unwind_stop_reason_to_string (enum unwind_stop_reason reason) { switch (reason) { @@ -2552,6 +2844,20 @@ frame_stop_reason_string (enum unwind_stop_reason reason) } } +const char * +frame_stop_reason_string (struct frame_info *fi) +{ + gdb_assert (fi->prev_p); + gdb_assert (fi->prev == NULL); + + /* Return the specific string if we have one. */ + if (fi->stop_string != NULL) + return fi->stop_string; + + /* Return the generic string if we have nothing better. */ + return unwind_stop_reason_to_string (fi->stop_reason); +} + /* Return the enum symbol name of REASON as a string, to use in debug output. */ @@ -2574,11 +2880,9 @@ frame_stop_reason_symbol_string (enum unwind_stop_reason reason) /* Clean up after a failed (wrong unwinder) attempt to unwind past FRAME. */ -static void -frame_cleanup_after_sniffer (void *arg) +void +frame_cleanup_after_sniffer (struct frame_info *frame) { - struct frame_info *frame = arg; - /* The sniffer should not allocate a prologue cache if it did not match this frame. */ gdb_assert (frame->prologue_cache == NULL); @@ -2603,83 +2907,76 @@ frame_cleanup_after_sniffer (void *arg) } /* Set FRAME's unwinder temporarily, so that we can call a sniffer. - Return a cleanup which should be called if unwinding fails, and - discarded if it succeeds. */ + If sniffing fails, the caller should be sure to call + frame_cleanup_after_sniffer. */ -struct cleanup * +void frame_prepare_for_sniffer (struct frame_info *frame, const struct frame_unwind *unwind) { gdb_assert (frame->unwind == NULL); frame->unwind = unwind; - return make_cleanup (frame_cleanup_after_sniffer, frame); } -extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */ - static struct cmd_list_element *set_backtrace_cmdlist; static struct cmd_list_element *show_backtrace_cmdlist; -static void -set_backtrace_cmd (char *args, int from_tty) -{ - help_list (set_backtrace_cmdlist, "set backtrace ", -1, gdb_stdout); -} +/* Definition of the "set backtrace" settings that are exposed as + "backtrace" command options. */ -static void -show_backtrace_cmd (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); frame_stash_create (); - observer_attach_target_changed (frame_observer_target_changed); + 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\ @@ -2689,6 +2986,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."), _("\