X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fframe.c;h=7df7c43e2967d4ba5815b95692a610127d1fe005;hb=2c0b251b29eeafa90c84a3a938c744bc7ba81aea;hp=bf860fe2ccd03414341a8fbf8b0aaf34653097ac;hpb=6314f104748d0e970aa089d2ba544f81a491b565;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/frame.c b/gdb/frame.c index bf860fe2cc..dfd6b3d53c 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 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" @@ -28,7 +26,7 @@ #include "regcache.h" #include "gdb_assert.h" #include "gdb_string.h" -#include "builtin-regs.h" +#include "user-regs.h" #include "gdb_obstack.h" #include "dummy-frame.h" #include "sentinel-frame.h" @@ -36,16 +34,210 @@ #include "annotate.h" #include "language.h" #include "frame-unwind.h" +#include "frame-base.h" #include "command.h" #include "gdbcmd.h" +#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); + +/* We keep a cache of stack frames, each of which is a "struct + frame_info". The innermost one gets allocated (in + wait_for_inferior) each time the inferior stops; current_frame + points to it. Additional frames get allocated (in get_prev_frame) + as needed, and are chained through the next and prev fields. Any + time that the frame cache becomes invalid (most notably when we + execute something, but also if we change how we interpret the + frames (e.g. "set heuristic-fence-post" in mips-tdep.c, or anything + which reads new symbols)), we should call reinit_frame_cache. */ + +struct frame_info +{ + /* Level of this frame. The inner-most (youngest) frame is at level + 0. As you move towards the outer-most (oldest) frame, the level + increases. This is a cached value. It could just as easily be + computed by counting back from the selected frame to the inner + most frame. */ + /* NOTE: cagney/2002-04-05: Perhaps a level of ``-1'' should be + reserved to indicate a bogus frame - one that has been created + just to keep GDB happy (GDB always needs a frame). For the + moment leave this as speculation. */ + int level; + + /* The frame's low-level unwinder and corresponding cache. The + low-level unwinder is responsible for unwinding register values + for the previous frame. The low-level unwind methods are + selected based on the presence, or otherwise, of register unwind + information such as CFI. */ + void *prologue_cache; + const struct frame_unwind *unwind; + + /* Cached copy of the previous frame's resume address. */ + struct { + int p; + CORE_ADDR value; + } prev_pc; + + /* Cached copy of the previous frame's function address. */ + struct + { + CORE_ADDR addr; + int p; + } prev_func; + + /* This frame's ID. */ + struct + { + int p; + struct frame_id value; + } this_id; + + /* The frame's high-level base methods, and corresponding cache. + The high level base methods are selected based on the frame's + debug info. */ + const struct frame_base *base; + void *base_cache; + + /* Pointers to the next (down, inner, younger) and previous (up, + outer, older) frame_info's in the frame cache. */ + 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 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) +{ + if (p) + fprintf_unfiltered (file, "%s=0x%s", name, paddr_nz (addr)); + else + fprintf_unfiltered (file, "!%s", name); +} + +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); + 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); + fprintf_unfiltered (file, "}"); +} -/* Flag to indicate whether backtraces should stop at main. */ +static void +fprint_frame_type (struct ui_file *file, enum frame_type type) +{ + switch (type) + { + case NORMAL_FRAME: + fprintf_unfiltered (file, "NORMAL_FRAME"); + return; + case DUMMY_FRAME: + fprintf_unfiltered (file, "DUMMY_FRAME"); + return; + case SIGTRAMP_FRAME: + fprintf_unfiltered (file, "SIGTRAMP_FRAME"); + return; + default: + fprintf_unfiltered (file, ""); + return; + }; +} -static int backtrace_below_main; +static void +fprint_frame (struct ui_file *file, struct frame_info *fi) +{ + if (fi == NULL) + { + fprintf_unfiltered (file, ""); + return; + } + fprintf_unfiltered (file, "{"); + fprintf_unfiltered (file, "level=%d", fi->level); + fprintf_unfiltered (file, ","); + fprintf_unfiltered (file, "type="); + if (fi->unwind != NULL) + fprint_frame_type (file, fi->unwind->type); + else + fprintf_unfiltered (file, ""); + fprintf_unfiltered (file, ","); + fprintf_unfiltered (file, "unwind="); + if (fi->unwind != NULL) + gdb_print_host_address (fi->unwind, file); + else + fprintf_unfiltered (file, ""); + fprintf_unfiltered (file, ","); + fprintf_unfiltered (file, "pc="); + if (fi->next != NULL && fi->next->prev_pc.p) + fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_pc.value)); + else + fprintf_unfiltered (file, ""); + fprintf_unfiltered (file, ","); + fprintf_unfiltered (file, "id="); + if (fi->this_id.p) + fprint_frame_id (file, fi->this_id.value); + else + fprintf_unfiltered (file, ""); + fprintf_unfiltered (file, ","); + fprintf_unfiltered (file, "func="); + if (fi->next != NULL && fi->next->prev_func.p) + fprintf_unfiltered (file, "0x%s", paddr_nz (fi->next->prev_func.addr)); + else + fprintf_unfiltered (file, ""); + fprintf_unfiltered (file, "}"); +} /* Return a frame uniq ID that can be used to, later, re-find the frame. */ @@ -57,113 +249,338 @@ get_frame_id (struct frame_info *fi) { return null_frame_id; } - else + if (!fi->this_id.p) { - struct frame_id id; - id.base = fi->frame; - id.pc = fi->pc; - return id; + 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. */ + fi->unwind->this_id (fi, &fi->prologue_cache, &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 fi->this_id.value; +} + +struct frame_id +frame_unwind_id (struct frame_info *next_frame) +{ + /* Use prev_frame, 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. */ + return get_frame_id (get_prev_frame_1 (next_frame)); } const struct frame_id null_frame_id; /* All zeros. */ struct frame_id -frame_id_build (CORE_ADDR base, CORE_ADDR func_or_pc) +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.code_addr = code_addr; + id.code_addr_p = 1; + id.special_addr = special_addr; + id.special_addr_p = 1; + return id; +} + +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.code_addr = code_addr; + id.code_addr_p = 1; + return id; +} + +struct frame_id +frame_id_build_wild (CORE_ADDR stack_addr) { - struct frame_id id; - id.base = base; - id.pc = func_or_pc; + struct frame_id id = null_frame_id; + id.stack_addr = stack_addr; + id.stack_addr_p = 1; return id; } int frame_id_p (struct frame_id l) { - /* The .func can be NULL but the .base cannot. */ - return (l.base != 0); + int p; + /* The frame is valid iff it has a valid stack address. */ + p = l.stack_addr_p; + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l="); + fprint_frame_id (gdb_stdlog, l); + fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", p); + } + return p; } int frame_id_eq (struct frame_id l, struct frame_id r) { - /* If .base is different, the frames are different. */ - if (l.base != r.base) - return 0; - /* Add a test to check that the frame ID's are for the same function - here. */ - return 1; + int eq; + if (!l.stack_addr_p || !r.stack_addr_p) + /* 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) + /* If .stack addresses are different, the frames are different. */ + eq = 0; + else if (!l.code_addr_p || !r.code_addr_p) + /* An invalid code addr is a wild card, always succeed. */ + eq = 1; + else if (l.code_addr != r.code_addr) + /* If .code addresses are different, the frames are different. */ + eq = 0; + else if (!l.special_addr_p || !r.special_addr_p) + /* An invalid special addr is a wild card (or unused), always succeed. */ + eq = 1; + else if (l.special_addr == r.special_addr) + /* Frames are equal. */ + eq = 1; + else + /* No luck. */ + eq = 0; + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l="); + fprint_frame_id (gdb_stdlog, l); + fprintf_unfiltered (gdb_stdlog, ",r="); + fprint_frame_id (gdb_stdlog, r); + fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", eq); + } + 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. + + * If frame NEXT is the immediate inner frame to THIS, and NEXT + is a NORMAL frame, then 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 frame NEXT is the immediate inner frame to THIS, and NEXT + is a NORMAL frame, and 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. */ + +static int +frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r) { - /* Only return non-zero when strictly inner than. Note that, per - comment in "frame.h", there is some fuzz here. Frameless - functions are not strictly inner than (same .base but different - .func). */ - return INNER_THAN (l.base, r.base); + int inner; + if (!l.stack_addr_p || !r.stack_addr_p) + /* Like NaN, any operation involving an invalid ID always fails. */ + inner = 0; + else + /* Only return non-zero when strictly inner than. Note that, per + 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 = gdbarch_inner_than (gdbarch, l.stack_addr, r.stack_addr); + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "{ frame_id_inner (l="); + fprint_frame_id (gdb_stdlog, l); + fprintf_unfiltered (gdb_stdlog, ",r="); + fprint_frame_id (gdb_stdlog, r); + fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", inner); + } + return inner; } 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; } CORE_ADDR -frame_pc_unwind (struct frame_info *frame) +frame_pc_unwind (struct frame_info *this_frame) +{ + if (!this_frame->prev_pc.p) + { + CORE_ADDR pc; + 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 + determine the value of registers in THIS frame, and hence + the value of this frame's PC (resume address). A typical + implementation is no more than: + + frame_unwind_register (this_frame, ISA_PC_REGNUM, buf); + return extract_unsigned_integer (buf, size of ISA_PC_REGNUM); + + Note: this method is very heavily dependent on a correct + register-unwind implementation, it pays to fix that + method first; this method is frame type agnostic, since + it only deals with register values, it works with any + frame. This is all in stark contrast to the old + FRAME_SAVED_PC which would try to directly handle all the + different ways that a PC could be unwound. */ + pc = gdbarch_unwind_pc (get_frame_arch (this_frame), this_frame); + } + 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_pc_unwind (this_frame=%d) -> 0x%s }\n", + this_frame->level, + paddr_nz (this_frame->prev_pc.value)); + } + return this_frame->prev_pc.value; +} + +CORE_ADDR +get_frame_func (struct frame_info *this_frame) { - if (!frame->pc_unwind_cache_p) + struct frame_info *next_frame = this_frame->next; + + if (!next_frame->prev_func.p) { - frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache); - frame->pc_unwind_cache_p = 1; + /* 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) -> 0x%s }\n", + this_frame->level, + paddr_nz (next_frame->prev_func.addr)); } - return frame->pc_unwind_cache; + return next_frame->prev_func.addr; +} + +static int +do_frame_register_read (void *src, int regnum, gdb_byte *buf) +{ + return frame_register_read (src, regnum, buf); +} + +struct regcache * +frame_save_as_regcache (struct frame_info *this_frame) +{ + 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); + return regcache; } void -frame_pop (struct frame_info *frame) +frame_pop (struct frame_info *this_frame) { - /* FIXME: cagney/2003-01-18: There is probably a chicken-egg problem - with passing in current_regcache. The pop function needs to be - written carefully so as to not overwrite registers whose [old] - values are needed to restore other registers. Instead, this code - should pass in a scratch cache and, as a second step, restore the - registers using that. */ - frame->unwind->pop (frame, &frame->unwind_cache, current_regcache); - flush_cached_frames (); + 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 + at the same time writing new values into that same cache. */ + 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 + register transfer and that the sequence of register writes should + be batched. The pair target_prepare_to_store() and + target_store_registers() kind of suggest this functionality. + Unfortunately, they don't implement it. Their lack of a formal + definition can lead to targets writing back bogus values + (arguably a bug in the target code mind). */ + /* Now copy those saved registers into the current regcache. + Here, regcache_cpy() calls regcache_restore(). */ + regcache_cpy (get_current_regcache (), scratch); + do_cleanups (cleanups); + + /* We've made right mess of GDB's local state, just discard + everything. */ + 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; + struct value *value; /* Require all but BUFFERP to be valid. A NULL BUFFERP indicates that the value proper does not need to be fetched. */ @@ -173,21 +590,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, 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); - /* Ask this frame to unwind its register. */ - frame->unwind->reg (frame, &frame->unwind_cache, regnum, - optimizedp, lvalp, addrp, realnump, bufferp); + gdb_assert (value != NULL); + + *optimizedp = value_optimized_out (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))); + + /* 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. */ @@ -197,32 +622,6 @@ frame_register (struct frame_info *frame, int regnum, gdb_assert (realnump != NULL); /* gdb_assert (bufferp != NULL); */ - /* Ulgh! Old code that, for lval_register, sets ADDRP to the offset - of the register in the register cache. It should instead return - the REGNUM corresponding to that register. Translate the . */ - if (GET_SAVED_REGISTER_P ()) - { - GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame, regnum, lvalp); - /* Compute the REALNUM if the caller wants it. */ - if (*lvalp == lval_register) - { - int regnum; - for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++) - { - if (*addrp == register_offset_hack (current_gdbarch, regnum)) - { - *realnump = regnum; - return; - } - } - internal_error (__FILE__, __LINE__, - "Failed to compute the register number corresponding" - " to 0x%s", paddr_d (*addrp)); - } - *realnump = -1; - return; - } - /* Obtain the register value by unwinding the register from the next (more inner frame). */ gdb_assert (frame != NULL && frame->next != NULL); @@ -231,7 +630,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; @@ -242,120 +641,149 @@ frame_unwind_register (struct frame_info *frame, int regnum, void *buf) } void -frame_unwind_signed_register (struct frame_info *frame, int regnum, - LONGEST *val) +get_frame_register (struct frame_info *frame, + int regnum, gdb_byte *buf) { - void *buf = alloca (MAX_REGISTER_RAW_SIZE); - frame_unwind_register (frame, regnum, buf); - (*val) = extract_signed_integer (buf, REGISTER_VIRTUAL_SIZE (regnum)); + frame_unwind_register (frame->next, regnum, buf); } -void -frame_unwind_unsigned_register (struct frame_info *frame, int regnum, - ULONGEST *val) +struct value * +frame_unwind_register_value (struct frame_info *frame, int regnum) { - void *buf = alloca (MAX_REGISTER_RAW_SIZE); - frame_unwind_register (frame, regnum, buf); - (*val) = extract_unsigned_integer (buf, REGISTER_VIRTUAL_SIZE (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; } -void -frame_read_register (struct frame_info *frame, int regnum, void *buf) +struct value * +get_frame_register_value (struct frame_info *frame, int regnum) { - gdb_assert (frame != NULL && frame->next != NULL); - frame_unwind_register (frame->next, regnum, buf); + return frame_unwind_register_value (frame->next, regnum); } -void -frame_read_unsigned_register (struct frame_info *frame, int regnum, - ULONGEST *val) -{ - /* NOTE: cagney/2002-10-31: There is a bit of dogma here - there is - always a frame. Both this, and the equivalent - frame_read_signed_register() function, can only be called with a - valid frame. If, for some reason, this function is called - without a frame then the problem isn't here, but rather in the - caller. It should of first created a frame and then passed that - in. */ - /* NOTE: cagney/2002-10-31: As a side bar, keep in mind that the - ``current_frame'' should not be treated as a special case. While - ``get_next_frame (current_frame) == NULL'' currently holds, it - should, as far as possible, not be relied upon. In the future, - ``get_next_frame (current_frame)'' may instead simply return a - normal frame object that simply always gets register values from - the register cache. Consequently, frame code should try to avoid - tests like ``if get_next_frame() == NULL'' and instead just rely - on recursive frame calls (like the below code) when manipulating - a frame chain. */ - gdb_assert (frame != NULL && frame->next != NULL); - frame_unwind_unsigned_register (frame->next, regnum, val); +LONGEST +frame_unwind_register_signed (struct frame_info *frame, int regnum) +{ + gdb_byte buf[MAX_REGISTER_SIZE]; + frame_unwind_register (frame, regnum, buf); + return extract_signed_integer (buf, register_size (get_frame_arch (frame), + regnum)); } -void -frame_read_signed_register (struct frame_info *frame, int regnum, - LONGEST *val) +LONGEST +get_frame_register_signed (struct frame_info *frame, int regnum) { - /* See note above in frame_read_unsigned_register(). */ - gdb_assert (frame != NULL && frame->next != NULL); - frame_unwind_signed_register (frame->next, regnum, val); + return frame_unwind_register_signed (frame->next, regnum); } -void -generic_unwind_get_saved_register (char *raw_buffer, - int *optimizedp, - CORE_ADDR *addrp, - struct frame_info *frame, - int regnum, - enum lval_type *lvalp) -{ - int optimizedx; - CORE_ADDR addrx; - int realnumx; - enum lval_type lvalx; - - if (!target_has_registers) - error ("No registers."); - - /* Keep things simple, ensure that all the pointers (except valuep) - are non NULL. */ - if (optimizedp == NULL) - optimizedp = &optimizedx; - if (lvalp == NULL) - lvalp = &lvalx; - if (addrp == NULL) - addrp = &addrx; +ULONGEST +frame_unwind_register_unsigned (struct frame_info *frame, int regnum) +{ + gdb_byte buf[MAX_REGISTER_SIZE]; + frame_unwind_register (frame, regnum, buf); + return extract_unsigned_integer (buf, register_size (get_frame_arch (frame), + regnum)); +} - gdb_assert (frame != NULL && frame->next != NULL); - frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp, - &realnumx, raw_buffer); +ULONGEST +get_frame_register_unsigned (struct frame_info *frame, int regnum) +{ + return frame_unwind_register_unsigned (frame->next, regnum); } void -get_saved_register (char *raw_buffer, - int *optimized, - CORE_ADDR *addrp, - struct frame_info *frame, - int regnum, - enum lval_type *lval) -{ - if (GET_SAVED_REGISTER_P ()) +put_frame_register (struct frame_info *frame, int regnum, + const gdb_byte *buf) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + int realnum; + int optim; + enum lval_type lval; + 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.")); + switch (lval) { - GET_SAVED_REGISTER (raw_buffer, optimized, addrp, frame, regnum, lval); - return; + 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)); + break; + } + case lval_register: + regcache_cooked_write (get_current_regcache (), realnum, buf); + break; + default: + error (_("Attempt to assign to an unmodifiable value.")); } - generic_unwind_get_saved_register (raw_buffer, optimized, addrp, frame, - regnum, lval); } /* frame_register_read () Find and return the value of REGNUM for the specified stack frame. - The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). + The number of bytes copied is REGISTER_SIZE (REGNUM). 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; @@ -363,86 +791,137 @@ 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. - - 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. */ - - if (register_cached (regnum) < 0) - return 0; /* register value not available */ - return !optimized; } - -/* 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. */ - int -frame_map_name_to_regnum (const char *name, int len) +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 (len < 0) - len = strlen (name); + /* Skip registers wholly inside of OFFSET. */ + while (offset >= register_size (gdbarch, regnum)) + { + offset -= register_size (gdbarch, regnum); + regnum++; + } - /* Search register name space. */ - for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) - if (REGISTER_NAME (i) && len == strlen (REGISTER_NAME (i)) - && strncmp (name, REGISTER_NAME (i), len) == 0) - { - return i; - } + /* 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; + } - /* Try builtin registers. */ - i = builtin_reg_map_name_to_regnum (name, len); - if (i >= 0) + /* Copy the data. */ + while (len > 0) { - /* A builtin register doesn't fall into the architecture's - register range. */ - gdb_assert (i >= NUM_REGS + NUM_PSEUDO_REGS); - return i; + 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); + } + + myaddr += curr_len; + len -= curr_len; + offset = 0; + regnum++; } - return -1; + return 1; } -const char * -frame_map_regnum_to_name (int regnum) +void +put_frame_register_bytes (struct frame_info *frame, int regnum, + CORE_ADDR offset, int len, const gdb_byte *myaddr) { - if (regnum < 0) - return NULL; - if (regnum < NUM_REGS + NUM_PSEUDO_REGS) - return REGISTER_NAME (regnum); - return builtin_reg_map_regnum_to_name (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. */ -struct frame_info * +static struct frame_info * create_sentinel_frame (struct regcache *regcache) { struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info); - frame->type = NORMAL_FRAME; frame->level = -1; /* Explicitly initialize the sentinel frame's cache. Provide it with the underlying regcache. In the future additional information, such as the frame's thread will be added. */ - frame->unwind_cache = sentinel_frame_cache (regcache); + frame->prologue_cache = sentinel_frame_cache (regcache); /* For the moment there is only one sentinel frame implementation. */ 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; - /* Always unwind the PC as part of creating this frame. This - ensures that the frame's PC points at something valid. */ - /* FIXME: cagney/2003-01-10: Problem here. Unwinding a sentinel - frame's PC may require information such as the frame's thread's - stop reason. Is it possible to get to that? */ - frame->pc = frame_pc_unwind (frame); + /* Make the sentinel frame's ID valid, but invalid. That way all + comparisons with it should fail. */ + frame->this_id.p = 1; + frame->this_id.value = null_frame_id; + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "{ create_sentinel_frame (...) -> "); + fprint_frame (gdb_stdlog, frame); + fprintf_unfiltered (gdb_stdlog, " }\n"); + } return frame; } @@ -464,20 +943,6 @@ frame_obstack_zalloc (unsigned long size) return data; } -CORE_ADDR * -frame_saved_regs_zalloc (struct frame_info *fi) -{ - fi->saved_regs = (CORE_ADDR *) - frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS); - return fi->saved_regs; -} - -CORE_ADDR * -get_frame_saved_regs (struct frame_info *fi) -{ - return fi->saved_regs; -} - /* Return the innermost (currently executing) stack frame. This is split into two functions. The function unwind_to_current_frame() is wrapped in catch exceptions so that, even when the unwind of the @@ -487,7 +952,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, eg, because it's PC value + /* A sentinel frame can fail to unwind, e.g., because its PC value lands in somewhere like start. */ if (frame == NULL) return 1; @@ -498,18 +963,26 @@ unwind_to_current_frame (struct ui_out *ui_out, void *args) struct frame_info * get_current_frame (void) { - if (!target_has_stack) - error ("No stack."); + /* First check, and report, the lack of registers. Having GDB + report "No stack!" or "No memory" when the target doesn't even + have registers is very confusing. Besides, "printcmd.exp" + 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.")); if (!target_has_memory) - error ("No memory."); + error (_("No memory.")); + 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. */ @@ -522,23 +995,53 @@ 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; + + /* If the current thread is executing, don't try to read from + it. */ + if (is_executing (inferior_ptid)) + return 0; + + return 1; +} -/* Return the selected frame. Always non-null (unless there isn't an +/* Return the selected frame. Always non-NULL (unless there isn't an inferior sufficient for creating a frame) in which case an error is thrown. */ struct frame_info * -get_selected_frame (void) +get_selected_frame (const char *message) { - if (deprecated_selected_frame == NULL) - /* 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 ()); + if (selected_frame == NULL) + { + 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 + the inferior does not have a frame; in that case it will return + NULL instead of calling error(). */ + +struct frame_info * +deprecated_safe_get_selected_frame (void) +{ + if (!has_stack_frames ()) + return NULL; + return get_selected_frame (NULL); } /* Select frame FI (or NULL - to invalidate the current frame). */ @@ -546,28 +1049,34 @@ get_selected_frame (void) void select_frame (struct frame_info *fi) { - register struct symtab *s; + struct symtab *s; - deprecated_selected_frame = fi; - /* NOTE: cagney/2002-05-04: FI can be NULL. This occures when the + selected_frame = fi; + /* NOTE: cagney/2002-05-04: FI can be NULL. This occurs when the frame is being invalidated. */ - if (selected_frame_level_changed_hook) - selected_frame_level_changed_hook (frame_relative_level (fi)); + 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 + selected_frame_level_changed_event() right here, but due to limitations in the current interfaces, we would end up flooding UIs with events - because select_frame is used extensively internally. + because select_frame() is used extensively internally. 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 users 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) { - s = find_pc_symtab (fi->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. */ + s = find_pc_symtab (get_frame_address_in_block (fi)); if (s && s->language != current_language->la_language && s->language != language_unknown @@ -577,711 +1086,270 @@ select_frame (struct frame_info *fi) } } } + +/* Create an arbitrary (i.e. address specified by user) or innermost frame. + Always returns a non-NULL value. */ -/* Return the register saved in the simplistic ``saved_regs'' cache. - If the value isn't here AND a value is needed, try the next inner - most frame. */ - -static void -frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnump, void *bufferp) +struct frame_info * +create_new_frame (CORE_ADDR addr, CORE_ADDR pc) { - /* There is always a frame at this point. And THIS is the frame - we're interested in. */ - gdb_assert (frame != NULL); - /* If we're using generic dummy frames, we'd better not be in a call - dummy. (generic_call_dummy_register_unwind ought to have been called - instead.) */ - gdb_assert (!(DEPRECATED_USE_GENERIC_DUMMY_FRAMES - && (get_frame_type (frame) == DUMMY_FRAME))); - - /* Only (older) architectures that implement the - DEPRECATED_FRAME_INIT_SAVED_REGS method should be using this - function. */ - gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ()); - - /* Load the saved_regs register cache. */ - if (get_frame_saved_regs (frame) == NULL) - DEPRECATED_FRAME_INIT_SAVED_REGS (frame); - - if (get_frame_saved_regs (frame) != NULL - && get_frame_saved_regs (frame)[regnum] != 0) - { - if (regnum == SP_REGNUM) - { - /* SP register treated specially. */ - *optimizedp = 0; - *lvalp = not_lval; - *addrp = 0; - *realnump = -1; - if (bufferp != NULL) - store_address (bufferp, REGISTER_RAW_SIZE (regnum), - get_frame_saved_regs (frame)[regnum]); - } - else - { - /* Any other register is saved in memory, fetch it but cache - a local copy of its value. */ - *optimizedp = 0; - *lvalp = lval_memory; - *addrp = get_frame_saved_regs (frame)[regnum]; - *realnump = -1; - if (bufferp != NULL) - { -#if 1 - /* Save each register value, as it is read in, in a - frame based cache. */ - void **regs = (*cache); - if (regs == NULL) - { - int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS) - * sizeof (void *)); - regs = frame_obstack_zalloc (sizeof_cache); - (*cache) = regs; - } - if (regs[regnum] == NULL) - { - regs[regnum] - = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum)); - read_memory (get_frame_saved_regs (frame)[regnum], regs[regnum], - REGISTER_RAW_SIZE (regnum)); - } - memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum)); -#else - /* Read the value in from memory. */ - read_memory (get_frame_saved_regs (frame)[regnum], bufferp, - REGISTER_RAW_SIZE (regnum)); -#endif - } - } - return; - } - - /* No luck, assume this and the next frame have the same register - value. Pass the request down the frame chain to the next frame. - Hopefully that will find the register's location, either in a - register or in memory. */ - frame_register (frame, regnum, optimizedp, lvalp, addrp, realnump, - bufferp); -} + struct frame_info *fi; -static CORE_ADDR -frame_saved_regs_pc_unwind (struct frame_info *frame, void **cache) -{ - gdb_assert (FRAME_SAVED_PC_P ()); - return FRAME_SAVED_PC (frame); -} - -static void -frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache, - struct frame_id *id) -{ - int fromleaf; - CORE_ADDR base; - CORE_ADDR pc; - - /* Start out by assuming it's NULL. */ - (*id) = null_frame_id; - - if (frame_relative_level (next_frame) <= 0) - /* FIXME: 2002-11-09: Frameless functions can occure anywhere in - the frame chain, not just the inner most frame! The generic, - per-architecture, frame code should handle this and the below - should simply be removed. */ - fromleaf = FRAMELESS_FUNCTION_INVOCATION (next_frame); - else - fromleaf = 0; - - if (fromleaf) - /* A frameless inner-most frame. The `FP' (which isn't an - architecture frame-pointer register!) of the caller is the same - as the callee. */ - /* FIXME: 2002-11-09: There isn't any reason to special case this - edge condition. Instead the per-architecture code should hande - it locally. */ - base = get_frame_base (next_frame); - else + if (frame_debug) { - /* Two macros defined in tm.h specify the machine-dependent - actions to be performed here. - - First, get the frame's chain-pointer. - - If that is zero, the frame is the outermost frame or a leaf - called by the outermost frame. This means that if start - calls main without a frame, we'll return 0 (which is fine - anyway). - - Nope; there's a problem. This also returns when the current - routine is a leaf of main. This is unacceptable. We move - this to after the ffi test; I'd rather have backtraces from - start go curfluy than have an abort called from main not show - main. */ - gdb_assert (FRAME_CHAIN_P ()); - base = FRAME_CHAIN (next_frame); - - if (!frame_chain_valid (base, next_frame)) - return; + fprintf_unfiltered (gdb_stdlog, + "{ create_new_frame (addr=0x%s, pc=0x%s) ", + paddr_nz (addr), paddr_nz (pc)); } - if (base == 0) - return; - - /* FIXME: cagney/2002-06-08: This should probably return the frame's - function and not the PC (a.k.a. resume address). */ - pc = frame_pc_unwind (next_frame); - id->pc = pc; - id->base = base; -} - -static void -frame_saved_regs_pop (struct frame_info *fi, void **cache, - struct regcache *regcache) -{ - gdb_assert (POP_FRAME_P ()); - POP_FRAME; -} - -const struct frame_unwind trad_frame_unwinder = { - frame_saved_regs_pop, - frame_saved_regs_pc_unwind, - frame_saved_regs_id_unwind, - frame_saved_regs_register_unwind -}; -const struct frame_unwind *trad_frame_unwind = &trad_frame_unwinder; - - -/* Function: get_saved_register - Find register number REGNUM relative to FRAME and put its (raw, - target format) contents in *RAW_BUFFER. - - Set *OPTIMIZED if the variable was optimized out (and thus can't be - fetched). Note that this is never set to anything other than zero - in this implementation. - - Set *LVAL to lval_memory, lval_register, or not_lval, depending on - whether the value was fetched from memory, from a register, or in a - strange and non-modifiable way (e.g. a frame pointer which was - calculated rather than fetched). We will use not_lval for values - fetched from generic dummy frames. - - Set *ADDRP to the address, either in memory or as a REGISTER_BYTE - offset into the registers array. If the value is stored in a dummy - frame, set *ADDRP to zero. - - To use this implementation, define a function called - "get_saved_register" in your target code, which simply passes all - of its arguments to this function. - - The argument RAW_BUFFER must point to aligned memory. */ -void -deprecated_generic_get_saved_register (char *raw_buffer, int *optimized, - CORE_ADDR *addrp, - struct frame_info *frame, int regnum, - enum lval_type *lval) -{ - if (!target_has_registers) - error ("No registers."); + fi = FRAME_OBSTACK_ZALLOC (struct frame_info); - gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ()); + fi->next = create_sentinel_frame (get_current_regcache ()); - /* Normal systems don't optimize out things with register numbers. */ - if (optimized != NULL) - *optimized = 0; + /* 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; - if (addrp) /* default assumption: not found in memory */ - *addrp = 0; + /* 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); - /* Note: since the current frame's registers could only have been - saved by frames INTERIOR TO the current frame, we skip examining - the current frame itself: otherwise, we would be getting the - previous frame's registers which were saved by the current frame. */ + fi->this_id.p = 1; + fi->this_id.value = frame_id_build (addr, pc); - if (frame != NULL) + if (frame_debug) { - for (frame = get_next_frame (frame); - frame_relative_level (frame) >= 0; - frame = get_next_frame (frame)) - { - if (get_frame_type (frame) == DUMMY_FRAME) - { - if (lval) /* found it in a CALL_DUMMY frame */ - *lval = not_lval; - if (raw_buffer) - /* FIXME: cagney/2002-06-26: This should be via the - gdbarch_register_read() method so that it, on the - fly, constructs either a raw or pseudo register - from the raw register cache. */ - regcache_raw_read - (generic_find_dummy_frame (get_frame_pc (frame), - get_frame_base (frame)), - regnum, raw_buffer); - return; - } - - DEPRECATED_FRAME_INIT_SAVED_REGS (frame); - if (get_frame_saved_regs (frame) != NULL - && get_frame_saved_regs (frame)[regnum] != 0) - { - if (lval) /* found it saved on the stack */ - *lval = lval_memory; - if (regnum == SP_REGNUM) - { - if (raw_buffer) /* SP register treated specially */ - store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), - get_frame_saved_regs (frame)[regnum]); - } - else - { - if (addrp) /* any other register */ - *addrp = get_frame_saved_regs (frame)[regnum]; - if (raw_buffer) - read_memory (get_frame_saved_regs (frame)[regnum], raw_buffer, - REGISTER_RAW_SIZE (regnum)); - } - return; - } - } + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, fi); + fprintf_unfiltered (gdb_stdlog, " }\n"); } - /* If we get thru the loop to this point, it means the register was - not saved in any frame. Return the actual live-register value. */ - - if (lval) /* found it in a live register */ - *lval = lval_register; - if (addrp) - *addrp = REGISTER_BYTE (regnum); - if (raw_buffer) - deprecated_read_register_gen (regnum, raw_buffer); -} - -/* Determine the frame's type based on its PC. */ - -static enum frame_type -frame_type_from_pc (CORE_ADDR pc) -{ - /* FIXME: cagney/2002-11-24: Can't yet directly call - pc_in_dummy_frame() as some architectures don't set - PC_IN_CALL_DUMMY() to generic_pc_in_call_dummy() (remember the - latter is implemented by simply calling pc_in_dummy_frame). */ - if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES - && DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)) - return DUMMY_FRAME; - else - { - char *name; - find_pc_partial_function (pc, &name, NULL, NULL); - if (PC_IN_SIGTRAMP (pc, name)) - return SIGTRAMP_FRAME; - else - return NORMAL_FRAME; - } + return fi; } -/* Create an arbitrary (i.e. address specified by user) or innermost frame. - Always returns a non-NULL value. */ +/* Return the frame that THIS_FRAME calls (NULL if THIS_FRAME is the + innermost frame). Be careful to not fall off the bottom of the + frame chain and onto the sentinel frame. */ struct frame_info * -create_new_frame (CORE_ADDR addr, CORE_ADDR pc) +get_next_frame (struct frame_info *this_frame) { - struct frame_info *fi; - - fi = frame_obstack_zalloc (sizeof (struct frame_info)); - - fi->frame = addr; - fi->pc = pc; - fi->next = create_sentinel_frame (current_regcache); - fi->type = frame_type_from_pc (pc); - - if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()) - DEPRECATED_INIT_EXTRA_FRAME_INFO (0, fi); - - /* Select/initialize an unwind function. */ - fi->unwind = frame_unwind_find_by_pc (current_gdbarch, fi->pc); - - return fi; + if (this_frame->level > 0) + return this_frame->next; + else + return NULL; } -/* Return the frame that FRAME calls (NULL if FRAME is the innermost - frame). Be careful to not fall off the bottom of the frame chain - and onto the sentinel frame. */ +/* Observer for the target_changed event. */ -struct frame_info * -get_next_frame (struct frame_info *frame) +static void +frame_observer_target_changed (struct target_ops *target) { - if (frame->level > 0) - return frame->next; - else - return NULL; + 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, "{ 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 ()); - } -} - -/* Create the previous frame using the deprecated methods - INIT_EXTRA_INFO, INIT_FRAME_PC and INIT_FRAME_PC_FIRST. */ + frame_register_unwind (this_frame, regnum, optimizedp, lvalp, + addrp, realnump, NULL); -static struct frame_info * -legacy_get_prev_frame (struct frame_info *next_frame) -{ - CORE_ADDR address = 0; - struct frame_info *prev; - int fromleaf; - - /* This code only works on normal frames. A sentinel frame, where - the level is -1, should never reach this code. */ - gdb_assert (next_frame->level >= 0); - - /* On some machines it is possible to call a function without - setting up a stack frame for it. On these machines, we - define this macro to take two args; a frameinfo pointer - identifying a frame and a variable to set or clear if it is - or isn't leafless. */ - - /* Still don't want to worry about this except on the innermost - frame. This macro will set FROMLEAF if NEXT_FRAME is a frameless - function invocation. */ - if (next_frame->level == 0) - /* FIXME: 2002-11-09: Frameless functions can occure anywhere in - the frame chain, not just the inner most frame! The generic, - per-architecture, frame code should handle this and the below - should simply be removed. */ - fromleaf = FRAMELESS_FUNCTION_INVOCATION (next_frame); - else - fromleaf = 0; - - if (fromleaf) - /* A frameless inner-most frame. The `FP' (which isn't an - architecture frame-pointer register!) of the caller is the same - as the callee. */ - /* FIXME: 2002-11-09: There isn't any reason to special case this - edge condition. Instead the per-architecture code should hande - it locally. */ - address = get_frame_base (next_frame); - else - { - /* Two macros defined in tm.h specify the machine-dependent - actions to be performed here. - - First, get the frame's chain-pointer. - - If that is zero, the frame is the outermost frame or a leaf - called by the outermost frame. This means that if start - calls main without a frame, we'll return 0 (which is fine - anyway). - - Nope; there's a problem. This also returns when the current - routine is a leaf of main. This is unacceptable. We move - this to after the ffi test; I'd rather have backtraces from - start go curfluy than have an abort called from main not show - main. */ - gdb_assert (FRAME_CHAIN_P ()); - address = FRAME_CHAIN (next_frame); - - if (!frame_chain_valid (address, next_frame)) - return 0; - } - if (address == 0) - return 0; + if (*optimizedp) + break; - /* Create an initially zero previous frame. */ - prev = frame_obstack_zalloc (sizeof (struct frame_info)); + if (*lvalp != lval_register) + break; - /* Link it in. */ - next_frame->prev = prev; - prev->next = next_frame; - prev->frame = address; - prev->level = next_frame->level + 1; - /* FIXME: cagney/2002-11-18: Should be setting the frame's type - here, before anything else, and not last. Various INIT functions - are full of work-arounds for the frames type not being set - correctly from the word go. Ulgh! */ - prev->type = NORMAL_FRAME; - - /* This change should not be needed, FIXME! We should determine - whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen - after DEPRECATED_INIT_EXTRA_FRAME_INFO and come up with a simple - way to express what goes on here. - - DEPRECATED_INIT_EXTRA_FRAME_INFO is called from two places: - create_new_frame (where the PC is already set up) and here (where - it isn't). DEPRECATED_INIT_FRAME_PC is only called from here, - always after DEPRECATED_INIT_EXTRA_FRAME_INFO. - - The catch is the MIPS, where DEPRECATED_INIT_EXTRA_FRAME_INFO - requires the PC value (which hasn't been set yet). Some other - machines appear to require DEPRECATED_INIT_EXTRA_FRAME_INFO - before they can do DEPRECATED_INIT_FRAME_PC. Phoo. - - We shouldn't need DEPRECATED_INIT_FRAME_PC_FIRST to add more - complication to an already overcomplicated part of GDB. - gnu@cygnus.com, 15Sep92. - - Assuming that some machines need DEPRECATED_INIT_FRAME_PC after - DEPRECATED_INIT_EXTRA_FRAME_INFO, one possible scheme: - - SETUP_INNERMOST_FRAME(): Default version is just create_new_frame - (read_fp ()), read_pc ()). Machines with extra frame info would - do that (or the local equivalent) and then set the extra fields. - - SETUP_ARBITRARY_FRAME(argc, argv): Only change here is that - create_new_frame would no longer init extra frame info; - SETUP_ARBITRARY_FRAME would have to do that. - - INIT_PREV_FRAME(fromleaf, prev) Replace - DEPRECATED_INIT_EXTRA_FRAME_INFO and DEPRECATED_INIT_FRAME_PC. - This should also return a flag saying whether to keep the new - frame, or whether to discard it, because on some machines (e.g. - mips) it is really awkward to have FRAME_CHAIN_VALID called - BEFORE DEPRECATED_INIT_EXTRA_FRAME_INFO (there is no good way to - get information deduced in FRAME_CHAIN_VALID into the extra - fields of the new frame). std_frame_pc(fromleaf, prev) - - This is the default setting for INIT_PREV_FRAME. It just does - what the default DEPRECATED_INIT_FRAME_PC does. Some machines - will call it from INIT_PREV_FRAME (either at the beginning, the - end, or in the middle). Some machines won't use it. - - kingdon@cygnus.com, 13Apr93, 31Jan94, 14Dec94. */ - - /* NOTE: cagney/2002-11-09: Just ignore the above! There is no - reason for things to be this complicated. - - The trick is to assume that there is always a frame. Instead of - special casing the inner-most frame, create fake frame - (containing the hardware registers) that is inner to the - user-visible inner-most frame (...) and then unwind from that. - That way architecture code can use use the standard - frame_XX_unwind() functions and not differentiate between the - inner most and any other case. - - Since there is always a frame to unwind from, there is always - somewhere (NEXT_FRAME) to store all the info needed to construct - a new (previous) frame without having to first create it. This - means that the convolution below - needing to carefully order a - frame's initialization - isn't needed. - - The irony here though, is that FRAME_CHAIN(), at least for a more - up-to-date architecture, always calls FRAME_SAVED_PC(), and - FRAME_SAVED_PC() computes the PC but without first needing the - frame! Instead of the convolution below, we could have simply - called FRAME_SAVED_PC() and been done with it! Note that - FRAME_SAVED_PC() is being superseed by frame_pc_unwind() and that - function does have somewhere to cache that PC value. */ - - if (DEPRECATED_INIT_FRAME_PC_FIRST_P ()) - prev->pc = (DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf, prev)); - - if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()) - DEPRECATED_INIT_EXTRA_FRAME_INFO (fromleaf, prev); - - /* This entry is in the frame queue now, which is good since - FRAME_SAVED_PC may use that queue to figure out its value (see - tm-sparc.h). We want the pc saved in the inferior frame. */ - if (DEPRECATED_INIT_FRAME_PC_P ()) - prev->pc = DEPRECATED_INIT_FRAME_PC (fromleaf, prev); - - /* If ->frame and ->pc are unchanged, we are in the process of - getting ourselves into an infinite backtrace. Some architectures - check this in FRAME_CHAIN or thereabouts, but it seems like there - is no reason this can't be an architecture-independent check. */ - if (prev->frame == next_frame->frame - && prev->pc == next_frame->pc) - { - next_frame->prev = NULL; - obstack_free (&frame_cache_obstack, prev); - return NULL; + regnum = *realnump; + this_frame = get_next_frame (this_frame); } - - /* Initialize the code used to unwind the frame PREV based on the PC - (and probably other architectural information). The PC lets you - check things like the debug info at that point (dwarf2cfi?) and - use that to decide how the frame should be unwound. */ - prev->unwind = frame_unwind_find_by_pc (current_gdbarch, prev->pc); - - /* NOTE: cagney/2002-11-18: The code segments, found in - create_new_frame and get_prev_frame(), that initializes the - frames type is subtly different. The latter only updates ->type - when it encounters a SIGTRAMP_FRAME or DUMMY_FRAME. This stops - get_prev_frame() overriding the frame's type when the INIT code - has previously set it. This is really somewhat bogus. The - initialization, as seen in create_new_frame(), should occur - before the INIT function has been called. */ - if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES - && (DEPRECATED_PC_IN_CALL_DUMMY_P () - ? DEPRECATED_PC_IN_CALL_DUMMY (prev->pc, 0, 0) - : pc_in_dummy_frame (prev->pc))) - prev->type = DUMMY_FRAME; - else - { - /* FIXME: cagney/2002-11-10: This should be moved to before the - INIT code above so that the INIT code knows what the frame's - type is (in fact, for a [generic] dummy-frame, the type can - be set and then the entire initialization can be skipped. - Unforunatly, its the INIT code that sets the PC (Hmm, catch - 22). */ - char *name; - find_pc_partial_function (prev->pc, &name, NULL, NULL); - if (PC_IN_SIGTRAMP (prev->pc, name)) - prev->type = SIGTRAMP_FRAME; - /* FIXME: cagney/2002-11-11: Leave prev->type alone. Some - architectures are forcing the frame's type in INIT so we - don't want to override it here. Remember, NORMAL_FRAME == 0, - so it all works (just :-/). Once this initialization is - moved to the start of this function, all this nastness will - go away. */ - } - - return prev; } -/* Return a structure containing various interesting information - about the frame that called NEXT_FRAME. Returns NULL - if there is no such frame. */ +/* Return a "struct frame_info" corresponding to the frame that called + THIS_FRAME. Returns NULL if there is no such frame. -struct frame_info * -get_prev_frame (struct frame_info *next_frame) + Unlike get_prev_frame, this function always tries to unwind the + frame. */ + +static struct frame_info * +get_prev_frame_1 (struct frame_info *this_frame) { struct frame_info *prev_frame; + struct frame_id this_id; + struct gdbarch *gdbarch; - /* 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 is - block_innermost_frame() is, when the target has no state - (registers, memory, ...), 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 (next_frame == NULL) + gdb_assert (this_frame != NULL); + gdbarch = get_frame_arch (this_frame); + + if (frame_debug) { - /* 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 - NEXT_FRAME. */ - return current_frame; + fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_1 (this_frame="); + if (this_frame != NULL) + fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level); + else + fprintf_unfiltered (gdb_stdlog, ""); + fprintf_unfiltered (gdb_stdlog, ") "); } - /* There is always a frame. If this assertion fails, suspect that - something should be calling get_selected_frame() or - get_current_frame(). */ - gdb_assert (next_frame != NULL); - - if (next_frame->level >= 0 - && !backtrace_below_main - && inside_main_func (get_frame_pc (next_frame))) - /* Don't unwind past main(), bug always unwind the sentinel frame. - Note, this is done _before_ the frame has been marked as - previously unwound. That way if the user later decides to - allow unwinds past main(), that just happens. */ + /* Only try to do the unwind once. */ + if (this_frame->prev_p) { if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "Outermost frame - inside main func.\n"); + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, this_frame->prev); + fprintf_unfiltered (gdb_stdlog, " // cached \n"); + } + 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 + the sentinel frame. */ + this_id = get_frame_id (this_frame); + if (this_frame->level >= 0 && !frame_id_p (this_id)) + { + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n"); + } + this_frame->stop_reason = UNWIND_NULL_ID; return NULL; } - /* Only try to do the unwind once. */ - if (next_frame->prev_p) - return next_frame->prev; - next_frame->prev_p = 1; - - /* If we're inside the entry file, it isn't valid. Don't apply this - test to a dummy frame - dummy frame PC's typically land in the - entry file. Don't apply this test to the sentinel frame. - Sentinel frames should always be allowed to unwind. */ - /* NOTE: drow/2002-12-25: should there be a way to disable this - check? It assumes a single small entry file, and the way some - debug readers (e.g. dbxread) figure out which object is the - entry file is somewhat hokey. */ - /* NOTE: cagney/2003-01-10: If there is a way of disabling this test - then it should probably be moved to before the ->prev_p test, - above. */ - if (next_frame->type != DUMMY_FRAME && next_frame->level >= 0 - && inside_entry_file (get_frame_pc (next_frame))) + /* Check that this frame's ID isn't inner to (younger, below, next) + the next frame. This happens when a frame unwind goes backwards. + This check is valid only if the next frame is NORMAL. See the + comment at frame_id_inner for details. */ + if (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, - "Outermost frame - inside entry file\n"); + { + 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; } - /* If we're already inside the entry function for the main objfile, - then it isn't valid. Don't apply this test to a dummy frame - - dummy frame PC's typically land in the entry func. Don't apply - this test to the sentinel frame. Sentinel frames should always - be allowed to unwind. */ - /* NOTE: cagney/2003-02-25: Don't enable until someone has found - hard evidence that this is needed. */ - if (0 - && next_frame->type != DUMMY_FRAME && next_frame->level >= 0 - && inside_entry_func (get_frame_pc (next_frame))) + /* 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, - "Outermost frame - inside entry func\n"); + { + 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; } - /* If any of the old frame initialization methods are around, use - the legacy get_prev_frame method. Just don't try to unwind a - sentinel frame using that method - it doesn't work. All sentinal - frames use the new unwind code. */ - if ((DEPRECATED_INIT_FRAME_PC_P () - || DEPRECATED_INIT_FRAME_PC_FIRST_P () - || DEPRECATED_INIT_EXTRA_FRAME_INFO_P () - || FRAME_CHAIN_P ()) - && next_frame->level >= 0) + /* 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) { - prev_frame = legacy_get_prev_frame (next_frame); - if (frame_debug && prev_frame == NULL) - fprintf_unfiltered (gdb_stdlog, - "Outermost frame - legacy_get_prev_frame NULL.\n"); - return prev_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. @@ -1295,153 +1363,240 @@ get_prev_frame (struct frame_info *next_frame) been here before' check above will stop repeated memory allocation calls. */ prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info); - prev_frame->level = next_frame->level + 1; - - /* Try to unwind the PC. If that doesn't work, assume we've reached - the oldest frame and simply return. Is there a better sentinal - value? The unwound PC value is then used to initialize the new - previous frame's type. - - Note that the pc-unwind is intentionally performed before the - frame chain. This is ok since, for old targets, both - frame_pc_unwind (nee, FRAME_SAVED_PC) and FRAME_CHAIN()) assume - NEXT_FRAME's data structures have already been initialized (using - DEPRECATED_INIT_EXTRA_FRAME_INFO) and hence the call order - doesn't matter. - - By unwinding the PC first, it becomes possible to, in the case of - a dummy frame, avoid also unwinding the frame ID. This is - because (well ignoring the PPC) a dummy frame can be located - using NEXT_FRAME's frame ID. */ - - prev_frame->pc = frame_pc_unwind (next_frame); - if (prev_frame->pc == 0) + prev_frame->level = this_frame->level + 1; + + /* Don't yet compute ->unwind (and hence ->type). It is computed + on-demand in get_frame_type, frame_register_unwind, and + get_frame_id. */ + + /* Don't yet compute the frame's ID. It is computed on-demand by + get_frame_id(). */ + + /* The unwound frame ID is validate at the start of this function, + as part of the logic to decide if that frame should be further + unwound, and not here while the prev frame is being created. + Doing this makes it possible for the user to examine a frame that + has an invalid frame ID. + + Some very old VAX code noted: [...] For the sake of argument, + suppose that the stack is somewhat trashed (which is one reason + that "info frame" exists). So, return 0 (indicating we don't + know the address of the arglist) if we don't know what frame this + frame calls. */ + + /* Link it in. */ + this_frame->prev = prev_frame; + prev_frame->next = this_frame; + + if (frame_debug) { - /* The allocated PREV_FRAME will be reclaimed when the frame - obstack is next purged. */ - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "Outermost frame - unwound PC zero\n"); - return NULL; + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, prev_frame); + fprintf_unfiltered (gdb_stdlog, " }\n"); } - prev_frame->type = frame_type_from_pc (prev_frame->pc); - /* Set the unwind functions based on that identified PC. */ - prev_frame->unwind = frame_unwind_find_by_pc (current_gdbarch, - prev_frame->pc); + return prev_frame; +} + +/* Debug routine to print a NULL frame being returned. */ - /* Find the prev's frame's ID. */ - switch (prev_frame->type) +static void +frame_debug_got_null_frame (struct frame_info *this_frame, + const char *reason) +{ + if (frame_debug) { - case DUMMY_FRAME: - /* When unwinding a normal frame, the stack structure is - determined by analyzing the frame's function's code (be it - using brute force prologue analysis, or the dwarf2 CFI). In - the case of a dummy frame, that simply isn't possible. The - The PC is either the program entry point, or some random - address on the stack. Trying to use that PC to apply - standard frame ID unwind techniques is just asking for - trouble. */ - if (gdbarch_unwind_dummy_id_p (current_gdbarch)) - { - /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS, - previously saved the dummy frame's ID. Things only work - if the two return the same value. */ - gdb_assert (SAVE_DUMMY_FRAME_TOS_P ()); - /* Use an architecture specific method to extract the prev's - dummy ID from the next frame. Note that this method uses - frame_register_unwind to obtain the register values - needed to determine the dummy frame's ID. */ - prev_frame->id = gdbarch_unwind_dummy_id (current_gdbarch, - next_frame); - } - else if (next_frame->level < 0) - { - /* We're unwinding a sentinel frame, the PC of which is - pointing at a stack dummy. Fake up the dummy frame's ID - using the same sequence as is found a traditional - unwinder. Once all architectures supply the - unwind_dummy_id method, this code can go away. */ - prev_frame->id.base = read_fp (); - prev_frame->id.pc = read_pc (); - } + fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame (this_frame="); + if (this_frame != NULL) + fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level); else - { - /* Outch! We're not on the innermost frame yet we're trying - to unwind to a dummy. The architecture must provide the - unwind_dummy_id() method. Abandon the unwind process but - only after first warning the user. */ - internal_warning (__FILE__, __LINE__, - "Missing unwind_dummy_id architecture method"); - return NULL; - } - break; - case NORMAL_FRAME: - case SIGTRAMP_FRAME: - /* FIXME: cagney/2003-03-04: The below call isn't right. It - should instead be doing something like "prev_frame -> unwind - -> id (next_frame, & prev_frame -> unwind_cache, & prev_frame - -> id)" but that requires more extensive (pending) changes. */ - next_frame->unwind->id (next_frame, &next_frame->unwind_cache, - &prev_frame->id); - /* Check that the unwound ID is valid. */ - if (!frame_id_p (prev_frame->id)) - { - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "Outermost frame - unwound frame ID invalid\n"); - return NULL; - } - /* Check that the new frame isn't inner to (younger, below, - next) the old frame. If that happens the frame unwind is - going backwards. */ - /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since - that doesn't have a valid frame ID. Should instead set the - sentinel frame's frame ID to a `sentinel'. Leave it until - after the switch to storing the frame ID, instead of the - frame base, in the frame object. */ - if (next_frame->level >= 0 - && frame_id_inner (prev_frame->id, get_frame_id (next_frame))) - error ("Unwound frame inner-to selected frame (corrupt stack?)"); - /* Note that, due to frameless functions, the stronger test of - the new frame being outer to the old frame can't be used - - frameless functions differ by only their PC value. */ - break; - default: - internal_error (__FILE__, __LINE__, "bad switch"); + fprintf_unfiltered (gdb_stdlog, ""); + fprintf_unfiltered (gdb_stdlog, ") -> // %s}\n", reason); } +} - /* FIXME: cagney/2002-12-18: Instead of this hack, should only store - the frame ID in PREV_FRAME. Unfortunatly, some architectures - (HP/UX) still reply on EXTRA_FRAME_INFO and, hence, still poke at - the "struct frame_info" object directly. */ - prev_frame->frame = prev_frame->id.base; +/* Is this (non-sentinel) frame in the "main"() function? */ - /* Link it in. */ - next_frame->prev = prev_frame; - prev_frame->next = next_frame; - - /* FIXME: cagney/2002-01-19: This call will go away. Instead of - initializing extra info, all frames will use the frame_cache - (passed to the unwind functions) to store additional frame info. - Unfortunatly legacy targets can't use legacy_get_prev_frame() to - unwind the sentinel frame and, consequently, are forced to take - this code path and rely on the below call to - DEPRECATED_INIT_EXTRA_FRAME_INFO to initialize the inner-most +static int +inside_main_func (struct frame_info *this_frame) +{ + struct minimal_symbol *msymbol; + CORE_ADDR maddr; + + if (symfile_objfile == 0) + return 0; + msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile); + if (msymbol == 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), + ¤t_target); + return maddr == get_frame_func (this_frame); +} + +/* Test whether THIS_FRAME is inside the process entry point function. */ + +static int +inside_entry_func (struct frame_info *this_frame) +{ + return (get_frame_func (this_frame) == entry_point_address ()); +} + +/* Return a structure containing various interesting information about + the frame that called THIS_FRAME. Returns NULL if there is entier + no such frame or the frame fails any of a set of target-independent + condition that should terminate the frame chain (e.g., as unwinding + past main()). + + This function should not contain target-dependent tests, such as + checking whether the program-counter is zero. */ + +struct frame_info * +get_prev_frame (struct frame_info *this_frame) +{ + struct frame_info *prev_frame; + + /* 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); + + /* 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 + frame may have an address "inside_main_func" is on HPUX. On HPUX, the + pcsqh register (space register for the instruction at the head of the + instruction queue) cannot be written directly; the only way to set it + is to branch to code that is in the target space. In order to implement + frame dummies on HPUX, the called function is made to jump back to where + the inferior was when the user function was called. If gdb was inside + the main function when we created the dummy frame, the dummy frame will + point inside the main function. */ + if (this_frame->level >= 0 + && get_frame_type (this_frame) != DUMMY_FRAME + && !backtrace_past_main + && 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 + user later decides to enable unwinds past main(), that will + automatically happen. */ + { + frame_debug_got_null_frame (this_frame, "inside main func"); + return NULL; + } + + /* 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 (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()) + if (this_frame->level + 2 > backtrace_limit) { - gdb_assert (prev_frame->level == 0); - DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev_frame); + frame_debug_got_null_frame (this_frame, "backtrace limit exceeded"); + return NULL; } - return prev_frame; + /* If we're already inside the entry function for the main objfile, + then it isn't valid. Don't apply this test to a dummy frame - + dummy frame PCs typically land in the entry func. Don't apply + this test to the sentinel frame. Sentinel frames should always + be allowed to unwind. */ + /* NOTE: cagney/2003-07-07: Fixed a bug in inside_main_func() - + wasn't checking for "main" in the minimal symbols. With that + fixed asm-source tests now stop in "main" instead of halting the + backtrace in weird and wonderful ways somewhere inside the entry + file. Suspect that tests for inside the entry file/func were + added to work around that (now fixed) case. */ + /* NOTE: cagney/2003-07-15: danielj (if I'm reading it right) + suggested having the inside_entry_func test use the + inside_main_func() msymbol trick (along with entry_point_address() + I guess) to determine the address range of the start function. + That should provide a far better stopper than the current + heuristics. */ + /* NOTE: tausq/2004-10-09: this is needed if, for example, the compiler + applied tail-call optimizations to main so that a function called + from main returns directly to the caller of main. Since we don't + stop at main, we should at least stop at the entry point of the + application. */ + if (!backtrace_past_entry + && get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0 + && inside_entry_func (this_frame)) + { + frame_debug_got_null_frame (this_frame, "inside entry func"); + return NULL; + } + + /* Assume that the only way to get a zero PC is through something + like a SIGSEGV or a dummy frame, and hence that NORMAL frames + will never unwind a zero PC. */ + if (this_frame->level > 0 + && get_frame_type (this_frame) == NORMAL_FRAME + && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME + && get_frame_pc (this_frame) == 0) + { + frame_debug_got_null_frame (this_frame, "zero PC"); + return NULL; + } + + return get_prev_frame_1 (this_frame); } CORE_ADDR get_frame_pc (struct frame_info *frame) { - return frame->pc; + gdb_assert (frame->next != NULL); + return frame_pc_unwind (frame->next); +} + +/* Return an address that falls within THIS_FRAME's code block. */ + +CORE_ADDR +get_frame_address_in_block (struct frame_info *this_frame) +{ + /* A draft address. */ + 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; + + return pc; } static int @@ -1464,7 +1619,7 @@ pc_notcurrent (struct frame_info *frame) void find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) { - (*sal) = find_pc_line (frame->pc, pc_notcurrent (frame)); + (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame)); } /* Per "frame.h", return the ``address'' of the frame. Code should @@ -1472,7 +1627,55 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal) CORE_ADDR get_frame_base (struct frame_info *fi) { - return fi->frame; + return get_frame_id (fi).stack_addr; +} + +/* High-level offsets into the frame. Used by the debug info. */ + +CORE_ADDR +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); + /* 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, &fi->prologue_cache); + return fi->base->this_base (fi, &fi->base_cache); +} + +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. */ + if (fi->base == NULL) + 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_locals (fi, &fi->prologue_cache); + return fi->base->this_locals (fi, &fi->base_cache); +} + +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. */ + if (fi->base == NULL) + 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_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, ... @@ -1490,148 +1693,178 @@ frame_relative_level (struct frame_info *fi) enum frame_type get_frame_type (struct frame_info *frame) { - /* Some targets still don't use [generic] dummy frames. Catch them - here. */ - if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES - && deprecated_frame_in_dummy (frame)) - return DUMMY_FRAME; - return frame->type; + 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); + return frame->unwind->type; } -void -deprecated_set_frame_type (struct frame_info *frame, enum frame_type type) -{ - /* Arrrg! See comment in "frame.h". */ - frame->type = type; -} - -#ifdef FRAME_FIND_SAVED_REGS -/* XXX - deprecated. This is a compatibility function for targets - that do not yet implement DEPRECATED_FRAME_INIT_SAVED_REGS. */ -/* Find the addresses in which registers are saved in FRAME. */ +/* Memory access methods. */ void -deprecated_get_frame_saved_regs (struct frame_info *frame, - struct frame_saved_regs *saved_regs_addr) +get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr, + gdb_byte *buf, int len) { - if (frame->saved_regs == NULL) - { - frame->saved_regs = (CORE_ADDR *) - frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS); - } - if (saved_regs_addr == NULL) - { - struct frame_saved_regs saved_regs; - FRAME_FIND_SAVED_REGS (frame, saved_regs); - memcpy (frame->saved_regs, &saved_regs, SIZEOF_FRAME_SAVED_REGS); - } - else - { - FRAME_FIND_SAVED_REGS (frame, *saved_regs_addr); - memcpy (frame->saved_regs, saved_regs_addr, SIZEOF_FRAME_SAVED_REGS); - } + read_memory (addr, buf, len); } -#endif -struct frame_extra_info * -get_frame_extra_info (struct frame_info *fi) +LONGEST +get_frame_memory_signed (struct frame_info *this_frame, CORE_ADDR addr, + int len) { - return fi->extra_info; + return read_memory_integer (addr, len); } -struct frame_extra_info * -frame_extra_info_zalloc (struct frame_info *fi, long size) +ULONGEST +get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr, + int len) { - fi->extra_info = frame_obstack_zalloc (size); - return fi->extra_info; + return read_memory_unsigned_integer (addr, len); } -void -deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc) +int +safe_frame_unwind_memory (struct frame_info *this_frame, + CORE_ADDR addr, gdb_byte *buf, int len) { - /* See comment in "frame.h". */ - frame->pc = pc; - /* 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 go. */ - gdb_assert (frame->next != NULL); - frame->next->pc_unwind_cache = pc; - frame->next->pc_unwind_cache_p = 1; + /* NOTE: target_read_memory returns zero on success! */ + return !target_read_memory (addr, buf, len); } -void -deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base) -{ - /* See comment in "frame.h". */ - frame->frame = base; -} +/* Architecture method. */ -void -deprecated_set_frame_saved_regs_hack (struct frame_info *frame, - CORE_ADDR *saved_regs) +struct gdbarch * +get_frame_arch (struct frame_info *this_frame) { - frame->saved_regs = saved_regs; + /* 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; } -void -deprecated_set_frame_extra_info_hack (struct frame_info *frame, - struct frame_extra_info *extra_info) +/* Stack pointer methods. */ + +CORE_ADDR +get_frame_sp (struct frame_info *this_frame) { - frame->extra_info = extra_info; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + /* Normality - an architecture that provides a way of obtaining any + frame inner-most address. */ + if (gdbarch_unwind_sp_p (gdbarch)) + /* NOTE drow/2008-06-28: gdbarch_unwind_sp could be converted to + operate on THIS_FRAME now. */ + return gdbarch_unwind_sp (gdbarch, this_frame->next); + /* Now things are really are grim. Hope that the value returned by + the gdbarch_sp_regnum register is meaningful. */ + if (gdbarch_sp_regnum (gdbarch) >= 0) + return get_frame_register_unsigned (this_frame, + gdbarch_sp_regnum (gdbarch)); + internal_error (__FILE__, __LINE__, _("Missing unwind SP method")); } -void -deprecated_set_frame_next_hack (struct frame_info *fi, - struct frame_info *next) +/* Return the reason why we can't unwind past FRAME. */ + +enum unwind_stop_reason +get_frame_unwind_stop_reason (struct frame_info *frame) { - fi->next = next; + /* 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; } -void -deprecated_set_frame_prev_hack (struct frame_info *fi, - struct frame_info *prev) +/* Return a string explaining REASON. */ + +const char * +frame_stop_reason_string (enum unwind_stop_reason reason) { - fi->prev = prev; + switch (reason) + { + 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"); + } } -struct context * -deprecated_get_frame_context (struct frame_info *fi) +/* Clean up after a failed (wrong unwinder) attempt to unwind past + FRAME. */ + +static void +frame_cleanup_after_sniffer (void *arg) { - return fi->context; + 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; } -void -deprecated_set_frame_context (struct frame_info *fi, - struct context *context) +/* 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) { - fi->context = context; + gdb_assert (frame->unwind == NULL); + frame->unwind = unwind; + return make_cleanup (frame_cleanup_after_sniffer, frame); } -struct frame_info * -deprecated_frame_xmalloc (void) +extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */ + +static struct cmd_list_element *set_backtrace_cmdlist; +static struct cmd_list_element *show_backtrace_cmdlist; + +static void +set_backtrace_cmd (char *args, int from_tty) { - struct frame_info *frame = XMALLOC (struct frame_info); - memset (frame, 0, sizeof (struct frame_info)); - return frame; + help_list (set_backtrace_cmdlist, "set backtrace ", -1, gdb_stdout); } -struct frame_info * -deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs, - long sizeof_extra_info) +static void +show_backtrace_cmd (char *args, int from_tty) { - struct frame_info *frame = deprecated_frame_xmalloc (); - make_cleanup (xfree, frame); - if (sizeof_saved_regs > 0) - { - frame->saved_regs = xcalloc (1, sizeof_saved_regs); - make_cleanup (xfree, frame->saved_regs); - } - if (sizeof_extra_info > 0) - { - frame->extra_info = xcalloc (1, sizeof_extra_info); - make_cleanup (xfree, frame->extra_info); - } - return frame; + cmd_show_list (show_backtrace_cmdlist, from_tty, ""); } void @@ -1639,27 +1872,62 @@ _initialize_frame (void) { obstack_init (&frame_cache_obstack); - /* FIXME: cagney/2003-01-19: This command needs a rename. Suggest - `set backtrace {past,beyond,...}-main'. Also suggest adding `set - backtrace ...-start' to control backtraces past start. The - problem with `below' is that it stops the `up' command. */ - - add_setshow_boolean_cmd ("backtrace-below-main", class_obscure, - &backtrace_below_main, "\ -Set whether backtraces should continue past \"main\".\n\ -Normally the caller of \"main\" is not of interest, so GDB will terminate\n\ -the backtrace at \"main\". Set this variable if you need to see the rest\n\ -of the stack trace.", "\ -Show whether backtraces should continue past \"main\".\n\ + observer_attach_target_changed (frame_observer_target_changed); + + add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\ +Set backtrace specific variables.\n\ +Configure backtrace variables such as the backtrace limit"), + &set_backtrace_cmdlist, "set backtrace ", + 0/*allow-unknown*/, &setlist); + add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, _("\ +Show backtrace specific variables\n\ +Show backtrace variables such as the backtrace limit"), + &show_backtrace_cmdlist, "show backtrace ", + 0/*allow-unknown*/, &showlist); + + add_setshow_boolean_cmd ("past-main", class_obscure, + &backtrace_past_main, _("\ +Set whether backtraces should continue past \"main\"."), _("\ +Show whether backtraces should continue past \"main\"."), _("\ Normally the caller of \"main\" is not of interest, so GDB will terminate\n\ the backtrace at \"main\". Set this variable if you need to see the rest\n\ -of the stack trace.", - NULL, NULL, &setlist, &showlist); - +of the stack trace."), + NULL, + show_backtrace_past_main, + &set_backtrace_cmdlist, + &show_backtrace_cmdlist); + + add_setshow_boolean_cmd ("past-entry", class_obscure, + &backtrace_past_entry, _("\ +Set whether backtraces should continue past the entry point of a program."), + _("\ +Show whether backtraces should continue past the entry point of a program."), + _("\ +Normally there are no callers beyond the entry point of a program, so GDB\n\ +will terminate the backtrace there. Set this variable if you need to see \n\ +the rest of the stack trace."), + NULL, + show_backtrace_past_entry, + &set_backtrace_cmdlist, + &show_backtrace_cmdlist); + + 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."), + NULL, + show_backtrace_limit, + &set_backtrace_cmdlist, + &show_backtrace_cmdlist); /* Debug this files internals. */ - 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); }