#include "defs.h"
#include "symtab.h"
#include "opcode/vax.h"
#include "gdbcore.h"
#include "inferior.h"
#include "regcache.h"
#include "frame.h"
#include "value.h"
#include "arch-utils.h"
#include "gdb_string.h"
#include "osabi.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;
#define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000)
#define MAXLEN 62
#define NOPCODES (sizeof votstrs / sizeof votstrs[0])
static unsigned char *print_insn_arg ();
static const char *
vax_register_name (int regno)
{
static char *register_names[] =
{
"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]);
}
static int
vax_register_byte (int regno)
{
return (regno * 4);
}
static int
vax_register_raw_size (int regno)
{
return (4);
}
static int
vax_register_virtual_size (int regno)
{
return (4);
}
static struct type *
vax_register_virtual_type (int regno)
{
return (builtin_type_int);
}
static void
vax_frame_init_saved_regs (struct frame_info *frame)
{
int regnum, regmask;
CORE_ADDR next_addr;
if (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;
for (regnum = 0; regnum < VAX_AP_REGNUM; regnum++)
{
if (regmask & (1 << regnum))
get_frame_saved_regs (frame)[regnum] = next_addr += 4;
}
get_frame_saved_regs (frame)[SP_REGNUM] = next_addr + 4;
if (regmask & (1 << FP_REGNUM))
get_frame_saved_regs (frame)[SP_REGNUM] +=
4 + (4 * read_memory_integer (next_addr + 4, 4));
get_frame_saved_regs (frame)[PC_REGNUM] = get_frame_base (frame) + 16;
get_frame_saved_regs (frame)[FP_REGNUM] = get_frame_base (frame) + 12;
get_frame_saved_regs (frame)[VAX_AP_REGNUM] = get_frame_base (frame) + 8;
get_frame_saved_regs (frame)[PS_REGNUM] = get_frame_base (frame) + 4;
}
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);
if (get_next_frame (frame))
sigcontext_addr = read_memory_typed_address
(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);
target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, 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));
return (read_memory_integer (get_frame_base (frame) + 16, 4));
}
CORE_ADDR
vax_frame_args_address_correct (struct frame_info *frame)
{
if (get_next_frame (frame))
return (read_memory_integer (get_frame_base (get_next_frame (frame)) + 8, 4));
return (0);
}
static CORE_ADDR
vax_frame_args_address (struct frame_info *frame)
{
if (get_next_frame (frame))
return (read_memory_integer (get_frame_base (get_next_frame (frame)) + 8, 4));
return (read_register (VAX_AP_REGNUM));
}
static CORE_ADDR
vax_frame_locals_address (struct frame_info *frame)
{
return (get_frame_base (frame));
}
static int
vax_frame_num_args (struct frame_info *fi)
{
return (0xff & read_memory_integer (FRAME_ARGS_ADDRESS (fi), 1));
}
static CORE_ADDR
vax_frame_chain (struct frame_info *frame)
{
if (inside_entry_file (get_frame_pc (frame)))
return (0);
return (read_memory_integer (get_frame_base (frame) + 12, 4));
}
static void
vax_push_dummy_frame (void)
{
CORE_ADDR sp = read_register (SP_REGNUM);
int regnum;
sp = push_word (sp, 0);
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));
}
static void
vax_pop_frame (void)
{
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 ();
}
static LONGEST vax_call_dummy_words[] = { 0x329f69fb, 0x03323232 };
static int sizeof_vax_call_dummy_words = sizeof(vax_call_dummy_words);
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);
}
static void
vax_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
{
write_register (1, addr);
}
static void
vax_extract_return_value (struct type *valtype, char *regbuf, char *valbuf)
{
memcpy (valbuf, regbuf + REGISTER_BYTE (0), TYPE_LENGTH (valtype));
}
static void
vax_store_return_value (struct type *valtype, char *valbuf)
{
deprecated_write_register_bytes (0, valbuf, TYPE_LENGTH (valtype));
}
static CORE_ADDR
vax_extract_struct_value_address (char *regbuf)
{
return (extract_address (regbuf + REGISTER_BYTE (0), REGISTER_RAW_SIZE (0)));
}
static const unsigned char *
vax_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
static const unsigned char vax_breakpoint[] = { 3 };
*lenptr = sizeof(vax_breakpoint);
return (vax_breakpoint);
}
static CORE_ADDR
vax_skip_prologue (CORE_ADDR pc)
{
register int op = (unsigned char) read_memory_integer (pc, 1);
if (op == 0x11)
pc += 2;
if (op == 0x31)
pc += 3;
if (op == 0xC2
&& ((unsigned char) read_memory_integer (pc + 2, 1)) == 0x5E)
pc += 3;
if (op == 0x9E
&& ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xAE
&& ((unsigned char) read_memory_integer (pc + 3, 1)) == 0x5E)
pc += 4;
if (op == 0x9E
&& ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xCE
&& ((unsigned char) read_memory_integer (pc + 4, 1)) == 0x5E)
pc += 5;
if (op == 0x9E
&& ((unsigned char) read_memory_integer (pc + 1, 1)) == 0xEE
&& ((unsigned char) read_memory_integer (pc + 6, 1)) == 0x5E)
pc += 7;
return pc;
}
static CORE_ADDR
vax_saved_pc_after_call (struct frame_info *frame)
{
return (FRAME_SAVED_PC(frame));
}
static int
vax_print_insn (CORE_ADDR memaddr, disassemble_info *info)
{
unsigned char buffer[MAXLEN];
register int i;
register unsigned char *p;
const char *d;
int status = (*info->read_memory_func) (memaddr, buffer, MAXLEN, info);
if (status != 0)
{
(*info->memory_error_func) (status, memaddr, info);
return -1;
}
for (i = 0; i < NOPCODES; i++)
if (votstrs[i].detail.code == buffer[0]
|| votstrs[i].detail.code == *(unsigned short *) buffer)
break;
if (i == NOPCODES)
{
(*info->fprintf_func) (info->stream, "0%o", buffer[0]);
return 1;
}
(*info->fprintf_func) (info->stream, "%s", votstrs[i].name);
p = buffer + 1 + (votstrs[i].detail.code >= 0x100);
d = votstrs[i].detail.args;
if (*d)
(*info->fprintf_func) (info->stream, " ");
while (*d)
{
p = print_insn_arg (d, p, memaddr + (p - buffer), info);
d += 2;
if (*d)
(*info->fprintf_func) (info->stream, ",");
}
return p - buffer;
}
static unsigned char *
print_insn_arg (char *d, register char *p, CORE_ADDR addr,
disassemble_info *info)
{
register int regnum = *p & 0xf;
float floatlitbuf;
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:
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:
p = (char *) print_insn_arg (d, p, addr + 1, info);
(*info->fprintf_func) (info->stream, "[%s]", REGISTER_NAME (regnum));
break;
case 5:
(*info->fprintf_func) (info->stream, REGISTER_NAME (regnum));
break;
case 7:
(*info->fprintf_func) (info->stream, "-");
case 6:
(*info->fprintf_func) (info->stream, "(%s)", REGISTER_NAME (regnum));
break;
case 9:
(*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:
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:
(*info->fprintf_func) (info->stream, "@");
case 10:
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:
(*info->fprintf_func) (info->stream, "@");
case 12:
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:
(*info->fprintf_func) (info->stream, "@");
case 14:
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;
}
static struct gdbarch *
vax_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return arches->gdbarch;
gdbarch = gdbarch_alloc (&info, NULL);
set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
set_gdbarch_num_regs (gdbarch, VAX_NUM_REGS);
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_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_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);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
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);
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_breakpoint_from_pc (gdbarch, vax_breakpoint_from_pc);
set_gdbarch_decr_pc_after_break (gdbarch, 0);
set_gdbarch_function_start_offset (gdbarch, 2);
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
gdbarch_init_osabi (info, gdbarch);
return (gdbarch);
}
void
_initialize_vax_tdep (void)
{
gdbarch_register (bfd_arch_vax, vax_gdbarch_init, NULL);
tm_print_insn = vax_print_insn;
}