* dummy-frame.h (dummy_frame_id_unwind): Delete declaration.
(dummy_frame_pc_unwind, dummy_frame_register_unwind): Ditto.
(struct frame_unwind): Declare opaque.
(dummy_frame_p): Declare function.
* dummy-frame.c (dummy_frame_id_unwind): Make static.
(dummy_frame_pc_unwind, dummy_frame_register_unwind): Ditto.
* dummy-frame.c: Include "frame-unwind.h".
(dummy_frame_p): New function.
(dummy_frame_unwind): New variable.
* frame.c: Include "frame-unwind.h".
(frame_pc_unwind, frame_id_unwind, frame_register_unwind): Update
to use the new unwind field.
(set_unwind_by_pc): Delete function.
(create_new_frame, get_prev_frame): Set unwind field using
frame_unwind_find_by_pc.
(trad_frame_unwind, trad_frame_unwinder): New variables.
* frame.h (trad_frame_unwind): Declare variable.
(frame_id_unwind_ftype): Delete declaration.
(frame_pc_unwind_ftype, frame_register_unwind_ftype): Ditto.
(struct frame_unwind): Declare opaque.
(struct frame_info): Replace the fields id_unwind, pc_unwind and
register_unwind with a single unwind pointer.
* frame-unwind.h, frame-unwind.c: New files.
* Makefile.in (SFILES): Add frame-unwind.c.
(frame_unwind_h): Define.
(COMMON_OBS): Add frame-unwind.o.
(frame-unwind.o): Specify dependencies.
(frame.o, dummy-frame.o): Update dependencies.
+2003-01-18 Andrew Cagney <ac131313@redhat.com>
+
+ * dummy-frame.h (dummy_frame_id_unwind): Delete declaration.
+ (dummy_frame_pc_unwind, dummy_frame_register_unwind): Ditto.
+ (struct frame_unwind): Declare opaque.
+ (dummy_frame_p): Declare function.
+ * dummy-frame.c (dummy_frame_id_unwind): Make static.
+ (dummy_frame_pc_unwind, dummy_frame_register_unwind): Ditto.
+ * dummy-frame.c: Include "frame-unwind.h".
+ (dummy_frame_p): New function.
+ (dummy_frame_unwind): New variable.
+ * frame.c: Include "frame-unwind.h".
+ (frame_pc_unwind, frame_id_unwind, frame_register_unwind): Update
+ to use the new unwind field.
+ (set_unwind_by_pc): Delete function.
+ (create_new_frame, get_prev_frame): Set unwind field using
+ frame_unwind_find_by_pc.
+ (trad_frame_unwind, trad_frame_unwinder): New variables.
+ * frame.h (trad_frame_unwind): Declare variable.
+ (frame_id_unwind_ftype): Delete declaration.
+ (frame_pc_unwind_ftype, frame_register_unwind_ftype): Ditto.
+ (struct frame_unwind): Declare opaque.
+ (struct frame_info): Replace the fields id_unwind, pc_unwind and
+ register_unwind with a single unwind pointer.
+ * frame-unwind.h, frame-unwind.c: New files.
+ * Makefile.in (SFILES): Add frame-unwind.c.
+ (frame_unwind_h): Define.
+ (COMMON_OBS): Add frame-unwind.o.
+ (frame-unwind.o): Specify dependencies.
+ (frame.o, dummy-frame.o): Update dependencies.
+
2003-01-18 Andrew Cagney <ac131313@redhat.com>
* ada-valprint.c: Eliminate PTR.
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 \
+ frame-unwind.c \
gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
hpacc-abi.c \
inf-loop.c infcmd.c inflow.c infrun.c \
expression_h = expression.h $(symtab_h) $(doublest_h)
f_lang_h = f-lang.h
frame_h = frame.h
+frame_unwind_h = frame-unwind.h
gdb_events_h = gdb-events.h
gdb_stabs_h = gdb-stabs.h
gdb_h = gdb.h
c-valprint.o cp-valprint.o f-valprint.o m2-valprint.o \
nlmread.o serial.o mdebugread.o top.o utils.o \
ui-file.o \
- frame.o doublest.o \
+ frame.o frame-unwind.o doublest.o \
gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o \
reggroups.o
dpx2-nat.o: dpx2-nat.c $(defs_h) $(gdbcore_h) $(gdb_string_h)
dsrec.o: dsrec.c $(defs_h) $(serial_h) $(srec_h)
dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \
- $(frame_h) $(inferior_h) $(gdb_assert_h)
+ $(frame_h) $(inferior_h) $(gdb_assert_h) $(frame_unwind_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) \
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)
+ $(language_h) $(frame_unwind_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) \
$(arch_utils_h) $(regcache_h)
gcore.o: gcore.c $(defs_h) $(cli_decode_h) $(inferior_h) $(gdbcore_h) \
#include "frame.h"
#include "inferior.h"
#include "gdb_assert.h"
+#include "frame-unwind.h"
/* Dummy frame. This saves the processor state just prior to setting
up the inferior function call. Older targets save the registers
/* Given a call-dummy dummy-frame, return the registers. Here the
register value is taken from the local copy of the register buffer. */
-void
+static void
dummy_frame_register_unwind (struct frame_info *frame, void **cache,
int regnum, int *optimized,
enum lval_type *lvalp, CORE_ADDR *addrp,
}
}
-CORE_ADDR
+/* Assuming that FRAME is a dummy, return the resume address for the
+ previous frame. */
+
+static CORE_ADDR
dummy_frame_pc_unwind (struct frame_info *frame,
void **cache)
{
}
-void
-dummy_frame_id_unwind (struct frame_info *frame, void **cache,
+/* Assuming that FRAME is a dummy, return the ID of the calling frame
+ (the frame that the dummy has the saved state of). */
+
+static void
+dummy_frame_id_unwind (struct frame_info *frame,
+ void **cache,
struct frame_id *id)
{
struct dummy_frame *dummy = cached_find_dummy_frame (frame, cache);
(*id) = dummy->id;
}
+static struct frame_unwind dummy_frame_unwind =
+{
+ dummy_frame_pc_unwind,
+ dummy_frame_id_unwind,
+ dummy_frame_register_unwind
+};
+
+const struct frame_unwind *
+dummy_frame_p (CORE_ADDR pc)
+{
+ if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
+ ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
+ : pc_in_dummy_frame (pc))
+ return &dummy_frame_unwind;
+ else
+ return NULL;
+}
struct frame_info;
struct regcache;
+struct frame_unwind;
struct frame_id;
/* GENERIC DUMMY FRAMES
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. */
+/* If the PC falls in a dummy frame, return a dummy frame
+ unwinder. */
-extern void dummy_frame_register_unwind (struct frame_info *frame,
- void **unwind_cache,
- int regnum,
- int *optimized,
- enum lval_type *lvalp,
- CORE_ADDR *addrp,
- int *realnump,
- void *valuep);
-
-/* Assuming that FRAME is a dummy, return the resume address for the
- previous frame. */
-
-extern CORE_ADDR dummy_frame_pc_unwind (struct frame_info *frame,
- void **unwind_cache);
-
-/* Assuming that FRAME is a dummy, return the ID of the calling frame
- (the frame that the dummy has the saved state of). */
-
-extern void dummy_frame_id_unwind (struct frame_info *frame,
- void **unwind_cache,
- struct frame_id *id);
+extern const struct frame_unwind *dummy_frame_p (CORE_ADDR pc);
/* Does the PC fall in a dummy frame?
--- /dev/null
+/* Definitions for frame unwinder, 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. */
+
+#include "defs.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "gdb_assert.h"
+#include "dummy-frame.h"
+
+static struct gdbarch_data *frame_unwind_data;
+
+struct frame_unwind_table
+{
+ frame_unwind_p_ftype **p;
+ int middle;
+ int nr;
+};
+
+/* Append a predicate to the end of the table. */
+static void
+append_predicate (struct frame_unwind_table *table, frame_unwind_p_ftype *p)
+{
+ table->p = xrealloc (table->p, ((table->nr + 1)
+ * sizeof (frame_unwind_p_ftype *)));
+ table->p[table->nr] = p;
+ table->nr++;
+}
+
+static void *
+frame_unwind_init (struct gdbarch *gdbarch)
+{
+ struct frame_unwind_table *table = XCALLOC (1, struct frame_unwind_table);
+ append_predicate (table, dummy_frame_p);
+ return table;
+}
+
+static void
+frame_unwind_free (struct gdbarch *gdbarch, void *data)
+{
+ struct frame_unwind_table *table =
+ gdbarch_data (gdbarch, frame_unwind_data);
+ xfree (table->p);
+ xfree (table);
+}
+
+void
+frame_unwind_append_predicate (struct gdbarch *gdbarch,
+ frame_unwind_p_ftype *p)
+{
+ struct frame_unwind_table *table =
+ gdbarch_data (gdbarch, frame_unwind_data);
+ if (table == NULL)
+ {
+ /* ULGH, called during architecture initialization. Patch
+ things up. */
+ table = frame_unwind_init (gdbarch);
+ set_gdbarch_data (gdbarch, frame_unwind_data, table);
+ }
+ append_predicate (table, p);
+}
+
+const struct frame_unwind *
+frame_unwind_find_by_pc (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ int i;
+ struct frame_unwind_table *table =
+ gdbarch_data (gdbarch, frame_unwind_data);
+ /* Seriously old code. Don't even try to use this new mechanism. */
+ if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
+ return trad_frame_unwind;
+ for (i = 0; i < table->nr; i++)
+ {
+ const struct frame_unwind *desc = table->p[i] (pc);
+ if (desc != NULL)
+ return desc;
+ }
+ return trad_frame_unwind;
+}
+
+void
+_initialize_frame_unwind (void)
+{
+ frame_unwind_data = register_gdbarch_data (frame_unwind_init,
+ frame_unwind_free);
+}
--- /dev/null
+/* Definitions for a frame unwinder, 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 (FRAME_UNWIND_H)
+#define FRAME_UNWIND_H 1
+
+struct frame_info;
+struct frame_id;
+struct frame_unwind;
+struct gdbarch;
+struct regcache;
+
+/* Return the frame unwind methods for the function that contains PC,
+ or NULL if this this unwinder can't handle this frame. */
+
+typedef const struct frame_unwind *(frame_unwind_p_ftype) (CORE_ADDR pc);
+
+/* Add a frame unwinder to the list. The predicates are polled in the
+ order that they are appended. The initial list contains the dummy
+ frame's predicate. */
+
+extern void frame_unwind_append_predicate (struct gdbarch *gdbarch,
+ frame_unwind_p_ftype *p);
+
+/* Iterate through the list of frame unwinders until one returns an
+ implementation. */
+
+extern const struct frame_unwind *frame_unwind_find_by_pc (struct gdbarch
+ *gdbarch,
+ CORE_ADDR pc);
+
+/* Return the location (and possibly value) of REGNUM for the previous
+ (older, up) frame. All parameters except VALUEP can be assumed to
+ be non NULL. When VALUEP is NULL, just the location of the
+ register should be returned.
+
+ UNWIND_CACHE is provided as mechanism for implementing a per-frame
+ local cache. It's initial value being NULL. Memory for that cache
+ should be allocated using frame_obstack_zalloc().
+
+ Register window architectures (eg SPARC) should note that REGNUM
+ identifies the register for the previous frame. For instance, a
+ request for the value of "o1" for the previous frame would be found
+ in the register "i1" in this FRAME. */
+
+typedef void (frame_unwind_reg_ftype) (struct frame_info * frame,
+ void **unwind_cache,
+ int regnum,
+ int *optimized,
+ enum lval_type * lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep);
+
+/* Same as for registers above, but return the address at which the
+ calling frame would resume. */
+
+typedef CORE_ADDR (frame_unwind_pc_ftype) (struct frame_info * frame,
+ void **unwind_cache);
+
+/* Same as for registers above, but return the ID of the frame that
+ called this one. */
+
+typedef void (frame_unwind_id_ftype) (struct frame_info * frame,
+ void **unwind_cache,
+ struct frame_id * id);
+
+
+struct frame_unwind
+{
+ /* Should the frame's type go here? */
+ /* Should an attribute indicating the frame's address-in-block go
+ here? */
+ frame_unwind_pc_ftype *pc;
+ frame_unwind_id_ftype *id;
+ frame_unwind_reg_ftype *reg;
+};
+
+#endif
#include "gdbcore.h"
#include "annotate.h"
#include "language.h"
+#include "frame-unwind.h"
/* Return a frame uniq ID that can be used to, later, re-find the
frame. */
{
if (!frame->pc_unwind_cache_p)
{
- frame->pc_unwind_cache = frame->pc_unwind (frame, &frame->unwind_cache);
+ frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache);
frame->pc_unwind_cache_p = 1;
}
return frame->pc_unwind_cache;
{
if (!frame->id_unwind_cache_p)
{
- frame->id_unwind (frame, &frame->unwind_cache, &frame->id_unwind_cache);
+ frame->unwind->id (frame, &frame->unwind_cache, &frame->id_unwind_cache);
frame->id_unwind_cache_p = 1;
}
return frame->id_unwind_cache;
}
/* Ask this frame to unwind its register. */
- frame->register_unwind (frame, &frame->unwind_cache, regnum,
- optimizedp, lvalp, addrp, realnump, bufferp);
+ frame->unwind->reg (frame, &frame->unwind_cache, regnum,
+ optimizedp, lvalp, addrp, realnump, bufferp);
}
void
id->base = base;
}
+const struct frame_unwind trad_frame_unwinder = {
+ frame_saved_regs_pc_unwind,
+ frame_saved_regs_id_unwind,
+ frame_saved_regs_register_unwind
+};
+const struct frame_unwind *trad_frame_unwind = &trad_frame_unwinder;
+
+
/* Function: get_saved_register
Find register number REGNUM relative to FRAME and put its (raw,
target format) contents in *RAW_BUFFER.
deprecated_read_register_gen (regnum, raw_buffer);
}
-/* Using the PC, select a mechanism for unwinding a frame returning
- the previous frame. The register unwind function should, on
- demand, initialize the ->context object. */
-
-static void
-set_unwind_by_pc (CORE_ADDR pc, CORE_ADDR fp,
- frame_register_unwind_ftype **unwind_register,
- frame_pc_unwind_ftype **unwind_pc,
- frame_id_unwind_ftype **unwind_id)
-{
- if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
- {
- /* Still need to set this to something. The ``info frame'' code
- calls this function to find out where the saved registers are.
- Hopefully this is robust enough to stop any core dumps and
- return vaguely correct values.. */
- *unwind_register = frame_saved_regs_register_unwind;
- *unwind_pc = frame_saved_regs_pc_unwind;
- *unwind_id = frame_saved_regs_id_unwind;
- }
- else if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
- ? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
- : pc_in_dummy_frame (pc))
- {
- *unwind_register = dummy_frame_register_unwind;
- *unwind_pc = dummy_frame_pc_unwind;
- *unwind_id = dummy_frame_id_unwind;
- }
- else
- {
- *unwind_register = frame_saved_regs_register_unwind;
- *unwind_pc = frame_saved_regs_pc_unwind;
- *unwind_id = frame_saved_regs_id_unwind;
- }
-}
-
/* Create an arbitrary (i.e. address specified by user) or innermost frame.
Always returns a non-NULL value. */
INIT_EXTRA_FRAME_INFO (0, fi);
/* Select/initialize an unwind function. */
- set_unwind_by_pc (fi->pc, fi->frame, &fi->register_unwind,
- &fi->pc_unwind, &fi->id_unwind);
+ fi->unwind = frame_unwind_find_by_pc (current_gdbarch, fi->pc);
return fi;
}
(and probably other architectural information). The PC lets you
check things like the debug info at that point (dwarf2cfi?) and
use that to decide how the frame should be unwound. */
- set_unwind_by_pc (prev->pc, prev->frame, &prev->register_unwind,
- &prev->pc_unwind, &prev->id_unwind);
+ prev->unwind = frame_unwind_find_by_pc (current_gdbarch, prev->pc);
/* NOTE: cagney/2002-11-18: The code segments, found in
create_new_frame and get_prev_frame(), that initializes the
#define FRAME_H 1
struct symtab_and_line;
+struct frame_unwind;
+
+/* The traditional frame unwinder. */
+extern const struct frame_unwind *trad_frame_unwind;
/* The frame object. */
caller's frame. */
extern struct frame_id frame_id_unwind (struct frame_info *frame);
-\f
-/* Return the location (and possibly value) of REGNUM for the previous
- (older, up) frame. All parameters except VALUEP can be assumed to
- be non NULL. When VALUEP is NULL, just the location of the
- register should be returned.
-
- UNWIND_CACHE is provided as mechanism for implementing a per-frame
- local cache. It's initial value being NULL. Memory for that cache
- should be allocated using frame_obstack_zalloc().
-
- Register window architectures (eg SPARC) should note that REGNUM
- identifies the register for the previous frame. For instance, a
- request for the value of "o1" for the previous frame would be found
- in the register "i1" in this FRAME. */
-
-typedef void (frame_register_unwind_ftype) (struct frame_info *frame,
- void **unwind_cache,
- int regnum,
- int *optimized,
- enum lval_type *lvalp,
- CORE_ADDR *addrp,
- int *realnump,
- void *valuep);
-
-/* Same as for registers above, but return the address at which the
- calling frame would resume. */
-
-typedef CORE_ADDR (frame_pc_unwind_ftype) (struct frame_info *frame,
- void **unwind_cache);
-
-/* Same as for registers above, but return the ID of the frame that
- called this one. */
-
-typedef void (frame_id_unwind_ftype) (struct frame_info *frame,
- void **unwind_cache,
- struct frame_id *id);
-
/* Describe the saved registers of a frame. */
#if defined (EXTRA_FRAME_INFO) || defined (FRAME_FIND_SAVED_REGS)
better all agree as to the contents. */
void *unwind_cache;
- /* See description above. The previous frame's registers. */
- frame_register_unwind_ftype *register_unwind;
+ /* The frame's unwinder. */
+ const struct frame_unwind *unwind;
- /* See description above. The previous frame's resume address.
- Save the previous PC in a local cache. */
- frame_pc_unwind_ftype *pc_unwind;
+ /* Cached copy of the previous frame's resume address. */
int pc_unwind_cache_p;
CORE_ADDR pc_unwind_cache;
- /* See description above. The previous frame's resume address.
- Save the previous PC in a local cache. */
- frame_id_unwind_ftype *id_unwind;
+ /* Cached copy of the previous frame's ID. */
int id_unwind_cache_p;
struct frame_id id_unwind_cache;