* Makefile.in (d10v-tdep.o): Update dependencies.
(SFILES): Add trad-frame.c.
(trad_frame_h): Define.
(COMMON_OBS): Add trad-frame.o.
(trad-frame.o): Specify dependencies.
* d10v-tdep.c: Include "trad-frame.h".
(saved_regs_unwinder): Delete function.
(d10v_frame_prev_register): Use trad_frame_prev_register.
(struct d10v_unwind_cache): Change type of "saved_regs" to "struct
trad_frame", delete "regs" and "prev_sp".
(prologue_find_regs): Use trad-frame.
* trad-frame.h, trad-frame.c: New files.
+2003-06-08 Andrew Cagney <cagney@redhat.com>
+
+ * Makefile.in (d10v-tdep.o): Update dependencies.
+ (SFILES): Add trad-frame.c.
+ (trad_frame_h): Define.
+ (COMMON_OBS): Add trad-frame.o.
+ (trad-frame.o): Specify dependencies.
+ * d10v-tdep.c: Include "trad-frame.h".
+ (saved_regs_unwinder): Delete function.
+ (d10v_frame_prev_register): Use trad_frame_prev_register.
+ (struct d10v_unwind_cache): Change type of "saved_regs" to "struct
+ trad_frame", delete "regs" and "prev_sp".
+ (prologue_find_regs): Use trad-frame.
+ * trad-frame.h, trad-frame.c: New files.
+
2003-06-08 Mark Kettenis <kettenis@gnu.org>
* dwarf2cfi.c, dwarf2cfi.h: Remove.
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 \
+ target.c thread.c top.c tracepoint.c \
+ trad-frame.c \
+ typeprint.c \
tui/tui.c tui/tui.h tui/tuiCommand.c tui/tuiCommand.h \
tui/tuiData.c tui/tuiData.h tui/tuiDataWin.c tui/tuiDataWin.h \
tui/tuiDisassem.c tui/tuiDisassem.h tui/tuiGeneralWin.c \
target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h)
terminal_h = terminal.h
top_h = top.h
+trad_frame_h = trad-frame.h
infttrace_h = infttrace.h
tracepoint_h = tracepoint.h
typeprint_h = typeprint.h
frame-base.o \
gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o \
cp-namespace.o \
- reggroups.o
+ reggroups.o \
+ trad-frame.o
OBS = $(COMMON_OBS) $(ANNOTATE_OBS)
d10v-tdep.o: d10v-tdep.c $(defs_h) $(frame_h) $(frame_unwind_h) \
$(frame_base_h) $(symtab_h) $(gdbtypes_h) $(gdbcmd_h) $(gdbcore_h) \
$(gdb_string_h) $(value_h) $(inferior_h) $(dis_asm_h) $(symfile_h) \
- $(objfiles_h) $(language_h) $(arch_utils_h) $(regcache_h) \
- $(remote_h) $(floatformat_h) $(gdb_sim_d10v_h) $(sim_regno_h) \
- $(gdb_assert_h) $(disasm_h)
+ $(objfiles_h) $(language_h) $(arch_utils_h) $(regcache_h) $(remote_h) \
+ $(floatformat_h) $(gdb_sim_d10v_h) $(sim_regno_h) $(disasm_h) \
+ $(trad_frame_h) $(gdb_assert_h)
dbug-rom.o: dbug-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \
$(serial_h) $(regcache_h) $(m68k_tdep_h)
dbxread.o: dbxread.c $(defs_h) $(gdb_string_h) $(gdb_obstack_h) \
$(gdb_string_h) $(inferior_h) $(tracepoint_h) $(remote_h) \
$(linespec_h) $(regcache_h) $(completer_h) $(gdb_events_h) \
$(block_h) $(ax_h) $(ax_gdb_h) $(readline_h)
+trad-frame.o: trad-frame.c $(defs_h) $(frame_h) $(trad_frame_h) $(regcache_h)
typeprint.o: typeprint.c $(defs_h) $(gdb_obstack_h) $(bfd_h) $(symtab_h) \
$(gdbtypes_h) $(expression_h) $(value_h) $(gdbcore_h) $(command_h) \
$(gdbcmd_h) $(target_h) $(language_h) $(cp_abi_h) $(gdb_string_h)
#include "gdb/sim-d10v.h"
#include "sim-regno.h"
#include "disasm.h"
+#include "trad-frame.h"
#include "gdb_assert.h"
/* The frame's base, optionally used by the high-level debug info. */
CORE_ADDR base;
int size;
- CORE_ADDR *saved_regs;
/* How far the SP and r11 (FP) have been offset from the start of
the stack frame (as defined by the previous frame's stack
pointer). */
LONGEST sp_offset;
LONGEST r11_offset;
int uses_frame;
- void **regs;
+ /* Table indicating the location of each and every register. */
+ struct trad_frame *saved_regs;
};
static int
{
n = (op & 0x1E0) >> 5;
info->sp_offset -= 2;
- info->saved_regs[n] = info->sp_offset;
+ info->saved_regs[n].addr = info->sp_offset;
return 1;
}
{
n = (op & 0x1E0) >> 5;
info->sp_offset -= 4;
- info->saved_regs[n] = info->sp_offset;
- info->saved_regs[n + 1] = info->sp_offset + 2;
+ info->saved_regs[n + 0].addr = info->sp_offset + 0;
+ info->saved_regs[n + 1].addr = info->sp_offset + 2;
return 1;
}
if ((op & 0x7E1F) == 0x6816)
{
n = (op & 0x1E0) >> 5;
- info->saved_regs[n] = info->r11_offset;
+ info->saved_regs[n].addr = info->r11_offset;
return 1;
}
if ((op & 0x7E1F) == 0x681E)
{
n = (op & 0x1E0) >> 5;
- info->saved_regs[n] = info->sp_offset;
+ info->saved_regs[n].addr = info->sp_offset;
return 1;
}
if ((op & 0x7E3F) == 0x3A1E)
{
n = (op & 0x1E0) >> 5;
- info->saved_regs[n] = info->sp_offset;
- info->saved_regs[n + 1] = info->sp_offset + 2;
+ info->saved_regs[n + 0].addr = info->sp_offset + 0;
+ info->saved_regs[n + 1].addr = info->sp_offset + 2;
return 1;
}
info = FRAME_OBSTACK_ZALLOC (struct d10v_unwind_cache);
(*this_prologue_cache) = info;
- info->saved_regs = FRAME_OBSTACK_CALLOC (NUM_REGS, CORE_ADDR);
+ info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
info->size = 0;
info->sp_offset = 0;
/* st rn, @(offset,sp) */
short offset = op & 0xFFFF;
short n = (op >> 20) & 0xF;
- info->saved_regs[n] = info->sp_offset + offset;
+ info->saved_regs[n].addr = info->sp_offset + offset;
}
else if ((op & 0x3F1F0000) == 0x350F0000)
{
/* st2w rn, @(offset,sp) */
short offset = op & 0xFFFF;
short n = (op >> 20) & 0xF;
- info->saved_regs[n] = info->sp_offset + offset;
- info->saved_regs[n + 1] = info->sp_offset + offset + 2;
+ info->saved_regs[n + 0].addr = info->sp_offset + offset + 0;
+ info->saved_regs[n + 1].addr = info->sp_offset + offset + 2;
}
else
break;
info->size = -info->sp_offset;
- /* Compute the frame's base, and the previous frame's SP. */
+ /* Compute the previous frame's stack pointer (which is also the
+ frame's ID's stack address), and this frame's base pointer. */
if (info->uses_frame)
{
/* The SP was moved to the FP. This indicates that a new frame
to before the first saved register giving the SP. */
prev_sp = this_base + info->size;
}
- else if (info->saved_regs[D10V_SP_REGNUM])
- {
- /* The SP was saved (which is very unusual), the frame base is
- just the PREV's frame's TOP-OF-STACK. */
- this_base
- = get_frame_memory_unsigned (next_frame,
- info->saved_regs[D10V_SP_REGNUM],
- register_size (gdbarch, D10V_SP_REGNUM));
- prev_sp = this_base;
- }
else
{
/* Assume that the FP is this frame's SP but with that pushed
prev_sp = this_base + info->size;
}
+ /* Convert that SP/BASE into real addresses. */
+ info->prev_sp = d10v_make_daddr (prev_sp);
info->base = d10v_make_daddr (this_base);
- info->prev_sp = d10v_make_daddr (prev_sp);
/* Adjust all the saved registers so that they contain addresses and
not offsets. */
for (i = 0; i < NUM_REGS - 1; i++)
- if (info->saved_regs[i])
+ if (info->saved_regs[i].addr)
{
- info->saved_regs[i] = (info->prev_sp + info->saved_regs[i]);
+ info->saved_regs[i].addr = (info->prev_sp + info->saved_regs[i].addr);
}
- /* The D10V_SP_REGNUM is special. Instead of the address of the SP, the
- previous frame's SP value is saved. */
- info->saved_regs[D10V_SP_REGNUM] = info->prev_sp;
+ /* The call instruction moves the caller's PC in the callee's LR.
+ Since this is an unwind, do the reverse. Copy the location of LR
+ into PC (the address / regnum) so that a request for PC will be
+ converted into a request for the LR. */
+ info->saved_regs[D10V_PC_REGNUM] = info->saved_regs[LR_REGNUM];
+
+ /* The previous frame's SP needed to be computed. Save the computed
+ value. */
+ trad_frame_register_value (info->saved_regs, D10V_SP_REGNUM,
+ d10v_make_daddr (prev_sp));
return info;
}
}
static void
-saved_regs_unwinder (struct frame_info *next_frame,
- CORE_ADDR *this_saved_regs,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *bufferp)
-{
- struct gdbarch *gdbarch = get_frame_arch (next_frame);
- if (this_saved_regs[regnum] != 0)
- {
- if (regnum == D10V_SP_REGNUM)
- {
- /* SP register treated specially. */
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (bufferp != NULL)
- store_unsigned_integer (bufferp,
- register_size (gdbarch, regnum),
- this_saved_regs[regnum]);
- }
- else
- {
- /* Any other register is saved in memory, fetch it but cache
- a local copy of its value. */
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = this_saved_regs[regnum];
- *realnump = -1;
- if (bufferp != NULL)
- {
- /* Read the value in from memory. */
- get_frame_memory (next_frame, this_saved_regs[regnum], bufferp,
- register_size (gdbarch, regnum));
- }
- }
- return;
- }
-
- /* 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. */
- frame_register_unwind (next_frame, regnum, optimizedp, lvalp, addrp,
- realnump, bufferp);
-}
-
-
-static void
d10v_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, int *optimizedp,
{
struct d10v_unwind_cache *info
= d10v_frame_unwind_cache (next_frame, this_prologue_cache);
- if (regnum == D10V_PC_REGNUM)
- {
- /* The call instruction saves the caller's PC in LR. The
- function prologue of the callee may then save the LR on the
- stack. Find that possibly saved LR value and return it. */
- saved_regs_unwinder (next_frame, info->saved_regs, LR_REGNUM, optimizedp,
- lvalp, addrp, realnump, bufferp);
- }
- else
- {
- saved_regs_unwinder (next_frame, info->saved_regs, regnum, optimizedp,
- lvalp, addrp, realnump, bufferp);
- }
+ trad_frame_prev_register (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, bufferp);
}
static const struct frame_unwind d10v_frame_unwind = {
--- /dev/null
+/* Traditional frame unwind support, 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 "trad-frame.h"
+#include "regcache.h"
+
+/* A traditional frame is unwound by analysing the function prologue
+ and using the information gathered to track registers. For
+ non-optimized frames, the technique is reliable (just need to check
+ for all potential instruction sequences). */
+
+struct trad_frame *
+trad_frame_alloc_saved_regs (struct frame_info *next_frame)
+{
+ int i;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ int numregs = NUM_REGS + NUM_PSEUDO_REGS;
+ struct trad_frame *this_saved_regs
+ = FRAME_OBSTACK_CALLOC (numregs, struct trad_frame);
+ for (i = 0; i < numregs; i++)
+ this_saved_regs[i].regnum = i;
+ return this_saved_regs;
+}
+
+void
+trad_frame_register_value (struct trad_frame this_saved_regs[],
+ int regnum, LONGEST val)
+{
+ /* Make the REGNUM invalid, indicating that the ADDR contains the
+ register's value. */
+ this_saved_regs[regnum].regnum = -1;
+ this_saved_regs[regnum].addr = val;
+}
+
+void
+trad_frame_prev_register (struct frame_info *next_frame,
+ struct trad_frame this_saved_regs[],
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp)
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ if (this_saved_regs[regnum].regnum >= 0
+ && this_saved_regs[regnum].addr != 0)
+ {
+ /* The register was saved on the stack, fetch it. */
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = this_saved_regs[regnum].addr;
+ *realnump = -1;
+ if (bufferp != NULL)
+ {
+ /* Read the value in from memory. */
+ get_frame_memory (next_frame, this_saved_regs[regnum].addr, bufferp,
+ register_size (gdbarch, regnum));
+ }
+ }
+ else if (this_saved_regs[regnum].regnum >= 0
+ && this_saved_regs[regnum].addr == 0)
+ {
+ /* As the next frame to return the value of the register. */
+ frame_register_unwind (next_frame, this_saved_regs[regnum].regnum,
+ optimizedp, lvalp, addrp, realnump, bufferp);
+ }
+ else
+ {
+ /* The register's value is available. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (bufferp != NULL)
+ store_unsigned_integer (bufferp, register_size (gdbarch, regnum),
+ this_saved_regs[regnum].addr);
+ }
+}
--- /dev/null
+/* Traditional frame unwind support, 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. */
+
+#ifndef TRAD_FRAME_H
+#define TRAD_FRAME_H
+
+struct trad_frame
+{
+ /* If non-zero (and regnum >= 0), the stack address at which the
+ register is saved. By default, it is assumed that the register
+ was not saved (addr == 0). Remember, a LONGEST can always fit a
+ CORE_ADDR. */
+ LONGEST addr;
+ /* else, if regnum >=0 (and addr == 0), the REGNUM that contains
+ this registers value. By default, it is assumed that the
+ registers are not moved (the register's value is still in that
+ register and regnum == the index). */
+ int regnum;
+ /* else, if regnum < 0, ADDR is the registers value. */
+};
+
+/* Convenience function, encode the register's value in the
+ trad-frame. */
+void trad_frame_register_value (struct trad_frame this_saved_regs[],
+ int regnum, LONGEST val);
+
+/* Return a freshly allocated (and initialized) trad_frame array. */
+struct trad_frame *trad_frame_alloc_saved_regs (struct frame_info *next_frame);
+
+/* Given the trad_frame info, return the location of the specified
+ register. */
+void trad_frame_prev_register (struct frame_info *next_frame,
+ struct trad_frame this_saved_regs[],
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *bufferp);
+
+#endif