diff options
-rw-r--r-- | gdb/ChangeLog | 23 | ||||
-rw-r--r-- | gdb/frame.c | 94 | ||||
-rw-r--r-- | gdb/frame.h | 12 |
3 files changed, 94 insertions, 35 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 666beb6..9740a23 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,26 @@ +2016-11-16 Kevin Buettner <kevinb@redhat.com> + + * frame.h (enum frame_id_stack_status): Add FID_STACK_SENTINEL. + (struct frame_id): Increase number of bits required for storing + stack status to 3 from 2. + (sentinel_frame_id): New declaration. + (get_next_frame_sentinel_okay): Declare. + (frame_find_by_id_sentinel_okay): Declare. + * frame.c (current_frame): Rename this static global to... + (sentinel_frame): ...this static global, which has also been + moved an earlier location in the file. + (fprint_frame_id): Add case for sentinel frame id. + (get_frame_id): Return early for sentinel frame. + (sentinel_frame_id): Define. + (frame_find_by_id): Add case for sentinel_frame_id. + (create_sentinel_frame): Use sentinel_frame_id for this_id.value + instead of null_frame_id. + (get_current_frame): Add local declaration for `current_frame'. + Remove local declaration for `sentinel_frame.' + (get_next_frame_sentinel_okay): New function. + (reinit_frame_cache): Use `sentinel_frame' in place of + `current_frame'. + 2016-11-15 Pedro Alves <palves@redhat.com> * gnulib/update-gnulib.sh (GNULIB_COMMIT_SHA1): Set to diff --git a/gdb/frame.c b/gdb/frame.c index d3f3056..54dc833 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -43,6 +43,15 @@ #include "hashtab.h" #include "valprint.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; + 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); @@ -65,7 +74,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 @@ -323,6 +332,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=<unavailable>"); + else if (id.stack_status == FID_STACK_SENTINEL) + fprintf_unfiltered (file, "stack=<sentinel>"); else fprintf_unfiltered (file, "stack=%s", hex_string (id.stack_addr)); fprintf_unfiltered (file, ","); @@ -562,6 +573,7 @@ frame_unwind_caller_id (struct frame_info *next_frame) } 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 @@ -797,6 +809,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) @@ -1474,10 +1490,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 (...) -> "); @@ -1487,10 +1502,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. */ @@ -1511,6 +1522,8 @@ 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" @@ -1526,29 +1539,23 @@ get_current_frame (void) if (get_traceframe_number () < 0) validate_registers_access (); - if (current_frame == NULL) - { - int stashed; - struct frame_info *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); - - /* No need to compute the frame id yet. That'll be done lazily - from inside get_frame_id instead. */ - } + 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); return current_frame; } @@ -1729,6 +1736,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 @@ -1745,7 +1771,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); @@ -1757,10 +1783,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) diff --git a/gdb/frame.h b/gdb/frame.h index a05ac82..dc25ce9 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -90,6 +90,9 @@ enum frame_id_stack_status /* Stack address is valid, and is found in the stack_addr field. */ FID_STACK_VALID = 1, + /* Sentinel frame. */ + FID_STACK_SENTINEL = 2, + /* Stack address is unavailable. I.e., there's a valid stack, but we don't know where it is (because memory or registers we'd compute it from were not collected). */ @@ -150,7 +153,7 @@ struct frame_id CORE_ADDR special_addr; /* Flags to indicate the above fields have valid contents. */ - ENUM_BITFIELD(frame_id_stack_status) stack_status : 2; + ENUM_BITFIELD(frame_id_stack_status) stack_status : 3; unsigned int code_addr_p : 1; unsigned int special_addr_p : 1; @@ -166,6 +169,9 @@ struct frame_id /* For convenience. All fields are zero. This means "there is no frame". */ extern const struct frame_id null_frame_id; +/* Sentinel frame. */ +extern const struct frame_id sentinel_frame_id; + /* This means "there is no frame ID, but there is a frame". It should be replaced by best-effort frame IDs for the outermost frame, somehow. The implementation is only special_addr_p set. */ @@ -310,6 +316,10 @@ extern void select_frame (struct frame_info *); extern struct frame_info *get_prev_frame (struct frame_info *); extern struct frame_info *get_next_frame (struct frame_info *); +/* Like get_next_frame(), but allows return of the sentinel frame. NULL + is never returned. */ +extern struct frame_info *get_next_frame_sentinel_okay (struct frame_info *); + /* Return a "struct frame_info" corresponding to the frame that called THIS_FRAME. Returns NULL if there is no such frame. |