From 0bb428781c4782c6236beb58c06052dccd382aa1 Mon Sep 17 00:00:00 2001 From: David Carlton Date: Wed, 16 Apr 2003 19:57:09 +0000 Subject: 2003-04-16 David Carlton * Merge with mainline; tag is carlton_dictionary-20030416-merge. --- gdb/frame.c | 1375 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 1004 insertions(+), 371 deletions(-) (limited to 'gdb/frame.c') diff --git a/gdb/frame.c b/gdb/frame.c index 5d220c9..3871aa1 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -36,9 +36,101 @@ #include "annotate.h" #include "language.h" #include "frame-unwind.h" +#include "frame-base.h" #include "command.h" #include "gdbcmd.h" +/* 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: Perhaphs 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 type. */ + /* FIXME: cagney/2003-04-02: Should instead be returning + ->unwind->type. Unfortunatly, legacy code is still explicitly + setting the type using the method deprecated_set_frame_type. + Eliminate that method and this field can be eliminated. */ + enum frame_type type; + + /* For each register, address of where it was saved on entry to the + frame, or zero if it was not saved on entry to this frame. This + includes special registers such as pc and fp saved in special + ways in the stack frame. The SP_REGNUM is even more special, the + address here is the sp for the previous frame, not the address + where the sp was saved. */ + /* Allocated by frame_saved_regs_zalloc () which is called / + initialized by DEPRECATED_FRAME_INIT_SAVED_REGS(). */ + CORE_ADDR *saved_regs; /*NUM_REGS + NUM_PSEUDO_REGS*/ + + /* Anything extra for this structure that may have been defined in + the machine dependent files. */ + /* Allocated by frame_extra_info_zalloc () which is called / + initialized by DEPRECATED_INIT_EXTRA_FRAME_INFO */ + struct frame_extra_info *extra_info; + + /* If dwarf2 unwind frame informations is used, this structure holds + all related unwind data. */ + struct context *context; + + /* 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 otherwize, 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 */ +}; + /* Flag to control debugging. */ static int frame_debug; @@ -47,6 +139,77 @@ static int frame_debug; static int backtrace_below_main; +static void +fprint_frame_id (struct ui_file *file, struct frame_id id) +{ + fprintf_unfiltered (file, "{stack=0x%s,code=0x%s}", + paddr_nz (id.stack_addr), + paddr_nz (id.code_addr)); +} + +static void +fprint_frame_type (struct ui_file *file, enum frame_type type) +{ + switch (type) + { + case UNKNOWN_FRAME: + fprintf_unfiltered (file, "UNKNOWN_FRAME"); + return; + 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 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="); + fprint_frame_type (file, fi->type); + 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,52 +220,118 @@ 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; + gdb_assert (!legacy_frame_p (current_gdbarch)); + 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_pc (current_gdbarch, + get_frame_pc (fi)); + /* FIXME: cagney/2003-04-02: Rather than storing the frame's + type in the frame, the unwinder's type should be returned + directly. Unfortunatly, legacy code, called by + legacy_get_prev_frame, explicitly set the frames type + using the method deprecated_set_frame_type(). */ + gdb_assert (fi->unwind->type != UNKNOWN_FRAME); + fi->type = fi->unwind->type; + } + /* Find THIS frame's ID. */ + fi->unwind->this_id (fi->next, &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; } 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 (CORE_ADDR stack_addr, CORE_ADDR code_addr) { struct frame_id id; - id.base = base; - id.pc = func_or_pc; + id.stack_addr = stack_addr; + id.code_addr = code_addr; 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 .code can be NULL but the .stack cannot. */ + p = (l.stack_addr != 0); + 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 == 0 || r.stack_addr == 0) + /* Like a NaN, if either ID is invalid, the result is false. */ + 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 == 0 || r.code_addr == 0) + /* A zero code addr is a wild card, always succeed. */ + eq = 1; + else if (l.code_addr == r.code_addr) + /* The .stack and .code are identical, the ID's are identical. */ + eq = 1; + else + /* FIXME: cagney/2003-04-06: This should be zero. Can't yet do + this because most frame ID's are not being initialized + correctly. */ + eq = 1; + 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) { - /* 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 == 0 || r.stack_addr == 0) + /* 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). */ + inner = INNER_THAN (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 * @@ -135,26 +364,127 @@ frame_find_by_id (struct frame_id id) } 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 (current_gdbarch)) + { + /* 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_address (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 (current_gdbarch, this_frame); + } + else if (this_frame->level < 0) + { + /* FIXME: cagney/2003-03-06: Old code and and a sentinel + frame. Do like was always done. Fetch the PC's value + direct from the global registers array (via read_pc). + This assumes that this frame belongs to the current + global register cache. The assumption is dangerous. */ + pc = read_pc (); + } + else if (DEPRECATED_FRAME_SAVED_PC_P ()) + { + /* FIXME: cagney/2003-03-06: Old code, but not a sentinel + frame. Do like was always done. Note that this method, + unlike unwind_pc(), tries to handle all the different + frame cases directly. It fails. */ + pc = DEPRECATED_FRAME_SAVED_PC (this_frame); + } + else + internal_error (__FILE__, __LINE__, "No gdbarch_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 +frame_func_unwind (struct frame_info *fi) { - if (!frame->pc_unwind_cache_p) + if (!fi->prev_func.p) { - frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache); - frame->pc_unwind_cache_p = 1; + fi->prev_func.p = 1; + fi->prev_func.addr = get_pc_function_start (frame_pc_unwind (fi)); + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "{ frame_func_unwind (fi=%d) -> 0x%s }\n", + fi->level, paddr_nz (fi->prev_func.addr)); } - return frame->pc_unwind_cache; + return fi->prev_func.addr; +} + +CORE_ADDR +get_frame_func (struct frame_info *fi) +{ + return frame_func_unwind (fi->next); +} + +static int +do_frame_unwind_register (void *src, int regnum, void *buf) +{ + frame_unwind_register (src, regnum, buf); + return 1; } void -frame_pop (struct frame_info *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); +frame_pop (struct frame_info *this_frame) +{ + struct regcache *scratch_regcache; + struct cleanup *cleanups; + + if (DEPRECATED_POP_FRAME_P ()) + { + /* A legacy architecture that has implemented a custom pop + function. All new architectures should instead be using the + generic code below. */ + DEPRECATED_POP_FRAME; + } + else + { + /* 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 betweening trying to extract the old values from the + current_regcache while, at the same time writing new values + into that same cache. */ + struct regcache *scratch = regcache_xmalloc (current_gdbarch); + struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch); + regcache_save (scratch, do_frame_unwind_register, this_frame); + /* 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. Unfortunatly, 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 (current_regcache, scratch); + do_cleanups (cleanups); + } + /* We've made right mess of GDB's local state, just discard + everything. */ flush_cached_frames (); } @@ -165,6 +495,13 @@ frame_register_unwind (struct frame_info *frame, int regnum, { struct frame_unwind_cache *cache; + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, + "{ frame_register_unwind (frame=%d,regnum=\"%s\",...) ", + frame->level, frame_map_regnum_to_name (regnum)); + } + /* Require all but BUFFERP to be valid. A NULL BUFFERP indicates that the value proper does not need to be fetched. */ gdb_assert (optimizedp != NULL); @@ -179,9 +516,46 @@ frame_register_unwind (struct frame_info *frame, int regnum, detected the problem before calling here. */ gdb_assert (frame != NULL); - /* Ask this frame to unwind its register. */ - frame->unwind->reg (frame, &frame->unwind_cache, regnum, - optimizedp, lvalp, addrp, realnump, bufferp); + /* Find the unwinder. */ + if (frame->unwind == NULL) + { + frame->unwind = frame_unwind_find_by_pc (current_gdbarch, + get_frame_pc (frame)); + /* FIXME: cagney/2003-04-02: Rather than storing the frame's + type in the frame, the unwinder's type should be returned + directly. Unfortunatly, legacy code, called by + legacy_get_prev_frame, explicitly set the frames type using + the method deprecated_set_frame_type(). */ + gdb_assert (frame->unwind->type != UNKNOWN_FRAME); + frame->type = frame->unwind->type; + } + + /* Ask this frame to unwind its register. See comment in + "frame-unwind.h" for why NEXT frame and this unwind cace are + passed in. */ + frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum, + optimizedp, lvalp, addrp, realnump, bufferp); + + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "->"); + fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp)); + fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp)); + fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp))); + fprintf_unfiltered (gdb_stdlog, " *bufferp="); + if (bufferp == NULL) + fprintf_unfiltered (gdb_stdlog, ""); + else + { + int i; + const char *buf = bufferp; + fprintf_unfiltered (gdb_stdlog, "["); + for (i = 0; i < register_size (current_gdbarch, regnum); i++) + fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]); + fprintf_unfiltered (gdb_stdlog, "]"); + } + fprintf_unfiltered (gdb_stdlog, " }\n"); + } } void @@ -200,9 +574,10 @@ frame_register (struct frame_info *frame, int regnum, /* 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 ()) + if (DEPRECATED_GET_SAVED_REGISTER_P ()) { - GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame, regnum, lvalp); + DEPRECATED_GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame, + regnum, lvalp); /* Compute the REALNUM if the caller wants it. */ if (*lvalp == lval_register) { @@ -330,23 +705,6 @@ generic_unwind_get_saved_register (char *raw_buffer, &realnumx, raw_buffer); } -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 ()) - { - GET_SAVED_REGISTER (raw_buffer, optimized, addrp, frame, regnum, lval); - return; - } - 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. @@ -431,18 +789,22 @@ create_sentinel_frame (struct regcache *regcache) /* 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; } @@ -498,10 +860,15 @@ 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."); + if (!target_has_stack) + error ("No stack."); if (!target_has_memory) error ("No memory."); if (current_frame == NULL) @@ -567,7 +934,7 @@ select_frame (struct frame_info *fi) source language of this frame, and switch to it if desired. */ if (fi) { - s = find_pc_symtab (fi->pc); + s = find_pc_symtab (get_frame_pc (fi)); if (s && s->language != current_language->la_language && s->language != language_unknown @@ -583,19 +950,20 @@ select_frame (struct frame_info *fi) 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) +legacy_saved_regs_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) { - /* There is always a frame at this point. And THIS is the frame - we're interested in. */ + /* HACK: New code is passed the next frame and this cache. + Unfortunatly, old code expects this frame. Since this is a + backward compatibility hack, cheat by walking one level along the + prologue chain to the frame the old code expects. + + Do not try this at home. Professional driver, closed course. */ + struct frame_info *frame = next_frame->prev; 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 @@ -633,13 +1001,13 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, #if 1 /* Save each register value, as it is read in, in a frame based cache. */ - void **regs = (*cache); + void **regs = (*this_prologue_cache); if (regs == NULL) { int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS) * sizeof (void *)); regs = frame_obstack_zalloc (sizeof_cache); - (*cache) = regs; + (*this_prologue_cache) = regs; } if (regs[regnum] == NULL) { @@ -659,102 +1027,35 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, 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); + /* No luck. Assume this and the next frame have the same register + value. Pass the unwind request down the frame chain to the next + frame. Hopefully that frame will find the register's location. */ + frame_register_unwind (next_frame, regnum, optimizedp, lvalp, addrp, + realnump, bufferp); } -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) +legacy_saved_regs_this_id (struct frame_info *next_frame, + void **this_prologue_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 - { - /* 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; - } - 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; + /* legacy_get_prev_frame() always sets ->this_id.p, hence this is + never needed. */ + internal_error (__FILE__, __LINE__, "legacy_saved_regs_this_id() called"); } -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 legacy_saved_regs_unwinder = { + /* Not really. It gets overridden by legacy_get_prev_frame. */ + UNKNOWN_FRAME, + legacy_saved_regs_this_id, + legacy_saved_regs_prev_register }; -const struct frame_unwind *trad_frame_unwind = &trad_frame_unwinder; +const struct frame_unwind *legacy_saved_regs_unwind = &legacy_saved_regs_unwinder; -/* Function: get_saved_register +/* Function: deprecated_generic_get_saved_register Find register number REGNUM relative to FRAME and put its (raw, - target format) contents in *RAW_BUFFER. + 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 @@ -770,10 +1071,6 @@ const struct frame_unwind *trad_frame_unwind = &trad_frame_unwinder; 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 @@ -888,31 +1185,51 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) { struct frame_info *fi; + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, + "{ create_new_frame (addr=0x%s, pc=0x%s) ", + paddr_nz (addr), paddr_nz (pc)); + } + 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); + + /* Select/initialize both the unwind function and the frame's type + based on the PC. */ + fi->unwind = frame_unwind_find_by_pc (current_gdbarch, pc); + if (fi->unwind->type != UNKNOWN_FRAME) + fi->type = fi->unwind->type; + else + fi->type = frame_type_from_pc (pc); + + fi->this_id.p = 1; + deprecated_update_frame_base_hack (fi, addr); + deprecated_update_frame_pc_hack (fi, 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); + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, fi); + fprintf_unfiltered (gdb_stdlog, " }\n"); + } return fi; } -/* 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. */ +/* 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 * -get_next_frame (struct frame_info *frame) +get_next_frame (struct frame_info *this_frame) { - if (frame->level > 0) - return frame->next; + if (this_frame->level > 0) + return this_frame->next; else return NULL; } @@ -929,6 +1246,8 @@ flush_cached_frames (void) current_frame = NULL; /* Invalidate cache */ select_frame (NULL); annotate_frames_invalid (); + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, "{ flush_cached_frames () }\n"); } /* Flush the frame cache, and start a new one if necessary. */ @@ -949,15 +1268,183 @@ reinit_frame_cache (void) INIT_EXTRA_INFO, INIT_FRAME_PC and INIT_FRAME_PC_FIRST. */ static struct frame_info * -legacy_get_prev_frame (struct frame_info *next_frame) +legacy_get_prev_frame (struct frame_info *this_frame) { CORE_ADDR address = 0; struct frame_info *prev; int fromleaf; + /* Don't frame_debug print legacy_get_prev_frame() here, just + confuses the output. */ + + /* Allocate the new frame. + + There is no reason to worry about memory leaks, should the + remainder of the function fail. The allocated memory will be + quickly reclaimed when the frame cache is flushed, and the `we've + been here before' check, in get_prev_frame will stop repeated + memory allocation calls. */ + prev = FRAME_OBSTACK_ZALLOC (struct frame_info); + prev->level = this_frame->level + 1; + + /* Do not completly wire it in to the frame chain. Some (bad) code + in INIT_FRAME_EXTRA_INFO tries to look along frame->prev to pull + some fancy tricks (of course such code is, by definition, + recursive). + + On the other hand, methods, such as get_frame_pc() and + get_frame_base() rely on being able to walk along the frame + chain. Make certain that at least they work by providing that + link. Of course things manipulating prev can't go back. */ + prev->next = this_frame; + + /* NOTE: cagney/2002-11-18: Should have been correctly setting the + frame's type here, before anything else, and not last, at the + bottom of this function. The various + DEPRECATED_INIT_EXTRA_FRAME_INFO, DEPRECATED_INIT_FRAME_PC, + DEPRECATED_INIT_FRAME_PC_FIRST and + DEPRECATED_FRAME_INIT_SAVED_REGS methods are full of work-arounds + that handle the frame not being correctly set from the start. + Unfortunatly those same work-arounds rely on the type defaulting + to NORMAL_FRAME. Ulgh! The new frame code does not have this + problem. */ + prev->type = UNKNOWN_FRAME; + + /* A legacy frame's ID is always computed here. Mark it as valid. */ + prev->this_id.p = 1; + + /* Handle sentinel frame unwind as a special case. */ + if (this_frame->level < 0) + { + /* 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, DEPRECATED_FRAME_SAVED_PC) and + DEPRECATED_FRAME_CHAIN()) assume THIS_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 THIS_FRAME's frame ID. */ + + deprecated_update_frame_pc_hack (prev, frame_pc_unwind (this_frame)); + if (get_frame_pc (prev) == 0) + { + /* The allocated PREV_FRAME will be reclaimed when the frame + obstack is next purged. */ + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, + " // unwound legacy PC zero }\n"); + } + return NULL; + } + + /* Set the unwind functions based on that identified PC. Ditto + for the "type" but strongly prefer the unwinder's frame type. */ + prev->unwind = frame_unwind_find_by_pc (current_gdbarch, + get_frame_pc (prev)); + if (prev->unwind->type == UNKNOWN_FRAME) + prev->type = frame_type_from_pc (get_frame_pc (prev)); + else + prev->type = prev->unwind->type; + + /* Find the prev's frame's ID. */ + if (prev->type == DUMMY_FRAME + && gdbarch_unwind_dummy_id_p (current_gdbarch)) + { + /* 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. */ + /* Assume call_function_by_hand(), 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->this_id.value = gdbarch_unwind_dummy_id (current_gdbarch, + this_frame); + } + else + { + /* 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->this_id.value = frame_id_build (read_fp (), read_pc ()); + } + + /* Check that the unwound ID is valid. */ + if (!frame_id_p (prev->this_id.value)) + { + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, + " // unwound legacy 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. */ + + /* Link it in. */ + this_frame->prev = prev; + + /* 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 frame. */ + if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()) + { + DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev); + } + + if (prev->type == NORMAL_FRAME) + prev->this_id.value.code_addr + = get_pc_function_start (prev->this_id.value.code_addr); + + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, prev); + fprintf_unfiltered (gdb_stdlog, " } // legacy innermost frame\n"); + } + return prev; + } + /* 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); + gdb_assert (this_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 @@ -966,14 +1453,14 @@ legacy_get_prev_frame (struct frame_info *next_frame) 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 + frame. This macro will set FROMLEAF if THIS_FRAME is a frameless function invocation. */ - if (next_frame->level == 0) + if (this_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); + fromleaf = FRAMELESS_FUNCTION_INVOCATION (this_frame); else fromleaf = 0; @@ -984,7 +1471,7 @@ legacy_get_prev_frame (struct frame_info *next_frame) /* 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); + address = get_frame_base (this_frame); else { /* Two macros defined in tm.h specify the machine-dependent @@ -1002,28 +1489,36 @@ legacy_get_prev_frame (struct frame_info *next_frame) 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); + gdb_assert (DEPRECATED_FRAME_CHAIN_P ()); + address = DEPRECATED_FRAME_CHAIN (this_frame); - if (!frame_chain_valid (address, next_frame)) - return 0; + if (!legacy_frame_chain_valid (address, this_frame)) + { + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, + " // legacy frame chain invalid }\n"); + } + return NULL; + } } if (address == 0) - return 0; - - /* Create an initially zero previous frame. */ - prev = frame_obstack_zalloc (sizeof (struct frame_info)); + { + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, + " // legacy frame chain NULL }\n"); + } + return NULL; + } - /* 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; + /* Link in the already allocated prev frame. */ + this_frame->prev = prev; + deprecated_update_frame_base_hack (prev, address); /* This change should not be needed, FIXME! We should determine whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen @@ -1059,10 +1554,11 @@ legacy_get_prev_frame (struct frame_info *next_frame) 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) + mips) it is really awkward to have DEPRECATED_FRAME_CHAIN_VALID + called BEFORE DEPRECATED_INIT_EXTRA_FRAME_INFO (there is no good + way to get information deduced in DEPRECATED_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 @@ -1083,21 +1579,24 @@ legacy_get_prev_frame (struct frame_info *next_frame) 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 + somewhere (THIS_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. */ + The irony here though, is that DEPRECATED_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)); + deprecated_update_frame_pc_hack (prev, + DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf, + prev)); if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()) DEPRECATED_INIT_EXTRA_FRAME_INFO (fromleaf, prev); @@ -1106,17 +1605,27 @@ legacy_get_prev_frame (struct frame_info *next_frame) 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); + deprecated_update_frame_pc_hack (prev, + 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) + check this in DEPRECATED_FRAME_CHAIN or thereabouts, but it seems + like there is no reason this can't be an architecture-independent + check. */ + if (get_frame_base (prev) == get_frame_base (this_frame) + && get_frame_pc (prev) == get_frame_pc (this_frame)) { - next_frame->prev = NULL; + this_frame->prev = NULL; obstack_free (&frame_cache_obstack, prev); + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, + " // legacy this.id == prev.id }\n"); + } return NULL; } @@ -1124,7 +1633,25 @@ legacy_get_prev_frame (struct frame_info *next_frame) (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); + prev->unwind = frame_unwind_find_by_pc (current_gdbarch, + get_frame_pc (prev)); + + /* If the unwinder provides a frame type, use it. Otherwize + continue on to that heuristic mess. */ + if (prev->unwind->type != UNKNOWN_FRAME) + { + prev->type = prev->unwind->type; + if (prev->type == NORMAL_FRAME) + prev->this_id.value.code_addr + = get_pc_function_start (prev->this_id.value.code_addr); + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, prev); + fprintf_unfiltered (gdb_stdlog, " } // legacy with unwound type\n"); + } + return prev; + } /* NOTE: cagney/2002-11-18: The code segments, found in create_new_frame and get_prev_frame(), that initializes the @@ -1136,8 +1663,8 @@ legacy_get_prev_frame (struct frame_info *next_frame) 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))) + ? DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (prev), 0, 0) + : pc_in_dummy_frame (get_frame_pc (prev)))) prev->type = DUMMY_FRAME; else { @@ -1148,8 +1675,8 @@ legacy_get_prev_frame (struct frame_info *next_frame) 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)) + find_pc_partial_function (get_frame_pc (prev), &name, NULL, NULL); + if (PC_IN_SIGTRAMP (get_frame_pc (prev), 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 @@ -1159,18 +1686,39 @@ legacy_get_prev_frame (struct frame_info *next_frame) go away. */ } + if (prev->type == NORMAL_FRAME) + prev->this_id.value.code_addr + = get_pc_function_start (prev->this_id.value.code_addr); + + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, prev); + fprintf_unfiltered (gdb_stdlog, " } // legacy with confused type\n"); + } + return prev; } /* Return a structure containing various interesting information - about the frame that called NEXT_FRAME. Returns NULL + about 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) +get_prev_frame (struct frame_info *this_frame) { struct frame_info *prev_frame; + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame (this_frame="); + if (this_frame != NULL) + fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level); + else + fprintf_unfiltered (gdb_stdlog, ""); + fprintf_unfiltered (gdb_stdlog, ") "); + } + /* 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 @@ -1189,7 +1737,7 @@ get_prev_frame (struct frame_info *next_frame) 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) + if (this_frame == NULL) { /* NOTE: cagney/2002-11-09: There was a code segment here that would error out when CURRENT_FRAME was NULL. The comment @@ -1202,34 +1750,42 @@ get_prev_frame (struct frame_info *next_frame) thing to do.'' Per the above, this code shouldn't even be called with a NULL - NEXT_FRAME. */ + THIS_FRAME. */ return current_frame; } /* There is always a frame. If this assertion fails, suspect that something should be calling get_selected_frame() or get_current_frame(). */ - gdb_assert (next_frame != NULL); + gdb_assert (this_frame != NULL); - if (next_frame->level >= 0 + if (this_frame->level >= 0 && !backtrace_below_main - && inside_main_func (get_frame_pc (next_frame))) + && inside_main_func (get_frame_pc (this_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. */ { if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "Outermost frame - inside main func.\n"); + fprintf_unfiltered (gdb_stdlog, "-> NULL // inside main func }\n"); return NULL; } /* Only try to do the unwind once. */ - if (next_frame->prev_p) - return next_frame->prev; - next_frame->prev_p = 1; + if (this_frame->prev_p) + { + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, this_frame->prev); + fprintf_unfiltered (gdb_stdlog, " // cached \n"); + } + return this_frame->prev; + } + this_frame->prev_p = 1; +#if 0 /* 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. @@ -1241,14 +1797,27 @@ get_prev_frame (struct frame_info *next_frame) /* 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))) + /* NOTE: vinschen/2003-04-01: Disabled. It turns out that the call to + inside_entry_file destroys a meaningful backtrace under some + conditions. E. g. the backtrace tests in the asm-source testcase + are broken for some targets. In this test the functions are all + implemented as part of one file and the testcase is not necessarily + linked with a start file (depending on the target). What happens is, + that the first frame is printed normaly and following frames are + treated as being inside the enttry file then. This way, only the + #0 frame is printed in the backtrace output. */ + if (this_frame->type != DUMMY_FRAME && this_frame->level >= 0 + && inside_entry_file (get_frame_pc (this_frame))) { 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, " // inside entry file }\n"); + } return NULL; } +#endif /* 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 - @@ -1258,32 +1827,61 @@ get_prev_frame (struct frame_info *next_frame) /* 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))) + && this_frame->type != DUMMY_FRAME && this_frame->level >= 0 + && inside_entry_func (get_frame_pc (this_frame))) { 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, "// inside entry func }\n"); + } 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) + the legacy get_prev_frame method. */ + if (legacy_frame_p (current_gdbarch)) { - 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"); + prev_frame = legacy_get_prev_frame (this_frame); return prev_frame; } + /* 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. */ + if (this_frame->level >= 0 && !frame_id_p (get_frame_id (this_frame))) + { + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n"); + } + return NULL; + } + + /* Check that this frame's ID isn't inner to (younger, below, next) + the next frame. This happens when frame unwind goes backwards. + Since the sentinel frame isn't valid, don't apply this if this + frame is entier the inner-most or sentinel frame. */ + if (this_frame->level > 0 + && frame_id_inner (get_frame_id (this_frame), + get_frame_id (this_frame->next))) + error ("This frame inner-to next frame (corrupt stack?)"); + + /* Check that this and the next frame are different. If they are + not, there is most likely a stack cycle. As with the inner-than + test, avoid the inner-most and sentinel frames. */ + /* FIXME: cagney/2003-03-17: Can't yet enable this this check. The + frame_id_eq() method doesn't yet use function addresses when + comparing frame IDs. */ + if (0 + && this_frame->level > 0 + && frame_id_eq (get_frame_id (this_frame), + get_frame_id (this_frame->next))) + error ("This frame identical to next frame (corrupt stack?)"); + /* Allocate the new frame but do not wire it in to the frame chain. Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along frame->next to pull some fancy tricks (of course such code is, by @@ -1295,7 +1893,7 @@ 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; + prev_frame->level = this_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 @@ -1304,88 +1902,58 @@ get_prev_frame (struct frame_info *next_frame) 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 + frame_pc_unwind (nee, FRAME_SAVED_PC) and + DEPRECATED_FRAME_CHAIN()) assume THIS_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. */ + using THIS_FRAME's frame ID. */ - prev_frame->pc = frame_pc_unwind (next_frame); - if (prev_frame->pc == 0) + if (frame_pc_unwind (this_frame) == 0) { /* 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; - } - 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); - - /* FIXME: cagney/2003-01-13: A dummy frame doesn't need to unwind - the frame ID because the frame ID comes from the previous frame. - The other frames do though. True? */ - /* 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. As of 2003-02-24 the x86-64 - was returning an invalid frame ID when trying to do an unwind a - sentinel frame that belonged to a frame dummy. */ - if (!frame_id_p (prev_frame->id)) - { - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "Outermost frame - unwound frame ID invalid\n"); + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, " // unwound PC zero }\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. */ - - /* 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; + + /* 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. + + The very old VAX frame_args_address_correct() method 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. */ - 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 - frame. */ - if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()) + this_frame->prev = prev_frame; + prev_frame->next = this_frame; + + if (frame_debug) { - gdb_assert (prev_frame->level == 0); - DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev_frame); + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, prev_frame); + fprintf_unfiltered (gdb_stdlog, " }\n"); } return prev_frame; @@ -1394,7 +1962,8 @@ get_prev_frame (struct frame_info *next_frame) CORE_ADDR get_frame_pc (struct frame_info *frame) { - return frame->pc; + gdb_assert (frame->next != NULL); + return frame_pc_unwind (frame->next); } static int @@ -1417,7 +1986,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 @@ -1425,7 +1994,59 @@ 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_pc (current_gdbarch, get_frame_pc (fi)); + /* Sneaky: If the low-level unwind and high-level base code share a + common unwinder, let them share the prologue cache. */ + if (fi->base->unwind == fi->unwind) + return fi->base->this_base (fi->next, &fi->prologue_cache); + return fi->base->this_base (fi->next, &fi->base_cache); +} + +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_pc (current_gdbarch, get_frame_pc (fi)); + /* Sneaky: If the low-level unwind and high-level base code share a + common unwinder, let them share the prologue cache. */ + if (fi->base->unwind == fi->unwind) + cache = &fi->prologue_cache; + else + cache = &fi->base_cache; + return fi->base->this_locals (fi->next, cache); +} + +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_pc (current_gdbarch, get_frame_pc (fi)); + /* Sneaky: If the low-level unwind and high-level base code share a + common unwinder, let them share the prologue cache. */ + if (fi->base->unwind == fi->unwind) + cache = &fi->prologue_cache; + else + cache = &fi->base_cache; + return fi->base->this_args (fi->next, cache); } /* Level of the selected frame: 0 for innermost, 1 for its caller, ... @@ -1448,7 +2069,24 @@ get_frame_type (struct frame_info *frame) 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 it is that which + provides the frame's type. */ + frame->unwind = frame_unwind_find_by_pc (current_gdbarch, + get_frame_pc (frame)); + /* FIXME: cagney/2003-04-02: Rather than storing the frame's + type in the frame, the unwinder's type should be returned + directly. Unfortunatly, legacy code, called by + legacy_get_prev_frame, explicitly set the frames type using + the method deprecated_set_frame_type(). */ + gdb_assert (frame->unwind->type != UNKNOWN_FRAME); + frame->type = frame->unwind->type; + } + if (frame->type == UNKNOWN_FRAME) + return NORMAL_FRAME; + else + return frame->type; } void @@ -1458,34 +2096,6 @@ deprecated_set_frame_type (struct frame_info *frame, enum frame_type type) 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. */ - -void -deprecated_get_frame_saved_regs (struct frame_info *frame, - struct frame_saved_regs *saved_regs_addr) -{ - 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); - } -} -#endif - struct frame_extra_info * get_frame_extra_info (struct frame_info *fi) { @@ -1502,21 +2112,33 @@ frame_extra_info_zalloc (struct frame_info *fi, long size) void deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc) { - /* 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; + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "{ deprecated_update_frame_pc_hack (frame=%d,pc=0x%s) }\n", + frame->level, paddr_nz (pc)); + /* NOTE: cagney/2003-03-11: Some architectures (e.g., Arm) are + maintaining a locally allocated frame object. Since such frame's + are not in the frame chain, it isn't possible to assume that the + frame has a next. Sigh. */ + if (frame->next != NULL) + { + /* While we're at it, update this frame's cached PC value, found + in the next frame. Oh for the day when "struct frame_info" + is opaque and this hack on hack can just go away. */ + frame->next->prev_pc.value = pc; + frame->next->prev_pc.p = 1; + } } void deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base) { + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "{ deprecated_update_frame_base_hack (frame=%d,base=0x%s) }\n", + frame->level, paddr_nz (base)); /* See comment in "frame.h". */ - frame->frame = base; + frame->this_id.value.stack_addr = base; } void @@ -1563,8 +2185,8 @@ deprecated_set_frame_context (struct frame_info *fi, struct frame_info * deprecated_frame_xmalloc (void) { - struct frame_info *frame = XMALLOC (struct frame_info); - memset (frame, 0, sizeof (struct frame_info)); + struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info); + frame->this_id.p = 1; return frame; } @@ -1587,6 +2209,17 @@ deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs, return frame; } +int +legacy_frame_p (struct gdbarch *current_gdbarch) +{ + return (DEPRECATED_INIT_FRAME_PC_P () + || DEPRECATED_INIT_FRAME_PC_FIRST_P () + || DEPRECATED_INIT_EXTRA_FRAME_INFO_P () + || DEPRECATED_FRAME_CHAIN_P () + || !gdbarch_unwind_dummy_id_p (current_gdbarch) + || !SAVE_DUMMY_FRAME_TOS_P ()); +} + void _initialize_frame (void) { -- cgit v1.1