#include "inferior.h"
#include "regcache.h"
#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "trad-frame.h"
#include "value.h"
#include "arch-utils.h"
#include "gdb_string.h"
#include "vax-tdep.h"
-static gdbarch_skip_prologue_ftype vax_skip_prologue;
-static gdbarch_frame_num_args_ftype vax_frame_num_args;
-static gdbarch_deprecated_frame_chain_ftype vax_frame_chain;
-
-static gdbarch_deprecated_extract_return_value_ftype vax_extract_return_value;
-
-static gdbarch_deprecated_push_dummy_frame_ftype vax_push_dummy_frame;
-\f
-
/* Return the name of register REGNUM. */
static const char *
return builtin_type_int;
}
\f
-static void
-vax_frame_init_saved_regs (struct frame_info *frame)
-{
- int regnum, regmask;
- CORE_ADDR next_addr;
-
- if (deprecated_get_frame_saved_regs (frame))
- return;
-
- frame_saved_regs_zalloc (frame);
-
- regmask = read_memory_integer (get_frame_base (frame) + 4, 4) >> 16;
-
- next_addr = get_frame_base (frame) + 16;
-
- /* regmask's low bit is for register 0, which is the first one
- what would be pushed. */
- for (regnum = 0; regnum < VAX_AP_REGNUM; regnum++)
- {
- if (regmask & (1 << regnum))
- deprecated_get_frame_saved_regs (frame)[regnum] = next_addr += 4;
- }
-
- deprecated_get_frame_saved_regs (frame)[SP_REGNUM] = next_addr + 4;
- if (regmask & (1 << DEPRECATED_FP_REGNUM))
- deprecated_get_frame_saved_regs (frame)[SP_REGNUM] +=
- 4 + (4 * read_memory_integer (next_addr + 4, 4));
-
- deprecated_get_frame_saved_regs (frame)[PC_REGNUM] = get_frame_base (frame) + 16;
- deprecated_get_frame_saved_regs (frame)[DEPRECATED_FP_REGNUM] = get_frame_base (frame) + 12;
- deprecated_get_frame_saved_regs (frame)[VAX_AP_REGNUM] = get_frame_base (frame) + 8;
- deprecated_get_frame_saved_regs (frame)[PS_REGNUM] = get_frame_base (frame) + 4;
-}
-
-/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp. */
-
-static CORE_ADDR
-vax_sigtramp_saved_pc (struct frame_info *frame)
-{
- CORE_ADDR sigcontext_addr;
- char *buf;
- int ptrbytes = TYPE_LENGTH (builtin_type_void_func_ptr);
- int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT;
-
- buf = alloca (ptrbytes);
- /* Get sigcontext address, it is the third parameter on the stack. */
- if (get_next_frame (frame))
- sigcontext_addr = read_memory_typed_address
- (DEPRECATED_FRAME_ARGS_ADDRESS (get_next_frame (frame))
- + FRAME_ARGS_SKIP + sigcontext_offs,
- builtin_type_void_data_ptr);
- else
- sigcontext_addr = read_memory_typed_address
- (read_register (SP_REGNUM) + sigcontext_offs, builtin_type_void_data_ptr);
-
- /* Offset to saved PC in sigcontext, from <sys/signal.h>. Don't
- cause a memory_error when accessing sigcontext in case the stack
- layout has changed or the stack is corrupt. */
- target_read_memory (sigcontext_addr + 12, buf, ptrbytes);
- return extract_typed_address (buf, builtin_type_void_func_ptr);
-}
-
-static CORE_ADDR
-vax_frame_saved_pc (struct frame_info *frame)
-{
- if ((get_frame_type (frame) == SIGTRAMP_FRAME))
- return (vax_sigtramp_saved_pc (frame)); /* XXXJRT */
-
- return (read_memory_integer (get_frame_base (frame) + 16, 4));
-}
-
-static CORE_ADDR
-vax_frame_args_address (struct frame_info *frame)
-{
- /* In most of GDB, getting the args address is too important to just
- say "I don't know". This is sometimes wrong for functions that
- aren't on top of the stack, but c'est la vie. */
- if (get_next_frame (frame))
- return (read_memory_integer (get_frame_base (get_next_frame (frame)) + 8, 4));
- /* Cannot find the AP register value directly from the FP value.
- Must find it saved in the frame called by this one, or in the AP
- register for the innermost frame. However, there is no way to
- tell the difference between the innermost frame and a frame for
- which we just don't know the frame that it called (e.g. "info
- frame 0x7ffec789"). For the sake of argument, suppose that the
- stack is somewhat trashed (which is one reason that "info frame"
- exists). So, return 0 (indicating we don't know the address of
- the arglist) if we don't know what frame this frame calls. */
- return 0;
-}
-
-static int
-vax_frame_num_args (struct frame_info *fi)
-{
- return (0xff & read_memory_integer (DEPRECATED_FRAME_ARGS_ADDRESS (fi), 1));
-}
-static CORE_ADDR
-vax_frame_chain (struct frame_info *frame)
-{
- /* In the case of the VAX, the frame's nominal address is the FP value,
- and 12 bytes later comes the saved previous FP value as a 4-byte word. */
- return (read_memory_integer (get_frame_base (frame) + 12, 4));
-}
-\f
static void
vax_push_dummy_frame (void)
{
for (regnum = 11; regnum >= 0; regnum--)
sp = push_word (sp, read_register (regnum));
sp = push_word (sp, read_register (PC_REGNUM));
- sp = push_word (sp, read_register (DEPRECATED_FP_REGNUM));
+ sp = push_word (sp, read_register (VAX_FP_REGNUM));
sp = push_word (sp, read_register (VAX_AP_REGNUM));
sp = push_word (sp, (read_register (PS_REGNUM) & 0xffef) + 0x2fff0000);
sp = push_word (sp, 0);
write_register (SP_REGNUM, sp);
- write_register (DEPRECATED_FP_REGNUM, sp);
+ write_register (VAX_FP_REGNUM, sp);
write_register (VAX_AP_REGNUM, sp + (17 * 4));
}
static void
vax_pop_frame (void)
{
- CORE_ADDR fp = read_register (DEPRECATED_FP_REGNUM);
+ CORE_ADDR fp = read_register (VAX_FP_REGNUM);
int regnum;
int regmask = read_memory_integer (fp + 4, 4);
(regmask & 0xffff)
| (read_register (PS_REGNUM) & 0xffff0000));
write_register (PC_REGNUM, read_memory_integer (fp + 16, 4));
- write_register (DEPRECATED_FP_REGNUM, read_memory_integer (fp + 12, 4));
+ write_register (VAX_FP_REGNUM, read_memory_integer (fp + 12, 4));
write_register (VAX_AP_REGNUM, read_memory_integer (fp + 8, 4));
fp += 16;
for (regnum = 0; regnum < 12; regnum++)
pc += 7; /* skip movab */
return pc;
}
+\f
+
+/* Unwinding the stack is relatively easy since the VAX has a
+ dedicated frame pointer, and frames are set up automatically as the
+ result of a function call. Most of the relevant information can be
+ inferred from the documentation of the Procedure Call Instructions
+ in the VAX MACRO and Instruction Set Reference Manual. */
+
+struct vax_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+
+ /* Table of saved registers. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+struct vax_frame_cache *
+vax_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct vax_frame_cache *cache;
+ CORE_ADDR addr;
+ ULONGEST mask;
+ int regnum;
+
+ if (*this_cache)
+ return *this_cache;
+
+ /* Allocate a new cache. */
+ cache = FRAME_OBSTACK_ZALLOC (struct vax_frame_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* The frame pointer is used as the base for the frame. */
+ cache->base = frame_unwind_register_unsigned (next_frame, VAX_FP_REGNUM);
+ if (cache->base == 0)
+ return cache;
+
+ /* The register save mask and control bits determine the layout of
+ the stack frame. */
+ mask = get_frame_memory_unsigned (next_frame, cache->base + 4, 4) >> 16;
+
+ /* These are always saved. */
+ cache->saved_regs[VAX_PC_REGNUM].addr = cache->base + 16;
+ cache->saved_regs[VAX_FP_REGNUM].addr = cache->base + 12;
+ cache->saved_regs[VAX_AP_REGNUM].addr = cache->base + 8;
+ cache->saved_regs[VAX_PS_REGNUM].addr = cache->base + 4;
+
+ /* Scan the register save mask and record the location of the saved
+ registers. */
+ addr = cache->base + 20;
+ for (regnum = 0; regnum < VAX_AP_REGNUM; regnum++)
+ {
+ if (mask & (1 << regnum))
+ {
+ cache->saved_regs[regnum].addr = addr;
+ addr += 4;
+ }
+ }
+
+ /* The CALLS/CALLG flag determines whether this frame has a General
+ Argument List or a Stack Argument List. */
+ if (mask & (1 << 13))
+ {
+ ULONGEST numarg;
+
+ /* This is a procedure with Stack Argument List. Adjust the
+ stack address for the arguments thet were pushed onto the
+ stack. The return instruction will automatically pop the
+ arguments from the stack. */
+ numarg = get_frame_memory_unsigned (next_frame, addr, 1);
+ addr += 4 + numarg * 4;
+ }
+
+ /* Bits 1:0 of the stack pointer were saved in the control bits. */
+ trad_frame_set_value (cache->saved_regs, VAX_SP_REGNUM, addr + (mask >> 14));
+
+ return cache;
+}
+
+static void
+vax_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct vax_frame_cache *cache = vax_frame_cache (next_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (cache->base, frame_pc_unwind (next_frame));
+}
+
+static void
+vax_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct vax_frame_cache *cache = vax_frame_cache (next_frame, this_cache);
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind vax_frame_unwind =
+{
+ NORMAL_FRAME,
+ vax_frame_this_id,
+ vax_frame_prev_register
+};
+
+static const struct frame_unwind *
+vax_frame_sniffer (struct frame_info *next_frame)
+{
+ return &vax_frame_unwind;
+}
+\f
+
+static CORE_ADDR
+vax_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+ struct vax_frame_cache *cache = vax_frame_cache (next_frame, this_cache);
+
+ return cache->base;
+}
static CORE_ADDR
-vax_saved_pc_after_call (struct frame_info *frame)
+vax_frame_args_address (struct frame_info *next_frame, void **this_cache)
+{
+ return frame_unwind_register_unsigned (next_frame, VAX_AP_REGNUM);
+}
+
+static const struct frame_base vax_frame_base =
{
- return (DEPRECATED_FRAME_SAVED_PC(frame));
+ &vax_frame_unwind,
+ vax_frame_base_address,
+ vax_frame_base_address,
+ vax_frame_args_address
+};
+
+/* Return number of arguments for FRAME. */
+
+static int
+vax_frame_num_args (struct frame_info *frame)
+{
+ CORE_ADDR args;
+
+ /* Assume that the argument pointer for the outermost frame is
+ hosed, as is the case on NetBSD/vax ELF. */
+ if (get_frame_base (frame) == 0)
+ return 0;
+
+ args = get_frame_register_unsigned (frame, VAX_AP_REGNUM);
+ return get_frame_memory_unsigned (frame, args, 1);
+}
+
+static CORE_ADDR
+vax_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, VAX_PC_REGNUM);
}
\f
+
/* Initialize the current architecture based on INFO. If possible, re-use an
architecture from ARCHES, which is a list of architectures already created
during this debugging session.
gdbarch = gdbarch_alloc (&info, NULL);
- /* NOTE: cagney/2002-12-06: This can be deleted when this arch is
- ready to unwind the PC first (see frame.c:get_prev_frame()). */
- set_gdbarch_deprecated_init_frame_pc (gdbarch, deprecated_init_frame_pc_default);
-
/* Register info */
set_gdbarch_num_regs (gdbarch, VAX_NUM_REGS);
set_gdbarch_register_name (gdbarch, vax_register_name);
set_gdbarch_register_type (gdbarch, vax_register_type);
set_gdbarch_sp_regnum (gdbarch, VAX_SP_REGNUM);
- set_gdbarch_deprecated_fp_regnum (gdbarch, VAX_FP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, VAX_PC_REGNUM);
set_gdbarch_ps_regnum (gdbarch, VAX_PS_REGNUM);
/* Frame and stack info */
set_gdbarch_skip_prologue (gdbarch, vax_skip_prologue);
- set_gdbarch_deprecated_saved_pc_after_call (gdbarch, vax_saved_pc_after_call);
-
set_gdbarch_frame_num_args (gdbarch, vax_frame_num_args);
- set_gdbarch_deprecated_frame_chain (gdbarch, vax_frame_chain);
- set_gdbarch_deprecated_frame_saved_pc (gdbarch, vax_frame_saved_pc);
-
- set_gdbarch_deprecated_frame_args_address (gdbarch, vax_frame_args_address);
-
- set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, vax_frame_init_saved_regs);
-
set_gdbarch_frame_args_skip (gdbarch, 4);
/* Stack grows downward. */
/* Should be using push_dummy_call. */
set_gdbarch_deprecated_dummy_write_sp (gdbarch, deprecated_write_sp);
+ set_gdbarch_unwind_pc (gdbarch, vax_unwind_pc);
+
+ frame_base_set_default (gdbarch, &vax_frame_base);
+
/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
+ frame_unwind_append_sniffer (gdbarch, vax_frame_sniffer);
+
set_gdbarch_print_insn (gdbarch, print_insn_vax);
return (gdbarch);