2003-01-27 Andrew Cagney <ac131313@redhat.com>
* sentinel-frame.h, sentinel-frame.c: New files. * Makefile.in (frame.o): Update dependencies. (SFILES): Add sentinel-frame.c. (sentinel_frame_h): Define. (COMMON_OBS): Add sentinel-frame.o. (sentinel-frame.o): Specify dependencies. * frame.c: Include "sentinel-frame.h". (frame_register_unwind): Rewrite assuming that there is always a a ->next frame. (frame_register, generic_unwind_get_saved_register): Ditto. (frame_read_unsigned_register, frame_read_signed_register): Ditto. (create_sentinel_frame, unwind_to_current_frame): New functions. (get_current_frame): Rewrite using create_sentinel_frame and unwind_to_current_frame. When possible, always create a frame. (create_new_frame): Set next to the sentinel frame. (get_next_frame): Rewrite. Don't go below the level 0 frame. (deprecated_update_frame_pc_hack): Update the next frame's PC and ID cache when necessary. (frame_saved_regs_id_unwind): Use frame_relative_level. (deprecated_generic_get_saved_register): Use frame_relative_level, get_frame_saved_regs, get_frame_pc, get_frame_base and get_next_frame. (frame_saved_regs_register_unwind): Use get_frame_saved_regs and frame_register.
This commit is contained in:
parent
5378adc435
commit
a94dd1fda2
5 changed files with 328 additions and 132 deletions
|
@ -1,3 +1,30 @@
|
|||
2003-01-27 Andrew Cagney <ac131313@redhat.com>
|
||||
|
||||
* sentinel-frame.h, sentinel-frame.c: New files.
|
||||
* Makefile.in (frame.o): Update dependencies.
|
||||
(SFILES): Add sentinel-frame.c.
|
||||
(sentinel_frame_h): Define.
|
||||
(COMMON_OBS): Add sentinel-frame.o.
|
||||
(sentinel-frame.o): Specify dependencies.
|
||||
* frame.c: Include "sentinel-frame.h".
|
||||
(frame_register_unwind): Rewrite assuming that there is always a a
|
||||
->next frame.
|
||||
(frame_register, generic_unwind_get_saved_register): Ditto.
|
||||
(frame_read_unsigned_register, frame_read_signed_register): Ditto.
|
||||
(create_sentinel_frame, unwind_to_current_frame): New functions.
|
||||
(get_current_frame): Rewrite using create_sentinel_frame and
|
||||
unwind_to_current_frame. When possible, always create a frame.
|
||||
(create_new_frame): Set next to the sentinel frame.
|
||||
(get_next_frame): Rewrite. Don't go below the level 0 frame.
|
||||
(deprecated_update_frame_pc_hack): Update the next frame's PC and
|
||||
ID cache when necessary.
|
||||
(frame_saved_regs_id_unwind): Use frame_relative_level.
|
||||
(deprecated_generic_get_saved_register): Use frame_relative_level,
|
||||
get_frame_saved_regs, get_frame_pc, get_frame_base and
|
||||
get_next_frame.
|
||||
(frame_saved_regs_register_unwind): Use get_frame_saved_regs and
|
||||
frame_register.
|
||||
|
||||
2003-01-27 Daniel Jacobowitz <drow@mvista.com>
|
||||
|
||||
* gdb_indent.sh: Add -T bfd and -T asection to the indent arguments.
|
||||
|
|
|
@ -528,7 +528,9 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
|
|||
objfiles.c osabi.c \
|
||||
p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
|
||||
regcache.c reggroups.c remote.c \
|
||||
scm-exp.c scm-lang.c scm-valprint.c serial.c ser-unix.c source.c \
|
||||
scm-exp.c scm-lang.c scm-valprint.c \
|
||||
sentinel-frame.c \
|
||||
serial.c ser-unix.c source.c \
|
||||
stabsread.c stack.c std-regs.c symfile.c symmisc.c symtab.c \
|
||||
target.c thread.c top.c tracepoint.c typeprint.c \
|
||||
tui/tui.c tui/tui.h tui/tuiCommand.c tui/tuiCommand.h \
|
||||
|
@ -686,6 +688,7 @@ remote_utils_h = remote-utils.h $(target_h)
|
|||
remote_h = remote.h
|
||||
scm_lang_h = scm-lang.h $(scm_tags_h)
|
||||
scm_tags_h = scm-tags.h
|
||||
sentinel_frame_h = sentinel-frame.h
|
||||
ser_unix_h = ser-unix.h
|
||||
serial_h = serial.h
|
||||
sh_tdep_h = sh-tdep.h
|
||||
|
@ -832,7 +835,9 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \
|
|||
varobj.o wrapper.o \
|
||||
jv-lang.o jv-valprint.o jv-typeprint.o \
|
||||
m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
|
||||
scm-exp.o scm-lang.o scm-valprint.o complaints.o typeprint.o \
|
||||
scm-exp.o scm-lang.o scm-valprint.o \
|
||||
sentinel-frame.o \
|
||||
complaints.o typeprint.o \
|
||||
c-typeprint.o f-typeprint.o m2-typeprint.o \
|
||||
c-valprint.o cp-valprint.o f-valprint.o m2-valprint.o \
|
||||
nlmread.o serial.o mdebugread.o top.o utils.o \
|
||||
|
@ -1692,7 +1697,8 @@ fork-child.o: fork-child.c $(defs_h) $(gdb_string_h) $(frame_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) $(frame_unwind_h) $(command_h) $(gdbcmd_h)
|
||||
$(language_h) $(frame_unwind_h) $(command_h) $(gdbcmd_h) \
|
||||
$(sentinel_frame_h)
|
||||
frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_h) \
|
||||
$(gdb_assert_h) $(dummy_frame_h) $(legacy_frame_h)
|
||||
frv-tdep.o: frv-tdep.c $(defs_h) $(inferior_h) $(symfile_h) $(gdbcore_h) \
|
||||
|
@ -2125,6 +2131,8 @@ scm-lang.o: scm-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
|
|||
scm-valprint.o: scm-valprint.c $(defs_h) $(symtab_h) $(gdbtypes_h) \
|
||||
$(expression_h) $(parser_defs_h) $(language_h) $(value_h) \
|
||||
$(scm_lang_h) $(valprint_h) $(gdbcore_h)
|
||||
sentinel-frame.o: sentinel-frame.c $(defs_h) $(regcache_h) \
|
||||
$(sentinel_frame_h) $(inferior_h) $(frame_unwind_h)
|
||||
ser-e7kpc.o: ser-e7kpc.c $(defs_h) $(serial_h) $(gdb_string_h)
|
||||
ser-go32.o: ser-go32.c $(defs_h) $(gdbcmd_h) $(serial_h) $(gdb_string_h)
|
||||
ser-pipe.o: ser-pipe.c $(defs_h) $(serial_h) $(ser_unix_h) $(gdb_vfork_h) \
|
||||
|
|
265
gdb/frame.c
265
gdb/frame.c
|
@ -31,6 +31,7 @@
|
|||
#include "builtin-regs.h"
|
||||
#include "gdb_obstack.h"
|
||||
#include "dummy-frame.h"
|
||||
#include "sentinel-frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "annotate.h"
|
||||
#include "language.h"
|
||||
|
@ -179,29 +180,11 @@ frame_register_unwind (struct frame_info *frame, int regnum,
|
|||
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)
|
||||
deprecated_read_register_gen (regnum, bufferp);
|
||||
return;
|
||||
}
|
||||
/* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame
|
||||
is broken. There is always a frame. If there, for some reason,
|
||||
isn't, there is some pretty busted code as it should have
|
||||
detected the problem before calling here. */
|
||||
gdb_assert (frame != NULL);
|
||||
|
||||
/* Ask this frame to unwind its register. */
|
||||
frame->unwind->reg (frame, &frame->unwind_cache, regnum,
|
||||
|
@ -247,25 +230,11 @@ frame_register (struct frame_info *frame, int regnum,
|
|||
return;
|
||||
}
|
||||
|
||||
/* 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, realnump,
|
||||
bufferp);
|
||||
else
|
||||
frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
|
||||
realnump, bufferp);
|
||||
/* Obtain the register value by unwinding the register from the next
|
||||
(more inner frame). */
|
||||
gdb_assert (frame != NULL && frame->next != NULL);
|
||||
frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
|
||||
realnump, bufferp);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -317,17 +286,17 @@ frame_read_unsigned_register (struct frame_info *frame, int regnum,
|
|||
tests like ``if get_next_frame() == NULL'' and instead just rely
|
||||
on recursive frame calls (like the below code) when manipulating
|
||||
a frame chain. */
|
||||
gdb_assert (frame != NULL);
|
||||
frame_unwind_unsigned_register (get_next_frame (frame), regnum, val);
|
||||
gdb_assert (frame != NULL && frame->next != NULL);
|
||||
frame_unwind_unsigned_register (frame->next, regnum, val);
|
||||
}
|
||||
|
||||
void
|
||||
frame_read_signed_register (struct frame_info *frame, int regnum,
|
||||
LONGEST *val)
|
||||
{
|
||||
/* See note in frame_read_unsigned_register(). */
|
||||
gdb_assert (frame != NULL);
|
||||
frame_unwind_signed_register (get_next_frame (frame), regnum, val);
|
||||
/* See note above in frame_read_unsigned_register(). */
|
||||
gdb_assert (frame != NULL && frame->next != NULL);
|
||||
frame_unwind_signed_register (frame->next, regnum, val);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -355,25 +324,9 @@ generic_unwind_get_saved_register (char *raw_buffer,
|
|||
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
|
||||
frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
|
||||
&realnumx, raw_buffer);
|
||||
gdb_assert (frame != NULL && frame->next != NULL);
|
||||
frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
|
||||
&realnumx, raw_buffer);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -463,6 +416,32 @@ frame_map_regnum_to_name (int regnum)
|
|||
return builtin_reg_map_regnum_to_name (regnum);
|
||||
}
|
||||
|
||||
/* Create a sentinel frame. */
|
||||
|
||||
struct frame_info *
|
||||
create_sentinel_frame (struct regcache *regcache)
|
||||
{
|
||||
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
|
||||
frame->type = NORMAL_FRAME;
|
||||
frame->level = -1;
|
||||
/* Explicitly initialize the sentinel frame's cache. Provide it
|
||||
with the underlying regcache. In the future additional
|
||||
information, such as the frame's thread will be added. */
|
||||
frame->unwind_cache = sentinel_frame_cache (regcache);
|
||||
/* For the moment there is only one sentinel frame implementation. */
|
||||
frame->unwind = sentinel_frame_unwind;
|
||||
/* Link this frame back to itself. The frame is self referential
|
||||
(the unwound PC is the same as the pc), so make it so. */
|
||||
frame->next = frame;
|
||||
/* Always unwind the PC as part of creating this frame. This
|
||||
ensures that the frame's PC points at something valid. */
|
||||
/* FIXME: cagney/2003-01-10: Problem here. Unwinding a sentinel
|
||||
frame's PC may require information such as the frame's thread's
|
||||
stop reason. Is it possible to get to that? */
|
||||
frame->pc = frame_pc_unwind (frame);
|
||||
return frame;
|
||||
}
|
||||
|
||||
/* Info about the innermost stack frame (contents of FP register) */
|
||||
|
||||
static struct frame_info *current_frame;
|
||||
|
@ -495,17 +474,43 @@ get_frame_saved_regs (struct frame_info *fi)
|
|||
return fi->saved_regs;
|
||||
}
|
||||
|
||||
/* Return the innermost (currently executing) stack frame. */
|
||||
/* Return the innermost (currently executing) stack frame. This is
|
||||
split into two functions. The function unwind_to_current_frame()
|
||||
is wrapped in catch exceptions so that, even when the unwind of the
|
||||
sentinel frame fails, the function still returns a stack frame. */
|
||||
|
||||
static int
|
||||
unwind_to_current_frame (struct ui_out *ui_out, void *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;
|
||||
}
|
||||
|
||||
struct frame_info *
|
||||
get_current_frame (void)
|
||||
{
|
||||
if (!target_has_stack)
|
||||
error ("No stack.");
|
||||
if (!target_has_registers)
|
||||
error ("No registers.");
|
||||
if (!target_has_memory)
|
||||
error ("No memory.");
|
||||
if (current_frame == NULL)
|
||||
{
|
||||
if (target_has_stack)
|
||||
current_frame = create_new_frame (read_fp (), read_pc ());
|
||||
else
|
||||
error ("No stack.");
|
||||
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)
|
||||
{
|
||||
/* Oops! Fake a current frame? Is this useful? It has a PC
|
||||
of zero, for instance. */
|
||||
current_frame = sentinel_frame;
|
||||
}
|
||||
}
|
||||
return current_frame;
|
||||
}
|
||||
|
@ -593,11 +598,11 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
|
|||
gdb_assert (FRAME_INIT_SAVED_REGS_P ());
|
||||
|
||||
/* Load the saved_regs register cache. */
|
||||
if (frame->saved_regs == NULL)
|
||||
if (get_frame_saved_regs (frame) == NULL)
|
||||
FRAME_INIT_SAVED_REGS (frame);
|
||||
|
||||
if (frame->saved_regs != NULL
|
||||
&& frame->saved_regs[regnum] != 0)
|
||||
if (get_frame_saved_regs (frame) != NULL
|
||||
&& get_frame_saved_regs (frame)[regnum] != 0)
|
||||
{
|
||||
if (regnum == SP_REGNUM)
|
||||
{
|
||||
|
@ -608,7 +613,7 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
|
|||
*realnump = -1;
|
||||
if (bufferp != NULL)
|
||||
store_address (bufferp, REGISTER_RAW_SIZE (regnum),
|
||||
frame->saved_regs[regnum]);
|
||||
get_frame_saved_regs (frame)[regnum]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -616,7 +621,7 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
|
|||
a local copy of its value. */
|
||||
*optimizedp = 0;
|
||||
*lvalp = lval_memory;
|
||||
*addrp = frame->saved_regs[regnum];
|
||||
*addrp = get_frame_saved_regs (frame)[regnum];
|
||||
*realnump = -1;
|
||||
if (bufferp != NULL)
|
||||
{
|
||||
|
@ -635,13 +640,13 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
|
|||
{
|
||||
regs[regnum]
|
||||
= frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum));
|
||||
read_memory (frame->saved_regs[regnum], regs[regnum],
|
||||
read_memory (get_frame_saved_regs (frame)[regnum], regs[regnum],
|
||||
REGISTER_RAW_SIZE (regnum));
|
||||
}
|
||||
memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum));
|
||||
#else
|
||||
/* Read the value in from memory. */
|
||||
read_memory (frame->saved_regs[regnum], bufferp,
|
||||
read_memory (get_frame_saved_regs (frame)[regnum], bufferp,
|
||||
REGISTER_RAW_SIZE (regnum));
|
||||
#endif
|
||||
}
|
||||
|
@ -650,21 +655,11 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
|
|||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
value. Pass the request down the frame chain to the next frame.
|
||||
Hopefully that will find the register's location, either in a
|
||||
register or in memory. */
|
||||
frame_register (frame, regnum, optimizedp, lvalp, addrp, realnump,
|
||||
bufferp);
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
|
@ -684,7 +679,7 @@ frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache,
|
|||
/* Start out by assuming it's NULL. */
|
||||
(*id) = null_frame_id;
|
||||
|
||||
if (next_frame->next == NULL)
|
||||
if (frame_relative_level (next_frame) <= 0)
|
||||
/* 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
|
||||
|
@ -797,44 +792,50 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
|
|||
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 (frame != NULL)
|
||||
{
|
||||
if (get_frame_type (frame) == DUMMY_FRAME)
|
||||
for (frame = get_next_frame (frame);
|
||||
frame_relative_level (frame) >= 0;
|
||||
frame = get_next_frame (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 (get_frame_type (frame) == DUMMY_FRAME)
|
||||
{
|
||||
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 (lval) /* found it in a CALL_DUMMY frame */
|
||||
*lval = not_lval;
|
||||
if (raw_buffer)
|
||||
read_memory (frame->saved_regs[regnum], raw_buffer,
|
||||
REGISTER_RAW_SIZE (regnum));
|
||||
/* 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 (get_frame_saved_regs (frame) != NULL
|
||||
&& get_frame_saved_regs (frame)[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),
|
||||
get_frame_saved_regs (frame)[regnum]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (addrp) /* any other register */
|
||||
*addrp = get_frame_saved_regs (frame)[regnum];
|
||||
if (raw_buffer)
|
||||
read_memory (get_frame_saved_regs (frame)[regnum], raw_buffer,
|
||||
REGISTER_RAW_SIZE (regnum));
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -884,6 +885,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
|
|||
|
||||
fi->frame = addr;
|
||||
fi->pc = pc;
|
||||
fi->next = create_sentinel_frame (current_regcache);
|
||||
fi->type = frame_type_from_pc (pc);
|
||||
|
||||
if (INIT_EXTRA_FRAME_INFO_P ())
|
||||
|
@ -896,12 +898,16 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
|
|||
}
|
||||
|
||||
/* Return the frame that FRAME calls (NULL if FRAME is the innermost
|
||||
frame). */
|
||||
frame). Be careful to not fall off the bottom of the frame chain
|
||||
and onto the sentinel frame. */
|
||||
|
||||
struct frame_info *
|
||||
get_next_frame (struct frame_info *frame)
|
||||
{
|
||||
return frame->next;
|
||||
if (frame->level > 0)
|
||||
return frame->next;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Flush the entire frame cache. */
|
||||
|
@ -1415,6 +1421,7 @@ void
|
|||
deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
|
||||
{
|
||||
/* See comment in "frame.h". */
|
||||
gdb_assert (frame->next != NULL);
|
||||
frame->pc = pc;
|
||||
}
|
||||
|
||||
|
|
113
gdb/sentinel-frame.c
Normal file
113
gdb/sentinel-frame.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/* Code dealing with register 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 "regcache.h"
|
||||
#include "sentinel-frame.h"
|
||||
#include "inferior.h"
|
||||
#include "frame-unwind.h"
|
||||
|
||||
struct frame_unwind_cache
|
||||
{
|
||||
struct regcache *regcache;
|
||||
};
|
||||
|
||||
void *
|
||||
sentinel_frame_cache (struct regcache *regcache)
|
||||
{
|
||||
struct frame_unwind_cache *cache =
|
||||
FRAME_OBSTACK_ZALLOC (struct frame_unwind_cache);
|
||||
cache->regcache = regcache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
/* Here the register value is taken direct from the register cache. */
|
||||
|
||||
void
|
||||
sentinel_frame_register_unwind (struct frame_info *frame,
|
||||
void **unwind_cache,
|
||||
int regnum, int *optimized,
|
||||
enum lval_type *lvalp, CORE_ADDR *addrp,
|
||||
int *realnum, void *bufferp)
|
||||
{
|
||||
struct frame_unwind_cache *cache = *unwind_cache;
|
||||
/* Describe the register's location. A reg-frame maps all registers
|
||||
onto the corresponding hardware register. */
|
||||
*optimized = 0;
|
||||
*lvalp = lval_register;
|
||||
*addrp = REGISTER_BYTE (regnum);
|
||||
*realnum = regnum;
|
||||
|
||||
/* If needed, find and return the value of the register. */
|
||||
if (bufferp != 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 (cache->regcache, regnum, bufferp);
|
||||
}
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
sentinel_frame_pc_unwind (struct frame_info *frame,
|
||||
void **cache)
|
||||
{
|
||||
/* FIXME: cagney/2003-01-08: This should be using a per-architecture
|
||||
method that doesn't suffer from DECR_PC_AFTER_BREAK problems.
|
||||
Such a method would take unwind_cache, regcache and stop reason
|
||||
parameters. */
|
||||
return read_pc ();
|
||||
}
|
||||
|
||||
void
|
||||
sentinel_frame_id_unwind (struct frame_info *frame,
|
||||
void **cache,
|
||||
struct frame_id *id)
|
||||
{
|
||||
/* FIXME: cagney/2003-01-08: This should be using a per-architecture
|
||||
method that doesn't suffer from DECR_PC_AFTER_BREAK problems.
|
||||
Such a method would take unwind_cache, regcache and stop reason
|
||||
parameters. */
|
||||
id->base = read_fp ();
|
||||
id->pc = read_pc ();
|
||||
}
|
||||
|
||||
static void
|
||||
sentinel_frame_pop (struct frame_info *frame,
|
||||
void **cache,
|
||||
struct regcache *regcache)
|
||||
{
|
||||
internal_error (__FILE__, __LINE__, "Function sentinal_frame_pop called");
|
||||
}
|
||||
|
||||
const struct frame_unwind sentinel_frame_unwinder =
|
||||
{
|
||||
sentinel_frame_pop,
|
||||
sentinel_frame_pc_unwind,
|
||||
sentinel_frame_id_unwind,
|
||||
sentinel_frame_register_unwind
|
||||
};
|
||||
|
||||
const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
|
41
gdb/sentinel-frame.h
Normal file
41
gdb/sentinel-frame.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* Code dealing with register stack 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 (SENTINEL_FRAME_H)
|
||||
#define SENTINEL_FRAME_H 1
|
||||
|
||||
struct frame_unwind;
|
||||
struct regcache;
|
||||
|
||||
/* Implement the sentinel frame. The sentinel frame terminates the
|
||||
inner most end of the frame chain. If unwound, it returns the
|
||||
information need to construct an inner-most frame. */
|
||||
|
||||
/* Pump prime the sentinel frame's cache. Since this needs the
|
||||
REGCACHE provide that here. */
|
||||
|
||||
extern void *sentinel_frame_cache (struct regcache *regcache);
|
||||
|
||||
/* At present there is only one type of sentinel frame. */
|
||||
|
||||
extern const struct frame_unwind *const sentinel_frame_unwind;
|
||||
|
||||
#endif /* !defined (SENTINEL_FRAME_H) */
|
Loading…
Reference in a new issue