X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fframe.c;h=da5bfb9ee486ce3b409cc694fee1b4e6d2c74a4e;hb=2e0569314c2ee9e5635899d47b0bc0a4b9b08d8d;hp=12a38e70b16a98ffdbc9651d31fb301f7befe3b1;hpb=6c95b8df7fef5273da71c34775918c554aae0ea8;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/frame.c b/gdb/frame.c index 12a38e70b1..da5bfb9ee4 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1,7 +1,6 @@ /* Cache and manage frames for GDB, the GNU debugger. - Copyright (C) 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001, - 2002, 2003, 2004, 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 1986-2015 Free Software Foundation, Inc. This file is part of GDB. @@ -24,8 +23,6 @@ #include "value.h" #include "inferior.h" /* for inferior_ptid */ #include "regcache.h" -#include "gdb_assert.h" -#include "gdb_string.h" #include "user-regs.h" #include "gdb_obstack.h" #include "dummy-frame.h" @@ -39,13 +36,32 @@ #include "gdbcmd.h" #include "observer.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" -static struct frame_info *get_prev_frame_1 (struct frame_info *this_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); + +/* Status of some values cached in the frame_info object. */ + +enum cached_copy_status +{ + /* Value is unknown. */ + CC_UNKNOWN, + + /* We have a value. */ + CC_VALUE, + + /* Value was not saved. */ + CC_NOT_SAVED, + + /* Value is unavailable. */ + CC_UNAVAILABLE +}; /* We keep a cache of stack frames, each of which is a "struct frame_info". The innermost one gets allocated (in @@ -93,7 +109,7 @@ struct frame_info /* Cached copy of the previous frame's resume address. */ struct { - int p; + enum cached_copy_status status; CORE_ADDR value; } prev_pc; @@ -126,45 +142,127 @@ 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; }; -/* A frame stash used to speed up frame lookups. */ +/* 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 + the frame cache is invalidated. */ + +static htab_t frame_stash; + +/* Internal function to calculate a hash from the frame_id addresses, + using as many valid addresses as possible. Frames below level 0 + are not stored in the hash table. */ -/* We currently only stash one frame at a time, as this seems to be - sufficient for now. */ -static struct frame_info *frame_stash = NULL; +static hashval_t +frame_addr_hash (const void *ap) +{ + const struct frame_info *frame = ap; + const struct frame_id f_id = frame->this_id.value; + hashval_t hash = 0; + + gdb_assert (f_id.stack_status != FID_STACK_INVALID + || f_id.code_addr_p + || f_id.special_addr_p); + + if (f_id.stack_status == FID_STACK_VALID) + hash = iterative_hash (&f_id.stack_addr, + sizeof (f_id.stack_addr), hash); + if (f_id.code_addr_p) + hash = iterative_hash (&f_id.code_addr, + sizeof (f_id.code_addr), hash); + if (f_id.special_addr_p) + hash = iterative_hash (&f_id.special_addr, + sizeof (f_id.special_addr), hash); + + return hash; +} + +/* Internal equality function for the hash table. This function + defers equality operations to frame_id_eq. */ + +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; + + return frame_id_eq (f_entry->this_id.value, + f_element->this_id.value); +} -/* Add the following FRAME to the frame stash. */ +/* Internal function to create the frame_stash hash table. 100 seems + to be a good compromise to start the hash table at. */ static void +frame_stash_create (void) +{ + frame_stash = htab_create (100, + frame_addr_hash, + frame_addr_hash_eq, + NULL); +} + +/* Internal function to add a frame to the frame_stash hash table. + Returns false if a frame with the same ID was already stashed, true + otherwise. */ + +static int frame_stash_add (struct frame_info *frame) { - frame_stash = frame; + struct frame_info **slot; + + /* Do not try to stash the sentinel frame. */ + gdb_assert (frame->level >= 0); + + slot = (struct frame_info **) htab_find_slot (frame_stash, + frame, + INSERT); + + /* If we already have a frame in the stack with the same id, we + either have a stack cycle (corrupted stack?), or some bug + elsewhere in GDB. In any case, ignore the duplicate and return + an indication to the caller. */ + if (*slot != NULL) + return 0; + + *slot = frame; + return 1; } -/* Search the frame stash for an entry with the given frame ID. - If found, return that frame. Otherwise return NULL. */ +/* Internal function to search the frame stash for an entry with the + given frame ID. If found, return that frame. Otherwise return + NULL. */ static struct frame_info * frame_stash_find (struct frame_id id) { - if (frame_stash && frame_id_eq (frame_stash->this_id.value, id)) - return frame_stash; + struct frame_info dummy; + struct frame_info *frame; - return NULL; + dummy.this_id.value = id; + frame = htab_find (frame_stash, &dummy); + return frame; } -/* Invalidate the frame stash by removing all entries in it. */ +/* Internal function to invalidate the frame stash by removing all + entries in it. This only occurs when the frame cache is + invalidated. */ static void frame_stash_invalidate (void) { - frame_stash = NULL; + htab_empty (frame_stash); } /* Flag to control debugging. */ -int frame_debug; +unsigned int frame_debug; static void show_frame_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -179,8 +277,9 @@ static void show_backtrace_past_main (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("\ -Whether backtraces should continue past \"main\" is %s.\n"), + fprintf_filtered (file, + _("Whether backtraces should " + "continue past \"main\" is %s.\n"), value); } @@ -189,18 +288,19 @@ static void show_backtrace_past_entry (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("\ -Whether backtraces should continue past the entry point of a program is %s.\n"), + fprintf_filtered (file, _("Whether backtraces should continue past the " + "entry point of a program is %s.\n"), value); } -static int backtrace_limit = INT_MAX; +static unsigned int backtrace_limit = UINT_MAX; static void show_backtrace_limit (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("\ -An upper bound on the number of backtrace levels is %s.\n"), + fprintf_filtered (file, + _("An upper bound on the number " + "of backtrace levels is %s.\n"), value); } @@ -218,13 +318,23 @@ void fprint_frame_id (struct ui_file *file, struct frame_id id) { fprintf_unfiltered (file, "{"); - fprint_field (file, "stack", id.stack_addr_p, id.stack_addr); + + if (id.stack_status == FID_STACK_INVALID) + fprintf_unfiltered (file, "!stack"); + else if (id.stack_status == FID_STACK_UNAVAILABLE) + fprintf_unfiltered (file, "stack="); + else + fprintf_unfiltered (file, "stack=%s", hex_string (id.stack_addr)); fprintf_unfiltered (file, ","); + fprint_field (file, "code", id.code_addr_p, id.code_addr); fprintf_unfiltered (file, ","); + fprint_field (file, "special", id.special_addr_p, id.special_addr); - if (id.inline_depth) - fprintf_unfiltered (file, ",inlined=%d", id.inline_depth); + + if (id.artificial_depth) + fprintf_unfiltered (file, ",artificial=%d", id.artificial_depth); + fprintf_unfiltered (file, "}"); } @@ -242,8 +352,8 @@ fprint_frame_type (struct ui_file *file, enum frame_type type) case INLINE_FRAME: fprintf_unfiltered (file, "INLINE_FRAME"); return; - case SENTINEL_FRAME: - fprintf_unfiltered (file, "SENTINEL_FRAME"); + case TAILCALL_FRAME: + fprintf_unfiltered (file, "TAILCALL_FRAME"); return; case SIGTRAMP_FRAME: fprintf_unfiltered (file, "SIGTRAMP_FRAME"); @@ -251,6 +361,9 @@ fprint_frame_type (struct ui_file *file, enum frame_type type) case ARCH_FRAME: fprintf_unfiltered (file, "ARCH_FRAME"); return; + case SENTINEL_FRAME: + fprintf_unfiltered (file, "SENTINEL_FRAME"); + return; default: fprintf_unfiltered (file, ""); return; @@ -281,10 +394,15 @@ fprint_frame (struct ui_file *file, struct frame_info *fi) fprintf_unfiltered (file, ""); fprintf_unfiltered (file, ","); fprintf_unfiltered (file, "pc="); - if (fi->next != NULL && fi->next->prev_pc.p) - fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_pc.value)); - else + 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)); + else if (fi->next->prev_pc.status == CC_NOT_SAVED) + val_print_not_saved (file); + else if (fi->next->prev_pc.status == CC_UNAVAILABLE) + val_print_unavailable (file); fprintf_unfiltered (file, ","); fprintf_unfiltered (file, "id="); if (fi->this_id.p) @@ -300,18 +418,54 @@ fprint_frame (struct ui_file *file, struct frame_info *fi) fprintf_unfiltered (file, "}"); } -/* Given FRAME, return the enclosing normal frame for inlined - function frames. Otherwise return the original frame. */ +/* 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. */ static struct frame_info * -skip_inlined_frames (struct frame_info *frame) -{ - while (get_frame_type (frame) == INLINE_FRAME) - frame = get_prev_frame (frame); +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. */ + while (get_frame_type (frame) == INLINE_FRAME + || get_frame_type (frame) == TAILCALL_FRAME) + frame = get_prev_frame_always (frame); return frame; } +/* Compute the frame's uniq ID that can be used to, later, re-find the + frame. */ + +static void +compute_frame_id (struct frame_info *fi) +{ + gdb_assert (!fi->this_id.p); + + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, "{ compute_frame_id (fi=%d) ", + fi->level); + /* Find the unwinder. */ + if (fi->unwind == NULL) + frame_unwind_find_by_frame (fi, &fi->prologue_cache); + /* Find THIS frame's ID. */ + /* Default to outermost if no ID is found. */ + fi->this_id.value = outer_frame_id; + fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value); + gdb_assert (frame_id_p (fi->this_id.value)); + fi->this_id.p = 1; + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame_id (gdb_stdlog, fi->this_id.value); + fprintf_unfiltered (gdb_stdlog, " }\n"); + } +} + /* Return a frame uniq ID that can be used to, later, re-find the frame. */ @@ -321,37 +475,14 @@ get_frame_id (struct frame_info *fi) if (fi == NULL) return null_frame_id; - if (!fi->this_id.p) - { - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ", - fi->level); - /* Find the unwinder. */ - if (fi->unwind == NULL) - fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache); - /* Find THIS frame's ID. */ - /* Default to outermost if no ID is found. */ - fi->this_id.value = outer_frame_id; - fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value); - gdb_assert (frame_id_p (fi->this_id.value)); - fi->this_id.p = 1; - if (frame_debug) - { - fprintf_unfiltered (gdb_stdlog, "-> "); - fprint_frame_id (gdb_stdlog, fi->this_id.value); - fprintf_unfiltered (gdb_stdlog, " }\n"); - } - } - - frame_stash_add (fi); - + gdb_assert (fi->this_id.p); return fi->this_id.value; } struct frame_id get_stack_frame_id (struct frame_info *next_frame) { - return get_frame_id (skip_inlined_frames (next_frame)); + return get_frame_id (skip_artificial_frames (next_frame)); } struct frame_id @@ -359,29 +490,59 @@ frame_unwind_caller_id (struct frame_info *next_frame) { struct frame_info *this_frame; - /* Use get_prev_frame_1, 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 a caller requests the frame - ID of "main()"s caller. */ + /* 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 a caller + requests the frame ID of "main()"s caller. */ - next_frame = skip_inlined_frames (next_frame); - this_frame = get_prev_frame_1 (next_frame); + next_frame = skip_artificial_frames (next_frame); + this_frame = get_prev_frame_always (next_frame); if (this_frame) - return get_frame_id (skip_inlined_frames (this_frame)); + return get_frame_id (skip_artificial_frames (this_frame)); else return null_frame_id; } const struct frame_id null_frame_id; /* All zeros. */ -const struct frame_id outer_frame_id = { 0, 0, 0, 0, 0, 1, 0 }; +const struct frame_id outer_frame_id = { 0, 0, 0, FID_STACK_INVALID, 0, 1, 0 }; struct frame_id frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr, CORE_ADDR special_addr) { struct frame_id id = null_frame_id; + id.stack_addr = stack_addr; - id.stack_addr_p = 1; + id.stack_status = FID_STACK_VALID; + id.code_addr = code_addr; + id.code_addr_p = 1; + id.special_addr = special_addr; + id.special_addr_p = 1; + return id; +} + +/* See frame.h. */ + +struct frame_id +frame_id_build_unavailable_stack (CORE_ADDR code_addr) +{ + struct frame_id id = null_frame_id; + + id.stack_status = FID_STACK_UNAVAILABLE; + id.code_addr = code_addr; + id.code_addr_p = 1; + return id; +} + +/* See frame.h. */ + +struct frame_id +frame_id_build_unavailable_stack_special (CORE_ADDR code_addr, + CORE_ADDR special_addr) +{ + struct frame_id id = null_frame_id; + + id.stack_status = FID_STACK_UNAVAILABLE; id.code_addr = code_addr; id.code_addr_p = 1; id.special_addr = special_addr; @@ -393,8 +554,9 @@ struct frame_id frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr) { struct frame_id id = null_frame_id; + id.stack_addr = stack_addr; - id.stack_addr_p = 1; + id.stack_status = FID_STACK_VALID; id.code_addr = code_addr; id.code_addr_p = 1; return id; @@ -404,8 +566,9 @@ struct frame_id frame_id_build_wild (CORE_ADDR stack_addr) { struct frame_id id = null_frame_id; + id.stack_addr = stack_addr; - id.stack_addr_p = 1; + id.stack_status = FID_STACK_VALID; return id; } @@ -413,8 +576,9 @@ int frame_id_p (struct frame_id l) { int p; + /* The frame is valid iff it has a valid stack address. */ - p = l.stack_addr_p; + p = l.stack_status != FID_STACK_INVALID; /* outer_frame_id is also valid. */ if (!p && memcmp (&l, &outer_frame_id, sizeof (l)) == 0) p = 1; @@ -428,30 +592,33 @@ frame_id_p (struct frame_id l) } int -frame_id_inlined_p (struct frame_id l) +frame_id_artificial_p (struct frame_id l) { if (!frame_id_p (l)) return 0; - return (l.inline_depth != 0); + return (l.artificial_depth != 0); } int frame_id_eq (struct frame_id l, struct frame_id r) { int eq; - if (!l.stack_addr_p && l.special_addr_p && !r.stack_addr_p && r.special_addr_p) + + if (l.stack_status == FID_STACK_INVALID && l.special_addr_p + && r.stack_status == FID_STACK_INVALID && r.special_addr_p) /* The outermost frame marker is equal to itself. This is the dodgy thing about outer_frame_id, since between execution steps we might step into another function - from which we can't unwind either. More thought required to get rid of outer_frame_id. */ eq = 1; - else if (!l.stack_addr_p || !r.stack_addr_p) + else if (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; - else if (l.stack_addr != r.stack_addr) + else if (l.stack_status != r.stack_status || l.stack_addr != r.stack_addr) /* If .stack addresses are different, the frames are different. */ eq = 0; else if (l.code_addr_p && r.code_addr_p && l.code_addr != r.code_addr) @@ -463,8 +630,8 @@ frame_id_eq (struct frame_id l, struct frame_id r) /* An invalid special addr is a wild card (or unused). Otherwise if special addresses are different, the frames are different. */ eq = 0; - else if (l.inline_depth != r.inline_depth) - /* If inline depths are different, the frames must be different. */ + else if (l.artificial_depth != r.artificial_depth) + /* If artifical depths are different, the frames must be different. */ eq = 0; else /* Frames are equal. */ @@ -489,7 +656,7 @@ frame_id_eq (struct frame_id l, struct frame_id r) to sigaltstack). However, it can be used as safety net to discover invalid frame - IDs in certain circumstances. Assuming that NEXT is the immediate + IDs in certain circumstances. Assuming that NEXT is the immediate inner frame to THIS and that NEXT and THIS are both NORMAL frames: * The stack address of NEXT must be inner-than-or-equal to the stack @@ -509,7 +676,7 @@ frame_id_eq (struct frame_id l, struct frame_id r) is involved, because signal handlers might be executed on a different stack than the stack used by the routine that caused the signal to be raised. This can happen for instance when a thread exceeds - its maximum stack size. In this case, certain compilers implement + its maximum stack size. In this case, certain compilers implement a stack overflow strategy that cause the handler to be run on a different stack. */ @@ -517,17 +684,19 @@ static int frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r) { int inner; - if (!l.stack_addr_p || !r.stack_addr_p) - /* Like NaN, any operation involving an invalid ID always fails. */ + + if (l.stack_status != FID_STACK_VALID || r.stack_status != FID_STACK_VALID) + /* Like NaN, any operation involving an invalid ID always fails. + Likewise if either ID has an unavailable stack address. */ inner = 0; - else if (l.inline_depth > r.inline_depth + else if (l.artificial_depth > r.artificial_depth && l.stack_addr == r.stack_addr && l.code_addr_p == r.code_addr_p && l.special_addr_p == r.special_addr_p && 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); @@ -584,8 +753,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); - if (frame_id_eq (id, this)) + struct frame_id self = get_frame_id (frame); + + if (frame_id_eq (id, self)) /* An exact match. */ return frame; @@ -599,7 +769,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; @@ -610,11 +780,14 @@ frame_find_by_id (struct frame_id id) static CORE_ADDR frame_unwind_pc (struct frame_info *this_frame) { - if (!this_frame->prev_pc.p) + if (this_frame->prev_pc.status == CC_UNKNOWN) { - CORE_ADDR pc; 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 @@ -631,59 +804,146 @@ frame_unwind_pc (struct frame_info *this_frame) 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. */ - pc = gdbarch_unwind_pc (frame_unwind_arch (this_frame), this_frame); + prev_gdbarch = frame_unwind_arch (this_frame); + + TRY + { + pc = gdbarch_unwind_pc (prev_gdbarch, this_frame); + pc_p = 1; + } + CATCH (ex, RETURN_MASK_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 + + 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")); - this_frame->prev_pc.value = pc; - this_frame->prev_pc.p = 1; - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "{ frame_unwind_caller_pc (this_frame=%d) -> 0x%s }\n", - this_frame->level, - hex_string (this_frame->prev_pc.value)); } - return this_frame->prev_pc.value; + + if (this_frame->prev_pc.status == CC_VALUE) + return this_frame->prev_pc.value; + else if (this_frame->prev_pc.status == CC_UNAVAILABLE) + throw_error (NOT_AVAILABLE_ERROR, _("PC not available")); + else if (this_frame->prev_pc.status == CC_NOT_SAVED) + throw_error (OPTIMIZED_OUT_ERROR, _("PC not saved")); + else + internal_error (__FILE__, __LINE__, + "unexpected prev_pc status: %d", + (int) this_frame->prev_pc.status); } CORE_ADDR frame_unwind_caller_pc (struct frame_info *this_frame) { - return frame_unwind_pc (skip_inlined_frames (this_frame)); + return frame_unwind_pc (skip_artificial_frames (this_frame)); } -CORE_ADDR -get_frame_func (struct frame_info *this_frame) +int +get_frame_func_if_available (struct frame_info *this_frame, CORE_ADDR *pc) { struct frame_info *next_frame = this_frame->next; if (!next_frame->prev_func.p) { + CORE_ADDR addr_in_block; + /* Make certain that this, and not the adjacent, function is found. */ - CORE_ADDR addr_in_block = get_frame_address_in_block (this_frame); - next_frame->prev_func.p = 1; - next_frame->prev_func.addr = get_pc_function_start (addr_in_block); - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "{ get_frame_func (this_frame=%d) -> %s }\n", - this_frame->level, - hex_string (next_frame->prev_func.addr)); + if (!get_frame_address_in_block_if_available (this_frame, &addr_in_block)) + { + next_frame->prev_func.p = -1; + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "{ get_frame_func (this_frame=%d)" + " -> unavailable }\n", + this_frame->level); + } + else + { + next_frame->prev_func.p = 1; + next_frame->prev_func.addr = get_pc_function_start (addr_in_block); + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "{ get_frame_func (this_frame=%d) -> %s }\n", + this_frame->level, + hex_string (next_frame->prev_func.addr)); + } + } + + if (next_frame->prev_func.p < 0) + { + *pc = -1; + return 0; + } + else + { + *pc = next_frame->prev_func.addr; + return 1; } - return next_frame->prev_func.addr; } -static int +CORE_ADDR +get_frame_func (struct frame_info *this_frame) +{ + CORE_ADDR pc; + + if (!get_frame_func_if_available (this_frame, &pc)) + throw_error (NOT_AVAILABLE_ERROR, _("PC not available")); + + return pc; +} + +static enum register_status do_frame_register_read (void *src, int regnum, gdb_byte *buf) { - return frame_register_read (src, regnum, buf); + if (!deprecated_frame_register_read (src, regnum, buf)) + return REG_UNAVAILABLE; + else + return REG_VALID; } struct regcache * frame_save_as_regcache (struct frame_info *this_frame) { - struct regcache *regcache = regcache_xmalloc (get_frame_arch (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); + regcache_save (regcache, do_frame_register_read, this_frame); discard_cleanups (cleanups); return regcache; @@ -700,16 +960,21 @@ 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)); + dummy_frame_pop (get_frame_id (this_frame), inferior_ptid); return; } /* Ensure that we have a frame to pop to. */ - prev_frame = get_prev_frame_1 (this_frame); + prev_frame = get_prev_frame_always (this_frame); if (!prev_frame) error (_("Cannot pop the initial 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); + /* 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 @@ -737,8 +1002,9 @@ frame_pop (struct frame_info *this_frame) void frame_register_unwind (struct frame_info *frame, int regnum, - int *optimizedp, enum lval_type *lvalp, - CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp) + int *optimizedp, int *unavailablep, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, gdb_byte *bufferp) { struct value *value; @@ -755,13 +1021,19 @@ frame_register_unwind (struct frame_info *frame, int regnum, gdb_assert (value != NULL); *optimizedp = value_optimized_out (value); + *unavailablep = !value_entirely_available (value); *lvalp = VALUE_LVAL (value); *addrp = value_address (value); *realnump = VALUE_REGNUM (value); if (bufferp) - memcpy (bufferp, value_contents_all (value), - TYPE_LENGTH (value_type (value))); + { + if (!*optimizedp && !*unavailablep) + memcpy (bufferp, value_contents_all (value), + TYPE_LENGTH (value_type (value))); + else + memset (bufferp, 0, TYPE_LENGTH (value_type (value))); + } /* Dispose of the new value. This prevents watchpoints from trying to watch the saved frame pointer. */ @@ -771,7 +1043,7 @@ frame_register_unwind (struct frame_info *frame, int regnum, void frame_register (struct frame_info *frame, int regnum, - int *optimizedp, enum lval_type *lvalp, + int *optimizedp, int *unavailablep, enum lval_type *lvalp, CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp) { /* Require all but BUFFERP to be valid. A NULL BUFFERP indicates @@ -785,19 +1057,28 @@ frame_register (struct frame_info *frame, int regnum, /* Obtain the register value by unwinding the register from the next (more inner frame). */ gdb_assert (frame != NULL && frame->next != NULL); - frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp, - realnump, bufferp); + frame_register_unwind (frame->next, regnum, optimizedp, unavailablep, + lvalp, addrp, realnump, bufferp); } void frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf) { int optimized; + int unavailable; CORE_ADDR addr; int realnum; enum lval_type lval; - frame_register_unwind (frame, regnum, &optimized, &lval, &addr, - &realnum, buf); + + frame_register_unwind (frame, regnum, &optimized, &unavailable, + &lval, &addr, &realnum, buf); + + if (optimized) + throw_error (OPTIMIZED_OUT_ERROR, + _("Register %d was not saved"), regnum); + if (unavailable) + throw_error (NOT_AVAILABLE_ERROR, + _("Register %d is not available"), regnum); } void @@ -818,15 +1099,16 @@ frame_unwind_register_value (struct frame_info *frame, int regnum) if (frame_debug) { - fprintf_unfiltered (gdb_stdlog, "\ -{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ", + fprintf_unfiltered (gdb_stdlog, + "{ frame_unwind_register_value " + "(frame=%d,regnum=%d(%s),...) ", frame->level, regnum, user_reg_map_regnum_to_name (gdbarch, regnum)); } /* Find the unwinder. */ if (frame->unwind == NULL) - frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache); + frame_unwind_find_by_frame (frame, &frame->prologue_cache); /* Ask this frame to unwind its register. */ value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum); @@ -835,7 +1117,10 @@ frame_unwind_register_value (struct frame_info *frame, int regnum) { fprintf_unfiltered (gdb_stdlog, "->"); if (value_optimized_out (value)) - fprintf_unfiltered (gdb_stdlog, " optimized out"); + { + fprintf_unfiltered (gdb_stdlog, " "); + val_print_optimized_out (value, gdb_stdlog); + } else { if (VALUE_LVAL (value) == lval_register) @@ -882,6 +1167,7 @@ frame_unwind_register_signed (struct frame_info *frame, int regnum) enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int size = register_size (gdbarch, regnum); gdb_byte buf[MAX_REGISTER_SIZE]; + frame_unwind_register (frame, regnum, buf); return extract_signed_integer (buf, size, byte_order); } @@ -899,6 +1185,7 @@ frame_unwind_register_unsigned (struct frame_info *frame, int regnum) enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int size = register_size (gdbarch, regnum); gdb_byte buf[MAX_REGISTER_SIZE]; + frame_unwind_register (frame, regnum, buf); return extract_unsigned_integer (buf, size, byte_order); } @@ -909,6 +1196,26 @@ get_frame_register_unsigned (struct frame_info *frame, int regnum) return frame_unwind_register_unsigned (frame->next, regnum); } +int +read_frame_register_unsigned (struct frame_info *frame, int regnum, + ULONGEST *val) +{ + struct value *regval = get_frame_register_value (frame, regnum); + + if (!value_optimized_out (regval) + && value_entirely_available (regval)) + { + struct gdbarch *gdbarch = get_frame_arch (frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + int size = register_size (gdbarch, VALUE_REGNUM (regval)); + + *val = extract_unsigned_integer (value_contents (regval), size, byte_order); + return 1; + } + + return 0; +} + void put_frame_register (struct frame_info *frame, int regnum, const gdb_byte *buf) @@ -916,20 +1223,19 @@ put_frame_register (struct frame_info *frame, int regnum, struct gdbarch *gdbarch = get_frame_arch (frame); int realnum; int optim; + int unavail; enum lval_type lval; CORE_ADDR addr; - frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL); + + frame_register (frame, regnum, &optim, &unavail, + &lval, &addr, &realnum, NULL); if (optim) - error (_("Attempt to assign to a value that was optimized out.")); + error (_("Attempt to assign to a register that was not saved.")); switch (lval) { case lval_memory: { - /* FIXME: write_memory doesn't yet take constant buffers. - Arrrg! */ - gdb_byte tmp[MAX_REGISTER_SIZE]; - memcpy (tmp, buf, register_size (gdbarch, regnum)); - write_memory (addr, tmp, register_size (gdbarch, regnum)); + write_memory (addr, buf, register_size (gdbarch, regnum)); break; } case lval_register: @@ -940,7 +1246,8 @@ put_frame_register (struct frame_info *frame, int regnum, } } -/* frame_register_read () +/* This function is deprecated. Use get_frame_register_value instead, + which provides more accurate information. Find and return the value of REGNUM for the specified stack frame. The number of bytes copied is REGISTER_SIZE (REGNUM). @@ -948,21 +1255,25 @@ put_frame_register (struct frame_info *frame, int regnum, Returns 0 if the register value could not be found. */ int -frame_register_read (struct frame_info *frame, int regnum, +deprecated_frame_register_read (struct frame_info *frame, int regnum, gdb_byte *myaddr) { int optimized; + int unavailable; enum lval_type lval; CORE_ADDR addr; int realnum; - frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr); - return !optimized; + frame_register (frame, regnum, &optimized, &unavailable, + &lval, &addr, &realnum, myaddr); + + return !optimized && !unavailable; } int get_frame_register_bytes (struct frame_info *frame, int regnum, - CORE_ADDR offset, int len, gdb_byte *myaddr) + CORE_ADDR offset, int len, gdb_byte *myaddr, + int *optimizedp, int *unavailablep) { struct gdbarch *gdbarch = get_frame_arch (frame); int i; @@ -983,33 +1294,44 @@ get_frame_register_bytes (struct frame_info *frame, int regnum, for (i = regnum; i < numregs; i++) { int thissize = register_size (gdbarch, i); + if (thissize == 0) break; /* This register is not available on this architecture. */ maxsize += thissize; } if (len > maxsize) - { - warning (_("Bad debug information detected: " - "Attempt to read %d bytes from registers."), len); - return 0; - } + error (_("Bad debug information detected: " + "Attempt to read %d bytes from registers."), len); /* Copy the data. */ while (len > 0) { int curr_len = register_size (gdbarch, regnum) - offset; + if (curr_len > len) curr_len = len; if (curr_len == register_size (gdbarch, regnum)) { - if (!frame_register_read (frame, regnum, myaddr)) + enum lval_type lval; + CORE_ADDR addr; + int realnum; + + frame_register (frame, regnum, optimizedp, unavailablep, + &lval, &addr, &realnum, myaddr); + if (*optimizedp || *unavailablep) return 0; } else { gdb_byte buf[MAX_REGISTER_SIZE]; - if (!frame_register_read (frame, regnum, buf)) + enum lval_type lval; + CORE_ADDR addr; + int realnum; + + frame_register (frame, regnum, optimizedp, unavailablep, + &lval, &addr, &realnum, buf); + if (*optimizedp || *unavailablep) return 0; memcpy (myaddr, buf + offset, curr_len); } @@ -1020,6 +1342,8 @@ get_frame_register_bytes (struct frame_info *frame, int regnum, regnum++; } + *optimizedp = 0; + *unavailablep = 0; return 1; } @@ -1040,6 +1364,7 @@ put_frame_register_bytes (struct frame_info *frame, int regnum, while (len > 0) { int curr_len = register_size (gdbarch, regnum) - offset; + if (curr_len > len) curr_len = len; @@ -1050,7 +1375,8 @@ put_frame_register_bytes (struct frame_info *frame, int regnum, else { gdb_byte buf[MAX_REGISTER_SIZE]; - frame_register_read (frame, regnum, buf); + + deprecated_frame_register_read (frame, regnum, buf); memcpy (buf + offset, myaddr, curr_len); put_frame_register (frame, regnum, buf); } @@ -1068,6 +1394,7 @@ static struct frame_info * create_sentinel_frame (struct program_space *pspace, struct regcache *regcache) { struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info); + frame->level = -1; frame->pspace = pspace; frame->aspace = get_regcache_aspace (regcache); @@ -1076,7 +1403,7 @@ create_sentinel_frame (struct program_space *pspace, struct regcache *regcache) information, such as the frame's thread will be added. */ frame->prologue_cache = sentinel_frame_cache (regcache); /* For the moment there is only one sentinel frame implementation. */ - frame->unwind = sentinel_frame_unwind; + frame->unwind = &sentinel_frame_unwind; /* 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; @@ -1093,7 +1420,7 @@ create_sentinel_frame (struct program_space *pspace, struct regcache *regcache) return frame; } -/* Info about the innermost stack frame (contents of FP register) */ +/* Info about the innermost stack frame (contents of FP register). */ static struct frame_info *current_frame; @@ -1107,6 +1434,7 @@ void * frame_obstack_zalloc (unsigned long size) { void *data = obstack_alloc (&frame_cache_obstack, size); + memset (data, 0, size); return data; } @@ -1120,6 +1448,7 @@ 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) @@ -1142,19 +1471,23 @@ get_current_frame (void) error (_("No stack.")); if (!target_has_memory) error (_("No memory.")); - 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.")); + /* 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.")); + } if (current_frame == NULL) { struct frame_info *sentinel_frame = create_sentinel_frame (current_program_space, get_current_regcache ()); - if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame, - RETURN_MASK_ERROR) != 0) + 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. */ @@ -1175,17 +1508,21 @@ has_stack_frames (void) if (!target_has_registers || !target_has_stack || !target_has_memory) return 0; - /* No current inferior, no frame. */ - if (ptid_equal (inferior_ptid, null_ptid)) - return 0; + /* Traceframes are effectively a substitute for the live inferior. */ + if (get_traceframe_number () < 0) + { + /* No current inferior, no frame. */ + if (ptid_equal (inferior_ptid, null_ptid)) + return 0; - /* Don't try to read from a dead thread. */ - if (is_exited (inferior_ptid)) - return 0; + /* Don't try to read from a dead thread. */ + if (is_exited (inferior_ptid)) + return 0; - /* ... or from a spinning thread. */ - if (is_executing (inferior_ptid)) - return 0; + /* ... or from a spinning thread. */ + if (is_executing (inferior_ptid)) + return 0; + } return 1; } @@ -1211,6 +1548,14 @@ get_selected_frame (const char *message) return selected_frame; } +/* If there is a selected frame, return it. Otherwise, return NULL. */ + +struct frame_info * +get_selected_frame_if_set (void) +{ + return selected_frame; +} + /* This is a variant of get_selected_frame() which can be called when the inferior does not have a frame; in that case it will return NULL instead of calling error(). */ @@ -1228,13 +1573,9 @@ deprecated_safe_get_selected_frame (void) void select_frame (struct frame_info *fi) { - struct symtab *s; - 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 @@ -1243,29 +1584,34 @@ select_frame (struct frame_info *fi) Once we have frame-parameterized frame (and frame-related) commands, the event notification can be moved here, since this function will only - be called when the user's selected frame is being changed. */ + be called when the user's selected frame is being changed. */ /* Ensure that symbols for this frame are read in. Also, determine the source language of this frame, and switch to it if desired. */ if (fi) { - /* We retrieve the frame's symtab by using 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() which provides us with a PC which - is guaranteed to be inside the frame's code block. */ - s = find_pc_symtab (get_frame_address_in_block (fi)); - if (s - && s->language != current_language->la_language - && s->language != language_unknown - && language_mode == language_mode_auto) + CORE_ADDR pc; + + /* We retrieve the frame's symtab by using 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() which provides us with a + PC which is guaranteed to be inside the frame's code + block. */ + if (get_frame_address_in_block_if_available (fi, &pc)) { - set_language (s->language); + struct compunit_symtab *cust = find_pc_compunit_symtab (pc); + + if (cust != NULL + && compunit_language (cust) != current_language->la_language + && compunit_language (cust) != language_unknown + && language_mode == language_mode_auto) + set_language (compunit_language (cust)); } } } - + /* Create an arbitrary (i.e. address specified by user) or innermost frame. Always returns a non-NULL value. */ @@ -1283,14 +1629,15 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) fi = FRAME_OBSTACK_ZALLOC (struct frame_info); - fi->next = create_sentinel_frame (current_program_space, get_current_regcache ()); + fi->next = create_sentinel_frame (current_program_space, + get_current_regcache ()); /* Set/update this frame's cached PC value, found in the next frame. Do this before looking for this frame's unwinder. A sniffer is very likely to read this, and the corresponding unwinder is entitled to rely that the PC doesn't magically change. */ fi->next->prev_pc.value = pc; - fi->next->prev_pc.p = 1; + fi->next->prev_pc.status = CC_VALUE; /* We currently assume that frame chain's can't cross spaces. */ fi->pspace = fi->next->pspace; @@ -1298,7 +1645,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) /* Select/initialize both the unwind function and the frame's type based on the PC. */ - fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache); + frame_unwind_find_by_frame (fi, &fi->prologue_cache); fi->this_id.p = 1; fi->this_id.value = frame_id_build (addr, pc); @@ -1350,7 +1697,7 @@ reinit_frame_cache (void) fi->base->unwind->dealloc_cache (fi, fi->base_cache); } - /* Since we can't really be sure what the first object allocated was */ + /* Since we can't really be sure what the first object allocated was. */ obstack_free (&frame_cache_obstack, 0); obstack_init (&frame_cache_obstack); @@ -1377,8 +1724,10 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum, while (this_frame != NULL) { - frame_register_unwind (this_frame, regnum, optimizedp, lvalp, - addrp, realnump, NULL); + int unavailable; + + frame_register_unwind (this_frame, regnum, optimizedp, &unavailable, + lvalp, addrp, realnump, NULL); if (*optimizedp) break; @@ -1391,16 +1740,73 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum, } } -/* Return a "struct frame_info" corresponding to the frame that called - THIS_FRAME. Returns NULL if there is no such frame. +/* Called during frame unwinding to remove a previous frame pointer from a + frame passed in ARG. */ - Unlike get_prev_frame, this function always tries to unwind the - frame. */ +static void +remove_prev_frame (void *arg) +{ + struct frame_info *this_frame, *prev_frame; + + this_frame = (struct frame_info *) arg; + prev_frame = this_frame->prev; + gdb_assert (prev_frame != NULL); + + prev_frame->next = NULL; + this_frame->prev = NULL; +} + +/* Get the previous raw frame, and check that it is not identical to + same other frame frame already in the chain. If it is, there is + most likely a stack cycle, so we discard it, and mark THIS_FRAME as + outermost, with UNWIND_SAME_ID stop reason. Unlike the other + validity tests, that compare THIS_FRAME and the next frame, we do + this right after creating the previous frame, to avoid ever ending + up with two frames with the same id in the frame chain. */ + +static struct frame_info * +get_prev_frame_if_no_cycle (struct frame_info *this_frame) +{ + struct frame_info *prev_frame; + struct cleanup *prev_frame_cleanup; + + prev_frame = get_prev_frame_raw (this_frame); + if (prev_frame == NULL) + return NULL; + + /* The cleanup will remove the previous frame that get_prev_frame_raw + linked onto THIS_FRAME. */ + prev_frame_cleanup = make_cleanup (remove_prev_frame, this_frame); + + 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; + } + + discard_cleanups (prev_frame_cleanup); + return prev_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_1 (struct frame_info *this_frame) +get_prev_frame_always_1 (struct frame_info *this_frame) { - struct frame_id this_id; struct gdbarch *gdbarch; gdb_assert (this_frame != NULL); @@ -1408,7 +1814,7 @@ get_prev_frame_1 (struct frame_info *this_frame) if (frame_debug) { - fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_1 (this_frame="); + fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_always (this_frame="); if (this_frame != NULL) fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level); else @@ -1433,8 +1839,7 @@ get_prev_frame_1 (struct frame_info *this_frame) sniffers will think that this frame's sniffer tried to unwind further (see frame_cleanup_after_sniffer). */ if (this_frame->unwind == NULL) - this_frame->unwind - = frame_unwind_find_by_frame (this_frame, &this_frame->prologue_cache); + frame_unwind_find_by_frame (this_frame, &this_frame->prologue_cache); this_frame->prev_p = 1; this_frame->stop_reason = UNWIND_NO_REASON; @@ -1445,21 +1850,25 @@ get_prev_frame_1 (struct frame_info *this_frame) until we have unwound all the way down to the previous non-inline frame. */ if (get_frame_type (this_frame) == INLINE_FRAME) - return get_prev_frame_raw (this_frame); + return get_prev_frame_if_no_cycle (this_frame); + + /* Check that this frame is unwindable. If it isn't, don't try to + unwind to the prev frame. */ + this_frame->stop_reason + = this_frame->unwind->stop_reason (this_frame, + &this_frame->prologue_cache); - /* Check that this frame's ID was valid. If it wasn't, don't try to - unwind to the prev frame. Be careful to not apply this test to - the sentinel frame. */ - this_id = get_frame_id (this_frame); - if (this_frame->level >= 0 && frame_id_eq (this_id, outer_frame_id)) + if (this_frame->stop_reason != UNWIND_NO_REASON) { if (frame_debug) { + enum unwind_stop_reason reason = this_frame->stop_reason; + fprintf_unfiltered (gdb_stdlog, "-> "); fprint_frame (gdb_stdlog, NULL); - fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n"); + fprintf_unfiltered (gdb_stdlog, " // %s }\n", + frame_stop_reason_symbol_string (reason)); } - this_frame->stop_reason = UNWIND_NULL_ID; return NULL; } @@ -1469,33 +1878,31 @@ get_prev_frame_1 (struct frame_info *this_frame) See the comment at frame_id_inner for details. */ if (get_frame_type (this_frame) == NORMAL_FRAME && this_frame->next->unwind->type == NORMAL_FRAME - && frame_id_inner (get_frame_arch (this_frame->next), this_id, + && frame_id_inner (get_frame_arch (this_frame->next), + get_frame_id (this_frame), get_frame_id (this_frame->next))) { - if (frame_debug) + CORE_ADDR this_pc_in_block; + struct minimal_symbol *morestack_msym; + const char *morestack_name = NULL; + + /* gcc -fsplit-stack __morestack can continue the stack anywhere. */ + 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); + if (!morestack_name || strcmp (morestack_name, "__morestack") != 0) { - fprintf_unfiltered (gdb_stdlog, "-> "); - fprint_frame (gdb_stdlog, NULL); - fprintf_unfiltered (gdb_stdlog, " // this frame ID is inner }\n"); - } - this_frame->stop_reason = UNWIND_INNER_ID; - return NULL; - } - - /* Check that this and the next frame are not identical. If they - are, there is most likely a stack cycle. As with the inner-than - test above, avoid comparing the inner-most and sentinel frames. */ - if (this_frame->level > 0 - && frame_id_eq (this_id, get_frame_id (this_frame->next))) - { - if (frame_debug) - { - fprintf_unfiltered (gdb_stdlog, "-> "); - fprint_frame (gdb_stdlog, NULL); - fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n"); + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, + " // this frame ID is inner }\n"); + } + this_frame->stop_reason = UNWIND_INNER_ID; + return NULL; } - this_frame->stop_reason = UNWIND_SAME_ID; - return NULL; } /* Check that this and the next frame do not unwind the PC register @@ -1545,7 +1952,51 @@ get_prev_frame_1 (struct frame_info *this_frame) } } - return get_prev_frame_raw (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 (ex, RETURN_MASK_ERROR) + { + 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 = strlen (ex.message) + 1; + stop_string = frame_obstack_zalloc (size); + memcpy (stop_string, ex.message, size); + this_frame->stop_string = stop_string; + } + prev_frame = NULL; + } + else + throw_exception (ex); + } + END_CATCH + + return prev_frame; } /* Construct a new "struct frame_info" and link it previous to @@ -1629,18 +2080,18 @@ frame_debug_got_null_frame (struct frame_info *this_frame, static int inside_main_func (struct frame_info *this_frame) { - struct minimal_symbol *msymbol; + struct bound_minimal_symbol msymbol; CORE_ADDR maddr; if (symfile_objfile == 0) return 0; msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile); - if (msymbol == NULL) + if (msymbol.minsym == NULL) return 0; /* Make certain that the code, and not descriptor, address is returned. */ maddr = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame), - SYMBOL_VALUE_ADDRESS (msymbol), + BMSYMBOL_VALUE_ADDRESS (msymbol), ¤t_target); return maddr == get_frame_func (this_frame); } @@ -1650,7 +2101,12 @@ inside_main_func (struct frame_info *this_frame) static int inside_entry_func (struct frame_info *this_frame) { - return (get_frame_func (this_frame) == entry_point_address ()); + CORE_ADDR entry_point; + + if (!entry_point_address_query (&entry_point)) + return 0; + + return get_frame_func (this_frame) == entry_point; } /* Return a structure containing various interesting information about @@ -1665,12 +2121,14 @@ inside_entry_func (struct frame_info *this_frame) struct frame_info * get_prev_frame (struct frame_info *this_frame) { - struct frame_info *prev_frame; + CORE_ADDR frame_pc; + int frame_pc_p; /* There is always a frame. If this assertion fails, suspect that something should be calling get_selected_frame() or get_current_frame(). */ gdb_assert (this_frame != NULL); + 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 sense to stop unwinding at a dummy frame. One place where a dummy @@ -1685,6 +2143,7 @@ get_prev_frame (struct frame_info *this_frame) if (this_frame->level >= 0 && get_frame_type (this_frame) == NORMAL_FRAME && !backtrace_past_main + && frame_pc_p && inside_main_func (this_frame)) /* Don't unwind past main(). Note, this is done _before_ the frame has been marked as previously unwound. That way if the @@ -1731,6 +2190,7 @@ get_prev_frame (struct frame_info *this_frame) if (this_frame->level >= 0 && get_frame_type (this_frame) == NORMAL_FRAME && !backtrace_past_entry + && frame_pc_p && inside_entry_func (this_frame)) { frame_debug_got_null_frame (this_frame, "inside entry func"); @@ -1744,13 +2204,13 @@ get_prev_frame (struct frame_info *this_frame) && (get_frame_type (this_frame) == NORMAL_FRAME || get_frame_type (this_frame) == INLINE_FRAME) && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME - && get_frame_pc (this_frame) == 0) + && frame_pc_p && frame_pc == 0) { frame_debug_got_null_frame (this_frame, "zero PC"); return NULL; } - return get_prev_frame_1 (this_frame); + return get_prev_frame_always (this_frame); } CORE_ADDR @@ -1760,6 +2220,28 @@ get_frame_pc (struct frame_info *frame) return frame_unwind_pc (frame->next); } +int +get_frame_pc_if_available (struct frame_info *frame, CORE_ADDR *pc) +{ + + gdb_assert (frame->next != NULL); + + TRY + { + *pc = frame_unwind_pc (frame->next); + } + CATCH (ex, RETURN_MASK_ERROR) + { + if (ex.error == NOT_AVAILABLE_ERROR) + return 0; + else + throw_exception (ex); + } + END_CATCH + + return 1; +} + /* Return an address that falls within THIS_FRAME's code block. */ CORE_ADDR @@ -1812,19 +2294,42 @@ get_frame_address_in_block (struct frame_info *this_frame) while (get_frame_type (next_frame) == INLINE_FRAME) next_frame = next_frame->next; - if (get_frame_type (next_frame) == NORMAL_FRAME + if ((get_frame_type (next_frame) == NORMAL_FRAME + || get_frame_type (next_frame) == TAILCALL_FRAME) && (get_frame_type (this_frame) == NORMAL_FRAME + || get_frame_type (this_frame) == TAILCALL_FRAME || get_frame_type (this_frame) == INLINE_FRAME)) return pc - 1; return pc; } +int +get_frame_address_in_block_if_available (struct frame_info *this_frame, + CORE_ADDR *pc) +{ + + TRY + { + *pc = get_frame_address_in_block (this_frame); + } + CATCH (ex, RETURN_MASK_ERROR) + { + if (ex.error == NOT_AVAILABLE_ERROR) + return 0; + throw_exception (ex); + } + END_CATCH + + return 1; +} + void find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) { 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 @@ -1839,10 +2344,12 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) else sym = inline_skipped_symbol (inferior_ptid); + /* If frame is inline, it certainly has symbols. */ + gdb_assert (sym); init_sal (sal); if (SYMBOL_LINE (sym) != 0) { - sal->symtab = SYMBOL_SYMTAB (sym); + sal->symtab = symbol_symtab (sym); sal->line = SYMBOL_LINE (sym); } else @@ -1851,6 +2358,8 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) we can't do much better. */ sal->pc = get_frame_pc (frame); + sal->pspace = get_frame_program_space (frame); + return; } @@ -1863,8 +2372,14 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) PC and such a PC indicates the current (rather than next) instruction/line, consequently, for such cases, want to get the line containing fi->pc. */ - notcurrent = (get_frame_pc (frame) != get_frame_address_in_block (frame)); - (*sal) = find_pc_line (get_frame_pc (frame), notcurrent); + if (!get_frame_pc_if_available (frame, &pc)) + { + init_sal (sal); + return; + } + + notcurrent = (pc != get_frame_address_in_block (frame)); + (*sal) = find_pc_line (pc, notcurrent); } /* Per "frame.h", return the ``address'' of the frame. Code should @@ -1894,7 +2409,6 @@ get_frame_base_address (struct frame_info *fi) CORE_ADDR get_frame_locals_address (struct frame_info *fi) { - void **cache; if (get_frame_type (fi) != NORMAL_FRAME) return 0; /* If there isn't a frame address method, find it. */ @@ -1910,7 +2424,6 @@ get_frame_locals_address (struct frame_info *fi) CORE_ADDR get_frame_args_address (struct frame_info *fi) { - void **cache; if (get_frame_type (fi) != NORMAL_FRAME) return 0; /* If there isn't a frame address method, find it. */ @@ -1930,7 +2443,7 @@ int frame_unwinder_is (struct frame_info *fi, const struct frame_unwind *unwinder) { if (fi->unwind == NULL) - fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache); + frame_unwind_find_by_frame (fi, &fi->prologue_cache); return fi->unwind == unwinder; } @@ -1952,7 +2465,7 @@ get_frame_type (struct frame_info *frame) if (frame->unwind == NULL) /* Initialize the frame's unwinder because that's what provides the frame's type. */ - frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache); + frame_unwind_find_by_frame (frame, &frame->prologue_cache); return frame->unwind->type; } @@ -1994,6 +2507,7 @@ get_frame_memory_signed (struct frame_info *this_frame, CORE_ADDR addr, { struct gdbarch *gdbarch = get_frame_arch (this_frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + return read_memory_integer (addr, len, byte_order); } @@ -2003,6 +2517,7 @@ get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr, { struct gdbarch *gdbarch = get_frame_arch (this_frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + return read_memory_unsigned_integer (addr, len, byte_order); } @@ -2030,9 +2545,7 @@ frame_unwind_arch (struct frame_info *next_frame) struct gdbarch *arch; if (next_frame->unwind == NULL) - next_frame->unwind - = frame_unwind_find_by_frame (next_frame, - &next_frame->prologue_cache); + frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache); if (next_frame->unwind->prev_arch != NULL) arch = next_frame->unwind->prev_arch (next_frame, @@ -2055,7 +2568,7 @@ frame_unwind_arch (struct frame_info *next_frame) struct gdbarch * frame_unwind_caller_arch (struct frame_info *next_frame) { - return frame_unwind_arch (skip_inlined_frames (next_frame)); + return frame_unwind_arch (skip_artificial_frames (next_frame)); } /* Stack pointer methods. */ @@ -2064,6 +2577,7 @@ CORE_ADDR 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)) @@ -2083,37 +2597,58 @@ get_frame_sp (struct frame_info *this_frame) enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *frame) { - /* If we haven't tried to unwind past this point yet, then assume - that unwinding would succeed. */ - if (frame->prev_p == 0) - return UNWIND_NO_REASON; + /* Fill-in STOP_REASON. */ + get_prev_frame_always (frame); + gdb_assert (frame->prev_p); - /* Otherwise, we set a reason when we succeeded (or failed) to - unwind. */ return frame->stop_reason; } /* 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) { - case UNWIND_NULL_ID: - return _("unwinder did not report frame ID"); +#define SET(name, description) \ + case name: return _(description); +#include "unwind_stop_reasons.def" +#undef SET - case UNWIND_INNER_ID: - return _("previous frame inner to this frame (corrupt stack?)"); + default: + internal_error (__FILE__, __LINE__, + "Invalid frame stop reason"); + } +} - case UNWIND_SAME_ID: - return _("previous frame identical to this frame (corrupt stack?)"); +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); +} - case UNWIND_NO_SAVED_PC: - return _("frame did not save the PC"); +/* Return the enum symbol name of REASON as a string, to use in debug + output. */ + +static const char * +frame_stop_reason_symbol_string (enum unwind_stop_reason reason) +{ + switch (reason) + { +#define SET(name, description) \ + case name: return #name; +#include "unwind_stop_reasons.def" +#undef SET - case UNWIND_NO_REASON: - case UNWIND_FIRST_ERROR: default: internal_error (__FILE__, __LINE__, "Invalid frame stop reason"); @@ -2172,7 +2707,8 @@ 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); + help_list (set_backtrace_cmdlist, "set backtrace ", all_commands, + gdb_stdout); } static void @@ -2186,6 +2722,8 @@ _initialize_frame (void) { obstack_init (&frame_cache_obstack); + frame_stash_create (); + observer_attach_target_changed (frame_observer_target_changed); add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\ @@ -2218,30 +2756,30 @@ 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\ +will terminate the backtrace there. Set this variable if you need to see\n\ the rest of the stack trace."), NULL, show_backtrace_past_entry, &set_backtrace_cmdlist, &show_backtrace_cmdlist); - add_setshow_integer_cmd ("limit", class_obscure, - &backtrace_limit, _("\ + add_setshow_uinteger_cmd ("limit", class_obscure, + &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\ -Zero is unlimited."), - NULL, - show_backtrace_limit, - &set_backtrace_cmdlist, - &show_backtrace_cmdlist); +Literal \"unlimited\" or zero means no limit."), + NULL, + show_backtrace_limit, + &set_backtrace_cmdlist, + &show_backtrace_cmdlist); - /* Debug this files internals. */ - add_setshow_zinteger_cmd ("frame", class_maintenance, &frame_debug, _("\ + /* Debug this files internals. */ + add_setshow_zuinteger_cmd ("frame", class_maintenance, &frame_debug, _("\ Set frame debugging."), _("\ Show frame debugging."), _("\ When non-zero, frame specific internal debugging is enabled."), - NULL, - show_frame_debug, - &setdebuglist, &showdebuglist); + NULL, + show_frame_debug, + &setdebuglist, &showdebuglist); }