-/* Print VAX instructions for GDB, the GNU debugger.
- Copyright 1986, 1989, 1991, 1992, 1995, 1996, 1998, 1999, 2000, 2002
- Free Software Foundation, Inc.
+/* Target-dependent code for the VAX.
+
+ Copyright 1986, 1989, 1991, 1992, 1995, 1996, 1998, 1999, 2000,
+ 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
Boston, MA 02111-1307, USA. */
#include "defs.h"
-#include "symtab.h"
-#include "opcode/vax.h"
+#include "arch-utils.h"
+#include "dis-asm.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
#include "gdbcore.h"
-#include "inferior.h"
+#include "gdbtypes.h"
+#include "osabi.h"
#include "regcache.h"
-#include "frame.h"
+#include "regset.h"
+#include "trad-frame.h"
#include "value.h"
-#include "arch-utils.h"
+
#include "gdb_string.h"
#include "vax-tdep.h"
-static gdbarch_register_name_ftype vax_register_name;
-static gdbarch_register_byte_ftype vax_register_byte;
-static gdbarch_register_raw_size_ftype vax_register_raw_size;
-static gdbarch_register_virtual_size_ftype vax_register_virtual_size;
-static gdbarch_register_virtual_type_ftype vax_register_virtual_type;
-
-static gdbarch_skip_prologue_ftype vax_skip_prologue;
-static gdbarch_saved_pc_after_call_ftype vax_saved_pc_after_call;
-static gdbarch_frame_num_args_ftype vax_frame_num_args;
-static gdbarch_frame_chain_ftype vax_frame_chain;
-static gdbarch_frame_saved_pc_ftype vax_frame_saved_pc;
-static gdbarch_frame_args_address_ftype vax_frame_args_address;
-static gdbarch_frame_locals_address_ftype vax_frame_locals_address;
-static gdbarch_frame_init_saved_regs_ftype vax_frame_init_saved_regs;
-
-static gdbarch_store_struct_return_ftype vax_store_struct_return;
-static gdbarch_deprecated_extract_return_value_ftype vax_extract_return_value;
-static gdbarch_deprecated_extract_struct_value_address_ftype
- vax_extract_struct_value_address;
-
-static gdbarch_push_dummy_frame_ftype vax_push_dummy_frame;
-static gdbarch_pop_frame_ftype vax_pop_frame;
-static gdbarch_fix_call_dummy_ftype vax_fix_call_dummy;
-
-/* Return 1 if P points to an invalid floating point value.
- LEN is the length in bytes -- not relevant on the Vax. */
-
-/* FIXME: cagney/2002-01-19: The macro below was originally defined in
- tm-vax.h and used in values.c. Two problems. Firstly this is a
- very non-portable and secondly it is wrong. The VAX should be
- using floatformat and associated methods to identify and handle
- invalid floating-point values. Adding to the poor target's woes
- there is no floatformat_vax_{f,d} and no TARGET_FLOAT_FORMAT
- et.al.. */
-
-/* FIXME: cagney/2002-01-19: It turns out that the only thing that
- uses this macro is the vax disassembler code (so how old is this
- target?). This target should instead be using the opcodes
- disassembler. That allowing the macro to be eliminated. */
-
-#define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000)
-
-/* Vax instructions are never longer than this. */
-#define MAXLEN 62
-
-/* Number of elements in the opcode table. */
-#define NOPCODES (sizeof votstrs / sizeof votstrs[0])
-
-static unsigned char *print_insn_arg ();
-\f
+/* Return the name of register REGNUM. */
+
static const char *
-vax_register_name (int regno)
+vax_register_name (int regnum)
{
static char *register_names[] =
{
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc",
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc",
"ps",
};
- if (regno < 0)
- return (NULL);
- if (regno >= (sizeof(register_names) / sizeof(*register_names)))
- return (NULL);
- return (register_names[regno]);
-}
+ if (regnum >= 0 && regnum < ARRAY_SIZE (register_names))
+ return register_names[regnum];
-static int
-vax_register_byte (int regno)
-{
- return (regno * 4);
+ return NULL;
}
-static int
-vax_register_raw_size (int regno)
-{
- return (4);
-}
-
-static int
-vax_register_virtual_size (int regno)
-{
- return (4);
-}
+/* Return the GDB type object for the "standard" data type of data in
+ register REGNUM. */
static struct type *
-vax_register_virtual_type (int regno)
+vax_register_type (struct gdbarch *gdbarch, int regnum)
{
- return (builtin_type_int);
+ return builtin_type_int;
}
\f
-static void
-vax_frame_init_saved_regs (struct frame_info *frame)
-{
- int regnum, regmask;
- CORE_ADDR next_addr;
-
- if (frame->saved_regs)
- return;
-
- frame_saved_regs_zalloc (frame);
+/* Core file support. */
- regmask = read_memory_integer (frame->frame + 4, 4) >> 16;
+/* Supply register REGNUM from the buffer specified by GREGS and LEN
+ in the general-purpose register set REGSET to register cache
+ REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
- next_addr = frame->frame + 16;
+static void
+vax_supply_gregset (const struct regset *regset, struct regcache *regcache,
+ int regnum, const void *gregs, size_t len)
+{
+ const char *regs = gregs;
+ int i;
- /* 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++)
+ for (i = 0; i < VAX_NUM_REGS; i++)
{
- if (regmask & (1 << regnum))
- frame->saved_regs[regnum] = next_addr += 4;
+ if (regnum == i || regnum == -1)
+ regcache_raw_supply (regcache, i, regs + i * 4);
}
+}
- frame->saved_regs[SP_REGNUM] = next_addr + 4;
- if (regmask & (1 << FP_REGNUM))
- frame->saved_regs[SP_REGNUM] +=
- 4 + (4 * read_memory_integer (next_addr + 4, 4));
+/* VAX register set. */
- frame->saved_regs[PC_REGNUM] = frame->frame + 16;
- frame->saved_regs[FP_REGNUM] = frame->frame + 12;
- frame->saved_regs[VAX_AP_REGNUM] = frame->frame + 8;
- frame->saved_regs[PS_REGNUM] = frame->frame + 4;
-}
+static struct regset vax_gregset =
+{
+ NULL,
+ vax_supply_gregset
+};
-/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp. */
+/* Return the appropriate register set for the core section identified
+ by SECT_NAME and SECT_SIZE. */
-static CORE_ADDR
-vax_sigtramp_saved_pc (struct frame_info *frame)
+static const struct regset *
+vax_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name, size_t sect_size)
{
- 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 (frame->next)
- sigcontext_addr = read_memory_typed_address
- (FRAME_ARGS_ADDRESS (frame->next) + 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);
-
- /* 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 + SIGCONTEXT_PC_OFFSET, buf, ptrbytes);
- return extract_typed_address (buf, builtin_type_void_func_ptr);
+ if (strcmp (sect_name, ".reg") == 0 && sect_size >= VAX_NUM_REGS * 4)
+ return &vax_gregset;
+
+ return NULL;
}
+\f
+/* The VAX UNIX calling convention uses R1 to pass a structure return
+ value address instead of passing it as a first (hidden) argument as
+ the VMS calling convention suggests. */
static CORE_ADDR
-vax_frame_saved_pc (struct frame_info *frame)
+vax_store_arguments (struct regcache *regcache, int nargs,
+ struct value **args, CORE_ADDR sp)
{
- if ((get_frame_type (frame) == SIGTRAMP_FRAME))
- return (vax_sigtramp_saved_pc (frame)); /* XXXJRT */
+ char buf[4];
+ int count = 0;
+ int i;
- return (read_memory_integer (frame->frame + 16, 4));
-}
+ /* We create an argument list on the stack, and make the argument
+ pointer to it. */
-CORE_ADDR
-vax_frame_args_address_correct (struct frame_info *frame)
-{
- /* 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. */
- if (frame->next)
- return (read_memory_integer (frame->next->frame + 8, 4));
-
- return (0);
-}
+ /* Push arguments in reverse order. */
+ for (i = nargs - 1; i >= 0; i--)
+ {
+ int len = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (args[i]));
-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 (frame->next)
- return (read_memory_integer (frame->next->frame + 8, 4));
+ sp -= (len + 3) & ~3;
+ count += (len + 3) / 4;
+ write_memory (sp, VALUE_CONTENTS_ALL (args[i]), len);
+ }
- return (read_register (VAX_AP_REGNUM));
-}
+ /* Push argument count. */
+ sp -= 4;
+ store_unsigned_integer (buf, 4, count);
+ write_memory (sp, buf, 4);
-static CORE_ADDR
-vax_frame_locals_address (struct frame_info *frame)
-{
- return (frame->frame);
-}
+ /* Update the argument pointer. */
+ store_unsigned_integer (buf, 4, sp);
+ regcache_cooked_write (regcache, VAX_AP_REGNUM, buf);
-static int
-vax_frame_num_args (struct frame_info *fi)
-{
- return (0xff & read_memory_integer (FRAME_ARGS_ADDRESS (fi), 1));
+ return sp;
}
static CORE_ADDR
-vax_frame_chain (struct frame_info *frame)
+vax_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+ struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
+ struct value **args, CORE_ADDR sp, int struct_return,
+ CORE_ADDR struct_addr)
{
- /* 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. */
- if (inside_entry_file (get_frame_pc (frame)))
- return (0);
-
- return (read_memory_integer (frame->frame + 12, 4));
+ CORE_ADDR fp = sp;
+ char buf[4];
+
+ /* Set up the function arguments. */
+ sp = vax_store_arguments (regcache, nargs, args, sp);
+
+ /* Store return value address. */
+ if (struct_return)
+ regcache_cooked_write_unsigned (regcache, VAX_R1_REGNUM, struct_addr);
+
+ /* Store return address in the PC slot. */
+ sp -= 4;
+ store_unsigned_integer (buf, 4, bp_addr);
+ write_memory (sp, buf, 4);
+
+ /* Store the (fake) frame pointer in the FP slot. */
+ sp -= 4;
+ store_unsigned_integer (buf, 4, fp);
+ write_memory (sp, buf, 4);
+
+ /* Skip the AP slot. */
+ sp -= 4;
+
+ /* Store register save mask and control bits. */
+ sp -= 4;
+ store_unsigned_integer (buf, 4, 0);
+ write_memory (sp, buf, 4);
+
+ /* Store condition handler. */
+ sp -= 4;
+ store_unsigned_integer (buf, 4, 0);
+ write_memory (sp, buf, 4);
+
+ /* Update the stack pointer and frame pointer. */
+ store_unsigned_integer (buf, 4, sp);
+ regcache_cooked_write (regcache, VAX_SP_REGNUM, buf);
+ regcache_cooked_write (regcache, VAX_FP_REGNUM, buf);
+
+ /* Return the saved (fake) frame pointer. */
+ return fp;
}
-\f
-static void
-vax_push_dummy_frame (void)
+
+static struct frame_id
+vax_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- CORE_ADDR sp = read_register (SP_REGNUM);
- int regnum;
+ CORE_ADDR fp;
- sp = push_word (sp, 0); /* arglist */
- 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 (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 (FP_REGNUM, sp);
- write_register (VAX_AP_REGNUM, sp + (17 * 4));
+ fp = frame_unwind_register_unsigned (next_frame, VAX_FP_REGNUM);
+ return frame_id_build (fp, frame_pc_unwind (next_frame));
}
+\f
-static void
-vax_pop_frame (void)
+static enum return_value_convention
+vax_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, void *readbuf,
+ const void *writebuf)
{
- CORE_ADDR fp = read_register (FP_REGNUM);
- int regnum;
- int regmask = read_memory_integer (fp + 4, 4);
-
- write_register (PS_REGNUM,
- (regmask & 0xffff)
- | (read_register (PS_REGNUM) & 0xffff0000));
- write_register (PC_REGNUM, read_memory_integer (fp + 16, 4));
- write_register (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++)
- if (regmask & (0x10000 << regnum))
- write_register (regnum, read_memory_integer (fp += 4, 4));
- fp = fp + 4 + ((regmask >> 30) & 3);
- if (regmask & 0x20000000)
- {
- regnum = read_memory_integer (fp, 4);
- fp += (regnum + 1) * 4;
- }
- write_register (SP_REGNUM, fp);
- flush_cached_frames ();
-}
+ int len = TYPE_LENGTH (type);
+ char buf[8];
-/* The VAX call dummy sequence:
-
- calls #69, @#32323232
- bpt
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION
+ || TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ /* The default on VAX is to return structures in static memory.
+ Consequently a function must return the address where we can
+ find the return value. */
- It is 8 bytes long. The address and argc are patched by
- vax_fix_call_dummy(). */
-static LONGEST vax_call_dummy_words[] = { 0x329f69fb, 0x03323232 };
-static int sizeof_vax_call_dummy_words = sizeof(vax_call_dummy_words);
+ if (readbuf)
+ {
+ ULONGEST addr;
-static void
-vax_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
- struct value **args, struct type *type, int gcc_p)
-{
- dummy[1] = nargs;
- store_unsigned_integer (dummy + 3, 4, fun);
-}
-\f
-static void
-vax_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
-{
- write_register (1, addr);
-}
+ regcache_raw_read_unsigned (regcache, VAX_R0_REGNUM, &addr);
+ read_memory (addr, readbuf, len);
+ }
-static void
-vax_extract_return_value (struct type *valtype, char *regbuf, char *valbuf)
-{
- memcpy (valbuf, regbuf + REGISTER_BYTE (0), TYPE_LENGTH (valtype));
-}
+ return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+ }
-static void
-vax_store_return_value (struct type *valtype, char *valbuf)
-{
- deprecated_write_register_bytes (0, valbuf, TYPE_LENGTH (valtype));
-}
+ if (readbuf)
+ {
+ /* Read the contents of R0 and (if necessary) R1. */
+ regcache_cooked_read (regcache, VAX_R0_REGNUM, buf);
+ if (len > 4)
+ regcache_cooked_read (regcache, VAX_R1_REGNUM, buf + 4);
+ memcpy (readbuf, buf, len);
+ }
+ if (writebuf)
+ {
+ /* Read the contents to R0 and (if necessary) R1. */
+ memcpy (buf, writebuf, len);
+ regcache_cooked_write (regcache, VAX_R0_REGNUM, buf);
+ if (len > 4)
+ regcache_cooked_write (regcache, VAX_R1_REGNUM, buf + 4);
+ }
-static CORE_ADDR
-vax_extract_struct_value_address (char *regbuf)
-{
- return (extract_address (regbuf + REGISTER_BYTE (0), REGISTER_RAW_SIZE (0)));
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
\f
+
+/* Use the program counter to determine the contents and size of a
+ breakpoint instruction. Return a pointer to a string of bytes that
+ encode a breakpoint instruction, store the length of the string in
+ *LEN and optionally adjust *PC to point to the correct memory
+ location for inserting the breakpoint. */
+
static const unsigned char *
-vax_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+vax_breakpoint_from_pc (CORE_ADDR *pc, int *len)
{
- static const unsigned char vax_breakpoint[] = { 3 };
+ static unsigned char break_insn[] = { 3 };
- *lenptr = sizeof(vax_breakpoint);
- return (vax_breakpoint);
+ *len = sizeof (break_insn);
+ return break_insn;
}
\f
/* Advance PC across any function entry prologue instructions
static CORE_ADDR
vax_skip_prologue (CORE_ADDR pc)
{
- register int op = (unsigned char) read_memory_integer (pc, 1);
+ unsigned char op = read_memory_unsigned_integer (pc, 1);
+
if (op == 0x11)
pc += 2; /* skip brb */
if (op == 0x31)
pc += 3; /* skip brw */
if (op == 0xC2
- && ((unsigned char) read_memory_integer (pc + 2, 1)) == 0x5E)
+ && (read_memory_unsigned_integer (pc + 2, 1)) == 0x5E)
pc += 3; /* skip subl2 */
if (op == 0x9E
- && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xAE
- && ((unsigned char) read_memory_integer (pc + 3, 1)) == 0x5E)
+ && (read_memory_unsigned_integer (pc + 1, 1)) == 0xAE
+ && (read_memory_unsigned_integer (pc + 3, 1)) == 0x5E)
pc += 4; /* skip movab */
if (op == 0x9E
- && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xCE
- && ((unsigned char) read_memory_integer (pc + 4, 1)) == 0x5E)
+ && (read_memory_unsigned_integer (pc + 1, 1)) == 0xCE
+ && (read_memory_unsigned_integer (pc + 4, 1)) == 0x5E)
pc += 5; /* skip movab */
if (op == 0x9E
- && ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xEE
- && ((unsigned char) read_memory_integer (pc + 6, 1)) == 0x5E)
+ && (read_memory_unsigned_integer (pc + 1, 1)) == 0xEE
+ && (read_memory_unsigned_integer (pc + 6, 1)) == 0x5E)
pc += 7; /* skip movab */
+
return pc;
}
+\f
-static CORE_ADDR
-vax_saved_pc_after_call (struct frame_info *frame)
+/* 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
{
- return (FRAME_SAVED_PC(frame));
-}
-\f
-/* Print the vax instruction at address MEMADDR in debugged memory,
- from disassembler info INFO.
- Returns length of the instruction, in bytes. */
+ /* Base address. */
+ CORE_ADDR base;
-static int
-vax_print_insn (CORE_ADDR memaddr, disassemble_info *info)
+ /* 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)
{
- unsigned char buffer[MAXLEN];
- register int i;
- register unsigned char *p;
- const char *d;
+ 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;
- int status = (*info->read_memory_func) (memaddr, buffer, MAXLEN, info);
- if (status != 0)
+ /* 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++)
{
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
+ if (mask & (1 << regnum))
+ {
+ cache->saved_regs[regnum].addr = addr;
+ addr += 4;
+ }
}
- for (i = 0; i < NOPCODES; i++)
- if (votstrs[i].detail.code == buffer[0]
- || votstrs[i].detail.code == *(unsigned short *) buffer)
- break;
-
- /* Handle undefined instructions. */
- if (i == NOPCODES)
+ /* The CALLS/CALLG flag determines whether this frame has a General
+ Argument List or a Stack Argument List. */
+ if (mask & (1 << 13))
{
- (*info->fprintf_func) (info->stream, "0%o", buffer[0]);
- return 1;
+ 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 (next_frame, addr, 1);
+ addr += 4 + numarg * 4;
}
- (*info->fprintf_func) (info->stream, "%s", votstrs[i].name);
+ /* 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));
- /* Point at first byte of argument data,
- and at descriptor for first argument. */
- p = buffer + 1 + (votstrs[i].detail.code >= 0x100);
- d = votstrs[i].detail.args;
+ return cache;
+}
- if (*d)
- (*info->fprintf_func) (info->stream, " ");
+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);
- while (*d)
- {
- p = print_insn_arg (d, p, memaddr + (p - buffer), info);
- d += 2;
- if (*d)
- (*info->fprintf_func) (info->stream, ",");
- }
- return p - buffer;
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (cache->base, frame_func_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_get_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 unsigned char *
-print_insn_arg (char *d, register char *p, CORE_ADDR addr,
- disassemble_info *info)
+
+static CORE_ADDR
+vax_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
- register int regnum = *p & 0xf;
- float floatlitbuf;
+ struct vax_frame_cache *cache = vax_frame_cache (next_frame, this_cache);
- if (*d == 'b')
- {
- if (d[1] == 'b')
- (*info->fprintf_func) (info->stream, "0x%x", addr + *p++ + 1);
- else
- {
- (*info->fprintf_func) (info->stream, "0x%x", addr + *(short *) p + 2);
- p += 2;
- }
- }
- else
- switch ((*p++ >> 4) & 0xf)
- {
- case 0:
- case 1:
- case 2:
- case 3: /* Literal mode */
- if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
- {
- *(int *) &floatlitbuf = 0x4000 + ((p[-1] & 0x3f) << 4);
- (*info->fprintf_func) (info->stream, "$%f", floatlitbuf);
- }
- else
- (*info->fprintf_func) (info->stream, "$%d", p[-1] & 0x3f);
- break;
-
- case 4: /* Indexed */
- p = (char *) print_insn_arg (d, p, addr + 1, info);
- (*info->fprintf_func) (info->stream, "[%s]", REGISTER_NAME (regnum));
- break;
-
- case 5: /* Register */
- (*info->fprintf_func) (info->stream, REGISTER_NAME (regnum));
- break;
-
- case 7: /* Autodecrement */
- (*info->fprintf_func) (info->stream, "-");
- case 6: /* Register deferred */
- (*info->fprintf_func) (info->stream, "(%s)", REGISTER_NAME (regnum));
- break;
-
- case 9: /* Autoincrement deferred */
- (*info->fprintf_func) (info->stream, "@");
- if (regnum == PC_REGNUM)
- {
- (*info->fprintf_func) (info->stream, "#");
- info->target = *(long *) p;
- (*info->print_address_func) (info->target, info);
- p += 4;
- break;
- }
- case 8: /* Autoincrement */
- if (regnum == PC_REGNUM)
- {
- (*info->fprintf_func) (info->stream, "#");
- switch (d[1])
- {
- case 'b':
- (*info->fprintf_func) (info->stream, "%d", *p++);
- break;
-
- case 'w':
- (*info->fprintf_func) (info->stream, "%d", *(short *) p);
- p += 2;
- break;
-
- case 'l':
- (*info->fprintf_func) (info->stream, "%d", *(long *) p);
- p += 4;
- break;
-
- case 'q':
- (*info->fprintf_func) (info->stream, "0x%x%08x",
- ((long *) p)[1], ((long *) p)[0]);
- p += 8;
- break;
-
- case 'o':
- (*info->fprintf_func) (info->stream, "0x%x%08x%08x%08x",
- ((long *) p)[3], ((long *) p)[2],
- ((long *) p)[1], ((long *) p)[0]);
- p += 16;
- break;
-
- case 'f':
- if (INVALID_FLOAT (p, 4))
- (*info->fprintf_func) (info->stream,
- "<<invalid float 0x%x>>",
- *(int *) p);
- else
- (*info->fprintf_func) (info->stream, "%f", *(float *) p);
- p += 4;
- break;
-
- case 'd':
- if (INVALID_FLOAT (p, 8))
- (*info->fprintf_func) (info->stream,
- "<<invalid float 0x%x%08x>>",
- ((long *) p)[1], ((long *) p)[0]);
- else
- (*info->fprintf_func) (info->stream, "%f", *(double *) p);
- p += 8;
- break;
-
- case 'g':
- (*info->fprintf_func) (info->stream, "g-float");
- p += 8;
- break;
-
- case 'h':
- (*info->fprintf_func) (info->stream, "h-float");
- p += 16;
- break;
-
- }
- }
- else
- (*info->fprintf_func) (info->stream, "(%s)+", REGISTER_NAME (regnum));
- break;
-
- case 11: /* Byte displacement deferred */
- (*info->fprintf_func) (info->stream, "@");
- case 10: /* Byte displacement */
- if (regnum == PC_REGNUM)
- {
- info->target = addr + *p + 2;
- (*info->print_address_func) (info->target, info);
- }
- else
- (*info->fprintf_func) (info->stream, "%d(%s)", *p, REGISTER_NAME (regnum));
- p += 1;
- break;
-
- case 13: /* Word displacement deferred */
- (*info->fprintf_func) (info->stream, "@");
- case 12: /* Word displacement */
- if (regnum == PC_REGNUM)
- {
- info->target = addr + *(short *) p + 3;
- (*info->print_address_func) (info->target, info);
- }
- else
- (*info->fprintf_func) (info->stream, "%d(%s)",
- *(short *) p, REGISTER_NAME (regnum));
- p += 2;
- break;
-
- case 15: /* Long displacement deferred */
- (*info->fprintf_func) (info->stream, "@");
- case 14: /* Long displacement */
- if (regnum == PC_REGNUM)
- {
- info->target = addr + *(short *) p + 5;
- (*info->print_address_func) (info->target, info);
- }
- else
- (*info->fprintf_func) (info->stream, "%d(%s)",
- *(long *) p, REGISTER_NAME (regnum));
- p += 4;
- }
-
- return (unsigned char *) p;
+ return cache->base;
+}
+
+static CORE_ADDR
+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 =
+{
+ &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_address (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.
static struct gdbarch *
vax_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
- struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
- enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
-
- /* Try to determine the ABI of the object we are loading. */
-
- if (info.abfd != NULL)
- osabi = gdbarch_lookup_osabi (info.abfd);
-
- /* Find a candidate among extant architectures. */
- for (arches = gdbarch_list_lookup_by_info (arches, &info);
- arches != NULL;
- arches = gdbarch_list_lookup_by_info (arches->next, &info))
- {
- /* Make sure the ABI selection matches. */
- tdep = gdbarch_tdep (arches->gdbarch);
- if (tdep && tdep->osabi == osabi)
- return arches->gdbarch;
- }
- tdep = xmalloc (sizeof (struct gdbarch_tdep));
- gdbarch = gdbarch_alloc (&info, tdep);
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
- /* 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, init_frame_pc_default);
-
- tdep->osabi = osabi;
+ gdbarch = gdbarch_alloc (&info, NULL);
/* 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_fp_regnum (gdbarch, VAX_FP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, VAX_PC_REGNUM);
set_gdbarch_ps_regnum (gdbarch, VAX_PS_REGNUM);
- set_gdbarch_register_name (gdbarch, vax_register_name);
- set_gdbarch_register_size (gdbarch, VAX_REGISTER_SIZE);
- set_gdbarch_register_bytes (gdbarch, VAX_REGISTER_BYTES);
- set_gdbarch_register_byte (gdbarch, vax_register_byte);
- set_gdbarch_register_raw_size (gdbarch, vax_register_raw_size);
- set_gdbarch_max_register_raw_size (gdbarch, VAX_MAX_REGISTER_RAW_SIZE);
- set_gdbarch_register_virtual_size (gdbarch, vax_register_virtual_size);
- set_gdbarch_max_register_virtual_size (gdbarch,
- VAX_MAX_REGISTER_VIRTUAL_SIZE);
- set_gdbarch_register_virtual_type (gdbarch, vax_register_virtual_type);
+ set_gdbarch_regset_from_core_section
+ (gdbarch, vax_regset_from_core_section);
/* Frame and stack info */
set_gdbarch_skip_prologue (gdbarch, vax_skip_prologue);
- set_gdbarch_saved_pc_after_call (gdbarch, vax_saved_pc_after_call);
-
set_gdbarch_frame_num_args (gdbarch, vax_frame_num_args);
- set_gdbarch_frameless_function_invocation (gdbarch,
- generic_frameless_function_invocation_not);
-
- set_gdbarch_frame_chain (gdbarch, vax_frame_chain);
- set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
- set_gdbarch_frame_saved_pc (gdbarch, vax_frame_saved_pc);
-
- set_gdbarch_frame_args_address (gdbarch, vax_frame_args_address);
- set_gdbarch_frame_locals_address (gdbarch, vax_frame_locals_address);
-
- set_gdbarch_frame_init_saved_regs (gdbarch, vax_frame_init_saved_regs);
-
set_gdbarch_frame_args_skip (gdbarch, 4);
+ /* Stack grows downward. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
/* Return value info */
- set_gdbarch_store_struct_return (gdbarch, vax_store_struct_return);
- set_gdbarch_deprecated_extract_return_value (gdbarch, vax_extract_return_value);
- set_gdbarch_deprecated_store_return_value (gdbarch, vax_store_return_value);
- set_gdbarch_deprecated_extract_struct_value_address (gdbarch, vax_extract_struct_value_address);
-
- /* Call dummy info */
- set_gdbarch_push_dummy_frame (gdbarch, vax_push_dummy_frame);
- set_gdbarch_pop_frame (gdbarch, vax_pop_frame);
- set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
- set_gdbarch_call_dummy_p (gdbarch, 1);
- set_gdbarch_call_dummy_words (gdbarch, vax_call_dummy_words);
- set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof_vax_call_dummy_words);
- set_gdbarch_fix_call_dummy (gdbarch, vax_fix_call_dummy);
- set_gdbarch_call_dummy_start_offset (gdbarch, 0);
- set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
- set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 7);
- set_gdbarch_deprecated_use_generic_dummy_frames (gdbarch, 0);
- set_gdbarch_deprecated_pc_in_call_dummy (gdbarch, deprecated_pc_in_call_dummy_on_stack);
- set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+ set_gdbarch_return_value (gdbarch, vax_return_value);
+
+ /* Call dummy code. */
+ set_gdbarch_push_dummy_call (gdbarch, vax_push_dummy_call);
+ set_gdbarch_unwind_dummy_id (gdbarch, vax_unwind_dummy_id);
/* Breakpoint info */
set_gdbarch_breakpoint_from_pc (gdbarch, vax_breakpoint_from_pc);
- set_gdbarch_decr_pc_after_break (gdbarch, 0);
/* Misc info */
- set_gdbarch_function_start_offset (gdbarch, 2);
+ set_gdbarch_deprecated_function_start_offset (gdbarch, 2);
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
- /* Hook in ABI-specific overrides, if they have been registered. */
- gdbarch_init_osabi (info, gdbarch, osabi);
+ set_gdbarch_print_insn (gdbarch, print_insn_vax);
- return (gdbarch);
-}
+ set_gdbarch_unwind_pc (gdbarch, vax_unwind_pc);
-static void
-vax_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
-{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ frame_base_set_default (gdbarch, &vax_frame_base);
- if (tdep == NULL)
- return;
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ frame_unwind_append_sniffer (gdbarch, vax_frame_sniffer);
- fprintf_unfiltered (file, "vax_dump_tdep: OS ABI = %s\n",
- gdbarch_osabi_name (tdep->osabi));
+ return (gdbarch);
}
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_vax_tdep (void);
+
void
_initialize_vax_tdep (void)
{
- gdbarch_register (bfd_arch_vax, vax_gdbarch_init, vax_dump_tdep);
-
- tm_print_insn = vax_print_insn;
+ gdbarch_register (bfd_arch_vax, vax_gdbarch_init, NULL);
}