diff options
Diffstat (limited to 'gdb/frame.c')
-rw-r--r-- | gdb/frame.c | 210 |
1 files changed, 142 insertions, 68 deletions
diff --git a/gdb/frame.c b/gdb/frame.c index 24cd9071437..3b17bf5abf0 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1,4 +1,4 @@ -/* Cache and manage the values of registers for GDB, the GNU debugger. +/* Cache and manage frames for GDB, the GNU debugger. Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001, 2002 Free Software Foundation, Inc. @@ -26,6 +26,57 @@ #include "value.h" #include "inferior.h" /* for inferior_ptid */ #include "regcache.h" +#include "gdb_assert.h" + +/* Return a frame uniq ID that can be used to, later re-find the + frame. */ + +void +get_frame_id (struct frame_info *fi, struct frame_id *id) +{ + if (fi == NULL) + { + id->base = 0; + id->pc = 0; + } + else + { + id->base = FRAME_FP (fi); + id->pc = fi->pc; + } +} + +struct frame_info * +frame_find_by_id (struct frame_id id) +{ + struct frame_info *frame; + + /* ZERO denotes the null frame, let the caller decide what to do + about it. Should it instead return get_current_frame()? */ + if (id.base == 0 && id.pc == 0) + return NULL; + + for (frame = get_current_frame (); + frame != NULL; + frame = get_prev_frame (frame)) + { + if (INNER_THAN (FRAME_FP (frame), id.base)) + /* ``inner/current < frame < id.base''. Keep looking along + the frame chain. */ + continue; + if (INNER_THAN (id.base, FRAME_FP (frame))) + /* ``inner/current < id.base < frame''. Oops, gone past it. + Just give up. */ + return NULL; + /* FIXME: cagney/2002-04-21: This isn't sufficient. It should + use id.pc to check that the two frames belong to the same + function. Otherwise we'll do things like match dummy frames + or mis-match frameless functions. However, until someone + notices, stick with the existing behavour. */ + return frame; + } + return NULL; +} /* FIND_SAVED_REGISTER () @@ -43,10 +94,9 @@ find_saved_register (struct frame_info *frame, int regnum) if (frame == NULL) /* No regs saved if want current frame */ return 0; - /* Note that this next routine assumes that registers used in - frame x will be saved only in the frame that x calls and - frames interior to it. This is not true on the sparc, but the - above macro takes care of it, so we should be all right. */ + /* Note that the following loop assumes that registers used in + frame x will be saved only in the frame that x calls and frames + interior to it. */ while (1) { QUIT; @@ -56,82 +106,106 @@ find_saved_register (struct frame_info *frame, int regnum) frame = frame1; FRAME_INIT_SAVED_REGS (frame1); if (frame1->saved_regs[regnum]) - addr = frame1->saved_regs[regnum]; + { + addr = frame1->saved_regs[regnum]; + break; + } } return addr; } -/* DEFAULT_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). 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). Set *ADDRP to the address, either in memory - on as a REGISTER_BYTE offset into the registers array. - - Note that this implementation never sets *LVAL to not_lval. But - it can be replaced by defining GET_SAVED_REGISTER and supplying - your own. - - The argument RAW_BUFFER must point to aligned memory. */ - -static void -default_get_saved_register (char *raw_buffer, - int *optimized, - CORE_ADDR *addrp, - struct frame_info *frame, - int regnum, - enum lval_type *lval) +void +frame_register_unwind (struct frame_info *frame, int regnum, + int *optimizedp, enum lval_type *lvalp, + CORE_ADDR *addrp, int *realnump, void *bufferp) { - CORE_ADDR addr; + struct frame_unwind_cache *cache; + + /* 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); + gdb_assert (lvalp != NULL); + gdb_assert (addrp != NULL); + gdb_assert (realnump != NULL); + /* gdb_assert (bufferp != NULL); */ + + /* NOTE: cagney/2002-04-14: It would be nice if, instead of a + special case, there was always an inner frame dedicated to the + hardware registers. Unfortunatly, there is too much unwind code + around that looks up/down the frame chain while making the + assumption that each frame level is using the same unwind code. */ + + if (frame == NULL) + { + /* We're in the inner-most frame, get the value direct from the + register cache. */ + *optimizedp = 0; + *lvalp = lval_register; + /* ULGH! Code uses the offset into the raw register byte array + as a way of identifying a register. */ + *addrp = REGISTER_BYTE (regnum); + /* Should this code test ``register_cached (regnum) < 0'' and do + something like set realnum to -1 when the register isn't + available? */ + *realnump = regnum; + if (bufferp) + read_register_gen (regnum, bufferp); + return; + } + + /* Ask this frame to unwind its register. */ + frame->register_unwind (frame, &frame->register_unwind_cache, regnum, + optimizedp, lvalp, addrp, realnump, bufferp); +} + + +void +generic_unwind_get_saved_register (char *raw_buffer, + int *optimizedp, + CORE_ADDR *addrp, + struct frame_info *frame, + int regnum, + enum lval_type *lvalp) +{ + int optimizedx; + CORE_ADDR addrx; + int realnumx; + enum lval_type lvalx; if (!target_has_registers) error ("No registers."); - /* Normal systems don't optimize out things with register numbers. */ - if (optimized != NULL) - *optimized = 0; - addr = find_saved_register (frame, regnum); - if (addr != 0) - { - if (lval != NULL) - *lval = lval_memory; - if (regnum == SP_REGNUM) - { - if (raw_buffer != NULL) - { - /* Put it back in target format. */ - store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), - (LONGEST) addr); - } - if (addrp != NULL) - *addrp = 0; - return; - } - if (raw_buffer != NULL) - target_read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum)); - } + /* Keep things simple, ensure that all the pointers (except valuep) + are non NULL. */ + if (optimizedp == NULL) + optimizedp = &optimizedx; + if (lvalp == NULL) + lvalp = &lvalx; + if (addrp == NULL) + addrp = &addrx; + + /* Reached the the bottom (youngest, inner most) of the frame chain + (youngest, inner most) frame, go direct to the hardware register + cache (do not pass go, do not try to cache the value, ...). The + unwound value would have been cached in frame->next but that + doesn't exist. This doesn't matter as the hardware register + cache is stopping any unnecessary accesses to the target. */ + + /* NOTE: cagney/2002-04-14: It would be nice if, instead of a + special case, there was always an inner frame dedicated to the + hardware registers. Unfortunatly, there is too much unwind code + around that looks up/down the frame chain while making the + assumption that each frame level is using the same unwind code. */ + + if (frame == NULL) + frame_register_unwind (NULL, regnum, optimizedp, lvalp, addrp, &realnumx, + raw_buffer); else - { - if (lval != NULL) - *lval = lval_register; - addr = REGISTER_BYTE (regnum); - if (raw_buffer != NULL) - read_register_gen (regnum, raw_buffer); - } - if (addrp != NULL) - *addrp = addr; + frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp, + &realnumx, raw_buffer); } -#if !defined (GET_SAVED_REGISTER) -#define GET_SAVED_REGISTER(raw_buffer, optimized, addrp, frame, regnum, lval) \ - default_get_saved_register(raw_buffer, optimized, addrp, frame, regnum, lval) -#endif - void get_saved_register (char *raw_buffer, int *optimized, |