diff options
Diffstat (limited to 'gdb/frame.c')
-rw-r--r-- | gdb/frame.c | 356 |
1 files changed, 56 insertions, 300 deletions
diff --git a/gdb/frame.c b/gdb/frame.c index 79d0ee64171..0bac5808a2d 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -32,6 +32,7 @@ #include "gdb_obstack.h" #include "dummy-frame.h" #include "sentinel-frame.h" +#include "legacy-frame.h" #include "gdbcore.h" #include "annotate.h" #include "language.h" @@ -410,6 +411,12 @@ create_sentinel_frame (struct regcache *regcache) frame->pc_unwind = sentinel_frame_pc_unwind; frame->id_unwind = sentinel_frame_id_unwind; frame->register_unwind = sentinel_frame_register_unwind; + /* Always unwind the PC as part of creating this frame. This + ensures that the frame's PC points into something valid. */ + /* FIXME: cagney/2003-01-10: Problem here. Unwinding a sentinel + frame's PC may require information such as the frame thread's + stop reason. Is it possible to get to that? */ + frame->pc = frame_pc_unwind (frame); return frame; } @@ -450,7 +457,12 @@ get_frame_saved_regs (struct frame_info *fi) static int unwind_to_current_frame (struct ui_out *ui_out, void *args) { - current_frame = get_prev_frame (args); + struct frame_info *frame = get_prev_frame (args); + /* A sentinel frame can fail to unwind, eg, because it's PC value + lands in somewhere like start. */ + if (frame == NULL) + return 1; + current_frame = frame; return 0; } @@ -468,7 +480,7 @@ get_current_frame (void) struct frame_info *sentinel_frame = create_sentinel_frame (current_regcache); if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame, - NULL, RETURN_MASK_ERROR) < 0) + NULL, RETURN_MASK_ERROR) != 0) { /* Oops! Fake a current frame? Is this useful? It has a PC of zero, for instance. */ @@ -537,271 +549,6 @@ select_frame (struct frame_info *fi) } } -/* Return the register saved in the simplistic ``saved_regs'' cache. - If the value isn't here AND a value is needed, try the next inner - most frame. */ - -struct frame_unwind_cache -{ - void *regs[1]; -}; - -static void -frame_saved_regs_register_unwind (struct frame_info *frame, - struct frame_unwind_cache **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. */ - 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))); - - /* Load the saved_regs register cache. */ - if (frame->saved_regs == NULL) - FRAME_INIT_SAVED_REGS (frame); - - if (frame->saved_regs != NULL - && frame->saved_regs[regnum] != 0) - { - if (regnum == SP_REGNUM) - { - /* SP register treated specially. */ - *optimizedp = 0; - *lvalp = not_lval; - *addrp = 0; - *realnump = -1; - if (bufferp != NULL) - store_address (bufferp, REGISTER_RAW_SIZE (regnum), - frame->saved_regs[regnum]); - } - else - { - /* Any other register is saved in memory, fetch it but cache - a local copy of its value. */ - *optimizedp = 0; - *lvalp = lval_memory; - *addrp = frame->saved_regs[regnum]; - *realnump = -1; - if (bufferp != NULL) - { -#if 1 - /* Save each register value, as it is read in, in a - frame based cache. */ - if ((*cache) == NULL) - { - int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS) - * sizeof (void *)); - (*cache) = frame_obstack_zalloc (sizeof_cache); - } - if ((*cache)->regs[regnum] == NULL) - { - (*cache)->regs[regnum] - = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum)); - read_memory (frame->saved_regs[regnum], - (*cache)->regs[regnum], - REGISTER_RAW_SIZE (regnum)); - } - memcpy (bufferp, (*cache)->regs[regnum], - REGISTER_RAW_SIZE (regnum)); -#else - /* Read the value in from memory. */ - read_memory (frame->saved_regs[regnum], bufferp, - REGISTER_RAW_SIZE (regnum)); -#endif - } - } - return; - } - - /* No luck, assume this and the next frame have the same register - value. If a value is needed, pass the request on down the chain; - otherwise just return an indication that the value is in the same - register as the next frame. */ - if (bufferp == NULL) - { - *optimizedp = 0; - *lvalp = lval_register; - *addrp = 0; - *realnump = regnum; - } - else - { - frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp, - realnump, bufferp); - } -} - -static CORE_ADDR -frame_saved_regs_pc_unwind (struct frame_info *frame, - struct frame_unwind_cache **cache) -{ - return FRAME_SAVED_PC (frame); -} - -static void -frame_saved_regs_id_unwind (struct frame_info *next_frame, - struct frame_unwind_cache **cache, - struct frame_id *id) -{ - int fromleaf; - - if (next_frame->next == NULL) - /* 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. */ - id->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. */ - id->base = FRAME_CHAIN (next_frame); - - if (!frame_chain_valid (id->base, next_frame)) - { - *id = null_frame_id; - return; - } - } - if (id->base == 0) - { - *id = null_frame_id; - return; - } - - /* FIXME: cagney/2002-06-08: This should probably return the frame's - function and not the PC (a.k.a. resume address). */ - id->pc = frame_pc_unwind (next_frame); - return; -} - -/* Function: get_saved_register - Find register number REGNUM relative to FRAME and put its (raw, - target format) contents in *RAW_BUFFER. - - Set *OPTIMIZED if the variable was optimized out (and thus can't be - fetched). Note that this is never set to anything other than zero - in this implementation. - - Set *LVAL to lval_memory, lval_register, or not_lval, depending on - whether the value was fetched from memory, from a register, or in a - strange and non-modifiable way (e.g. a frame pointer which was - calculated rather than fetched). We will use not_lval for values - fetched from generic dummy frames. - - Set *ADDRP to the address, either in memory or as a REGISTER_BYTE - offset into the registers array. If the value is stored in a dummy - frame, set *ADDRP to zero. - - To use this implementation, define a function called - "get_saved_register" in your target code, which simply passes all - of its arguments to this function. - - The argument RAW_BUFFER must point to aligned memory. */ - -void -deprecated_generic_get_saved_register (char *raw_buffer, int *optimized, - CORE_ADDR *addrp, - struct frame_info *frame, int regnum, - enum lval_type *lval) -{ - if (!target_has_registers) - error ("No registers."); - - /* Normal systems don't optimize out things with register numbers. */ - if (optimized != NULL) - *optimized = 0; - - if (addrp) /* default assumption: not found in memory */ - *addrp = 0; - - /* Note: since the current frame's registers could only have been - saved by frames INTERIOR TO the current frame, we skip examining - the current frame itself: otherwise, we would be getting the - previous frame's registers which were saved by the current frame. */ - - while (frame && ((frame = frame->next) != NULL)) - { - if (get_frame_type (frame) == DUMMY_FRAME) - { - if (lval) /* found it in a CALL_DUMMY frame */ - *lval = not_lval; - if (raw_buffer) - /* FIXME: cagney/2002-06-26: This should be via the - gdbarch_register_read() method so that it, on the fly, - constructs either a raw or pseudo register from the raw - register cache. */ - regcache_raw_read (generic_find_dummy_frame (frame->pc, - frame->frame), - regnum, raw_buffer); - return; - } - - FRAME_INIT_SAVED_REGS (frame); - if (frame->saved_regs != NULL - && frame->saved_regs[regnum] != 0) - { - if (lval) /* found it saved on the stack */ - *lval = lval_memory; - if (regnum == SP_REGNUM) - { - if (raw_buffer) /* SP register treated specially */ - store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), - frame->saved_regs[regnum]); - } - else - { - if (addrp) /* any other register */ - *addrp = frame->saved_regs[regnum]; - if (raw_buffer) - read_memory (frame->saved_regs[regnum], raw_buffer, - REGISTER_RAW_SIZE (regnum)); - } - return; - } - } - - /* If we get thru the loop to this point, it means the register was - not saved in any frame. Return the actual live-register value. */ - - if (lval) /* found it in a live register */ - *lval = lval_register; - if (addrp) - *addrp = REGISTER_BYTE (regnum); - if (raw_buffer) - deprecated_read_register_gen (regnum, raw_buffer); -} - /* Using the PC, select a mechanism for unwinding a frame returning the previous frame. The register unwind function should, on demand, initialize the ->context object. */ @@ -818,9 +565,9 @@ set_unwind_by_pc (CORE_ADDR pc, calls this function to find out where the saved registers are. Hopefully this is robust enough to stop any core dumps and return vaguely correct values.. */ - *unwind_register = frame_saved_regs_register_unwind; - *unwind_pc = frame_saved_regs_pc_unwind; - *unwind_id = frame_saved_regs_id_unwind; + *unwind_register = legacy_frame_register_unwind; + *unwind_pc = legacy_frame_pc_unwind; + *unwind_id = legacy_frame_id_unwind; } else if (DEPRECATED_PC_IN_CALL_DUMMY_P () ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0) @@ -832,9 +579,9 @@ set_unwind_by_pc (CORE_ADDR pc, } else { - *unwind_register = frame_saved_regs_register_unwind; - *unwind_pc = frame_saved_regs_pc_unwind; - *unwind_id = frame_saved_regs_id_unwind; + *unwind_register = legacy_frame_register_unwind; + *unwind_pc = legacy_frame_pc_unwind; + *unwind_id = legacy_frame_id_unwind; } } @@ -933,17 +680,12 @@ reinit_frame_cache (void) method. */ static struct frame_info * -deprecated_get_prev_frame (struct frame_info *next_frame) +legacy_get_prev_frame (struct frame_info *next_frame) { CORE_ADDR address = 0; struct frame_info *prev; int fromleaf; - /* Only try to do the unwind once. */ - if (next_frame->prev_p) - return next_frame->prev; - next_frame->prev_p = 1; - /* On some machines it is possible to call a function without setting up a stack frame for it. On these machines, we define this macro to take two args; a frameinfo pointer @@ -1080,7 +822,7 @@ deprecated_get_prev_frame (struct frame_info *next_frame) 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 (INIT_EXTRA_FRAME_INFO_P ()) INIT_EXTRA_FRAME_INFO (fromleaf, prev); @@ -1089,14 +831,14 @@ deprecated_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) + if (get_frame_base (prev) == get_frame_base (next_frame) + && get_frame_pc (prev) == get_frame_pc (next_frame)) { next_frame->prev = NULL; obstack_free (&frame_cache_obstack, prev); @@ -1107,8 +849,8 @@ deprecated_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. */ - set_unwind_by_pc (prev->pc, &prev->register_unwind, &prev->pc_unwind, - &prev->id_unwind); + set_unwind_by_pc (get_frame_pc (prev), &prev->register_unwind, + &prev->pc_unwind, &prev->id_unwind); /* NOTE: cagney/2002-11-18: The code segments, found in create_new_frame and get_prev_frame(), that initializes the @@ -1120,8 +862,8 @@ deprecated_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 { @@ -1132,8 +874,8 @@ deprecated_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 @@ -1182,27 +924,41 @@ get_prev_frame (struct frame_info *next_frame) return current_frame; } - if ((DEPRECATED_INIT_FRAME_PC_P () - || DEPRECATED_INIT_FRAME_PC_FIRST_P ()) - && next_frame->level >= 0) - /* Don't try to unwind the sentinal frame using the old code. */ - return deprecated_get_prev_frame (next_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); + if (next_frame->level >= 0 + /* && !backtrace_below_main */ + && inside_main_func (get_frame_pc (next_frame))) + /* Don't unwind past main(), 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(), they can just happen. */ + return 0; + /* Only try to do the unwind once. */ if (next_frame->prev_p) return next_frame->prev; next_frame->prev_p = 1; - if (next_frame->level >= 0 - /* && !backtrace_below_main */ - && inside_main_func (next_frame->pc)) - /* Don't unwind past main(), always unwind the sentinel frame. */ - return 0; + /* If we're inside the entry file, it isn't valid. */ + /* NOTE: drow/2002-12-25: should there be a way to disable this + check? It assumes a single small entry file, and the way some + debug readers (e.g. dbxread) figure out which object is the + entry file is somewhat hokey. */ + /* NOTE: cagney/2003-01-10: If there is a way of disabling this test + then it should probably be moved to before the ->prev_p test, + above. */ + if (inside_entry_file (get_frame_pc (next_frame))) + return NULL; + + if ((DEPRECATED_INIT_FRAME_PC_P () + || DEPRECATED_INIT_FRAME_PC_FIRST_P ()) + && next_frame->level >= 0) + /* Don't try to unwind the sentinal frame using the old code. */ + return legacy_get_prev_frame (next_frame); /* Allocate the new frame but do not wire it in. Some (bad) code in INIT_EXTRA_FRAME_INFO tries to look along frame->next to pull |