diff options
Diffstat (limited to 'gdb/frame.c')
-rw-r--r-- | gdb/frame.c | 484 |
1 files changed, 311 insertions, 173 deletions
diff --git a/gdb/frame.c b/gdb/frame.c index bf860fe2ccd..cf9349d658c 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -135,26 +135,94 @@ 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 (!frame->pc_unwind_cache_p) + if (!this_frame->pc_unwind_cache_p) { - frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache); - frame->pc_unwind_cache_p = 1; + 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->pc_unwind_cache = pc; + this_frame->pc_unwind_cache_p = 1; } - return frame->pc_unwind_cache; + return this_frame->pc_unwind_cache; +} + +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) +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); + 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); + /* 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. */ + target_store_registers (-1); flush_cached_frames (); } @@ -200,9 +268,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 +399,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. @@ -498,10 +550,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) @@ -667,13 +724,6 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, 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) @@ -735,26 +785,17 @@ frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache, 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 +/* 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 +811,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 @@ -904,15 +941,15 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) 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; } @@ -949,15 +986,151 @@ 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; + /* 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 + definition, recursive). Try to prevent it. + + 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; + + /* 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 = NORMAL_FRAME; + + /* 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, FRAME_SAVED_PC) and 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. */ + + prev->pc = frame_pc_unwind (this_frame); + if (prev->pc == 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->type = frame_type_from_pc (prev->pc); + + /* Set the unwind functions based on that identified PC. */ + prev->unwind = frame_unwind_find_by_pc (current_gdbarch, prev->pc); + + /* 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 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->id = 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->id.base = read_fp (); + prev->id.pc = read_pc (); + } + + /* Check that the unwound ID is valid. */ + if (!frame_id_p (prev->id)) + { + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "Outermost legacy sentinel 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. */ + + /* 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 = prev->id.base; + + /* Link it in. */ + this_frame->prev = prev; + prev->next = this_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 ()) + { + DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev); + } + 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 +1139,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 +1157,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 @@ -1003,27 +1176,18 @@ legacy_get_prev_frame (struct frame_info *next_frame) start go curfluy than have an abort called from main not show main. */ gdb_assert (FRAME_CHAIN_P ()); - address = FRAME_CHAIN (next_frame); + address = FRAME_CHAIN (this_frame); - if (!frame_chain_valid (address, next_frame)) + if (!frame_chain_valid (address, this_frame)) return 0; } if (address == 0) return 0; - /* Create an initially zero previous frame. */ - prev = frame_obstack_zalloc (sizeof (struct frame_info)); - - /* Link it in. */ - next_frame->prev = prev; - prev->next = next_frame; + /* Link in the already allocated prev frame. */ + this_frame->prev = prev; + prev->next = this_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 @@ -1083,7 +1247,7 @@ 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. @@ -1112,10 +1276,10 @@ legacy_get_prev_frame (struct frame_info *next_frame) 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) + if (prev->frame == this_frame->frame + && prev->pc == this_frame->pc) { - next_frame->prev = NULL; + this_frame->prev = NULL; obstack_free (&frame_cache_obstack, prev); return NULL; } @@ -1163,11 +1327,11 @@ legacy_get_prev_frame (struct frame_info *next_frame) } /* 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; @@ -1189,7 +1353,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,18 +1366,18 @@ 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 @@ -1226,9 +1390,9 @@ get_prev_frame (struct frame_info *next_frame) } /* 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) + return this_frame->prev; + this_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 @@ -1241,8 +1405,8 @@ 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))) + 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, @@ -1258,8 +1422,8 @@ 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, @@ -1268,16 +1432,10 @@ get_prev_frame (struct frame_info *next_frame) } /* 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); + prev_frame = legacy_get_prev_frame (this_frame); if (frame_debug && prev_frame == NULL) fprintf_unfiltered (gdb_stdlog, "Outermost frame - legacy_get_prev_frame NULL.\n"); @@ -1295,7 +1453,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 @@ -1305,16 +1463,16 @@ 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 + 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); + prev_frame->pc = frame_pc_unwind (this_frame); if (prev_frame->pc == 0) { /* The allocated PREV_FRAME will be reclaimed when the frame @@ -1342,47 +1500,24 @@ get_prev_frame (struct frame_info *next_frame) 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 (); - } - 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; - } + gdb_assert (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, this_frame); 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 (this_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, + this_frame->unwind->id (this_frame, &this_frame->unwind_cache, &prev_frame->id); /* Check that the unwound ID is valid. */ if (!frame_id_p (prev_frame->id)) @@ -1400,8 +1535,8 @@ get_prev_frame (struct frame_info *next_frame) 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))) + if (this_frame->level >= 0 + && frame_id_inner (prev_frame->id, get_frame_id (this_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 - @@ -1418,22 +1553,8 @@ get_prev_frame (struct frame_info *next_frame) prev_frame->frame = prev_frame->id.base; /* 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 ()) - { - gdb_assert (prev_frame->level == 0); - DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev_frame); - } + this_frame->prev = prev_frame; + prev_frame->next = this_frame; return prev_frame; } @@ -1551,12 +1672,18 @@ 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; + /* 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->pc_unwind_cache = pc; + frame->next->pc_unwind_cache_p = 1; + } } void @@ -1634,6 +1761,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 () + || FRAME_CHAIN_P () + || !gdbarch_unwind_dummy_id_p (current_gdbarch) + || !SAVE_DUMMY_FRAME_TOS_P ()); +} + void _initialize_frame (void) { |