#include "defs.h"
#include "doublest.h"
#include "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "dwarf2-frame.h"
#include "inferior.h"
#include "symtab.h"
#include "value.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "dis-asm.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdb_string.h"
#include "linespec.h"
#include "regcache.h"
#include "reggroups.h"
#include "arch-utils.h"
#include "osabi.h"
#include "block.h"
#include "elf-bfd.h"
#include "alpha-tdep.h"
static const char *
alpha_register_name (int regno)
{
static const char * const register_names[] =
{
"v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
"t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
"a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
"t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "fpcr",
"pc", "", "unique"
};
if (regno < 0)
return NULL;
if (regno >= (sizeof(register_names) / sizeof(*register_names)))
return NULL;
return register_names[regno];
}
static int
alpha_cannot_fetch_register (int regno)
{
return regno == ALPHA_ZERO_REGNUM;
}
static int
alpha_cannot_store_register (int regno)
{
return regno == ALPHA_ZERO_REGNUM;
}
static struct type *
alpha_register_type (struct gdbarch *gdbarch, int regno)
{
if (regno == ALPHA_SP_REGNUM || regno == ALPHA_GP_REGNUM)
return builtin_type_void_data_ptr;
if (regno == ALPHA_PC_REGNUM)
return builtin_type_void_func_ptr;
if (regno >= ALPHA_FP0_REGNUM && regno < ALPHA_FP0_REGNUM + 31)
return builtin_type_ieee_double_little;
return builtin_type_int64;
}
static int
alpha_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
{
if (REGISTER_NAME (regnum) == NULL || *REGISTER_NAME (regnum) == '\0')
return 0;
if (group == all_reggroup)
return 1;
if (regnum == ALPHA_ZERO_REGNUM)
return 0;
if (group == save_reggroup || group == restore_reggroup)
return 1;
if (regnum == ALPHA_UNIQUE_REGNUM)
return group == system_reggroup;
if (regnum == ALPHA_FPCR_REGNUM)
return group == float_reggroup;
if (regnum >= ALPHA_FP0_REGNUM && regnum < ALPHA_FP0_REGNUM + 31)
return group == float_reggroup;
else
return group == general_reggroup;
}
static int
alpha_register_byte (int regno)
{
return (regno * 8);
}
static int
alpha_register_raw_size (int regno)
{
return 8;
}
static int
alpha_register_virtual_size (int regno)
{
return 8;
}
static void
alpha_lds (void *out, const void *in)
{
ULONGEST mem = extract_unsigned_integer (in, 4);
ULONGEST frac = (mem >> 0) & 0x7fffff;
ULONGEST sign = (mem >> 31) & 1;
ULONGEST exp_msb = (mem >> 30) & 1;
ULONGEST exp_low = (mem >> 23) & 0x7f;
ULONGEST exp, reg;
exp = (exp_msb << 10) | exp_low;
if (exp_msb)
{
if (exp_low == 0x7f)
exp = 0x7ff;
}
else
{
if (exp_low != 0x00)
exp |= 0x380;
}
reg = (sign << 63) | (exp << 52) | (frac << 29);
store_unsigned_integer (out, 8, reg);
}
static void
alpha_sts (void *out, const void *in)
{
ULONGEST reg, mem;
reg = extract_unsigned_integer (in, 8);
mem = ((reg >> 32) & 0xc0000000) | ((reg >> 29) & 0x3fffffff);
store_unsigned_integer (out, 4, mem);
}
static int
alpha_convert_register_p (int regno, struct type *type)
{
return (regno >= ALPHA_FP0_REGNUM && regno < ALPHA_FP0_REGNUM + 31);
}
static void
alpha_register_to_value (struct frame_info *frame, int regnum,
struct type *valtype, void *out)
{
char in[MAX_REGISTER_SIZE];
frame_register_read (frame, regnum, in);
switch (TYPE_LENGTH (valtype))
{
case 4:
alpha_sts (out, in);
break;
case 8:
memcpy (out, in, 8);
break;
default:
error ("Cannot retrieve value from floating point register");
}
}
static void
alpha_value_to_register (struct frame_info *frame, int regnum,
struct type *valtype, const void *in)
{
char out[MAX_REGISTER_SIZE];
switch (TYPE_LENGTH (valtype))
{
case 4:
alpha_lds (out, in);
break;
case 8:
memcpy (out, in, 8);
break;
default:
error ("Cannot store value in floating point register");
}
put_frame_register (frame, regnum, out);
}
static CORE_ADDR
alpha_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int i;
int accumulate_size = struct_return ? 8 : 0;
struct alpha_arg
{
char *contents;
int len;
int offset;
};
struct alpha_arg *alpha_args
= (struct alpha_arg *) alloca (nargs * sizeof (struct alpha_arg));
struct alpha_arg *m_arg;
char arg_reg_buffer[ALPHA_REGISTER_SIZE * ALPHA_NUM_ARG_REGS];
int required_arg_regs;
regcache_cooked_write_signed (regcache, ALPHA_T12_REGNUM, func_addr);
regcache_cooked_write_signed (regcache, ALPHA_RA_REGNUM, bp_addr);
for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++)
{
struct value *arg = args[i];
struct type *arg_type = check_typedef (VALUE_TYPE (arg));
switch (TYPE_CODE (arg_type))
{
case TYPE_CODE_INT:
case TYPE_CODE_BOOL:
case TYPE_CODE_CHAR:
case TYPE_CODE_RANGE:
case TYPE_CODE_ENUM:
if (TYPE_LENGTH (arg_type) == 4)
{
arg_type = builtin_type_int32;
arg = value_cast (arg_type, arg);
}
if (TYPE_LENGTH (arg_type) < ALPHA_REGISTER_SIZE)
{
arg_type = builtin_type_int64;
arg = value_cast (arg_type, arg);
}
break;
case TYPE_CODE_FLT:
if (accumulate_size < sizeof (arg_reg_buffer)
&& TYPE_LENGTH (arg_type) == 4)
{
arg_type = builtin_type_ieee_double_little;
arg = value_cast (arg_type, arg);
}
else if (TYPE_LENGTH (arg_type) == 16)
{
sp = (sp & -16) - 16;
write_memory (sp, VALUE_CONTENTS (arg), 16);
arg_type = lookup_pointer_type (arg_type);
arg = value_from_pointer (arg_type, sp);
}
break;
case TYPE_CODE_COMPLEX:
if (TYPE_LENGTH (arg_type) == 32)
{
sp = (sp & -16) - 16;
write_memory (sp, VALUE_CONTENTS (arg), 32);
arg_type = lookup_pointer_type (arg_type);
arg = value_from_pointer (arg_type, sp);
}
break;
default:
break;
}
m_arg->len = TYPE_LENGTH (arg_type);
m_arg->offset = accumulate_size;
accumulate_size = (accumulate_size + m_arg->len + 7) & ~7;
m_arg->contents = VALUE_CONTENTS (arg);
}
required_arg_regs = accumulate_size / 8;
if (required_arg_regs > ALPHA_NUM_ARG_REGS)
required_arg_regs = ALPHA_NUM_ARG_REGS;
if (accumulate_size < sizeof(arg_reg_buffer))
accumulate_size = 0;
else
accumulate_size -= sizeof(arg_reg_buffer);
sp -= accumulate_size;
sp &= ~15;
for (i = nargs; m_arg--, --i >= 0;)
{
char *contents = m_arg->contents;
int offset = m_arg->offset;
int len = m_arg->len;
if (offset < sizeof(arg_reg_buffer))
{
if (offset + len <= sizeof(arg_reg_buffer))
{
memcpy (arg_reg_buffer + offset, contents, len);
continue;
}
else
{
int tlen = sizeof(arg_reg_buffer) - offset;
memcpy (arg_reg_buffer + offset, contents, tlen);
offset += tlen;
contents += tlen;
len -= tlen;
}
}
write_memory (sp + offset - sizeof(arg_reg_buffer), contents, len);
}
if (struct_return)
store_unsigned_integer (arg_reg_buffer, ALPHA_REGISTER_SIZE, struct_addr);
for (i = 0; i < required_arg_regs; i++)
{
regcache_cooked_write (regcache, ALPHA_A0_REGNUM + i,
arg_reg_buffer + i*ALPHA_REGISTER_SIZE);
regcache_cooked_write (regcache, ALPHA_FPA0_REGNUM + i,
arg_reg_buffer + i*ALPHA_REGISTER_SIZE);
}
regcache_cooked_write_signed (regcache, ALPHA_SP_REGNUM, sp);
return sp;
}
static void
alpha_extract_return_value (struct type *valtype, struct regcache *regcache,
void *valbuf)
{
int length = TYPE_LENGTH (valtype);
char raw_buffer[ALPHA_REGISTER_SIZE];
ULONGEST l;
switch (TYPE_CODE (valtype))
{
case TYPE_CODE_FLT:
switch (length)
{
case 4:
regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, raw_buffer);
alpha_sts (valbuf, raw_buffer);
break;
case 8:
regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
break;
case 16:
regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l);
read_memory (l, valbuf, 16);
break;
default:
internal_error (__FILE__, __LINE__, "unknown floating point width");
}
break;
case TYPE_CODE_COMPLEX:
switch (length)
{
case 8:
regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
break;
case 16:
regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
regcache_cooked_read (regcache, ALPHA_FP0_REGNUM+1,
(char *)valbuf + 8);
break;
case 32:
regcache_cooked_read_signed (regcache, ALPHA_V0_REGNUM, &l);
read_memory (l, valbuf, 32);
break;
default:
internal_error (__FILE__, __LINE__, "unknown floating point width");
}
break;
default:
regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l);
store_unsigned_integer (valbuf, length, l);
break;
}
}
static CORE_ADDR
alpha_extract_struct_value_address (struct regcache *regcache)
{
ULONGEST addr;
regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &addr);
return addr;
}
static void
alpha_store_return_value (struct type *valtype, struct regcache *regcache,
const void *valbuf)
{
int length = TYPE_LENGTH (valtype);
char raw_buffer[ALPHA_REGISTER_SIZE];
ULONGEST l;
switch (TYPE_CODE (valtype))
{
case TYPE_CODE_FLT:
switch (length)
{
case 4:
alpha_lds (raw_buffer, valbuf);
regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, raw_buffer);
break;
case 8:
regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
break;
case 16:
error ("Cannot set a 128-bit long double return value.");
default:
internal_error (__FILE__, __LINE__, "unknown floating point width");
}
break;
case TYPE_CODE_COMPLEX:
switch (length)
{
case 8:
regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
break;
case 16:
regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
regcache_cooked_write (regcache, ALPHA_FP0_REGNUM+1,
(const char *)valbuf + 8);
break;
case 32:
error ("Cannot set a 128-bit long double return value.");
default:
internal_error (__FILE__, __LINE__, "unknown floating point width");
}
break;
default:
if (length == 4)
valtype = builtin_type_int32;
l = unpack_long (valtype, valbuf);
regcache_cooked_write_unsigned (regcache, ALPHA_V0_REGNUM, l);
break;
}
}
static const unsigned char *
alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
static const unsigned char alpha_breakpoint[] =
{ 0x80, 0, 0, 0 };
*lenptr = sizeof(alpha_breakpoint);
return (alpha_breakpoint);
}
CORE_ADDR
alpha_after_prologue (CORE_ADDR pc)
{
struct symtab_and_line sal;
CORE_ADDR func_addr, func_end;
if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
return 0;
sal = find_pc_line (func_addr, 0);
if (sal.end < func_end)
return sal.end;
return 0;
}
unsigned int
alpha_read_insn (CORE_ADDR pc)
{
char buf[4];
int status;
status = read_memory_nobpt (pc, buf, 4);
if (status)
memory_error (status, pc);
return extract_unsigned_integer (buf, 4);
}
static CORE_ADDR
alpha_skip_prologue (CORE_ADDR pc)
{
unsigned long inst;
int offset;
CORE_ADDR post_prologue_pc;
char buf[4];
if (target_read_memory (pc, buf, 4))
return pc;
post_prologue_pc = alpha_after_prologue (pc);
if (post_prologue_pc != 0)
return max (pc, post_prologue_pc);
for (offset = 0; offset < 100; offset += 4)
{
inst = alpha_read_insn (pc + offset);
if ((inst & 0xffff0000) == 0x27bb0000)
continue;
if ((inst & 0xffff0000) == 0x23bd0000)
continue;
if ((inst & 0xffff0000) == 0x23de0000)
continue;
if ((inst & 0xffe01fff) == 0x43c0153e)
continue;
if (((inst & 0xfc1f0000) == 0xb41e0000
|| (inst & 0xfc1f0000) == 0x9c1e0000)
&& (inst & 0x03e00000) != 0x03e00000)
continue;
if (inst == 0x47de040f)
continue;
if (inst == 0x47fe040f)
continue;
break;
}
return pc + offset;
}
static int
alpha_get_longjmp_target (CORE_ADDR *pc)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
CORE_ADDR jb_addr;
char raw_buffer[ALPHA_REGISTER_SIZE];
jb_addr = read_register (ALPHA_A0_REGNUM);
if (target_read_memory (jb_addr + (tdep->jb_pc * tdep->jb_elt_size),
raw_buffer, tdep->jb_elt_size))
return 0;
*pc = extract_unsigned_integer (raw_buffer, tdep->jb_elt_size);
return 1;
}
struct alpha_sigtramp_unwind_cache
{
CORE_ADDR sigcontext_addr;
};
static struct alpha_sigtramp_unwind_cache *
alpha_sigtramp_frame_unwind_cache (struct frame_info *next_frame,
void **this_prologue_cache)
{
struct alpha_sigtramp_unwind_cache *info;
struct gdbarch_tdep *tdep;
if (*this_prologue_cache)
return *this_prologue_cache;
info = FRAME_OBSTACK_ZALLOC (struct alpha_sigtramp_unwind_cache);
*this_prologue_cache = info;
tdep = gdbarch_tdep (current_gdbarch);
info->sigcontext_addr = tdep->sigcontext_addr (next_frame);
return info;
}
static CORE_ADDR
alpha_sigtramp_register_address (CORE_ADDR sigcontext_addr, int regnum)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
if (regnum >= 0 && regnum < 32)
return sigcontext_addr + tdep->sc_regs_offset + regnum * 8;
else if (regnum >= ALPHA_FP0_REGNUM && regnum < ALPHA_FP0_REGNUM + 32)
return sigcontext_addr + tdep->sc_fpregs_offset + regnum * 8;
else if (regnum == ALPHA_PC_REGNUM)
return sigcontext_addr + tdep->sc_pc_offset;
return 0;
}
static void
alpha_sigtramp_frame_this_id (struct frame_info *next_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct alpha_sigtramp_unwind_cache *info
= alpha_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
struct gdbarch_tdep *tdep;
CORE_ADDR stack_addr, code_addr;
if (info->sigcontext_addr == 0)
return;
tdep = gdbarch_tdep (current_gdbarch);
if (tdep->dynamic_sigtramp_offset)
{
int offset;
code_addr = frame_pc_unwind (next_frame);
offset = tdep->dynamic_sigtramp_offset (code_addr);
if (offset >= 0)
code_addr -= offset;
else
code_addr = 0;
}
else
code_addr = frame_func_unwind (next_frame);
stack_addr = alpha_sigtramp_register_address (info->sigcontext_addr,
ALPHA_SP_REGNUM);
stack_addr = get_frame_memory_unsigned (next_frame, stack_addr,
ALPHA_REGISTER_SIZE);
*this_id = frame_id_build (stack_addr, code_addr);
}
static void
alpha_sigtramp_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *bufferp)
{
struct alpha_sigtramp_unwind_cache *info
= alpha_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
CORE_ADDR addr;
if (info->sigcontext_addr != 0)
{
addr = alpha_sigtramp_register_address (info->sigcontext_addr, regnum);
if (addr != 0)
{
*optimizedp = 0;
*lvalp = lval_memory;
*addrp = addr;
*realnump = -1;
if (bufferp != NULL)
get_frame_memory (next_frame, addr, bufferp, ALPHA_REGISTER_SIZE);
return;
}
}
frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
realnump, bufferp);
}
static const struct frame_unwind alpha_sigtramp_frame_unwind = {
SIGTRAMP_FRAME,
alpha_sigtramp_frame_this_id,
alpha_sigtramp_frame_prev_register
};
static const struct frame_unwind *
alpha_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
char *name;
if (!gdbarch_tdep (current_gdbarch)->sigcontext_addr)
return NULL;
find_pc_partial_function (pc, &name, NULL, NULL);
if (PC_IN_SIGTRAMP (pc, name))
return &alpha_sigtramp_frame_unwind;
return NULL;
}
struct alpha_heuristic_unwind_cache
{
CORE_ADDR *saved_regs;
CORE_ADDR vfp;
CORE_ADDR start_pc;
int return_reg;
};
static unsigned int heuristic_fence_post = 0;
static CORE_ADDR
alpha_heuristic_proc_start (CORE_ADDR pc)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
CORE_ADDR last_non_nop = pc;
CORE_ADDR fence = pc - heuristic_fence_post;
CORE_ADDR orig_pc = pc;
CORE_ADDR func;
if (pc == 0)
return 0;
func = get_pc_function_start (pc);
if (func)
return func;
if (heuristic_fence_post == UINT_MAX
|| fence < tdep->vm_min_address)
fence = tdep->vm_min_address;
for (pc -= 4; pc >= fence; pc -= 4)
{
unsigned int insn = alpha_read_insn (pc);
switch (insn)
{
case 0:
case 0x6bfa8001:
return last_non_nop;
case 0x2ffe0000:
case 0x47ff041f:
break;
default:
last_non_nop = pc;
break;
}
}
if (stop_soon == NO_STOP_QUIETLY)
{
static int blurb_printed = 0;
if (fence == tdep->vm_min_address)
warning ("Hit beginning of text section without finding");
else
warning ("Hit heuristic-fence-post without finding");
warning ("enclosing function for address 0x%s", paddr_nz (orig_pc));
if (!blurb_printed)
{
printf_filtered ("\
This warning occurs if you are debugging a function without any symbols\n\
(for example, in a stripped executable). In that case, you may wish to\n\
increase the size of the search with the `set heuristic-fence-post' command.\n\
\n\
Otherwise, you told GDB there was a function where there isn't one, or\n\
(more likely) you have encountered a bug in GDB.\n");
blurb_printed = 1;
}
}
return 0;
}
static struct alpha_heuristic_unwind_cache *
alpha_heuristic_frame_unwind_cache (struct frame_info *next_frame,
void **this_prologue_cache,
CORE_ADDR start_pc)
{
struct alpha_heuristic_unwind_cache *info;
ULONGEST val;
CORE_ADDR limit_pc, cur_pc;
int frame_reg, frame_size, return_reg, reg;
if (*this_prologue_cache)
return *this_prologue_cache;
info = FRAME_OBSTACK_ZALLOC (struct alpha_heuristic_unwind_cache);
*this_prologue_cache = info;
info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
limit_pc = frame_pc_unwind (next_frame);
if (start_pc == 0)
start_pc = alpha_heuristic_proc_start (limit_pc);
info->start_pc = start_pc;
frame_reg = ALPHA_SP_REGNUM;
frame_size = 0;
return_reg = -1;
if (start_pc != 0)
{
if (start_pc + 200 < limit_pc)
limit_pc = start_pc + 200;
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
{
unsigned int word = alpha_read_insn (cur_pc);
if ((word & 0xffff0000) == 0x23de0000)
{
if (word & 0x8000)
{
if (frame_size == 0)
frame_size = (-word) & 0xffff;
}
else
{
break;
}
}
else if ((word & 0xfc1f0000) == 0xb41e0000)
{
reg = (word & 0x03e00000) >> 21;
if (reg == 31)
continue;
info->saved_regs[reg] = (word & 0xffff) + 1;
if (return_reg == -1
&& cur_pc < (start_pc + 80)
&& (reg == ALPHA_T7_REGNUM
|| reg == ALPHA_T9_REGNUM
|| reg == ALPHA_RA_REGNUM))
return_reg = reg;
}
else if ((word & 0xffe0ffff) == 0x6be08001)
return_reg = (word >> 16) & 0x1f;
else if (word == 0x47de040f)
frame_reg = ALPHA_GCC_FP_REGNUM;
else if (word == 0x47fe040f)
frame_reg = ALPHA_GCC_FP_REGNUM;
}
if (return_reg == -1)
{
while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80))
{
unsigned int word = alpha_read_insn (cur_pc);
if ((word & 0xfc1f0000) == 0xb41e0000)
{
reg = (word & 0x03e00000) >> 21;
if (reg == ALPHA_T7_REGNUM
|| reg == ALPHA_T9_REGNUM
|| reg == ALPHA_RA_REGNUM)
{
return_reg = reg;
break;
}
}
else if ((word & 0xffe0ffff) == 0x6be08001)
{
return_reg = (word >> 16) & 0x1f;
break;
}
cur_pc += 4;
}
}
}
if (return_reg == -1)
return_reg = ALPHA_RA_REGNUM;
info->return_reg = return_reg;
frame_unwind_unsigned_register (next_frame, frame_reg, &val);
info->vfp = val + frame_size;
for (reg = 0; reg < ALPHA_NUM_REGS; ++reg)
if (info->saved_regs[reg])
info->saved_regs[reg] += val - 1;
return info;
}
static void
alpha_heuristic_frame_this_id (struct frame_info *next_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct alpha_heuristic_unwind_cache *info
= alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
*this_id = frame_id_build (info->vfp, info->start_pc);
}
static void
alpha_heuristic_frame_prev_register (struct frame_info *next_frame,
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *bufferp)
{
struct alpha_heuristic_unwind_cache *info
= alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
if (regnum == ALPHA_PC_REGNUM)
regnum = info->return_reg;
if (info->saved_regs[regnum])
{
*optimizedp = 0;
*lvalp = lval_memory;
*addrp = info->saved_regs[regnum];
*realnump = -1;
if (bufferp != NULL)
get_frame_memory (next_frame, *addrp, bufferp, ALPHA_REGISTER_SIZE);
return;
}
if (regnum == ALPHA_SP_REGNUM)
{
*optimizedp = 0;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (bufferp != NULL)
store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp);
return;
}
frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
realnump, bufferp);
}
static const struct frame_unwind alpha_heuristic_frame_unwind = {
NORMAL_FRAME,
alpha_heuristic_frame_this_id,
alpha_heuristic_frame_prev_register
};
static const struct frame_unwind *
alpha_heuristic_frame_sniffer (struct frame_info *next_frame)
{
return &alpha_heuristic_frame_unwind;
}
static CORE_ADDR
alpha_heuristic_frame_base_address (struct frame_info *next_frame,
void **this_prologue_cache)
{
struct alpha_heuristic_unwind_cache *info
= alpha_heuristic_frame_unwind_cache (next_frame, this_prologue_cache, 0);
return info->vfp;
}
static const struct frame_base alpha_heuristic_frame_base = {
&alpha_heuristic_frame_unwind,
alpha_heuristic_frame_base_address,
alpha_heuristic_frame_base_address,
alpha_heuristic_frame_base_address
};
static void
reinit_frame_cache_sfunc (char *args, int from_tty, struct cmd_list_element *c)
{
reinit_frame_cache ();
}
struct frame_info *
alpha_setup_arbitrary_frame (int argc, CORE_ADDR *argv)
{
if (argc != 2)
error ("ALPHA frame specifications require two arguments: sp and pc");
return create_new_frame (argv[0], argv[1]);
}
static struct frame_id
alpha_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST base;
frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &base);
return frame_id_build (base, frame_pc_unwind (next_frame));
}
static CORE_ADDR
alpha_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
ULONGEST pc;
frame_unwind_unsigned_register (next_frame, ALPHA_PC_REGNUM, &pc);
return pc;
}
void
alpha_supply_int_regs (int regno, const void *r0_r30,
const void *pc, const void *unique)
{
int i;
for (i = 0; i < 31; ++i)
if (regno == i || regno == -1)
supply_register (i, (const char *)r0_r30 + i*8);
if (regno == ALPHA_ZERO_REGNUM || regno == -1)
supply_register (ALPHA_ZERO_REGNUM, NULL);
if (regno == ALPHA_PC_REGNUM || regno == -1)
supply_register (ALPHA_PC_REGNUM, pc);
if (regno == ALPHA_UNIQUE_REGNUM || regno == -1)
supply_register (ALPHA_UNIQUE_REGNUM, unique);
}
void
alpha_fill_int_regs (int regno, void *r0_r30, void *pc, void *unique)
{
int i;
for (i = 0; i < 31; ++i)
if (regno == i || regno == -1)
regcache_collect (i, (char *)r0_r30 + i*8);
if (regno == ALPHA_PC_REGNUM || regno == -1)
regcache_collect (ALPHA_PC_REGNUM, pc);
if (unique && (regno == ALPHA_UNIQUE_REGNUM || regno == -1))
regcache_collect (ALPHA_UNIQUE_REGNUM, unique);
}
void
alpha_supply_fp_regs (int regno, const void *f0_f30, const void *fpcr)
{
int i;
for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i)
if (regno == i || regno == -1)
supply_register (i, (const char *)f0_f30 + (i - ALPHA_FP0_REGNUM) * 8);
if (regno == ALPHA_FPCR_REGNUM || regno == -1)
supply_register (ALPHA_FPCR_REGNUM, fpcr);
}
void
alpha_fill_fp_regs (int regno, void *f0_f30, void *fpcr)
{
int i;
for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; ++i)
if (regno == i || regno == -1)
regcache_collect (i, (char *)f0_f30 + (i - ALPHA_FP0_REGNUM) * 8);
if (regno == ALPHA_FPCR_REGNUM || regno == -1)
regcache_collect (ALPHA_FPCR_REGNUM, fpcr);
}
static CORE_ADDR
alpha_next_pc (CORE_ADDR pc)
{
unsigned int insn;
unsigned int op;
int offset;
LONGEST rav;
insn = alpha_read_insn (pc);
op = (insn >> 26) & 0x3f;
if (op == 0x1a)
{
return (read_register ((insn >> 16) & 0x1f) & ~3);
}
if ((op & 0x30) == 0x30)
{
if (op == 0x30 ||
op == 0x34)
{
branch_taken:
offset = (insn & 0x001fffff);
if (offset & 0x00100000)
offset |= 0xffe00000;
offset *= 4;
return (pc + 4 + offset);
}
rav = (LONGEST) read_register ((insn >> 21) & 0x1f);
switch (op)
{
case 0x38:
if ((rav & 1) == 0)
goto branch_taken;
break;
case 0x3c:
if (rav & 1)
goto branch_taken;
break;
case 0x39:
if (rav == 0)
goto branch_taken;
break;
case 0x3d:
if (rav != 0)
goto branch_taken;
break;
case 0x3a:
if (rav < 0)
goto branch_taken;
break;
case 0x3b:
if (rav <= 0)
goto branch_taken;
break;
case 0x3f:
if (rav > 0)
goto branch_taken;
break;
case 0x3e:
if (rav >= 0)
goto branch_taken;
break;
}
}
return (pc + 4);
}
void
alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p)
{
static CORE_ADDR next_pc;
typedef char binsn_quantum[BREAKPOINT_MAX];
static binsn_quantum break_mem;
CORE_ADDR pc;
if (insert_breakpoints_p)
{
pc = read_pc ();
next_pc = alpha_next_pc (pc);
target_insert_breakpoint (next_pc, break_mem);
}
else
{
target_remove_breakpoint (next_pc, break_mem);
write_pc (next_pc);
}
}
static struct gdbarch *
alpha_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
{
if (bfd_get_flavour (info.abfd) == bfd_target_ecoff_flavour)
info.osabi = GDB_OSABI_OSF1;
}
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return arches->gdbarch;
tdep = xmalloc (sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
tdep->vm_min_address = (CORE_ADDR) 0x120000000;
tdep->dynamic_sigtramp_offset = NULL;
tdep->sigcontext_addr = NULL;
tdep->sc_pc_offset = 2 * 8;
tdep->sc_regs_offset = 4 * 8;
tdep->sc_fpregs_offset = tdep->sc_regs_offset + 32 * 8 + 8;
tdep->jb_pc = -1;
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_int_bit (gdbarch, 32);
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_float_bit (gdbarch, 32);
set_gdbarch_double_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 64);
set_gdbarch_ptr_bit (gdbarch, 64);
set_gdbarch_num_regs (gdbarch, ALPHA_NUM_REGS);
set_gdbarch_sp_regnum (gdbarch, ALPHA_SP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, ALPHA_PC_REGNUM);
set_gdbarch_fp0_regnum (gdbarch, ALPHA_FP0_REGNUM);
set_gdbarch_register_name (gdbarch, alpha_register_name);
set_gdbarch_deprecated_register_byte (gdbarch, alpha_register_byte);
set_gdbarch_deprecated_register_raw_size (gdbarch, alpha_register_raw_size);
set_gdbarch_deprecated_register_virtual_size (gdbarch, alpha_register_virtual_size);
set_gdbarch_register_type (gdbarch, alpha_register_type);
set_gdbarch_cannot_fetch_register (gdbarch, alpha_cannot_fetch_register);
set_gdbarch_cannot_store_register (gdbarch, alpha_cannot_store_register);
set_gdbarch_convert_register_p (gdbarch, alpha_convert_register_p);
set_gdbarch_register_to_value (gdbarch, alpha_register_to_value);
set_gdbarch_value_to_register (gdbarch, alpha_value_to_register);
set_gdbarch_register_reggroup_p (gdbarch, alpha_register_reggroup_p);
set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue);
set_gdbarch_print_insn (gdbarch, print_insn_alpha);
set_gdbarch_use_struct_convention (gdbarch, always_use_struct_convention);
set_gdbarch_extract_return_value (gdbarch, alpha_extract_return_value);
set_gdbarch_store_return_value (gdbarch, alpha_store_return_value);
set_gdbarch_deprecated_extract_struct_value_address (gdbarch, alpha_extract_struct_value_address);
set_gdbarch_push_dummy_call (gdbarch, alpha_push_dummy_call);
set_gdbarch_unwind_dummy_id (gdbarch, alpha_unwind_dummy_id);
set_gdbarch_unwind_pc (gdbarch, alpha_unwind_pc);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
set_gdbarch_breakpoint_from_pc (gdbarch, alpha_breakpoint_from_pc);
set_gdbarch_decr_pc_after_break (gdbarch, 4);
gdbarch_init_osabi (info, gdbarch);
if (tdep->jb_pc >= 0)
set_gdbarch_get_longjmp_target (gdbarch, alpha_get_longjmp_target);
frame_unwind_append_sniffer (gdbarch, alpha_sigtramp_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, alpha_heuristic_frame_sniffer);
frame_base_set_default (gdbarch, &alpha_heuristic_frame_base);
return gdbarch;
}
void
alpha_dwarf2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
}
extern initialize_file_ftype _initialize_alpha_tdep;
void
_initialize_alpha_tdep (void)
{
struct cmd_list_element *c;
gdbarch_register (bfd_arch_alpha, alpha_gdbarch_init, NULL);
c = add_set_cmd ("heuristic-fence-post", class_support, var_zinteger,
(char *) &heuristic_fence_post,
"\
Set the distance searched for the start of a function.\n\
If you are debugging a stripped executable, GDB needs to search through the\n\
program for the start of a function. This command sets the distance of the\n\
search. The only need to set it is when debugging a stripped executable.",
&setlist);
set_cmd_sfunc (c, reinit_frame_cache_sfunc);
add_show_from_set (c, &showlist);
}