#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "obstack.h"
#include "target.h"
#include "value.h"
#include "bfd.h"
#include "gdb_string.h"
#include "gdbcore.h"
#include "symfile.h"
#include "regcache.h"
int
m32r_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 8);
}
void
m32r_frame_find_saved_regs (struct frame_info *fi,
struct frame_saved_regs *regaddr)
{
memcpy (regaddr, &fi->fsr, sizeof (struct frame_saved_regs));
}
#if 0
static void
dump_insn (char *commnt, CORE_ADDR pc, int insn)
{
printf_filtered (" %s %08x %08x ",
commnt, (unsigned int) pc, (unsigned int) insn);
TARGET_PRINT_INSN (pc, &tm_print_insn_info);
printf_filtered ("\n");
}
#define insn_debug(args) { printf_filtered args; }
#else
#define dump_insn(a,b,c) {}
#define insn_debug(args) {}
#endif
#define DEFAULT_SEARCH_LIMIT 44
static void
decode_prologue (CORE_ADDR start_pc, CORE_ADDR scan_limit, CORE_ADDR *pl_endptr,
unsigned long *framelength, struct frame_info *fi,
struct frame_saved_regs *fsr)
{
unsigned long framesize;
int insn;
int op1;
int maybe_one_more = 0;
CORE_ADDR after_prologue = 0;
CORE_ADDR after_stack_adjust = 0;
CORE_ADDR current_pc;
framesize = 0;
after_prologue = 0;
insn_debug (("rd prolog l(%d)\n", scan_limit - current_pc));
for (current_pc = start_pc; current_pc < scan_limit; current_pc += 2)
{
insn = read_memory_unsigned_integer (current_pc, 2);
dump_insn ("insn-1", current_pc, insn);
if (current_pc & 0x02)
{
if (maybe_one_more)
{
if (!(insn & 0x8000))
{
insn_debug (("Really done"));
break;
}
}
insn &= 0x7fff;
}
else
{
if (maybe_one_more)
break;
if (insn & 0x8000)
{
insn_debug (("32 bit insn\n"));
if (current_pc == scan_limit)
scan_limit += 2;
current_pc += 2;
if (insn == 0x8faf)
{
insn_debug (("stack increment\n"));
framesize += -((short) read_memory_unsigned_integer (current_pc, 2));
}
else
{
if (((insn >> 8) == 0xe4) &&
read_memory_unsigned_integer (current_pc + 2, 2) == 0x0f24)
{
dump_insn ("insn-2", current_pc + 2, insn);
insn = read_memory_unsigned_integer (current_pc - 2, 4);
dump_insn ("insn-3(l4)", current_pc - 2, insn);
if (insn & 0x00800000)
insn |= 0xff000000;
else
insn &= 0x00ffffff;
framesize += insn;
}
}
after_prologue = current_pc;
continue;
}
}
op1 = insn & 0xf000;
if ((insn & 0xf0ff) == 0x207f)
{
int regno;
insn_debug (("push\n"));
#if 0
if (((insn & 0xffff) == 0x2d7f) && fi)
fi->using_frame_pointer = 1;
#endif
framesize += 4;
#if 0
if (current_pc == scan_limit)
scan_limit += 2;
#endif
regno = ((insn >> 8) & 0xf);
if (fsr)
fsr->regs[regno] = framesize;
after_prologue = 0;
continue;
}
if ((insn >> 8) == 0x4f)
{
int stack_adjust = (char) (insn & 0xff);
if (stack_adjust < 0)
{
framesize -= stack_adjust;
after_prologue = 0;
after_stack_adjust = current_pc + 2;
}
continue;
}
if (insn == 0x1d8f)
{
if (fi)
fi->using_frame_pointer = 1;
insn_debug (("done fp found\n"));
after_prologue = current_pc + 2;
break;
}
if (insn == 0x7000)
{
insn_debug (("nop\n"));
after_prologue = current_pc + 2;
continue;
}
if ((op1 == 0x7000)
|| (op1 == 0xb000)
|| (op1 == 0xf000))
{
after_prologue = current_pc;
insn_debug (("Done: branch\n"));
maybe_one_more = 1;
continue;
}
if (op1 == 0x1000)
{
int subop = insn & 0x0ff0;
if ((subop == 0x0ec0) || (subop == 0x0fc0))
{
insn_debug (("done: jmp\n"));
after_prologue = current_pc;
maybe_one_more = 1;
continue;
}
}
}
if (current_pc >= scan_limit)
{
if (pl_endptr)
{
#if 1
if (after_stack_adjust != 0)
{
*pl_endptr = after_stack_adjust;
if (framelength)
*framelength = framesize;
}
else
#endif
*pl_endptr = start_pc;
}
return;
}
if (after_prologue == 0)
after_prologue = current_pc;
insn_debug ((" framesize %d, firstline %08x\n", framesize, after_prologue));
if (framelength)
*framelength = framesize;
if (pl_endptr)
*pl_endptr = after_prologue;
}
CORE_ADDR
m32r_skip_prologue (CORE_ADDR pc)
{
CORE_ADDR func_addr, func_end;
struct symtab_and_line sal;
if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
{
sal = find_pc_line (func_addr, 0);
if (sal.line != 0 && sal.end <= func_end)
{
insn_debug (("BP after prologue %08x\n", sal.end));
func_end = sal.end;
}
else
{
insn_debug (("No line info, line(%x) sal_end(%x) funcend(%x)\n",
sal.line, sal.end, func_end));
func_end = min (func_end, func_addr + DEFAULT_SEARCH_LIMIT);
}
}
else
func_end = pc + DEFAULT_SEARCH_LIMIT;
decode_prologue (pc, func_end, &sal.end, 0, 0, 0);
return sal.end;
}
static unsigned long
m32r_scan_prologue (struct frame_info *fi, struct frame_saved_regs *fsr)
{
struct symtab_and_line sal;
CORE_ADDR prologue_start, prologue_end, current_pc;
unsigned long framesize = 0;
if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end))
{
sal = find_pc_line (prologue_start, 0);
if (sal.line == 0)
if (prologue_start == entry_point_address ())
return 0;
}
else
{
prologue_start = fi->pc;
prologue_end = prologue_start + 48;
}
#if 0
prologue_end = min (prologue_end, fi->pc);
#endif
insn_debug (("fipc(%08x) start(%08x) end(%08x)\n",
fi->pc, prologue_start, prologue_end));
prologue_end = min (prologue_end, prologue_start + DEFAULT_SEARCH_LIMIT);
decode_prologue (prologue_start, prologue_end, &prologue_end, &framesize,
fi, fsr);
return framesize;
}
void
m32r_init_extra_frame_info (struct frame_info *fi)
{
int reg;
if (fi->next)
fi->pc = FRAME_SAVED_PC (fi->next);
memset (fi->fsr.regs, '\000', sizeof fi->fsr.regs);
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
{
fi->frame = generic_read_register_dummy (fi->pc, fi->frame, SP_REGNUM);
fi->framesize = 0;
return;
}
else
{
fi->using_frame_pointer = 0;
fi->framesize = m32r_scan_prologue (fi, &fi->fsr);
if (!fi->next)
if (fi->using_frame_pointer)
{
fi->frame = read_register (FP_REGNUM);
}
else
fi->frame = read_register (SP_REGNUM);
else
if (fi->using_frame_pointer)
if (fi->next->fsr.regs[FP_REGNUM] != 0)
fi->frame = read_memory_integer (fi->next->fsr.regs[FP_REGNUM], 4);
for (reg = 0; reg < NUM_REGS; reg++)
if (fi->fsr.regs[reg] != 0)
fi->fsr.regs[reg] = fi->frame + fi->framesize - fi->fsr.regs[reg];
}
}
void
m32r_virtual_frame_pointer (CORE_ADDR pc, long *reg, long *offset)
{
struct frame_info fi;
fi.next = NULL;
fi.prev = NULL;
fi.frame = 0;
fi.pc = pc;
m32r_init_extra_frame_info (&fi);
if (fi.using_frame_pointer)
{
*reg = FP_REGNUM;
*offset = 0;
}
else
{
*reg = SP_REGNUM;
*offset = 0;
}
}
CORE_ADDR
m32r_find_callers_reg (struct frame_info *fi, int regnum)
{
for (; fi; fi = fi->next)
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
return generic_read_register_dummy (fi->pc, fi->frame, regnum);
else if (fi->fsr.regs[regnum] != 0)
return read_memory_integer (fi->fsr.regs[regnum],
REGISTER_RAW_SIZE (regnum));
return read_register (regnum);
}
CORE_ADDR
m32r_frame_chain (struct frame_info *fi)
{
CORE_ADDR fn_start, callers_pc, fp;
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
return fi->frame;
callers_pc = FRAME_SAVED_PC (fi);
fp = m32r_find_callers_reg (fi, FP_REGNUM);
if (PC_IN_CALL_DUMMY (callers_pc, fp, fp))
return fp;
if (find_pc_partial_function (fi->pc, 0, &fn_start, 0))
if (fn_start == entry_point_address ())
return 0;
if (fi->framesize == 0)
{
printf_filtered ("cannot determine frame size @ %s , pc(%s)\n",
paddr (fi->frame),
paddr (fi->pc));
return 0;
}
insn_debug (("m32rx frame %08x\n", fi->frame + fi->framesize));
return fi->frame + fi->framesize;
}
CORE_ADDR
m32r_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
{
write_register (RP_REGNUM, CALL_DUMMY_ADDRESS ());
return sp;
}
struct frame_info *
m32r_pop_frame (struct frame_info *frame)
{
int regnum;
if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
generic_pop_dummy_frame ();
else
{
for (regnum = 0; regnum < NUM_REGS; regnum++)
if (frame->fsr.regs[regnum] != 0)
write_register (regnum,
read_memory_integer (frame->fsr.regs[regnum], 4));
write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
write_register (SP_REGNUM, read_register (FP_REGNUM));
if (read_register (PSW_REGNUM) & 0x80)
write_register (SPU_REGNUM, read_register (SP_REGNUM));
else
write_register (SPI_REGNUM, read_register (SP_REGNUM));
}
flush_cached_frames ();
return NULL;
}
CORE_ADDR
m32r_frame_saved_pc (struct frame_info *fi)
{
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
return generic_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
else
return m32r_find_callers_reg (fi, RP_REGNUM);
}
CORE_ADDR
m32r_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
unsigned char struct_return, CORE_ADDR struct_addr)
{
int stack_offset, stack_alloc;
int argreg;
int argnum;
struct type *type;
CORE_ADDR regval;
char *val;
char valbuf[4];
int len;
int odd_sized_struct;
sp = sp & ~3;
argreg = ARG0_REGNUM;
if (struct_return)
write_register (argreg++, struct_addr);
for (argnum = 0, stack_alloc = 0;
argnum < nargs; argnum++)
stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
sp -= stack_alloc;
argreg = ARG0_REGNUM;
for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
memset (valbuf, 0, sizeof (valbuf));
if (len < 4)
{
memcpy (valbuf + (4 - len),
(char *) VALUE_CONTENTS (args[argnum]), len);
val = valbuf;
}
else
val = (char *) VALUE_CONTENTS (args[argnum]);
if (len > 4 && (len & 3) != 0)
odd_sized_struct = 1;
else
odd_sized_struct = 0;
while (len > 0)
{
if (argreg > ARGLAST_REGNUM || odd_sized_struct)
{
write_memory (sp + stack_offset, val, 4);
stack_offset += 4;
}
if (argreg <= ARGLAST_REGNUM)
{
regval = extract_address (val, REGISTER_RAW_SIZE (argreg));
write_register (argreg++, regval);
}
len -= REGISTER_RAW_SIZE (argreg);
val += REGISTER_RAW_SIZE (argreg);
}
}
return sp;
}
void
m32r_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
struct value **args, struct type *type, int gcc_p)
{
*(unsigned long *) (dummy) = (fun & 0x00ffffff) | 0xe8000000;
}
void
m32r_write_sp (CORE_ADDR val)
{
unsigned long psw = read_register (PSW_REGNUM);
if (psw & 0x80)
write_register (SPU_REGNUM, val);
else
write_register (SPI_REGNUM, val);
write_register (SP_REGNUM, val);
}
void
_initialize_m32r_tdep (void)
{
tm_print_insn = print_insn_m32r;
}