diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 166ac5b9f02..7985ef7e009 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,24 @@ +2002-11-08 Andrew Cagney + + * blockframe.c: Include "dummy-frame.h". + (struct dummy_frame, dummy_frame_stack) + (generic_find_dummy_frame, deprecated_generic_find_dummy_frame) + (generic_pc_in_call_dummy, deprecated_read_register_dummy) + (generic_push_dummy_frame, generic_save_dummy_frame_tos) + (generic_save_call_dummy_addr, generic_pop_current_frame) + (generic_pop_dummy_frame, generic_fix_call_dummy) + (generic_fix_call_dummy, generic_call_dummy_register_unwind): Move + dummy frame code from here... + * dummy-frame.c: ...to here. New file. + * dummy-frame.h: New file. + (generic_call_dummy_register_unwind): Declare. + (generic_find_dummy_frame): Declare. + * Makefile.in (SFILES): Add dummy-frame.c. + (dummy-frame.o): Specify dependencies. + (dummy_frame_h): Define. + (COMMON_OBS): Add dummy-frame.o. + (blockframe.o): Update dependencies. + 2002-11-08 Jim Blandy * dwarf2read.c (read_func_scope): Restore local_symbols and diff --git a/gdb/Makefile.in b/gdb/Makefile.in index afcca561f21..696bfefcc24 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -535,7 +535,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ c-exp.y c-lang.c c-typeprint.c c-valprint.c \ charset.c cli-out.c coffread.c complaints.c completer.c corefile.c \ cp-abi.c cp-support.c cp-valprint.c \ - dbxread.c demangle.c disasm.c doublest.c dwarfread.c dwarf2read.c \ + dbxread.c demangle.c disasm.c doublest.c \ + dummy-frame.c dwarfread.c dwarf2read.c \ elfread.c environ.c eval.c event-loop.c event-top.c expprint.c \ f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c frame.c \ gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \ @@ -640,6 +641,7 @@ defs_h = defs.h $(config_h) $(gdb_locale_h) $(gdb_signals_h) $(ansidecl_h) \ disasm_h = disasm.h doublest_h = doublest.h $(floatformat_h) dst_h = dst.h +dummy_frame_h = dummy-frame.h dwarf2cfi_h = dwarf2cfi.h environ_h = environ.h event_loop_h = event-loop.h @@ -829,7 +831,7 @@ TAGFILES_NO_SRCDIR = $(SFILES) $(HFILES_NO_SRCDIR) $(ALLDEPFILES) \ TAGFILES_WITH_SRCDIR = $(HFILES_WITH_SRCDIR) COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \ - charset.o disasm.o \ + charset.o disasm.o dummy-frame.o \ source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o \ symtab.o symfile.o symmisc.o linespec.o infcmd.o infrun.o \ expprint.o environ.o stack.o thread.o \ @@ -1532,7 +1534,8 @@ ax-general.o: ax-general.c $(defs_h) $(ax_h) $(value_h) $(gdb_string_h) bcache.o: bcache.c $(defs_h) $(gdb_obstack_h) $(bcache_h) $(gdb_string_h) blockframe.o: blockframe.c $(defs_h) $(symtab_h) $(bfd_h) $(symfile_h) \ $(objfiles_h) $(frame_h) $(gdbcore_h) $(value_h) $(target_h) \ - $(inferior_h) $(annotate_h) $(regcache_h) $(gdb_assert_h) + $(inferior_h) $(annotate_h) $(regcache_h) $(gdb_assert_h) \ + $(dummy_frame_h) breakpoint.o: breakpoint.c $(defs_h) $(symtab_h) $(frame_h) $(breakpoint_h) \ $(gdbtypes_h) $(expression_h) $(gdbcore_h) $(gdbcmd_h) $(value_h) \ $(command_h) $(inferior_h) $(gdbthread_h) $(target_h) $(language_h) \ @@ -1627,6 +1630,8 @@ doublest.o: doublest.c $(defs_h) $(doublest_h) $(floatformat_h) \ dpx2-nat.o: dpx2-nat.c $(defs_h) $(gdbcore_h) $(gdb_string_h) dsrec.o: dsrec.c $(defs_h) $(serial_h) $(srec_h) # OBSOLETE dstread.o: dstread.c +dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \ + $(frame_h) $(inferior_h) $(gdb_assert_h) dve3900-rom.o: dve3900-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \ $(serial_h) $(inferior_h) $(command_h) $(gdb_string_h) $(regcache_h) dwarf2cfi.o: dwarf2cfi.c $(defs_h) $(gdbcore_h) $(symtab_h) $(symfile_h) \ diff --git a/gdb/blockframe.c b/gdb/blockframe.c index 2b789e6dbb1..c34d3e06a0e 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -35,17 +35,10 @@ #include "annotate.h" #include "regcache.h" #include "gdb_assert.h" +#include "dummy-frame.h" /* Prototypes for exported functions. */ -static void generic_call_dummy_register_unwind (struct frame_info *frame, - void **cache, - int regnum, - int *optimized, - enum lval_type *lval, - CORE_ADDR *addrp, - int *realnum, - void *raw_buffer); static void frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, int regnum, @@ -1107,244 +1100,6 @@ pc_in_call_dummy_at_entry_point (CORE_ADDR pc, CORE_ADDR sp, } -/* - * GENERIC DUMMY FRAMES - * - * The following code serves to maintain the dummy stack frames for - * inferior function calls (ie. when gdb calls into the inferior via - * call_function_by_hand). This code saves the machine state before - * the call in host memory, so we must maintain an independent stack - * and keep it consistant etc. I am attempting to make this code - * generic enough to be used by many targets. - * - * The cheapest and most generic way to do CALL_DUMMY on a new target - * is probably to define CALL_DUMMY to be empty, CALL_DUMMY_LENGTH to - * zero, and CALL_DUMMY_LOCATION to AT_ENTRY. Then you must remember - * to define PUSH_RETURN_ADDRESS, because no call instruction will be - * being executed by the target. Also FRAME_CHAIN_VALID as - * generic_{file,func}_frame_chain_valid and FIX_CALL_DUMMY as - * generic_fix_call_dummy. */ - -/* Dummy 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 dummy_frame -{ - struct dummy_frame *next; - - CORE_ADDR pc; - CORE_ADDR fp; - CORE_ADDR sp; - CORE_ADDR top; - struct regcache *regcache; - - /* Address range of the call dummy code. Look for PC in the range - [LO..HI) (after allowing for DECR_PC_AFTER_BREAK). */ - CORE_ADDR call_lo; - CORE_ADDR call_hi; -}; - -static struct dummy_frame *dummy_frame_stack = NULL; - -/* Function: find_dummy_frame(pc, fp, sp) - - Search the stack of dummy frames for one matching the given PC and - FP/SP. Unlike PC_IN_CALL_DUMMY, this function doesn't need to - adjust for DECR_PC_AFTER_BREAK. This is because it is only legal - to call this function after the PC has been adjusted. */ - -static struct regcache * -generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp) -{ - struct dummy_frame *dummyframe; - - for (dummyframe = dummy_frame_stack; dummyframe != NULL; - dummyframe = dummyframe->next) - { - /* Does the PC fall within the dummy frame's breakpoint - instruction. If not, discard this one. */ - if (!(pc >= dummyframe->call_lo && pc < dummyframe->call_hi)) - continue; - /* Does the FP match? */ - if (dummyframe->top != 0) - { - /* If the target architecture explicitly saved the - top-of-stack before the inferior function call, assume - that that same architecture will always pass in an FP - (frame base) value that eactly matches that saved TOS. - Don't check the saved SP and SP as they can lead to false - hits. */ - if (fp != dummyframe->top) - continue; - } - else - { - /* An older target that hasn't explicitly or implicitly - saved the dummy frame's top-of-stack. Try matching the - FP against the saved SP and FP. NOTE: If you're trying - to fix a problem with GDB not correctly finding a dummy - frame, check the comments that go with FRAME_ALIGN() and - SAVE_DUMMY_FRAME_TOS(). */ - if (fp != dummyframe->fp && fp != dummyframe->sp) - continue; - } - /* The FP matches this dummy frame. */ - return dummyframe->regcache; - } - - return 0; -} - -char * -deprecated_generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp) -{ - struct regcache *regcache = generic_find_dummy_frame (pc, fp); - if (regcache == NULL) - return NULL; - return deprecated_grub_regcache_for_registers (regcache); -} - -/* Function: pc_in_call_dummy (pc, sp, fp) - - Return true if the PC falls in a dummy frame created by gdb for an - inferior call. The code below which allows DECR_PC_AFTER_BREAK is - for infrun.c, which may give the function a PC without that - subtracted out. */ - -int -generic_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR fp) -{ - struct dummy_frame *dummyframe; - for (dummyframe = dummy_frame_stack; - dummyframe != NULL; - dummyframe = dummyframe->next) - { - if ((pc >= dummyframe->call_lo) - && (pc < dummyframe->call_hi + DECR_PC_AFTER_BREAK)) - return 1; - } - return 0; -} - -/* Function: read_register_dummy - Find a saved register from before GDB calls a function in the inferior */ - -CORE_ADDR -deprecated_read_register_dummy (CORE_ADDR pc, CORE_ADDR fp, int regno) -{ - struct regcache *dummy_regs = generic_find_dummy_frame (pc, fp); - - if (dummy_regs) - { - /* NOTE: cagney/2002-08-12: Replaced a call to - regcache_raw_read_as_address() with a call to - regcache_cooked_read_unsigned(). The old, ...as_address - function was eventually calling extract_unsigned_integer (via - extract_address) to unpack the registers value. The below is - doing an unsigned extract so that it is functionally - equivalent. The read needs to be cooked as, otherwise, it - will never correctly return the value of a register in the - [NUM_REGS .. NUM_REGS+NUM_PSEUDO_REGS) range. */ - ULONGEST val; - regcache_cooked_read_unsigned (dummy_regs, regno, &val); - return val; - } - else - return 0; -} - -/* Save all the registers on the dummy frame stack. Most ports save the - registers on the target stack. This results in lots of unnecessary memory - references, which are slow when debugging via a serial line. Instead, we - save all the registers internally, and never write them to the stack. The - registers get restored when the called function returns to the entry point, - where a breakpoint is laying in wait. */ - -void -generic_push_dummy_frame (void) -{ - struct dummy_frame *dummy_frame; - CORE_ADDR fp = (get_current_frame ())->frame; - - /* check to see if there are stale dummy frames, - perhaps left over from when a longjump took us out of a - function that was called by the debugger */ - - dummy_frame = dummy_frame_stack; - while (dummy_frame) - if (INNER_THAN (dummy_frame->fp, fp)) /* stale -- destroy! */ - { - dummy_frame_stack = dummy_frame->next; - regcache_xfree (dummy_frame->regcache); - xfree (dummy_frame); - dummy_frame = dummy_frame_stack; - } - else - dummy_frame = dummy_frame->next; - - dummy_frame = xmalloc (sizeof (struct dummy_frame)); - dummy_frame->regcache = regcache_xmalloc (current_gdbarch); - - dummy_frame->pc = read_pc (); - dummy_frame->sp = read_sp (); - dummy_frame->top = 0; - dummy_frame->fp = fp; - regcache_cpy (dummy_frame->regcache, current_regcache); - dummy_frame->next = dummy_frame_stack; - dummy_frame_stack = dummy_frame; -} - -void -generic_save_dummy_frame_tos (CORE_ADDR sp) -{ - dummy_frame_stack->top = sp; -} - -/* Record the upper/lower bounds on the address of the call dummy. */ - -void -generic_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi) -{ - dummy_frame_stack->call_lo = lo; - dummy_frame_stack->call_hi = hi; -} - -/* Restore the machine state from either the saved dummy stack or a - real stack frame. */ - -void -generic_pop_current_frame (void (*popper) (struct frame_info * frame)) -{ - struct frame_info *frame = get_current_frame (); - - if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) - generic_pop_dummy_frame (); - else - (*popper) (frame); -} - -/* Function: pop_dummy_frame - Restore the machine state from a saved dummy stack frame. */ - -void -generic_pop_dummy_frame (void) -{ - struct dummy_frame *dummy_frame = dummy_frame_stack; - - /* FIXME: what if the first frame isn't the right one, eg.. - because one call-by-hand function has done a longjmp into another one? */ - - if (!dummy_frame) - error ("Can't pop dummy frame!"); - dummy_frame_stack = dummy_frame->next; - regcache_cpy (current_regcache, dummy_frame->regcache); - flush_cached_frames (); - - regcache_xfree (dummy_frame->regcache); - xfree (dummy_frame); -} - /* Function: frame_chain_valid Returns true for a user frame or a call_function_by_hand dummy frame, and false for the CRT0 start-up frame. Purpose is to terminate backtrace */ @@ -1373,63 +1128,6 @@ generic_func_frame_chain_valid (CORE_ADDR fp, struct frame_info *fi) && !inside_entry_func ((fi)->pc)); } -/* Function: fix_call_dummy - Stub function. Generic dummy frames typically do not need to fix - the frame being created */ - -void -generic_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, - struct value **args, struct type *type, int gcc_p) -{ - return; -} - -/* Given a call-dummy dummy-frame, return the registers. Here the - register value is taken from the local copy of the register buffer. */ - -static void -generic_call_dummy_register_unwind (struct frame_info *frame, void **cache, - int regnum, int *optimized, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnum, void *bufferp) -{ - gdb_assert (frame != NULL); - gdb_assert (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)); - - /* Describe the register's location. Generic dummy frames always - have the register value in an ``expression''. */ - *optimized = 0; - *lvalp = not_lval; - *addrp = 0; - *realnum = -1; - - /* If needed, find and return the value of the register. */ - if (bufferp != NULL) - { - struct regcache *registers; -#if 1 - /* Get the address of the register buffer that contains all the - saved registers for this dummy frame. Cache that address. */ - registers = (*cache); - if (registers == NULL) - { - registers = generic_find_dummy_frame (frame->pc, frame->frame); - (*cache) = registers; - } -#else - /* Get the address of the register buffer that contains the - saved registers and then extract the value from that. */ - registers = generic_find_dummy_frame (frame->pc, frame->frame); -#endif - gdb_assert (registers != NULL); - /* Return the actual value. */ - /* Use the regcache_cooked_read() method so that it, on the fly, - constructs either a raw or pseudo register from the raw - register cache. */ - regcache_cooked_read (registers, regnum, bufferp); - } -} - /* 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. */ diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c new file mode 100644 index 00000000000..1a2a315ea3c --- /dev/null +++ b/gdb/dummy-frame.c @@ -0,0 +1,308 @@ +/* Code dealing with dummy stack frames, for GDB, the GNU debugger. + + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 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 "dummy-frame.h" +#include "regcache.h" +#include "frame.h" +#include "inferior.h" +#include "gdb_assert.h" + +/* Dummy 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 dummy_frame +{ + struct dummy_frame *next; + + CORE_ADDR pc; + CORE_ADDR fp; + CORE_ADDR sp; + CORE_ADDR top; + struct regcache *regcache; + + /* Address range of the call dummy code. Look for PC in the range + [LO..HI) (after allowing for DECR_PC_AFTER_BREAK). */ + CORE_ADDR call_lo; + CORE_ADDR call_hi; +}; + +static struct dummy_frame *dummy_frame_stack = NULL; + +/* Function: find_dummy_frame(pc, fp, sp) + + Search the stack of dummy frames for one matching the given PC and + FP/SP. Unlike PC_IN_CALL_DUMMY, this function doesn't need to + adjust for DECR_PC_AFTER_BREAK. This is because it is only legal + to call this function after the PC has been adjusted. */ + +struct regcache * +generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp) +{ + struct dummy_frame *dummyframe; + + for (dummyframe = dummy_frame_stack; dummyframe != NULL; + dummyframe = dummyframe->next) + { + /* Does the PC fall within the dummy frame's breakpoint + instruction. If not, discard this one. */ + if (!(pc >= dummyframe->call_lo && pc < dummyframe->call_hi)) + continue; + /* Does the FP match? */ + if (dummyframe->top != 0) + { + /* If the target architecture explicitly saved the + top-of-stack before the inferior function call, assume + that that same architecture will always pass in an FP + (frame base) value that eactly matches that saved TOS. + Don't check the saved SP and SP as they can lead to false + hits. */ + if (fp != dummyframe->top) + continue; + } + else + { + /* An older target that hasn't explicitly or implicitly + saved the dummy frame's top-of-stack. Try matching the + FP against the saved SP and FP. NOTE: If you're trying + to fix a problem with GDB not correctly finding a dummy + frame, check the comments that go with FRAME_ALIGN() and + SAVE_DUMMY_FRAME_TOS(). */ + if (fp != dummyframe->fp && fp != dummyframe->sp) + continue; + } + /* The FP matches this dummy frame. */ + return dummyframe->regcache; + } + + return 0; +} + +char * +deprecated_generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp) +{ + struct regcache *regcache = generic_find_dummy_frame (pc, fp); + if (regcache == NULL) + return NULL; + return deprecated_grub_regcache_for_registers (regcache); +} + +/* Function: pc_in_call_dummy (pc, sp, fp) + + Return true if the PC falls in a dummy frame created by gdb for an + inferior call. The code below which allows DECR_PC_AFTER_BREAK is + for infrun.c, which may give the function a PC without that + subtracted out. */ + +int +generic_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR fp) +{ + struct dummy_frame *dummyframe; + for (dummyframe = dummy_frame_stack; + dummyframe != NULL; + dummyframe = dummyframe->next) + { + if ((pc >= dummyframe->call_lo) + && (pc < dummyframe->call_hi + DECR_PC_AFTER_BREAK)) + return 1; + } + return 0; +} + +/* Function: read_register_dummy + Find a saved register from before GDB calls a function in the inferior */ + +CORE_ADDR +deprecated_read_register_dummy (CORE_ADDR pc, CORE_ADDR fp, int regno) +{ + struct regcache *dummy_regs = generic_find_dummy_frame (pc, fp); + + if (dummy_regs) + { + /* NOTE: cagney/2002-08-12: Replaced a call to + regcache_raw_read_as_address() with a call to + regcache_cooked_read_unsigned(). The old, ...as_address + function was eventually calling extract_unsigned_integer (via + extract_address) to unpack the registers value. The below is + doing an unsigned extract so that it is functionally + equivalent. The read needs to be cooked as, otherwise, it + will never correctly return the value of a register in the + [NUM_REGS .. NUM_REGS+NUM_PSEUDO_REGS) range. */ + ULONGEST val; + regcache_cooked_read_unsigned (dummy_regs, regno, &val); + return val; + } + else + return 0; +} + +/* Save all the registers on the dummy frame stack. Most ports save the + registers on the target stack. This results in lots of unnecessary memory + references, which are slow when debugging via a serial line. Instead, we + save all the registers internally, and never write them to the stack. The + registers get restored when the called function returns to the entry point, + where a breakpoint is laying in wait. */ + +void +generic_push_dummy_frame (void) +{ + struct dummy_frame *dummy_frame; + CORE_ADDR fp = (get_current_frame ())->frame; + + /* check to see if there are stale dummy frames, + perhaps left over from when a longjump took us out of a + function that was called by the debugger */ + + dummy_frame = dummy_frame_stack; + while (dummy_frame) + if (INNER_THAN (dummy_frame->fp, fp)) /* stale -- destroy! */ + { + dummy_frame_stack = dummy_frame->next; + regcache_xfree (dummy_frame->regcache); + xfree (dummy_frame); + dummy_frame = dummy_frame_stack; + } + else + dummy_frame = dummy_frame->next; + + dummy_frame = xmalloc (sizeof (struct dummy_frame)); + dummy_frame->regcache = regcache_xmalloc (current_gdbarch); + + dummy_frame->pc = read_pc (); + dummy_frame->sp = read_sp (); + dummy_frame->top = 0; + dummy_frame->fp = fp; + regcache_cpy (dummy_frame->regcache, current_regcache); + dummy_frame->next = dummy_frame_stack; + dummy_frame_stack = dummy_frame; +} + +void +generic_save_dummy_frame_tos (CORE_ADDR sp) +{ + dummy_frame_stack->top = sp; +} + +/* Record the upper/lower bounds on the address of the call dummy. */ + +void +generic_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi) +{ + dummy_frame_stack->call_lo = lo; + dummy_frame_stack->call_hi = hi; +} + +/* Restore the machine state from either the saved dummy stack or a + real stack frame. */ + +void +generic_pop_current_frame (void (*popper) (struct frame_info * frame)) +{ + struct frame_info *frame = get_current_frame (); + + if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) + generic_pop_dummy_frame (); + else + (*popper) (frame); +} + +/* Function: pop_dummy_frame + Restore the machine state from a saved dummy stack frame. */ + +void +generic_pop_dummy_frame (void) +{ + struct dummy_frame *dummy_frame = dummy_frame_stack; + + /* FIXME: what if the first frame isn't the right one, eg.. + because one call-by-hand function has done a longjmp into another one? */ + + if (!dummy_frame) + error ("Can't pop dummy frame!"); + dummy_frame_stack = dummy_frame->next; + regcache_cpy (current_regcache, dummy_frame->regcache); + flush_cached_frames (); + + regcache_xfree (dummy_frame->regcache); + xfree (dummy_frame); +} + +/* Function: fix_call_dummy + Stub function. Generic dummy frames typically do not need to fix + the frame being created */ + +void +generic_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, + struct value **args, struct type *type, int gcc_p) +{ + return; +} + +/* Given a call-dummy dummy-frame, return the registers. Here the + register value is taken from the local copy of the register buffer. */ + +void +generic_call_dummy_register_unwind (struct frame_info *frame, void **cache, + int regnum, int *optimized, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnum, void *bufferp) +{ + gdb_assert (frame != NULL); + gdb_assert (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)); + + /* Describe the register's location. Generic dummy frames always + have the register value in an ``expression''. */ + *optimized = 0; + *lvalp = not_lval; + *addrp = 0; + *realnum = -1; + + /* If needed, find and return the value of the register. */ + if (bufferp != NULL) + { + struct regcache *registers; +#if 1 + /* Get the address of the register buffer that contains all the + saved registers for this dummy frame. Cache that address. */ + registers = (*cache); + if (registers == NULL) + { + registers = generic_find_dummy_frame (frame->pc, frame->frame); + (*cache) = registers; + } +#else + /* Get the address of the register buffer that contains the + saved registers and then extract the value from that. */ + registers = generic_find_dummy_frame (frame->pc, frame->frame); +#endif + gdb_assert (registers != NULL); + /* Return the actual value. */ + /* Use the regcache_cooked_read() method so that it, on the fly, + constructs either a raw or pseudo register from the raw + register cache. */ + regcache_cooked_read (registers, regnum, bufferp); + } +} + diff --git a/gdb/dummy-frame.h b/gdb/dummy-frame.h new file mode 100644 index 00000000000..6bdebee8878 --- /dev/null +++ b/gdb/dummy-frame.h @@ -0,0 +1,66 @@ +/* Code dealing with dummy stack frames, for GDB, the GNU debugger. + + Copyright 2002 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 (DUMMY_FRAME_H) +#define DUMMY_FRAME_H 1 + +struct frame_info; +struct regcache; + +/* GENERIC DUMMY FRAMES + + The following code serves to maintain the dummy stack frames for + inferior function calls (ie. when gdb calls into the inferior via + call_function_by_hand). This code saves the machine state before + the call in host memory, so we must maintain an independent stack + and keep it consistant etc. I am attempting to make this code + generic enough to be used by many targets. + + The cheapest and most generic way to do CALL_DUMMY on a new target + is probably to define CALL_DUMMY to be empty, CALL_DUMMY_LENGTH to + zero, and CALL_DUMMY_LOCATION to AT_ENTRY. Then you must remember + to define PUSH_RETURN_ADDRESS, because no call instruction will be + being executed by the target. Also FRAME_CHAIN_VALID as + generic_{file,func}_frame_chain_valid and FIX_CALL_DUMMY as + generic_fix_call_dummy. */ + +/* Assuming that FRAME is a dummy, return a register value for the + previous frame. */ + +extern void generic_call_dummy_register_unwind (struct frame_info *frame, + void **unwind_cache, + int regnum, + int *optimized, + enum lval_type *lvalp, + CORE_ADDR *addrp, + int *realnump, + void *valuep); + +/* Return the regcache that belongs to the dummy-frame identifed by PC + and FP, or NULL if no such frame exists. */ +/* FIXME: cagney/2002-11-08: The function only exists because of + deprecated_generic_get_saved_register. Eliminate that function and + this, to, can go. */ + +extern struct regcache *generic_find_dummy_frame (CORE_ADDR pc, + CORE_ADDR fp); + +#endif /* !defined (DUMMY_FRAME_H) */