X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Fframe.c;h=44a9c65d708f69145a7eb14c0b58e266ed390c76;hb=701e355da02cdaa4b6f1455ea32b61dfef9b2c51;hp=13a9f1d2734ab3726ca87b627a1624b10f7bd3d3;hpb=60250e8b18a4dee75e82d49da715681d41561b3b;p=binutils-gdb.git diff --git a/gdb/frame.c b/gdb/frame.c index 13a9f1d2734..44a9c65d708 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1,13 +1,13 @@ /* Cache and manage frames for GDB, the GNU debugger. - Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, - 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001, + 2002, 2003, 2004, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -16,9 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "frame.h" @@ -42,6 +40,7 @@ #include "observer.h" #include "objfiles.h" #include "exceptions.h" +#include "gdbthread.h" static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame); @@ -107,17 +106,54 @@ struct frame_info struct frame_info *next; /* down, inner, younger */ int prev_p; struct frame_info *prev; /* up, outer, older */ + + /* 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; }; /* Flag to control debugging. */ -static int frame_debug; +int frame_debug; +static void +show_frame_debug (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Frame debugging is %s.\n"), value); +} /* Flag to indicate whether backtraces should stop at main et.al. */ static int backtrace_past_main; +static void +show_backtrace_past_main (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("\ +Whether backtraces should continue past \"main\" is %s.\n"), + value); +} + static int backtrace_past_entry; -static unsigned int backtrace_limit = UINT_MAX; +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"), + value); +} + +static int backtrace_limit = INT_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"), + value); +} + static void fprint_field (struct ui_file *file, const char *name, int p, CORE_ADDR addr) @@ -220,10 +256,9 @@ get_frame_id (struct frame_info *fi) fi->level); /* Find the unwinder. */ if (fi->unwind == NULL) - fi->unwind = frame_unwind_find_by_frame (fi->next, - &fi->prologue_cache); + fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache); /* Find THIS frame's ID. */ - fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value); + fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value); fi->this_id.p = 1; if (frame_debug) { @@ -333,8 +368,40 @@ frame_id_eq (struct frame_id l, struct frame_id r) return eq; } -int -frame_id_inner (struct frame_id l, struct frame_id r) +/* Safety net to check whether frame ID L should be inner to + frame ID R, according to their stack addresses. + + This method cannot be used to compare arbitrary frames, as the + ranges of valid stack addresses may be discontiguous (e.g. due + to sigaltstack). + + However, it can be used as safety net to discover invalid frame + 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 + address of THIS. + + Therefore, if frame_id_inner (THIS, NEXT) holds, some unwind + error has occurred. + + * If NEXT and THIS have different stack addresses, no other frame + in the frame chain may have a stack address in between. + + Therefore, if frame_id_inner (TEST, THIS) holds, but + frame_id_inner (TEST, NEXT) does not hold, TEST cannot refer + to a valid frame in the frame chain. + + The sanity checks above cannot be performed when a SIGTRAMP frame + 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 + a stack overflow strategy that cause the handler to be run on a + different stack. */ + +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) @@ -345,7 +412,7 @@ frame_id_inner (struct frame_id l, struct frame_id r) comment in "frame.h", there is some fuzz here. Frameless functions are not strictly inner than (same .stack but different .code and/or .special address). */ - inner = INNER_THAN (l.stack_addr, r.stack_addr); + inner = gdbarch_inner_than (gdbarch, l.stack_addr, r.stack_addr); if (frame_debug) { fprintf_unfiltered (gdb_stdlog, "{ frame_id_inner (l="); @@ -360,28 +427,34 @@ frame_id_inner (struct frame_id l, struct frame_id r) struct frame_info * frame_find_by_id (struct frame_id id) { - struct frame_info *frame; + struct frame_info *frame, *prev_frame; /* ZERO denotes the null frame, let the caller decide what to do about it. Should it instead return get_current_frame()? */ if (!frame_id_p (id)) return NULL; - for (frame = get_current_frame (); - frame != NULL; - frame = get_prev_frame (frame)) + for (frame = get_current_frame (); ; frame = prev_frame) { struct frame_id this = get_frame_id (frame); if (frame_id_eq (id, this)) /* An exact match. */ return frame; - if (frame_id_inner (id, this)) - /* Gone to far. */ + + prev_frame = get_prev_frame (frame); + if (!prev_frame) + return NULL; + + /* As a safety net to avoid unnecessary backtracing while trying + to find an invalid ID, we check for a common situation where + we can detect from comparing stack addresses that no other + 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 (prev_frame), id, + get_frame_id (prev_frame))) return NULL; - /* Either we're not yet gone far enough out along the frame - chain (inner(this,id)), or we're comparing frameless functions - (same .base, different .func, no test available). Struggle - on until we've definitly gone to far. */ } return NULL; } @@ -392,15 +465,7 @@ frame_pc_unwind (struct frame_info *this_frame) if (!this_frame->prev_pc.p) { CORE_ADDR pc; - if (this_frame->unwind == NULL) - this_frame->unwind - = frame_unwind_find_by_frame (this_frame->next, - &this_frame->prologue_cache); - if (this_frame->unwind->prev_pc != NULL) - /* A per-frame unwinder, prefer it. */ - pc = this_frame->unwind->prev_pc (this_frame->next, - &this_frame->prologue_cache); - else if (gdbarch_unwind_pc_p (current_gdbarch)) + if (gdbarch_unwind_pc_p (get_frame_arch (this_frame))) { /* The right way. The `pure' way. The one true way. This method depends solely on the register-unwind code to @@ -418,10 +483,10 @@ frame_pc_unwind (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 (current_gdbarch, this_frame); + pc = gdbarch_unwind_pc (get_frame_arch (this_frame), this_frame); } else - internal_error (__FILE__, __LINE__, "No unwind_pc method"); + internal_error (__FILE__, __LINE__, _("No unwind_pc method")); this_frame->prev_pc.value = pc; this_frame->prev_pc.p = 1; if (frame_debug) @@ -434,40 +499,36 @@ frame_pc_unwind (struct frame_info *this_frame) } CORE_ADDR -frame_func_unwind (struct frame_info *fi) +get_frame_func (struct frame_info *this_frame) { - if (!fi->prev_func.p) + struct frame_info *next_frame = this_frame->next; + + if (!next_frame->prev_func.p) { /* Make certain that this, and not the adjacent, function is found. */ - CORE_ADDR addr_in_block = frame_unwind_address_in_block (fi); - fi->prev_func.p = 1; - fi->prev_func.addr = get_pc_function_start (addr_in_block); + 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, - "{ frame_func_unwind (fi=%d) -> 0x%s }\n", - fi->level, paddr_nz (fi->prev_func.addr)); + "{ get_frame_func (this_frame=%d) -> 0x%s }\n", + this_frame->level, + paddr_nz (next_frame->prev_func.addr)); } - return fi->prev_func.addr; -} - -CORE_ADDR -get_frame_func (struct frame_info *fi) -{ - return frame_func_unwind (fi->next); + return next_frame->prev_func.addr; } static int -do_frame_register_read (void *src, int regnum, void *buf) +do_frame_register_read (void *src, int regnum, gdb_byte *buf) { - frame_register_read (src, regnum, buf); - return 1; + return frame_register_read (src, regnum, buf); } struct regcache * frame_save_as_regcache (struct frame_info *this_frame) { - struct regcache *regcache = regcache_xmalloc (current_gdbarch); + struct regcache *regcache = regcache_xmalloc (get_frame_arch (this_frame)); struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache); regcache_save (regcache, do_frame_register_read, this_frame); discard_cleanups (cleanups); @@ -477,13 +538,30 @@ frame_save_as_regcache (struct frame_info *this_frame) void frame_pop (struct frame_info *this_frame) { + struct frame_info *prev_frame; + struct regcache *scratch; + struct cleanup *cleanups; + + if (get_frame_type (this_frame) == DUMMY_FRAME) + { + /* Popping a dummy frame involves restoring more than just registers. + dummy_frame_pop does all the work. */ + dummy_frame_pop (get_frame_id (this_frame)); + return; + } + + /* Ensure that we have a frame to pop to. */ + prev_frame = get_prev_frame_1 (this_frame); + + if (!prev_frame) + error (_("Cannot pop the initial 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 + trying to extract the old values from the current regcache while at the same time writing new values into that same cache. */ - struct regcache *scratch - = frame_save_as_regcache (get_prev_frame_1 (this_frame)); - struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch); + scratch = frame_save_as_regcache (prev_frame); + cleanups = make_cleanup_regcache_xfree (scratch); /* FIXME: cagney/2003-03-16: It should be possible to tell the target's register cache that it is about to be hit with a burst @@ -495,28 +573,20 @@ frame_pop (struct frame_info *this_frame) (arguably a bug in the target code mind). */ /* Now copy those saved registers into the current regcache. Here, regcache_cpy() calls regcache_restore(). */ - regcache_cpy (current_regcache, scratch); + regcache_cpy (get_current_regcache (), scratch); do_cleanups (cleanups); /* We've made right mess of GDB's local state, just discard everything. */ - flush_cached_frames (); + reinit_frame_cache (); } void frame_register_unwind (struct frame_info *frame, int regnum, int *optimizedp, enum lval_type *lvalp, - CORE_ADDR *addrp, int *realnump, void *bufferp) + CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp) { - struct frame_unwind_cache *cache; - - if (frame_debug) - { - fprintf_unfiltered (gdb_stdlog, "\ -{ frame_register_unwind (frame=%d,regnum=%d(%s),...) ", - frame->level, regnum, - frame_map_regnum_to_name (frame, regnum)); - } + struct value *value; /* Require all but BUFFERP to be valid. A NULL BUFFERP indicates that the value proper does not need to be fetched. */ @@ -526,49 +596,29 @@ frame_register_unwind (struct frame_info *frame, int regnum, gdb_assert (realnump != NULL); /* gdb_assert (bufferp != NULL); */ - /* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame - is broken. There is always a frame. If there, for some reason, - isn't a frame, there is some pretty busted code as it should have - detected the problem before calling here. */ - gdb_assert (frame != NULL); + value = frame_unwind_register_value (frame, regnum); - /* Find the unwinder. */ - if (frame->unwind == NULL) - frame->unwind = frame_unwind_find_by_frame (frame->next, - &frame->prologue_cache); + gdb_assert (value != NULL); - /* Ask this frame to unwind its register. See comment in - "frame-unwind.h" for why NEXT frame and this unwind cache are - passed in. */ - frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum, - optimizedp, lvalp, addrp, realnump, bufferp); + *optimizedp = value_optimized_out (value); + *lvalp = VALUE_LVAL (value); + *addrp = value_address (value); + *realnump = VALUE_REGNUM (value); - if (frame_debug) - { - fprintf_unfiltered (gdb_stdlog, "->"); - fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp)); - fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp)); - fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp))); - fprintf_unfiltered (gdb_stdlog, " *bufferp="); - if (bufferp == NULL) - fprintf_unfiltered (gdb_stdlog, ""); - else - { - int i; - const unsigned char *buf = bufferp; - fprintf_unfiltered (gdb_stdlog, "["); - for (i = 0; i < register_size (current_gdbarch, regnum); i++) - fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]); - fprintf_unfiltered (gdb_stdlog, "]"); - } - fprintf_unfiltered (gdb_stdlog, " }\n"); - } + if (bufferp) + memcpy (bufferp, value_contents_all (value), + TYPE_LENGTH (value_type (value))); + + /* Dispose of the new value. This prevents watchpoints from + trying to watch the saved frame pointer. */ + release_value (value); + value_free (value); } void frame_register (struct frame_info *frame, int regnum, int *optimizedp, enum lval_type *lvalp, - CORE_ADDR *addrp, int *realnump, void *bufferp) + CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp) { /* Require all but BUFFERP to be valid. A NULL BUFFERP indicates that the value proper does not need to be fetched. */ @@ -586,7 +636,7 @@ frame_register (struct frame_info *frame, int regnum, } void -frame_unwind_register (struct frame_info *frame, int regnum, void *buf) +frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf) { int optimized; CORE_ADDR addr; @@ -598,15 +648,81 @@ frame_unwind_register (struct frame_info *frame, int regnum, void *buf) void get_frame_register (struct frame_info *frame, - int regnum, void *buf) + int regnum, gdb_byte *buf) { frame_unwind_register (frame->next, regnum, buf); } +struct value * +frame_unwind_register_value (struct frame_info *frame, int regnum) +{ + struct value *value; + + gdb_assert (frame != NULL); + + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "\ +{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ", + frame->level, regnum, + user_reg_map_regnum_to_name + (get_frame_arch (frame), regnum)); + } + + /* Find the unwinder. */ + if (frame->unwind == NULL) + frame->unwind = 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); + + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "->"); + if (value_optimized_out (value)) + fprintf_unfiltered (gdb_stdlog, " optimized out"); + else + { + if (VALUE_LVAL (value) == lval_register) + fprintf_unfiltered (gdb_stdlog, " register=%d", + VALUE_REGNUM (value)); + else if (VALUE_LVAL (value) == lval_memory) + fprintf_unfiltered (gdb_stdlog, " address=0x%s", + paddr_nz (value_address (value))); + else + fprintf_unfiltered (gdb_stdlog, " computed"); + + if (value_lazy (value)) + fprintf_unfiltered (gdb_stdlog, " lazy"); + else + { + int i; + const gdb_byte *buf = value_contents (value); + + fprintf_unfiltered (gdb_stdlog, " bytes="); + fprintf_unfiltered (gdb_stdlog, "["); + for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++) + fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]); + fprintf_unfiltered (gdb_stdlog, "]"); + } + } + + fprintf_unfiltered (gdb_stdlog, " }\n"); + } + + return value; +} + +struct value * +get_frame_register_value (struct frame_info *frame, int regnum) +{ + return frame_unwind_register_value (frame->next, regnum); +} + LONGEST frame_unwind_register_signed (struct frame_info *frame, int regnum) { - char buf[MAX_REGISTER_SIZE]; + gdb_byte buf[MAX_REGISTER_SIZE]; frame_unwind_register (frame, regnum, buf); return extract_signed_integer (buf, register_size (get_frame_arch (frame), regnum)); @@ -621,7 +737,7 @@ get_frame_register_signed (struct frame_info *frame, int regnum) ULONGEST frame_unwind_register_unsigned (struct frame_info *frame, int regnum) { - char buf[MAX_REGISTER_SIZE]; + gdb_byte buf[MAX_REGISTER_SIZE]; frame_unwind_register (frame, regnum, buf); return extract_unsigned_integer (buf, register_size (get_frame_arch (frame), regnum)); @@ -634,18 +750,8 @@ get_frame_register_unsigned (struct frame_info *frame, int regnum) } void -frame_unwind_unsigned_register (struct frame_info *frame, int regnum, - ULONGEST *val) -{ - char buf[MAX_REGISTER_SIZE]; - frame_unwind_register (frame, regnum, buf); - (*val) = extract_unsigned_integer (buf, - register_size (get_frame_arch (frame), - regnum)); -} - -void -put_frame_register (struct frame_info *frame, int regnum, const void *buf) +put_frame_register (struct frame_info *frame, int regnum, + const gdb_byte *buf) { struct gdbarch *gdbarch = get_frame_arch (frame); int realnum; @@ -654,23 +760,23 @@ put_frame_register (struct frame_info *frame, int regnum, const void *buf) CORE_ADDR addr; frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL); if (optim) - error ("Attempt to assign to a value that was optimized out."); + error (_("Attempt to assign to a value that was optimized out.")); switch (lval) { case lval_memory: { /* FIXME: write_memory doesn't yet take constant buffers. Arrrg! */ - char tmp[MAX_REGISTER_SIZE]; + gdb_byte tmp[MAX_REGISTER_SIZE]; memcpy (tmp, buf, register_size (gdbarch, regnum)); write_memory (addr, tmp, register_size (gdbarch, regnum)); break; } case lval_register: - regcache_cooked_write (current_regcache, realnum, buf); + regcache_cooked_write (get_current_regcache (), realnum, buf); break; default: - error ("Attempt to assign to an unmodifiable value."); + error (_("Attempt to assign to an unmodifiable value.")); } } @@ -682,7 +788,8 @@ put_frame_register (struct frame_info *frame, int regnum, const void *buf) Returns 0 if the register value could not be found. */ int -frame_register_read (struct frame_info *frame, int regnum, void *myaddr) +frame_register_read (struct frame_info *frame, int regnum, + gdb_byte *myaddr) { int optimized; enum lval_type lval; @@ -690,34 +797,109 @@ frame_register_read (struct frame_info *frame, int regnum, void *myaddr) int realnum; frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr); - /* FIXME: cagney/2002-05-15: This test is just bogus. + return !optimized; +} - It indicates that the target failed to supply a value for a - register because it was "not available" at this time. Problem - is, the target still has the register and so get saved_register() - may be returning a value saved on the stack. */ +int +get_frame_register_bytes (struct frame_info *frame, int regnum, + CORE_ADDR offset, int len, gdb_byte *myaddr) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + int i; + int maxsize; + int numregs; - if (register_cached (regnum) < 0) - return 0; /* register value not available */ + /* Skip registers wholly inside of OFFSET. */ + while (offset >= register_size (gdbarch, regnum)) + { + offset -= register_size (gdbarch, regnum); + regnum++; + } - return !optimized; -} + /* Ensure that we will not read beyond the end of the register file. + This can only ever happen if the debug information is bad. */ + maxsize = -offset; + numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); + 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; + } + + /* 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)) + return 0; + } + else + { + gdb_byte buf[MAX_REGISTER_SIZE]; + if (!frame_register_read (frame, regnum, buf)) + return 0; + memcpy (myaddr, buf + offset, curr_len); + } -/* Map between a frame register number and its name. A frame register - space is a superset of the cooked register space --- it also - includes builtin registers. */ + myaddr += curr_len; + len -= curr_len; + offset = 0; + regnum++; + } -int -frame_map_name_to_regnum (struct frame_info *frame, const char *name, int len) -{ - return user_reg_map_name_to_regnum (get_frame_arch (frame), name, len); + return 1; } -const char * -frame_map_regnum_to_name (struct frame_info *frame, int regnum) +void +put_frame_register_bytes (struct frame_info *frame, int regnum, + CORE_ADDR offset, int len, const gdb_byte *myaddr) { - return user_reg_map_regnum_to_name (get_frame_arch (frame), regnum); + struct gdbarch *gdbarch = get_frame_arch (frame); + + /* Skip registers wholly inside of OFFSET. */ + while (offset >= register_size (gdbarch, regnum)) + { + offset -= register_size (gdbarch, regnum); + regnum++; + } + + /* 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)) + { + put_frame_register (frame, regnum, myaddr); + } + else + { + gdb_byte buf[MAX_REGISTER_SIZE]; + frame_register_read (frame, regnum, buf); + memcpy (buf + offset, myaddr, curr_len); + put_frame_register (frame, regnum, buf); + } + + myaddr += curr_len; + len -= curr_len; + offset = 0; + regnum++; + } } /* Create a sentinel frame. */ @@ -793,17 +975,24 @@ get_current_frame (void) explicitly checks that ``print $pc'' with no registers prints "No registers". */ if (!target_has_registers) - error ("No registers."); + error (_("No registers.")); if (!target_has_stack) - error ("No stack."); + error (_("No stack.")); if (!target_has_memory) - error ("No 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.")); + if (current_frame == NULL) { struct frame_info *sentinel_frame = - create_sentinel_frame (current_regcache); + create_sentinel_frame (get_current_regcache ()); if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame, - NULL, RETURN_MASK_ERROR) != 0) + RETURN_MASK_ERROR) != 0) { /* Oops! Fake a current frame? Is this useful? It has a PC of zero, for instance. */ @@ -816,7 +1005,28 @@ get_current_frame (void) /* The "selected" stack frame is used by default for local and arg access. May be zero, for no selected frame. */ -struct frame_info *deprecated_selected_frame; +static struct frame_info *selected_frame; + +int +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; + + /* 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; + + return 1; +} /* Return the selected frame. Always non-NULL (unless there isn't an inferior sufficient for creating a frame) in which case an error is @@ -825,20 +1035,18 @@ struct frame_info *deprecated_selected_frame; struct frame_info * get_selected_frame (const char *message) { - if (deprecated_selected_frame == NULL) + if (selected_frame == NULL) { - if (message != NULL && (!target_has_registers - || !target_has_stack - || !target_has_memory)) - error ("%s", message); + if (message != NULL && !has_stack_frames ()) + error (("%s"), message); /* Hey! Don't trust this. It should really be re-finding the last selected frame of the currently selected thread. This, though, is better than nothing. */ select_frame (get_current_frame ()); } /* There is always a frame. */ - gdb_assert (deprecated_selected_frame != NULL); - return deprecated_selected_frame; + gdb_assert (selected_frame != NULL); + return selected_frame; } /* This is a variant of get_selected_frame() which can be called when @@ -848,7 +1056,7 @@ get_selected_frame (const char *message) struct frame_info * deprecated_safe_get_selected_frame (void) { - if (!target_has_registers || !target_has_stack || !target_has_memory) + if (!has_stack_frames ()) return NULL; return get_selected_frame (NULL); } @@ -860,7 +1068,7 @@ select_frame (struct frame_info *fi) { struct symtab *s; - deprecated_selected_frame = fi; + selected_frame = fi; /* NOTE: cagney/2002-05-04: FI can be NULL. This occurs when the frame is being invalidated. */ if (deprecated_selected_frame_level_changed_hook) @@ -911,17 +1119,23 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) paddr_nz (addr), paddr_nz (pc)); } - fi = frame_obstack_zalloc (sizeof (struct frame_info)); + fi = FRAME_OBSTACK_ZALLOC (struct frame_info); + + fi->next = create_sentinel_frame (get_current_regcache ()); - fi->next = create_sentinel_frame (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; /* Select/initialize both the unwind function and the frame's type based on the PC. */ - fi->unwind = frame_unwind_find_by_frame (fi->next, &fi->prologue_cache); + fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache); fi->this_id.p = 1; - deprecated_update_frame_base_hack (fi, addr); - deprecated_update_frame_pc_hack (fi, pc); + fi->this_id.value = frame_id_build (addr, pc); if (frame_debug) { @@ -948,39 +1162,65 @@ get_next_frame (struct frame_info *this_frame) /* Observer for the target_changed event. */ -void +static void frame_observer_target_changed (struct target_ops *target) { - flush_cached_frames (); + reinit_frame_cache (); } /* Flush the entire frame cache. */ void -flush_cached_frames (void) +reinit_frame_cache (void) { + struct frame_info *fi; + + /* Tear down all frame caches. */ + for (fi = current_frame; fi != NULL; fi = fi->prev) + { + if (fi->prologue_cache && fi->unwind->dealloc_cache) + fi->unwind->dealloc_cache (fi, fi->prologue_cache); + if (fi->base_cache && fi->base->unwind->dealloc_cache) + fi->base->unwind->dealloc_cache (fi, fi->base_cache); + } + /* Since we can't really be sure what the first object allocated was */ obstack_free (&frame_cache_obstack, 0); obstack_init (&frame_cache_obstack); + if (current_frame != NULL) + annotate_frames_invalid (); + current_frame = NULL; /* Invalidate cache */ select_frame (NULL); - annotate_frames_invalid (); if (frame_debug) - fprintf_unfiltered (gdb_stdlog, "{ flush_cached_frames () }\n"); + fprintf_unfiltered (gdb_stdlog, "{ reinit_frame_cache () }\n"); } -/* Flush the frame cache, and start a new one if necessary. */ +/* Find where a register is saved (in memory or another register). + The result of frame_register_unwind is just where it is saved + relative to this particular frame. */ -void -reinit_frame_cache (void) +static void +frame_register_unwind_location (struct frame_info *this_frame, int regnum, + int *optimizedp, enum lval_type *lvalp, + CORE_ADDR *addrp, int *realnump) { - flush_cached_frames (); + gdb_assert (this_frame == NULL || this_frame->level >= 0); - /* FIXME: The inferior_ptid test is wrong if there is a corefile. */ - if (PIDGET (inferior_ptid) != 0) + while (this_frame != NULL) { - select_frame (get_current_frame ()); + frame_register_unwind (this_frame, regnum, optimizedp, lvalp, + addrp, realnump, NULL); + + if (*optimizedp) + break; + + if (*lvalp != lval_register) + break; + + regnum = *realnump; + this_frame = get_next_frame (this_frame); } } @@ -995,8 +1235,10 @@ get_prev_frame_1 (struct frame_info *this_frame) { struct frame_info *prev_frame; struct frame_id this_id; + struct gdbarch *gdbarch; gdb_assert (this_frame != NULL); + gdbarch = get_frame_arch (this_frame); if (frame_debug) { @@ -1019,7 +1261,17 @@ get_prev_frame_1 (struct frame_info *this_frame) } return this_frame->prev; } + + /* If the frame unwinder hasn't been selected yet, we must do so + before setting prev_p; otherwise the check for misbehaved + 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); + this_frame->prev_p = 1; + this_frame->stop_reason = UNWIND_NO_REASON; /* 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 @@ -1033,24 +1285,90 @@ get_prev_frame_1 (struct frame_info *this_frame) fprint_frame (gdb_stdlog, NULL); fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n"); } + this_frame->stop_reason = UNWIND_NULL_ID; return NULL; } /* Check that this frame's ID isn't inner to (younger, below, next) the next frame. This happens when a frame unwind goes backwards. - Exclude signal trampolines (due to sigaltstack the frame ID can - go backwards) and sentinel frames (the test is meaningless). */ - if (this_frame->next->level >= 0 - && this_frame->next->unwind->type != SIGTRAMP_FRAME - && frame_id_inner (this_id, get_frame_id (this_frame->next))) - error ("Previous frame inner to this frame (corrupt stack?)"); + This check is valid only if this frame and the next frame are NORMAL. + 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, + get_frame_id (this_frame->next))) + { + 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; + } /* 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))) - error ("Previous frame identical to this frame (corrupt stack?)"); + { + 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; + return NULL; + } + + /* Check that this and the next frame do not unwind the PC register + to the same memory location. If they do, then even though they + have different frame IDs, the new frame will be bogus; two + functions can't share a register save slot for the PC. This can + happen when the prologue analyzer finds a stack adjustment, but + no PC save. + + This check does assume that the "PC register" is roughly a + traditional PC, even if the gdbarch_unwind_pc method adjusts + it (we do not rely on the value, only on the unwound PC being + dependent on this value). A potential improvement would be + to have the frame prev_pc method and the gdbarch unwind_pc + method set the same lval and location information as + frame_register_unwind. */ + if (this_frame->level > 0 + && gdbarch_pc_regnum (gdbarch) >= 0 + && get_frame_type (this_frame) == NORMAL_FRAME + && get_frame_type (this_frame->next) == NORMAL_FRAME) + { + int optimized, realnum, nrealnum; + enum lval_type lval, nlval; + CORE_ADDR addr, naddr; + + frame_register_unwind_location (this_frame, + gdbarch_pc_regnum (gdbarch), + &optimized, &lval, &addr, &realnum); + frame_register_unwind_location (get_next_frame (this_frame), + gdbarch_pc_regnum (gdbarch), + &optimized, &nlval, &naddr, &nrealnum); + + if ((lval == lval_memory && lval == nlval && addr == naddr) + || (lval == lval_register && lval == nlval && realnum == nrealnum)) + { + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, " // no saved PC }\n"); + } + + this_frame->stop_reason = UNWIND_NO_SAVED_PC; + this_frame->prev = NULL; + return NULL; + } + } /* Allocate the new frame but do not wire it in to the frame chain. Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along @@ -1101,8 +1419,7 @@ get_prev_frame_1 (struct frame_info *this_frame) /* Debug routine to print a NULL frame being returned. */ static void -frame_debug_got_null_frame (struct ui_file *file, - struct frame_info *this_frame, +frame_debug_got_null_frame (struct frame_info *this_frame, const char *reason) { if (frame_debug) @@ -1131,7 +1448,7 @@ inside_main_func (struct frame_info *this_frame) return 0; /* Make certain that the code, and not descriptor, address is returned. */ - maddr = gdbarch_convert_from_func_ptr_addr (current_gdbarch, + maddr = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame), SYMBOL_VALUE_ADDRESS (msymbol), ¤t_target); return maddr == get_frame_func (this_frame); @@ -1159,42 +1476,6 @@ get_prev_frame (struct frame_info *this_frame) { struct frame_info *prev_frame; - /* Return the inner-most frame, when the caller passes in NULL. */ - /* NOTE: cagney/2002-11-09: Not sure how this would happen. The - caller should have previously obtained a valid frame using - get_selected_frame() and then called this code - only possibility - I can think of is code behaving badly. - - NOTE: cagney/2003-01-10: Talk about code behaving badly. Check - block_innermost_frame(). It does the sequence: frame = NULL; - while (1) { frame = get_prev_frame (frame); .... }. Ulgh! Why - it couldn't be written better, I don't know. - - NOTE: cagney/2003-01-11: I suspect what is happening in - block_innermost_frame() is, when the target has no state - (registers, memory, ...), it is still calling this function. The - assumption being that this function will return NULL indicating - that a frame isn't possible, rather than checking that the target - has state and then calling get_current_frame() and - get_prev_frame(). This is a guess mind. */ - if (this_frame == NULL) - { - /* NOTE: cagney/2002-11-09: There was a code segment here that - would error out when CURRENT_FRAME was NULL. The comment - that went with it made the claim ... - - ``This screws value_of_variable, which just wants a nice - clean NULL return from block_innermost_frame if there are no - frames. I don't think I've ever seen this message happen - otherwise. And returning NULL here is a perfectly legitimate - thing to do.'' - - Per the above, this code shouldn't even be called with a NULL - THIS_FRAME. */ - frame_debug_got_null_frame (gdb_stdlog, this_frame, "this_frame NULL"); - return current_frame; - } - /* There is always a frame. If this assertion fails, suspect that something should be calling get_selected_frame() or get_current_frame(). */ @@ -1219,13 +1500,19 @@ get_prev_frame (struct frame_info *this_frame) user later decides to enable unwinds past main(), that will automatically happen. */ { - frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside main func"); + frame_debug_got_null_frame (this_frame, "inside main func"); return NULL; } - if (this_frame->level > backtrace_limit) + /* If the user's backtrace limit has been exceeded, stop. We must + add two to the current level; one of those accounts for backtrace_limit + being 1-based and the level being 0-based, and the other accounts for + the level of the new frame instead of the level of the current + frame. */ + if (this_frame->level + 2 > backtrace_limit) { - error ("Backtrace limit of %d exceeded", backtrace_limit); + frame_debug_got_null_frame (this_frame, "backtrace limit exceeded"); + return NULL; } /* If we're already inside the entry function for the main objfile, @@ -1254,7 +1541,7 @@ get_prev_frame (struct frame_info *this_frame) && get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0 && inside_entry_func (this_frame)) { - frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside entry func"); + frame_debug_got_null_frame (this_frame, "inside entry func"); return NULL; } @@ -1266,7 +1553,7 @@ get_prev_frame (struct frame_info *this_frame) && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME && get_frame_pc (this_frame) == 0) { - frame_debug_got_null_frame (gdb_stdlog, this_frame, "zero PC"); + frame_debug_got_null_frame (this_frame, "zero PC"); return NULL; } @@ -1280,31 +1567,54 @@ get_frame_pc (struct frame_info *frame) return frame_pc_unwind (frame->next); } -/* Return an address of that falls within the frame's code block. */ +/* Return an address that falls within THIS_FRAME's code block. */ CORE_ADDR -frame_unwind_address_in_block (struct frame_info *next_frame) +get_frame_address_in_block (struct frame_info *this_frame) { /* A draft address. */ - CORE_ADDR pc = frame_pc_unwind (next_frame); - - /* If THIS frame is not inner most (i.e., NEXT isn't the sentinel), - and NEXT is `normal' (i.e., not a sigtramp, dummy, ....) THIS - frame's PC ends up pointing at the instruction fallowing the - "call". Adjust that PC value so that it falls on the call - instruction (which, hopefully, falls within THIS frame's code - block. So far it's proved to be a very good approximation. See - get_frame_type() for why ->type can't be used. */ - if (next_frame->level >= 0 - && get_frame_type (next_frame) == NORMAL_FRAME) - --pc; - return pc; -} + CORE_ADDR pc = get_frame_pc (this_frame); + + struct frame_info *next_frame = this_frame->next; + + /* Calling get_frame_pc returns the resume address for THIS_FRAME. + Normally the resume address is inside the body of the function + associated with THIS_FRAME, but there is a special case: when + calling a function which the compiler knows will never return + (for instance abort), the call may be the very last instruction + in the calling function. The resume address will point after the + call and may be at the beginning of a different function + entirely. + + If THIS_FRAME is a signal frame or dummy frame, then we should + not adjust the unwound PC. For a dummy frame, GDB pushed the + resume address manually onto the stack. For a signal frame, the + OS may have pushed the resume address manually and invoked the + handler (e.g. GNU/Linux), or invoked the trampoline which called + the signal handler - but in either case the signal handler is + expected to return to the trampoline. So in both of these + cases we know that the resume address is executable and + related. So we only need to adjust the PC if THIS_FRAME + is a normal function. + + If the program has been interrupted while THIS_FRAME is current, + then clearly the resume address is inside the associated + function. There are three kinds of interruption: debugger stop + (next frame will be SENTINEL_FRAME), operating system + signal or exception (next frame will be SIGTRAMP_FRAME), + or debugger-induced function call (next frame will be + DUMMY_FRAME). So we only need to adjust the PC if + NEXT_FRAME is a normal function. + + We check the type of NEXT_FRAME first, since it is already + known; frame type is determined by the unwinder, and since + we have THIS_FRAME we've already selected an unwinder for + NEXT_FRAME. */ + if (get_frame_type (next_frame) == NORMAL_FRAME + && get_frame_type (this_frame) == NORMAL_FRAME) + return pc - 1; -CORE_ADDR -get_frame_address_in_block (struct frame_info *this_frame) -{ - return frame_unwind_address_in_block (this_frame->next); + return pc; } static int @@ -1346,12 +1656,12 @@ get_frame_base_address (struct frame_info *fi) if (get_frame_type (fi) != NORMAL_FRAME) return 0; if (fi->base == NULL) - fi->base = frame_base_find_by_frame (fi->next); + fi->base = frame_base_find_by_frame (fi); /* Sneaky: If the low-level unwind and high-level base code share a common unwinder, let them share the prologue cache. */ if (fi->base->unwind == fi->unwind) - return fi->base->this_base (fi->next, &fi->prologue_cache); - return fi->base->this_base (fi->next, &fi->base_cache); + return fi->base->this_base (fi, &fi->prologue_cache); + return fi->base->this_base (fi, &fi->base_cache); } CORE_ADDR @@ -1362,14 +1672,12 @@ get_frame_locals_address (struct frame_info *fi) return 0; /* If there isn't a frame address method, find it. */ if (fi->base == NULL) - fi->base = frame_base_find_by_frame (fi->next); + fi->base = frame_base_find_by_frame (fi); /* Sneaky: If the low-level unwind and high-level base code share a common unwinder, let them share the prologue cache. */ if (fi->base->unwind == fi->unwind) - cache = &fi->prologue_cache; - else - cache = &fi->base_cache; - return fi->base->this_locals (fi->next, cache); + return fi->base->this_locals (fi, &fi->prologue_cache); + return fi->base->this_locals (fi, &fi->base_cache); } CORE_ADDR @@ -1380,14 +1688,12 @@ get_frame_args_address (struct frame_info *fi) return 0; /* If there isn't a frame address method, find it. */ if (fi->base == NULL) - fi->base = frame_base_find_by_frame (fi->next); + fi->base = frame_base_find_by_frame (fi); /* Sneaky: If the low-level unwind and high-level base code share a common unwinder, let them share the prologue cache. */ if (fi->base->unwind == fi->unwind) - cache = &fi->prologue_cache; - else - cache = &fi->base_cache; - return fi->base->this_args (fi->next, cache); + return fi->base->this_args (fi, &fi->prologue_cache); + return fi->base->this_args (fi, &fi->base_cache); } /* Level of the selected frame: 0 for innermost, 1 for its caller, ... @@ -1408,48 +1714,15 @@ 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->next, - &frame->prologue_cache); + frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache); return frame->unwind->type; } -void -deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc) -{ - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "{ deprecated_update_frame_pc_hack (frame=%d,pc=0x%s) }\n", - frame->level, paddr_nz (pc)); - /* NOTE: cagney/2003-03-11: Some architectures (e.g., Arm) are - maintaining a locally allocated frame object. Since such frames - are not in the frame chain, it isn't possible to assume that the - frame has a next. Sigh. */ - if (frame->next != NULL) - { - /* While we're at it, update this frame's cached PC value, found - in the next frame. Oh for the day when "struct frame_info" - is opaque and this hack on hack can just go away. */ - frame->next->prev_pc.value = pc; - frame->next->prev_pc.p = 1; - } -} - -void -deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base) -{ - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "{ deprecated_update_frame_base_hack (frame=%d,base=0x%s) }\n", - frame->level, paddr_nz (base)); - /* See comment in "frame.h". */ - frame->this_id.value.stack_addr = base; -} - /* Memory access methods. */ void -get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr, void *buf, - int len) +get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr, + gdb_byte *buf, int len) { read_memory (addr, buf, len); } @@ -1470,10 +1743,10 @@ get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr, int safe_frame_unwind_memory (struct frame_info *this_frame, - CORE_ADDR addr, void *buf, int len) + CORE_ADDR addr, gdb_byte *buf, int len) { - /* NOTE: deprecated_read_memory_nobpt returns zero on success! */ - return !deprecated_read_memory_nobpt (addr, buf, len); + /* NOTE: target_read_memory returns zero on success! */ + return !target_read_memory (addr, buf, len); } /* Architecture method. */ @@ -1481,6 +1754,11 @@ safe_frame_unwind_memory (struct frame_info *this_frame, struct gdbarch * get_frame_arch (struct frame_info *this_frame) { + /* In the future, this function will return a per-frame + architecture instead of current_gdbarch. Calling the + routine with a NULL value of this_frame is a bug! */ + gdb_assert (this_frame); + return current_gdbarch; } @@ -1489,29 +1767,105 @@ get_frame_arch (struct frame_info *this_frame) CORE_ADDR get_frame_sp (struct frame_info *this_frame) { - return frame_sp_unwind (this_frame->next); -} - -CORE_ADDR -frame_sp_unwind (struct frame_info *next_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 (current_gdbarch)) - return gdbarch_unwind_sp (current_gdbarch, next_frame); - /* Things are looking grim. If it's the inner-most frame and there - is a TARGET_READ_SP, then that can be used. */ - if (next_frame->level < 0 && TARGET_READ_SP_P ()) - return TARGET_READ_SP (); + if (gdbarch_unwind_sp_p (gdbarch)) + /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to + operate on THIS_FRAME now. */ + return gdbarch_unwind_sp (gdbarch, this_frame->next); /* Now things are really are grim. Hope that the value returned by - the SP_REGNUM register is meaningful. */ - if (SP_REGNUM >= 0) + the gdbarch_sp_regnum register is meaningful. */ + if (gdbarch_sp_regnum (gdbarch) >= 0) + return get_frame_register_unsigned (this_frame, + gdbarch_sp_regnum (gdbarch)); + internal_error (__FILE__, __LINE__, _("Missing unwind SP method")); +} + +/* Return the reason why we can't unwind past 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; + + /* 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) +{ + switch (reason) { - ULONGEST sp; - frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp); - return sp; + case UNWIND_NULL_ID: + return _("unwinder did not report frame ID"); + + case UNWIND_INNER_ID: + return _("previous frame inner to this frame (corrupt stack?)"); + + case UNWIND_SAME_ID: + return _("previous frame identical to this frame (corrupt stack?)"); + + case UNWIND_NO_SAVED_PC: + return _("frame did not save the PC"); + + case UNWIND_NO_REASON: + case UNWIND_FIRST_ERROR: + default: + internal_error (__FILE__, __LINE__, + "Invalid frame stop reason"); } - internal_error (__FILE__, __LINE__, "Missing unwind SP method"); +} + +/* Clean up after a failed (wrong unwinder) attempt to unwind past + FRAME. */ + +static void +frame_cleanup_after_sniffer (void *arg) +{ + struct frame_info *frame = arg; + + /* The sniffer should not allocate a prologue cache if it did not + match this frame. */ + gdb_assert (frame->prologue_cache == NULL); + + /* No sniffer should extend the frame chain; sniff based on what is + already certain. */ + gdb_assert (!frame->prev_p); + + /* The sniffer should not check the frame's ID; that's circular. */ + gdb_assert (!frame->this_id.p); + + /* Clear cached fields dependent on the unwinder. + + The previous PC is independent of the unwinder, but the previous + function is not (see get_frame_address_in_block). */ + frame->prev_func.p = 0; + frame->prev_func.addr = 0; + + /* Discard the unwinder last, so that we can easily find it if an assertion + in this function triggers. */ + frame->unwind = NULL; +} + +/* Set FRAME's unwinder temporarily, so that we can call a sniffer. + Return a cleanup which should be called if unwinding fails, and + discarded if it succeeds. */ + +struct cleanup * +frame_prepare_for_sniffer (struct frame_info *frame, + const struct frame_unwind *unwind) +{ + gdb_assert (frame->unwind == NULL); + frame->unwind = unwind; + return make_cleanup (frame_cleanup_after_sniffer, frame); } extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */ @@ -1538,53 +1892,60 @@ _initialize_frame (void) observer_attach_target_changed (frame_observer_target_changed); - add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, "\ + add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\ Set backtrace specific variables.\n\ -Configure backtrace variables such as the backtrace limit", +Configure backtrace variables such as the backtrace limit"), &set_backtrace_cmdlist, "set backtrace ", 0/*allow-unknown*/, &setlist); - add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, "\ + add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, _("\ Show backtrace specific variables\n\ -Show backtrace variables such as the backtrace limit", +Show backtrace variables such as the backtrace limit"), &show_backtrace_cmdlist, "show backtrace ", 0/*allow-unknown*/, &showlist); add_setshow_boolean_cmd ("past-main", class_obscure, - &backtrace_past_main, "\ -Set whether backtraces should continue past \"main\".", "\ -Show whether backtraces should continue past \"main\".", "\ + &backtrace_past_main, _("\ +Set whether backtraces should continue past \"main\"."), _("\ +Show whether backtraces should continue past \"main\"."), _("\ Normally the caller of \"main\" is not of interest, so GDB will terminate\n\ the backtrace at \"main\". Set this variable if you need to see the rest\n\ -of the stack trace.", "\ -Whether backtraces should continue past \"main\" is %s.", - NULL, NULL, &set_backtrace_cmdlist, +of the stack trace."), + NULL, + show_backtrace_past_main, + &set_backtrace_cmdlist, &show_backtrace_cmdlist); add_setshow_boolean_cmd ("past-entry", class_obscure, - &backtrace_past_entry, "\ -Set whether backtraces should continue past the entry point of a program.", "\ -Show whether backtraces should continue past the entry point of a program.", "\ + &backtrace_past_entry, _("\ +Set whether backtraces should continue past the entry point of a program."), + _("\ +Show whether backtraces should continue past the entry point of a program."), + _("\ Normally there are no callers beyond the entry point of a program, so GDB\n\ will terminate the backtrace there. Set this variable if you need to see \n\ -the rest of the stack trace.", "\ -Whether backtraces should continue past the entry point is %s.", - NULL, NULL, &set_backtrace_cmdlist, +the rest of the stack trace."), + NULL, + show_backtrace_past_entry, + &set_backtrace_cmdlist, &show_backtrace_cmdlist); - 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.", "\ + add_setshow_integer_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.", "\ -An upper bound on the number of backtrace levels is %s.", - NULL, NULL, &set_backtrace_cmdlist, - &show_backtrace_cmdlist); +Zero is unlimited."), + NULL, + show_backtrace_limit, + &set_backtrace_cmdlist, + &show_backtrace_cmdlist); /* Debug this files internals. */ - deprecated_add_show_from_set - (add_set_cmd ("frame", class_maintenance, var_zinteger, - &frame_debug, "Set frame debugging.\n\ -When non-zero, frame specific internal debugging is enabled.", &setdebuglist), - &showdebuglist); + add_setshow_zinteger_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); }