#include "defs.h"
#include "gdbcore.h"
#include "frame.h"
#include "value.h"
#include "symtab.h"
#include "inferior.h"
#include "gdbcmd.h"
#define TAGWORD_ZERO_MASK 0xff00f800
extern CORE_ADDR text_start;
static CORE_ADDR rstack_high_address = UINT_MAX;
int
a29k_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 16 * 4);
}
struct prologue_info
{
CORE_ADDR pc;
unsigned rsize, msize;
unsigned mfp_used:1;
unsigned rsize_valid:1;
unsigned msize_valid:1;
unsigned mfp_valid:1;
};
CORE_ADDR
examine_prologue (CORE_ADDR pc, unsigned *rsize, unsigned *msize, int *mfp_used)
{
long insn;
CORE_ADDR p = pc;
struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
struct prologue_info *mi = 0;
if (msymbol != NULL)
mi = (struct prologue_info *) msymbol->info;
if (mi != 0)
{
int valid = 1;
if (rsize != NULL)
{
*rsize = mi->rsize;
valid &= mi->rsize_valid;
}
if (msize != NULL)
{
*msize = mi->msize;
valid &= mi->msize_valid;
}
if (mfp_used != NULL)
{
*mfp_used = mi->mfp_used;
valid &= mi->mfp_valid;
}
if (valid)
return mi->pc;
}
if (rsize != NULL)
*rsize = 0;
if (msize != NULL)
*msize = 0;
if (mfp_used != NULL)
*mfp_used = 0;
insn = read_memory_integer (p, 4);
if ((insn & 0xffffff00) != 0x25010100)
{
int reg;
unsigned int rsize0;
if ((insn & 0xff000000) != 0x03000000)
{
p = pc;
goto done;
}
reg = (insn >> 8) & 0xff;
rsize0 = (((insn >> 8) & 0xff00) | (insn & 0xff));
p += 4;
insn = read_memory_integer (p, 4);
if ((insn & 0xffffff00) != 0x24010100
|| (insn & 0xff) != reg)
{
p = pc;
goto done;
}
if (rsize != NULL)
*rsize = rsize0;
}
else
{
if (rsize != NULL)
*rsize = (insn & 0xff);
}
p += 4;
insn = read_memory_integer (p, 4);
if ((insn & 0xff00ffff) == (0x5e000100 | RAB_HW_REGNUM))
{
p += 4;
}
insn = read_memory_integer (p, 4);
if ((insn & 0xffffff00) == 0x15810100)
p += 4;
else
{
int reg;
CORE_ADDR q;
if ((insn & 0xff000000) == 0x03000000)
{
reg = (insn >> 8) & 0xff;
q = p + 4;
insn = read_memory_integer (q, 4);
if ((insn & 0xffffff00) == 0x14810100
&& (insn & 0xff) == reg)
p = q;
}
}
insn = read_memory_integer (p, 4);
if (((insn & 0xff80ffff) == (0x15800000 | (MSP_HW_REGNUM << 8)))
|| ((insn & 0xff80ffff) == (0x81800000 | (MSP_HW_REGNUM << 8))))
{
p += 4;
if (mfp_used != NULL)
*mfp_used = 1;
}
insn = read_memory_integer (p, 4);
if ((insn & 0xffffff00) ==
(0x25000000 | (MSP_HW_REGNUM << 16) | (MSP_HW_REGNUM << 8)))
{
p += 4;
if (msize != NULL)
*msize = insn & 0xff;
}
else
{
int reg;
unsigned msize0;
CORE_ADDR q = p;
if ((insn & 0xff000000) == 0x03000000)
{
reg = (insn >> 8) & 0xff;
msize0 = ((insn >> 8) & 0xff00) | (insn & 0xff);
q += 4;
insn = read_memory_integer (q, 4);
if ((insn & 0xff000000) == 0x02000000
&& (insn & 0x0000ff00) == reg)
{
msize0 |= (insn << 8) & 0xff000000;
msize0 |= (insn << 16) & 0x00ff0000;
q += 4;
insn = read_memory_integer (q, 4);
}
if ((insn & 0xffffff00) ==
(0x24000000 | (MSP_HW_REGNUM << 16) | (MSP_HW_REGNUM << 8))
&& (insn & 0xff) == reg)
{
p = q + 4;
if (msize != NULL)
*msize = msize0;
}
}
}
insn = read_memory_integer (p, 4);
if ((insn & 0xff00ffff) == (0x5e000100 | RAB_HW_REGNUM))
{
p += 4;
}
done:
if (msymbol != NULL)
{
if (mi == 0)
{
mi = (struct prologue_info *) xmalloc (sizeof (struct prologue_info));
msymbol->info = (char *) mi;
mi->rsize_valid = 0;
mi->msize_valid = 0;
mi->mfp_valid = 0;
}
mi->pc = p;
if (rsize != NULL)
{
mi->rsize = *rsize;
mi->rsize_valid = 1;
}
if (msize != NULL)
{
mi->msize = *msize;
mi->msize_valid = 1;
}
if (mfp_used != NULL)
{
mi->mfp_used = *mfp_used;
mi->mfp_valid = 1;
}
}
return p;
}
CORE_ADDR
a29k_skip_prologue (CORE_ADDR pc)
{
return examine_prologue (pc, NULL, NULL, NULL);
}
static int
examine_tag (CORE_ADDR p, int *is_trans, int *argcount, unsigned *msize,
int *mfp_used)
{
unsigned int tag1, tag2;
tag1 = read_memory_integer (p, 4);
if ((tag1 & TAGWORD_ZERO_MASK) != 0)
return 0;
if (tag1 & (1 << 23))
{
tag2 = read_memory_integer (p - 4, 4);
if (msize)
*msize = tag2 * 2;
}
else
{
if (msize)
*msize = tag1 & 0x7ff;
}
if (is_trans)
*is_trans = ((tag1 & (1 << 21)) ? 1 : 0);
if (argcount)
*argcount = (tag1 >> 16) & 0x1f;
if (mfp_used)
*mfp_used = ((tag1 & (1 << 22)) ? 1 : 0);
return 1;
}
static void
init_frame_info (int innermost_frame, struct frame_info *frame)
{
CORE_ADDR p;
long insn;
unsigned rsize;
unsigned msize;
int mfp_used, trans;
struct symbol *func;
p = frame->pc;
if (innermost_frame)
frame->frame = read_register (GR1_REGNUM);
else
frame->frame = frame->next->frame + frame->next->rsize;
#if 0
This wont work;
#else
if (PC_IN_CALL_DUMMY (p, 0, 0))
#endif
{
frame->rsize = DUMMY_FRAME_RSIZE;
frame->msize = 0;
frame->saved_msp =
read_register_stack_integer (frame->frame + DUMMY_FRAME_RSIZE - 4, 4);
frame->flags |= (TRANSPARENT_FRAME | MFP_USED);
return;
}
func = find_pc_function (p);
if (func != NULL)
p = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
else
{
#if 1
while (p >= text_start
&& ((insn = read_memory_integer (p, 4)) & TAGWORD_ZERO_MASK) != 0)
p -= 4;
#else
char pat[4] =
{0, 0, 0, 0};
char mask[4];
char insn_raw[4];
store_unsigned_integer (mask, 4, TAGWORD_ZERO_MASK);
target_search (4, pat, mask, p, -4, text_start, p + 1, &p, &insn_raw);
insn = extract_unsigned_integer (insn_raw, 4);
#endif
if (p < text_start)
{
frame->saved_msp = 0;
frame->rsize = 0;
frame->msize = 0;
frame->flags = TRANSPARENT_FRAME;
return;
}
else
p += 4;
}
if (examine_tag (p - 4, &trans, (int *) NULL, &msize, &mfp_used))
examine_prologue (p, &rsize, 0, 0);
else
examine_prologue (p, &rsize, &msize, &mfp_used);
frame->rsize = rsize;
frame->msize = msize;
frame->flags = 0;
if (mfp_used)
frame->flags |= MFP_USED;
if (trans)
frame->flags |= TRANSPARENT_FRAME;
if (innermost_frame)
{
frame->saved_msp = read_register (MSP_REGNUM) + msize;
}
else
{
if (mfp_used)
frame->saved_msp =
read_register_stack_integer (frame->frame + rsize - 4, 4);
else
frame->saved_msp = frame->next->saved_msp + msize;
}
}
void
init_extra_frame_info (struct frame_info *frame)
{
if (frame->next == 0)
init_frame_info (1, frame);
else
{
;
}
}
void
init_frame_pc (int fromleaf, struct frame_info *frame)
{
frame->pc = (fromleaf ? SAVED_PC_AFTER_CALL (frame->next) :
frame->next ? FRAME_SAVED_PC (frame->next) : read_pc ());
init_frame_info (fromleaf, frame);
}
CORE_ADDR
frame_locals_address (struct frame_info *fi)
{
if (fi->flags & MFP_USED)
return fi->saved_msp;
else
return fi->saved_msp - fi->msize;
}
void
read_register_stack (CORE_ADDR memaddr, char *myaddr,
CORE_ADDR *actual_mem_addr, enum lval_type *lval)
{
long rfb = read_register (RFB_REGNUM);
long rsp = read_register (RSP_REGNUM);
if (memaddr >= rstack_high_address)
{
static char val[] =
{~0, ~0, ~0, ~0};
int regnum = (memaddr - rsp) / 4 + LR0_REGNUM;
if (myaddr != NULL)
{
memcpy (myaddr, val, 4);
}
supply_register (regnum, val);
if (lval != NULL)
*lval = lval_register;
if (actual_mem_addr != NULL)
*actual_mem_addr = REGISTER_BYTE (regnum);
}
else if (memaddr < rfb && memaddr >= rsp)
{
int regnum = (memaddr - rsp) / 4 + LR0_REGNUM;
if (regnum > LR0_REGNUM + 127)
error ("Attempt to read register stack out of range.");
if (myaddr != NULL)
read_register_gen (regnum, myaddr);
if (lval != NULL)
*lval = lval_register;
if (actual_mem_addr != NULL)
*actual_mem_addr = REGISTER_BYTE (regnum);
}
else
{
if (myaddr != NULL)
read_memory (memaddr, myaddr, 4);
if (lval != NULL)
*lval = lval_memory;
if (actual_mem_addr != NULL)
*actual_mem_addr = memaddr;
}
}
long
read_register_stack_integer (CORE_ADDR memaddr, int len)
{
char buf[4];
read_register_stack (memaddr, buf, NULL, NULL);
return extract_signed_integer (buf, 4);
}
static void
write_register_stack (CORE_ADDR memaddr, char *myaddr,
CORE_ADDR *actual_mem_addr)
{
long rfb = read_register (RFB_REGNUM);
long rsp = read_register (RSP_REGNUM);
if (memaddr >= rstack_high_address)
{
if (actual_mem_addr != NULL)
*actual_mem_addr = 0;
}
else if (memaddr < rfb)
{
int regnum = (memaddr - rsp) / 4 + LR0_REGNUM;
if (regnum < LR0_REGNUM || regnum > LR0_REGNUM + 127)
error ("Attempt to read register stack out of range.");
if (myaddr != NULL)
write_register (regnum, *(long *) myaddr);
if (actual_mem_addr != NULL)
*actual_mem_addr = 0;
}
else
{
if (myaddr != NULL)
write_memory (memaddr, myaddr, 4);
if (actual_mem_addr != NULL)
*actual_mem_addr = memaddr;
}
}
void
a29k_get_saved_register (char *raw_buffer, int *optimized, CORE_ADDR *addrp,
struct frame_info *frame, int regnum,
enum lval_type *lvalp)
{
struct frame_info *fi;
CORE_ADDR addr;
enum lval_type lval;
if (!target_has_registers)
error ("No registers.");
if (frame == 0)
return;
if (optimized != NULL)
*optimized = 0;
if (regnum == RSP_REGNUM)
{
if (raw_buffer != NULL)
{
store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), frame->frame);
}
if (lvalp != NULL)
*lvalp = not_lval;
return;
}
else if (regnum == PC_REGNUM && frame->next != NULL)
{
if (raw_buffer != NULL)
{
store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), frame->pc);
}
if (lvalp != NULL)
*lvalp = not_lval;
return;
}
else if (regnum == MSP_REGNUM)
{
if (raw_buffer != NULL)
{
if (frame->next != NULL)
{
store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
frame->next->saved_msp);
}
else
read_register_gen (MSP_REGNUM, raw_buffer);
}
if (lvalp != NULL)
*lvalp = not_lval;
return;
}
else if (regnum < LR0_REGNUM || regnum >= LR0_REGNUM + 128)
{
if (raw_buffer != NULL)
read_register_gen (regnum, raw_buffer);
if (lvalp != NULL)
*lvalp = lval_register;
if (addrp != NULL)
*addrp = REGISTER_BYTE (regnum);
return;
}
addr = frame->frame + (regnum - LR0_REGNUM) * 4;
if (raw_buffer != NULL)
read_register_stack (addr, raw_buffer, &addr, &lval);
if (lvalp != NULL)
*lvalp = lval;
if (addrp != NULL)
*addrp = addr;
}
void
pop_frame (void)
{
struct frame_info *frame = get_current_frame ();
CORE_ADDR rfb = read_register (RFB_REGNUM);
CORE_ADDR gr1 = frame->frame + frame->rsize;
CORE_ADDR lr1;
CORE_ADDR original_lr0;
int must_fix_lr0 = 0;
int i;
if (PC_IN_CALL_DUMMY (read_register (PC_REGNUM),
read_register (SP_REGNUM),
FRAME_FP (frame)))
{
int lrnum = LR0_REGNUM + DUMMY_ARG / 4;
for (i = 0; i < DUMMY_SAVE_SR128; ++i)
write_register (SR_REGNUM (i + 128), read_register (lrnum++));
for (i = 0; i < DUMMY_SAVE_SR160; ++i)
write_register (SR_REGNUM (i + 160), read_register (lrnum++));
for (i = 0; i < DUMMY_SAVE_GREGS; ++i)
write_register (RETURN_REGNUM + i, read_register (lrnum++));
write_register (PC_REGNUM, read_register (lrnum++));
write_register (NPC_REGNUM, read_register (lrnum++));
write_register (PC2_REGNUM, read_register (lrnum++));
original_lr0 = read_register (lrnum++);
must_fix_lr0 = 1;
}
write_register (MSP_REGNUM, frame->saved_msp);
write_register (GR1_REGNUM, gr1);
if (must_fix_lr0)
write_register (LR0_REGNUM, original_lr0);
lr1 = read_register (LR0_REGNUM + 1);
if (lr1 > rfb)
{
int num_bytes = lr1 - rfb;
int i;
long word;
write_register (RAB_REGNUM, read_register (RAB_REGNUM) + num_bytes);
write_register (RFB_REGNUM, lr1);
for (i = 0; i < num_bytes; i += 4)
{
word = read_memory_integer (rfb + i, 4);
write_register (LR0_REGNUM + ((rfb - gr1) % 0x80) + i / 4, word);
}
}
flush_cached_frames ();
}
void
push_dummy_frame (void)
{
long w;
CORE_ADDR rab, gr1;
CORE_ADDR msp = read_register (MSP_REGNUM);
int lrnum, i;
CORE_ADDR original_lr0;
original_lr0 = read_register (LR0_REGNUM);
gr1 = read_register (GR1_REGNUM) - DUMMY_FRAME_RSIZE;
write_register (GR1_REGNUM, gr1);
#ifdef VXWORKS_TARGET
vx_read_register (-1);
#endif
rab = read_register (RAB_REGNUM);
if (gr1 < rab)
{
int num_bytes = rab - gr1;
CORE_ADDR rfb = read_register (RFB_REGNUM);
int i;
long word;
write_register (RFB_REGNUM, rfb - num_bytes);
write_register (RAB_REGNUM, gr1);
for (i = 0; i < num_bytes; i += 4)
{
read_register_gen (LR0_REGNUM + i / 4, (char *) &word);
write_memory (rfb - num_bytes + i, (char *) &word, 4);
}
}
write_register (LR0_REGNUM + 1, gr1 + DUMMY_FRAME_RSIZE + 2 * 4);
write_register (LR0_REGNUM + DUMMY_FRAME_RSIZE / 4 - 1, msp);
write_register (MSP_REGNUM, msp - 16 * 4);
lrnum = LR0_REGNUM + DUMMY_ARG / 4;
for (i = 0; i < DUMMY_SAVE_SR128; ++i)
write_register (lrnum++, read_register (SR_REGNUM (i + 128)));
for (i = 0; i < DUMMY_SAVE_SR160; ++i)
write_register (lrnum++, read_register (SR_REGNUM (i + 160)));
for (i = 0; i < DUMMY_SAVE_GREGS; ++i)
write_register (lrnum++, read_register (RETURN_REGNUM + i));
write_register (lrnum++, read_register (PC_REGNUM));
write_register (lrnum++, read_register (NPC_REGNUM));
write_register (lrnum++, read_register (PC2_REGNUM));
write_register (lrnum++, original_lr0);
}
struct frame_info *
setup_arbitrary_frame (int argc, CORE_ADDR *argv)
{
struct frame_info *frame;
if (argc != 3)
error ("AMD 29k frame specifications require three arguments: rsp pc msp");
frame = create_new_frame (argv[0], argv[1]);
if (!frame)
internal_error ("create_new_frame returned invalid frame id");
frame->frame = argv[0];
frame->saved_msp = argv[2] + frame->msize;
return frame;
}
int
gdb_print_insn_a29k (bfd_vma memaddr, disassemble_info *info)
{
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
return print_insn_big_a29k (memaddr, info);
else
return print_insn_little_a29k (memaddr, info);
}
enum a29k_processor_types processor_type = a29k_unknown;
void
a29k_get_processor_type (void)
{
unsigned int cfg_reg = (unsigned int) read_register (CFG_REGNUM);
processor_type = a29k_no_freeze_mode;
switch ((cfg_reg >> 28) & 0xf)
{
case 0:
fprintf_filtered (gdb_stderr, "Remote debugging an Am29000");
break;
case 1:
fprintf_filtered (gdb_stderr, "Remote debugging an Am29005");
break;
case 2:
fprintf_filtered (gdb_stderr, "Remote debugging an Am29050");
processor_type = a29k_freeze_mode;
break;
case 3:
fprintf_filtered (gdb_stderr, "Remote debugging an Am29035");
break;
case 4:
fprintf_filtered (gdb_stderr, "Remote debugging an Am29030");
break;
case 5:
fprintf_filtered (gdb_stderr, "Remote debugging an Am2920*");
break;
case 6:
fprintf_filtered (gdb_stderr, "Remote debugging an Am2924*");
break;
case 7:
fprintf_filtered (gdb_stderr, "Remote debugging an Am29040");
break;
default:
fprintf_filtered (gdb_stderr, "Remote debugging an unknown Am29k\n");
return;
}
fprintf_filtered (gdb_stderr, " revision %c\n", 'A' + ((cfg_reg >> 24) & 0x0f));
}
#ifdef GET_LONGJMP_TARGET
int
get_longjmp_target (CORE_ADDR *pc)
{
CORE_ADDR jb_addr;
char buf[sizeof (CORE_ADDR)];
jb_addr = read_register (LR2_REGNUM);
if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, (char *) buf,
sizeof (CORE_ADDR)))
return 0;
*pc = extract_address ((PTR) buf, sizeof (CORE_ADDR));
return 1;
}
#endif
void
_initialize_a29k_tdep (void)
{
extern CORE_ADDR text_end;
tm_print_insn = gdb_print_insn_a29k;
add_show_from_set
(add_set_cmd ("rstack_high_address", class_support, var_uinteger,
(char *) &rstack_high_address,
"Set top address in memory of the register stack.\n\
Attempts to access registers saved above this address will be ignored\n\
or will produce the value -1.", &setlist),
&showlist);
add_show_from_set
(add_set_cmd ("call_scratch_address", class_support, var_uinteger,
(char *) &text_end,
"Set address in memory where small amounts of RAM can be used\n\
when making function calls into the inferior.", &setlist),
&showlist);
}