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:
Andrew Cagney 2003-01-27 21:41:41 +00:00
parent 5378adc435
commit a94dd1fda2
5 changed files with 328 additions and 132 deletions

View File

@ -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.

View File

@ -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) \

View File

@ -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
View 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
View 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) */