diff options
author | Andrew Cagney <cagney@redhat.com> | 2003-01-10 21:56:44 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2003-01-10 21:56:44 +0000 |
commit | 46c2fdb8b75e20f54bfe86eeecd57bd4ebdbad24 (patch) | |
tree | 5888b58afa7f8a1c8ab81b9a5bc5072865b68b2e | |
parent | a62552ff4c38daf8ed32707b05b834972adfc6f2 (diff) | |
download | gdb-46c2fdb8b75e20f54bfe86eeecd57bd4ebdbad24.tar.gz |
Move legacy frame code to legacy-frame.[hc].
-rw-r--r-- | gdb/ChangeLog | 36 | ||||
-rw-r--r-- | gdb/Makefile.in | 12 | ||||
-rw-r--r-- | gdb/frame.c | 356 | ||||
-rw-r--r-- | gdb/legacy-frame.c | 301 | ||||
-rw-r--r-- | gdb/legacy-frame.h | 61 |
5 files changed, 459 insertions, 307 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ec827624f82..7f562ccd1ed 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,9 +1,35 @@ 2003-01-10 Andrew Cagney <ac131313@redhat.com> - * sentinel-frame.c (sentinel_frame_register_unwind): Correctly set - LVALP and ADDRP. + * frame.c (create_sentinel_frame): Initialize sentinel frame's PC. - * frame.c: Include "ui-out.h". + * sentinel-frame.c (struct frame_unwind_cache): Add pc field. + + * sentinel-frame.h (sentinel_frame_cache): Add a pc parameter. + + * frame.c (deprecated_generic_get_saved_register): Move from here. + * legacy-frame.c (deprecated_generic_get_saved_register): to here. + + * legacy-frame.c: Include "regcache.h", "dummy-frame.h", and + "target.h". + + * frame.c (set_unwind_by_pc): Update. + (frame_saved_regs_id_unwind): Delete function. + (frame_saved_regs_register_unwind): Delete function. + (frame_saved_regs_pc_unwind): Delete function. + (legacy_get_prev_frame): Rename deprecated_get_prev_frame. + (get_prev_frame): Update call. + (get_prev_frame): Move check for inside_main_func to before + setting of prev_p. Add check for inside_entry_file, but after + prev_p. + + * Makefile.in (frame.o): Update dependencies. + + * frame.c: Include "legacy-frame.h". + + * Makefile.in (SFILES): Add legacy-frame.c. + (legacy_frame_h): Define. + (COMMON_OBS): Add legacy-frame.o. + (legacy-frame.o): Specify dependencies. 2003-01-09 Andrew Cagney <ac131313@redhat.com> @@ -14,6 +40,10 @@ (get_prev_frame): Rewrite. Unwind the PC first. Use frame_id_unwind. + * sentinel-frame.c (sentinel_frame_register_unwind): Correctly set + LVALP and ADDRP. + * frame.c: Include "ui-out.h". + 2003-01-09 Andrew Cagney <ac131313@redhat.com> * dummy-frame.h (dummy_frame_id_unwind): Update. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 84f1d74eab0..7fb480f8ed6 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -512,7 +512,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ inf-loop.c infcmd.c inflow.c infrun.c \ jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \ kod.c kod-cisco.c \ - language.c linespec.c \ + language.c legacy-frame.c linespec.c \ m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \ macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c \ @@ -649,6 +649,7 @@ inferior_h = inferior.h $(breakpoint_h) $(target_h) $(frame_h) jv_lang_h = jv-lang.h kod_h = kod.h language_h = language.h +legacy_frame_h = legacy-frame.h linespec_h = linespec.h m2_lang_h = m2-lang.h m68k_tdep_h = m68k-tdep.h @@ -834,7 +835,7 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \ frame.o doublest.o \ gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o \ sentinel-frame.o \ - reggroups.o + reggroups.o legacy-frame.o OBS = $(COMMON_OBS) $(ANNOTATE_OBS) @@ -1681,8 +1682,9 @@ fork-child.o: fork-child.c $(defs_h) $(gdb_string_h) $(frame_h) \ $(terminal_h) $(gdbthread_h) $(command_h) frame.o: frame.c $(defs_h) $(frame_h) $(target_h) $(value_h) $(inferior_h) \ $(regcache_h) $(gdb_assert_h) $(gdb_string_h) $(builtin_regs_h) \ - $(gdb_obstack_h) $(dummy_frame_h) $(gdbcore_h) $(annotate_h) \ - $(language_h) $(sentinel_frame_h) $(ui_out_h) + $(gdb_obstack_h) $(dummy_frame_h) $(sentinel_frame_h) \ + $(legacy_frame_h) $(gdbcore_h) $(annotate_h) $(language_h) \ + $(ui_out_h) frv-tdep.o: frv-tdep.c $(defs_h) $(inferior_h) $(symfile_h) $(gdbcore_h) \ $(arch_utils_h) $(regcache_h) gcore.o: gcore.c $(defs_h) $(cli_decode_h) $(inferior_h) $(gdbcore_h) \ @@ -1832,6 +1834,8 @@ language.o: language.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(parser_defs_h) $(jv_lang_h) lin-lwp.o: lin-lwp.c $(defs_h) $(gdb_assert_h) $(gdb_string_h) $(gdb_wait_h) \ $(gdbthread_h) $(inferior_h) $(target_h) $(regcache_h) $(gdbcmd_h) +legacy-frame.o: legacy-frame.c $(defs_h) $(legacy_frame_h) $(gdb_assert_h) \ + $(frame_h) $(gdbcore_h) $(regcache_h) $(target_h) $(dummy_frame_h) linespec.o: linespec.c $(defs_h) $(symtab_h) $(frame_h) $(command_h) \ $(symfile_h) $(objfiles_h) $(demangle_h) $(value_h) $(completer_h) \ $(cp_abi_h) $(source_h) $(parser_defs_h) 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 diff --git a/gdb/legacy-frame.c b/gdb/legacy-frame.c new file mode 100644 index 00000000000..99227806961 --- /dev/null +++ b/gdb/legacy-frame.c @@ -0,0 +1,301 @@ +/* Code dealing with legacy frames, for GDB, the GNU debugger. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + +#include "defs.h" +#include "legacy-frame.h" +#include "gdb_assert.h" +#include "frame.h" +#include "gdbcore.h" +#include "regcache.h" +#include "target.h" +#include "dummy-frame.h" /* For generic_find_dummy_frame. */ + +/* Legacy frame. This saves the processor state just prior to setting + up the inferior function call. Older targets save the registers + on the target stack (but that really slows down function calls). */ + +struct frame_unwind_cache +{ + void *regs[1]; +}; + +/* Given a legacy-frame, return the register 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. */ + +void +legacy_frame_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 (get_frame_saved_regs (frame) == NULL) + FRAME_INIT_SAVED_REGS (frame); + + if (get_frame_saved_regs (frame) != NULL + && get_frame_saved_regs (frame)[regnum] != 0) + { + if (regnum == SP_REGNUM) + { + /* SP register treated specially. */ + *optimizedp = 0; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + if (bufferp != NULL) + store_address (bufferp, REGISTER_RAW_SIZE (regnum), + get_frame_saved_regs (frame)[regnum]); + } + else + { + /* Any other register is saved in memory, fetch it but cache + a local copy of its value. */ + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = get_frame_saved_regs (frame)[regnum]; + *realnump = -1; + if (bufferp != NULL) + { +#if 1 + /* Save each register value, as it is read in, in a + frame based cache. */ + 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 (get_frame_saved_regs (frame)[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 (get_frame_saved_regs (frame)[regnum], bufferp, + REGISTER_RAW_SIZE (regnum)); +#endif + } + } + return; + } + + /* No luck, assume this and the next frame have the same register + value. 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 = REGISTER_BYTE (regnum); + *realnump = regnum; + } + else + { + frame_register (frame, regnum, optimizedp, lvalp, addrp, + realnump, bufferp); + } +} + +CORE_ADDR +legacy_frame_pc_unwind (struct frame_info *frame, + struct frame_unwind_cache **cache) +{ + return FRAME_SAVED_PC (frame); +} + +void +legacy_frame_id_unwind (struct frame_info *frame, + struct frame_unwind_cache **cache, + struct frame_id *id) +{ + int fromleaf; + + if (get_next_frame (frame) == 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 (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 (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 (frame); + + if (!frame_chain_valid (id->base, 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 (frame); + return; +} + +/* Function: deprecated_generic_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 = get_next_frame (frame)) != 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 (get_frame_pc (frame), + get_frame_base (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); +} diff --git a/gdb/legacy-frame.h b/gdb/legacy-frame.h new file mode 100644 index 00000000000..999e76afdc3 --- /dev/null +++ b/gdb/legacy-frame.h @@ -0,0 +1,61 @@ +/* Code dealing with legacy frames, for GDB, the GNU debugger. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#if !defined (LEGACY_FRAME_H) +#define LEGACY_FRAME_H 1 + +struct frame_info; +struct regcache; +struct frame_id; +struct frame_unwind_cache; + +/* LEGACY FRAMES + + The original extra frame info implementation of the`struct + frame_info' object. These frames always initialize the entire + frame object using extra frame info. */ + +/* Assuming that FRAME is a legacy, return a register value for the + previous frame. */ + +extern void legacy_frame_register_unwind (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache, + int regnum, + int *optimized, + enum lval_type *lvalp, + CORE_ADDR *addrp, + int *realnump, + void *valuep); + +/* Assuming that FRAME is a legacy, return the resume address for the + previous frame. */ + +extern CORE_ADDR legacy_frame_pc_unwind (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache); + +/* Assuming that FRAME is a legacy, return the ID of the calling frame + (the frame that the legacy has the saved state of). */ + +extern void legacy_frame_id_unwind (struct frame_info *frame, + struct frame_unwind_cache **unwind_cache, + struct frame_id *id); + +#endif |