X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gdb%2Fframe.c;h=5c4217c6d05a1c8ff8d9c3f1e35518bc6e0a8705;hb=ee959deb576c46b85b6174626d700e1393256adf;hp=535a5a6dde26c4001cb7c4737e5c14bb45985b4e;hpb=be2c48b4d50b992ba83bc51f086e316621a03a14;p=platform%2Fupstream%2Fbinutils.git diff --git a/gdb/frame.c b/gdb/frame.c index 535a5a6..5c4217c 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-2013 Free Software Foundation, Inc. + Copyright (C) 1986-2014 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" @@ -38,15 +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 @@ -94,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; @@ -127,6 +142,10 @@ 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. Create a hash table @@ -147,10 +166,11 @@ frame_addr_hash (const void *ap) const struct frame_id f_id = frame->this_id.value; hashval_t hash = 0; - gdb_assert (f_id.stack_addr_p || f_id.code_addr_p + gdb_assert (f_id.stack_status != FID_STACK_INVALID + || f_id.code_addr_p || f_id.special_addr_p); - if (f_id.stack_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) @@ -188,23 +208,31 @@ frame_stash_create (void) NULL); } -/* Internal function to add a frame to the frame_stash hash table. Do - not store frames below 0 as they may not have any addresses to - calculate a hash. */ +/* 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 void +static int frame_stash_add (struct frame_info *frame) { - /* Do not stash frames below level 0. */ - if (frame->level >= 0) - { - struct frame_info **slot; + struct frame_info **slot; - slot = (struct frame_info **) htab_find_slot (frame_stash, - frame, - INSERT); - *slot = frame; - } + /* 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; } /* Internal function to search the frame stash for an entry with the @@ -290,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.artificial_depth) fprintf_unfiltered (file, ",artificial=%d", id.artificial_depth); + fprintf_unfiltered (file, "}"); } @@ -356,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) @@ -382,13 +425,47 @@ fprint_frame (struct ui_file *file, struct frame_info *fi) static struct frame_info * 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 (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. */ @@ -398,29 +475,7 @@ 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) - 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; } @@ -435,13 +490,13 @@ 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_artificial_frames (next_frame); - this_frame = get_prev_frame_1 (next_frame); + this_frame = get_prev_frame_always (next_frame); if (this_frame) return get_frame_id (skip_artificial_frames (this_frame)); else @@ -449,7 +504,7 @@ frame_unwind_caller_id (struct frame_info *next_frame) } 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, @@ -458,7 +513,36 @@ frame_id_build_special (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; + 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; @@ -472,7 +556,7 @@ 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; @@ -484,7 +568,7 @@ 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; } @@ -494,7 +578,7 @@ 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; @@ -521,19 +605,20 @@ 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 + || l.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) @@ -600,8 +685,9 @@ 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.artificial_depth > r.artificial_depth && l.stack_addr == r.stack_addr @@ -610,7 +696,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); @@ -691,10 +777,10 @@ frame_find_by_id (struct frame_id id) return NULL; } -static int -frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc) +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) { if (gdbarch_unwind_pc_p (frame_unwind_arch (this_frame))) { @@ -724,24 +810,35 @@ frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc) { pc = gdbarch_unwind_pc (prev_gdbarch, this_frame); } - if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR) - { - this_frame->prev_pc.p = -1; - - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "{ frame_unwind_pc (this_frame=%d)" - " -> }\n", - this_frame->level); - } - else if (ex.reason < 0) + if (ex.reason < 0) { - throw_exception (ex); + 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); } else { this_frame->prev_pc.value = pc; - this_frame->prev_pc.p = 1; + this_frame->prev_pc.status = CC_VALUE; if (frame_debug) fprintf_unfiltered (gdb_stdlog, "{ frame_unwind_pc (this_frame=%d) " @@ -753,27 +850,17 @@ frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc) else internal_error (__FILE__, __LINE__, _("No unwind_pc method")); } - if (this_frame->prev_pc.p < 0) - { - *pc = -1; - return 0; - } - else - { - *pc = this_frame->prev_pc.value; - return 1; - } -} - -static CORE_ADDR -frame_unwind_pc (struct frame_info *this_frame) -{ - CORE_ADDR pc; - if (!frame_unwind_pc_if_available (this_frame, &pc)) + 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 - return pc; + internal_error (__FILE__, __LINE__, + "unexpected prev_pc status: %d", + (int) this_frame->prev_pc.status); } CORE_ADDR @@ -783,13 +870,6 @@ frame_unwind_caller_pc (struct frame_info *this_frame) } int -frame_unwind_caller_pc_if_available (struct frame_info *this_frame, - CORE_ADDR *pc) -{ - return frame_unwind_pc_if_available (skip_artificial_frames (this_frame), pc); -} - -int get_frame_func_if_available (struct frame_info *this_frame, CORE_ADDR *pc) { struct frame_info *next_frame = this_frame->next; @@ -877,12 +957,12 @@ 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.")); @@ -991,7 +1071,8 @@ frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf) &lval, &addr, &realnum, buf); if (optimized) - error (_("Register %d was optimized out"), regnum); + throw_error (OPTIMIZED_OUT_ERROR, + _("Register %d was not saved"), regnum); if (unavailable) throw_error (NOT_AVAILABLE_ERROR, _("Register %d is not available"), regnum); @@ -1033,7 +1114,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) @@ -1552,7 +1636,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) 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; @@ -1655,25 +1739,81 @@ 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_1 (struct frame_info *this_frame) +get_prev_frame_if_no_cycle (struct frame_info *this_frame) { - struct frame_id this_id; - struct gdbarch *gdbarch; 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_always_1 (struct frame_info *this_frame) +{ + struct gdbarch *gdbarch; gdb_assert (this_frame != NULL); gdbarch = get_frame_arch (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 @@ -1709,7 +1849,7 @@ 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. */ @@ -1718,21 +1858,16 @@ get_prev_frame_1 (struct frame_info *this_frame) &this_frame->prologue_cache); if (this_frame->stop_reason != UNWIND_NO_REASON) - return NULL; - - /* 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 (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; } @@ -1742,7 +1877,8 @@ 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))) { CORE_ADDR this_pc_in_block; @@ -1753,7 +1889,7 @@ get_prev_frame_1 (struct frame_info *this_frame) this_pc_in_block = get_frame_address_in_block (this_frame); morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block).minsym; if (morestack_msym) - morestack_name = SYMBOL_LINKAGE_NAME (morestack_msym); + morestack_name = MSYMBOL_LINKAGE_NAME (morestack_msym); if (!morestack_name || strcmp (morestack_name, "__morestack") != 0) { if (frame_debug) @@ -1815,28 +1951,48 @@ get_prev_frame_1 (struct frame_info *this_frame) } } - prev_frame = get_prev_frame_raw (this_frame); + return get_prev_frame_if_no_cycle (this_frame); +} - /* Check that this and the prev frame are not identical. If they - are, there is most likely a stack cycle. Unlike the tests above, - we do this right after creating the prev frame, to avoid ever - ending up with two frames with the same id in the frame - chain. */ - if (prev_frame != NULL - && frame_id_eq (get_frame_id (prev_frame), - get_frame_id (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) +{ + volatile struct gdb_exception ex; + struct frame_info *prev_frame = NULL; + + TRY_CATCH (ex, RETURN_MASK_ERROR) { - if (frame_debug) + prev_frame = get_prev_frame_always_1 (this_frame); + } + if (ex.reason < 0) + { + if (ex.error == MEMORY_ERROR) { - fprintf_unfiltered (gdb_stdlog, "-> "); - fprint_frame (gdb_stdlog, NULL); - fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n"); + 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; } - this_frame->stop_reason = UNWIND_SAME_ID; - /* Unlink. */ - prev_frame->next = NULL; - this_frame->prev = NULL; - return NULL; + else + throw_exception (ex); } return prev_frame; @@ -1923,18 +2079,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); } @@ -2053,7 +2209,7 @@ get_prev_frame (struct frame_info *this_frame) return NULL; } - return get_prev_frame_1 (this_frame); + return get_prev_frame_always (this_frame); } CORE_ADDR @@ -2438,20 +2594,17 @@ 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) { @@ -2466,6 +2619,39 @@ 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. */ + +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 + + default: + internal_error (__FILE__, __LINE__, + "Invalid frame stop reason"); + } +} + /* Clean up after a failed (wrong unwinder) attempt to unwind past FRAME. */ @@ -2518,7 +2704,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