+\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. */
+ trad_frame_saved_reg *saved_regs;
+};
+
+static struct vax_frame_cache *
+vax_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct vax_frame_cache *cache;
+ CORE_ADDR addr;
+ ULONGEST mask;
+ int regnum;
+
+ if (*this_cache)
+ return (struct vax_frame_cache *) *this_cache;
+
+ /* Allocate a new cache. */
+ cache = FRAME_OBSTACK_ZALLOC (struct vax_frame_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ /* The frame pointer is used as the base for the frame. */
+ cache->base = get_frame_register_unsigned (this_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 (this_frame, cache->base + 4, 4) >> 16;
+
+ /* These are always saved. */
+ cache->saved_regs[VAX_PC_REGNUM].set_addr (cache->base + 16);
+ cache->saved_regs[VAX_FP_REGNUM].set_addr (cache->base + 12);
+ cache->saved_regs[VAX_AP_REGNUM].set_addr (cache->base + 8);
+ cache->saved_regs[VAX_PS_REGNUM].set_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].set_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 that were pushed onto the
+ stack. The return instruction will automatically pop the
+ arguments from the stack. */
+ numarg = get_frame_memory_unsigned (this_frame, addr, 1);
+ addr += 4 + numarg * 4;
+ }
+
+ /* Bits 1:0 of the stack pointer were saved in the control bits. */
+ cache->saved_regs[VAX_SP_REGNUM].set_value (addr + (mask >> 14));
+
+ return cache;
+}
+
+static void
+vax_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct vax_frame_cache *cache = vax_frame_cache (this_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (cache->base, get_frame_func (this_frame));
+}
+
+static struct value *
+vax_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct vax_frame_cache *cache = vax_frame_cache (this_frame, this_cache);
+
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+static const struct frame_unwind vax_frame_unwind =
+{
+ "vax prologue",
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ vax_frame_this_id,
+ vax_frame_prev_register,
+ NULL,
+ default_frame_sniffer
+};
+\f