mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
2002-11-08 Andrew Cagney <ac131313@redhat.com>
* 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.
This commit is contained in:
parent
208d818701
commit
9c1412c1a1
@ -1,3 +1,24 @@
|
||||
2002-11-08 Andrew Cagney <ac131313@redhat.com>
|
||||
|
||||
* 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 <jimb@redhat.com>
|
||||
|
||||
* dwarf2read.c (read_func_scope): Restore local_symbols and
|
||||
|
@ -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) \
|
||||
|
304
gdb/blockframe.c
304
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. */
|
||||
|
308
gdb/dummy-frame.c
Normal file
308
gdb/dummy-frame.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
66
gdb/dummy-frame.h
Normal file
66
gdb/dummy-frame.h
Normal file
@ -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) */
|
Loading…
Reference in New Issue
Block a user