#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "target.h"
#include "value.h"
#include "bfd.h"
#include "gdb_string.h"
#include "gdbcore.h"
#include "symfile.h"
#include "regcache.h"
int
mn10200_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_NFIELDS (type) > 1 || TYPE_LENGTH (type) > 8);
}
#define MY_FRAME_IN_SP 0x1
#define MY_FRAME_IN_FP 0x2
#define CALLER_A2_IN_A0 0x4
#define NO_MORE_FRAMES 0x8
static CORE_ADDR
mn10200_analyze_prologue (struct frame_info *fi, CORE_ADDR pc)
{
CORE_ADDR func_addr, func_end, addr, stop;
CORE_ADDR stack_size = 0;
unsigned char buf[4];
int status;
char *name;
int out_of_line_prologue = 0;
pc = (fi ? fi->pc : pc);
status = find_pc_partial_function (pc, &name, &func_addr, &func_end);
if (status == 0)
return pc;
if (strcmp (name, "start") == 0)
{
if (fi)
fi->status = NO_MORE_FRAMES;
return pc;
}
if (fi)
fi->status = MY_FRAME_IN_SP;
if (fi && fi->pc + 1 == func_end)
{
status = target_read_memory (fi->pc, buf, 1);
if (status != 0)
{
if (fi->next == NULL)
fi->frame = read_sp ();
return fi->pc;
}
if (buf[0] == 0xfe)
{
if (fi->next == NULL)
fi->frame = read_sp ();
return fi->pc;
}
}
if (fi && fi->pc == func_addr)
{
if (fi->next == NULL)
fi->frame = read_sp ();
return fi->pc;
}
stop = fi ? fi->pc : func_end;
stop = stop > func_end ? func_end : stop;
addr = func_addr;
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
if (fi && fi->next == NULL && fi->status & MY_FRAME_IN_SP)
fi->frame = read_sp ();
return addr;
}
if (buf[0] == 0xdf
|| (buf[0] == 0xf4 && buf[1] == 0x77))
{
if (fi)
fi->status = NO_MORE_FRAMES;
return addr;
}
if (buf[0] == 0xf2 && buf[1] == 0x78)
{
if (fi)
fi->status |= CALLER_A2_IN_A0;
addr += 2;
if (addr >= stop)
{
if (fi && fi->next == NULL)
fi->frame = read_sp ();
return addr;
}
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
if (fi && fi->next == NULL)
fi->frame = read_sp ();
return addr;
}
if (buf[0] == 0xf2 && buf[1] == 0x7e)
{
addr += 2;
if (fi)
{
fi->status |= MY_FRAME_IN_FP;
fi->status &= ~MY_FRAME_IN_SP;
}
if (addr >= stop)
return addr;
}
else
{
if (fi && fi->next == NULL)
fi->frame = read_sp ();
return addr;
}
}
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
if (buf[0] == 0xd3)
{
stack_size = extract_signed_integer (&buf[1], 1);
if (fi)
fi->stack_size = stack_size;
addr += 2;
if (addr >= stop)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp () - stack_size;
return addr;
}
}
else if (buf[0] == 0xf7 && buf[1] == 0x0b)
{
status = target_read_memory (addr + 2, buf, 2);
if (status != 0)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
stack_size = extract_signed_integer (buf, 2);
if (fi)
fi->stack_size = stack_size;
addr += 4;
if (addr >= stop)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp () - stack_size;
return addr;
}
}
else if (buf[0] == 0xf4 && buf[1] == 0x67)
{
status = target_read_memory (addr + 2, buf, 3);
if (status != 0)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
stack_size = extract_signed_integer (buf, 3);
if (fi)
fi->stack_size = stack_size;
addr += 5;
if (addr >= stop)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp () - stack_size;
return addr;
}
}
status = target_read_memory (addr, buf, 2);
if (status != 0)
return addr;
if (buf[0] == 0xfd)
{
CORE_ADDR temp;
status = target_read_memory (addr + 1, buf, 2);
if (status != 0)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
temp = (extract_signed_integer (buf, 2) + addr + 3) & 0xffffff;
status = find_pc_partial_function (temp, &name, NULL, NULL);
if (status == 0)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
out_of_line_prologue = (strcmp (name, "__prologue") == 0);
if (out_of_line_prologue)
addr += 3;
if (addr >= stop)
{
if (fi && fi->next == NULL)
{
fi->stack_size -= 16;
fi->frame = read_sp () - fi->stack_size;
}
return addr;
}
}
else if (buf[0] == 0xf4 && buf[1] == 0xe1)
{
CORE_ADDR temp;
status = target_read_memory (addr + 2, buf, 3);
if (status != 0)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
temp = (extract_signed_integer (buf, 3) + addr + 5) & 0xffffff;
status = find_pc_partial_function (temp, &name, NULL, NULL);
if (status == 0)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
out_of_line_prologue = (strcmp (name, "__prologue") == 0);
if (out_of_line_prologue)
addr += 5;
if (addr >= stop)
{
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
{
fi->stack_size -= 16;
fi->frame = read_sp () - fi->stack_size;
}
return addr;
}
}
if (out_of_line_prologue)
{
int outgoing_args_size = 0;
if (fi)
fi->stack_size -= 16;
if (fi && fi->next == NULL)
fi->frame = read_sp () - fi->stack_size;
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
if (fi)
{
fi->fsr.regs[2] = fi->frame + fi->stack_size + 4;
fi->fsr.regs[3] = fi->frame + fi->stack_size + 8;
fi->fsr.regs[5] = fi->frame + fi->stack_size + 12;
fi->fsr.regs[6] = fi->frame + fi->stack_size + 16;
}
return addr;
}
if (buf[0] == 0xd3)
{
outgoing_args_size = extract_signed_integer (&buf[1], 1);
addr += 2;
}
else if (buf[0] == 0xf7 && buf[1] == 0x0b)
{
status = target_read_memory (addr + 2, buf, 2);
if (status != 0)
{
if (fi)
{
fi->fsr.regs[2] = fi->frame + fi->stack_size + 4;
fi->fsr.regs[3] = fi->frame + fi->stack_size + 8;
fi->fsr.regs[5] = fi->frame + fi->stack_size + 12;
fi->fsr.regs[6] = fi->frame + fi->stack_size + 16;
}
return addr;
}
outgoing_args_size = extract_signed_integer (buf, 2);
addr += 4;
}
else if (buf[0] == 0xf4 && buf[1] == 0x67)
{
status = target_read_memory (addr + 2, buf, 3);
if (status != 0)
{
if (fi && fi->next == NULL)
{
fi->fsr.regs[2] = fi->frame + fi->stack_size + 4;
fi->fsr.regs[3] = fi->frame + fi->stack_size + 8;
fi->fsr.regs[5] = fi->frame + fi->stack_size + 12;
fi->fsr.regs[6] = fi->frame + fi->stack_size + 16;
}
return addr;
}
outgoing_args_size = extract_signed_integer (buf, 3);
addr += 5;
}
else
outgoing_args_size = 0;
if (fi && fi->next == NULL)
fi->frame -= outgoing_args_size;
if (fi)
{
fi->fsr.regs[2] = fi->frame + fi->stack_size + 4;
fi->fsr.regs[3] = fi->frame + fi->stack_size + 8;
fi->fsr.regs[5] = fi->frame + fi->stack_size + 12;
fi->fsr.regs[6] = fi->frame + fi->stack_size + 16;
fi->stack_size += outgoing_args_size;
}
return addr;
}
if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP) != 0)
fi->frame = read_sp () - fi->stack_size;
status = target_read_memory (addr, buf, 2);
if (status != 0)
return addr;
if (buf[0] == 0xf5 && buf[1] == 0x5e)
{
if (fi)
{
status = target_read_memory (addr + 2, buf, 1);
if (status != 0)
return addr;
fi->fsr.regs[2] = (fi->frame + stack_size
+ extract_signed_integer (buf, 1));
}
addr += 3;
if (addr >= stop)
return addr;
status = target_read_memory (addr, buf, 2);
if (status != 0)
return addr;
}
if (buf[0] == 0xf5 && buf[1] == 0x5f)
{
if (fi)
{
status = target_read_memory (addr + 2, buf, 1);
if (status != 0)
return addr;
fi->fsr.regs[3] = (fi->frame + stack_size
+ extract_signed_integer (buf, 1));
}
addr += 3;
if (addr >= stop)
return addr;
status = target_read_memory (addr, buf, 2);
if (status != 0)
return addr;
}
if (buf[0] == 0x5d)
{
if (fi)
{
status = target_read_memory (addr + 1, buf, 1);
if (status != 0)
return addr;
fi->fsr.regs[5] = (fi->frame + stack_size
+ extract_signed_integer (buf, 1));
}
addr += 2;
if (addr >= stop)
return addr;
status = target_read_memory (addr, buf, 2);
if (status != 0)
return addr;
}
if (buf[0] == 0x5e || buf[0] == 0x5c)
{
if (fi)
{
status = target_read_memory (addr + 1, buf, 1);
if (status != 0)
return addr;
fi->fsr.regs[6] = (fi->frame + stack_size
+ extract_signed_integer (buf, 1));
fi->status &= ~CALLER_A2_IN_A0;
}
addr += 2;
if (addr >= stop)
return addr;
return addr;
}
return addr;
}
CORE_ADDR
mn10200_frame_chain (struct frame_info *fi)
{
struct frame_info dummy_frame;
if (fi->status == 0)
mn10200_analyze_prologue (fi, (CORE_ADDR) 0);
if (fi->status & NO_MORE_FRAMES)
return 0;
dummy_frame.pc = FRAME_SAVED_PC (fi);
dummy_frame.frame = fi->frame;
memset (dummy_frame.fsr.regs, '\000', sizeof dummy_frame.fsr.regs);
dummy_frame.status = 0;
dummy_frame.stack_size = 0;
mn10200_analyze_prologue (&dummy_frame, 0);
if (dummy_frame.status & MY_FRAME_IN_FP)
{
if (fi->fsr.regs[6])
return (read_memory_integer (fi->fsr.regs[FP_REGNUM], REGISTER_SIZE)
& 0xffffff);
else if (fi->status & CALLER_A2_IN_A0)
return read_register (4);
else
return read_register (FP_REGNUM);
}
else
{
return fi->frame + -dummy_frame.stack_size + 4;
}
}
CORE_ADDR
mn10200_skip_prologue (CORE_ADDR pc)
{
return mn10200_analyze_prologue (NULL, pc);
}
void
mn10200_pop_frame (struct frame_info *frame)
{
int regnum;
if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
generic_pop_dummy_frame ();
else
{
write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
for (regnum = 0; regnum < NUM_REGS; regnum++)
if (frame->fsr.regs[regnum] != 0)
{
ULONGEST value;
value = read_memory_unsigned_integer (frame->fsr.regs[regnum],
REGISTER_RAW_SIZE (regnum));
write_register (regnum, value);
}
write_register (SP_REGNUM, FRAME_FP (frame));
}
flush_cached_frames ();
}
CORE_ADDR
mn10200_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
unsigned char struct_return, CORE_ADDR struct_addr)
{
int argnum = 0;
int len = 0;
int stack_offset = 0;
int regsused = struct_return ? 1 : 0;
sp &= ~1;
for (argnum = 0; argnum < nargs; argnum++)
{
int arg_length = (TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 1) & ~1;
if (regsused >= 2 || arg_length > 4)
{
regsused = 2;
len += arg_length;
}
else if (arg_length <= 2
|| TYPE_CODE (VALUE_TYPE (args[argnum])) == TYPE_CODE_PTR)
{
regsused++;
}
else if (regsused == 0)
{
regsused = 2;
}
else
{
regsused = 2;
len += arg_length;
}
}
sp -= len;
regsused = struct_return ? 1 : 0;
for (argnum = 0; argnum < nargs; argnum++)
{
int len;
char *val;
if (TYPE_CODE (VALUE_TYPE (*args)) == TYPE_CODE_STRUCT
&& TYPE_LENGTH (VALUE_TYPE (*args)) > 8)
{
len = TYPE_LENGTH (VALUE_TYPE (*args));
val = (char *) VALUE_CONTENTS (*args);
}
else
{
len = TYPE_LENGTH (VALUE_TYPE (*args));
val = (char *) VALUE_CONTENTS (*args);
}
if (regsused < 2
&& (len <= 2
|| TYPE_CODE (VALUE_TYPE (*args)) == TYPE_CODE_PTR))
{
write_register (regsused, extract_unsigned_integer (val, 4));
regsused++;
}
else if (regsused == 0 && len == 4)
{
write_register (regsused, extract_unsigned_integer (val, 2));
write_register (regsused + 1, extract_unsigned_integer (val + 2, 2));
regsused = 2;
}
else
{
regsused = 2;
while (len > 0)
{
write_memory (sp + stack_offset, val, 2);
len -= 2;
val += 2;
stack_offset += 2;
}
}
args++;
}
return sp;
}
CORE_ADDR
mn10200_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
{
unsigned char buf[4];
store_unsigned_integer (buf, 4, CALL_DUMMY_ADDRESS ());
write_memory (sp - 4, buf, 4);
return sp - 4;
}
CORE_ADDR
mn10200_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
{
write_register (0, addr);
return sp;
}
CORE_ADDR
mn10200_frame_saved_pc (struct frame_info *fi)
{
return (read_memory_integer (fi->frame, REGISTER_SIZE) & 0xffffff);
}
void
mn10200_init_extra_frame_info (struct frame_info *fi)
{
if (fi->next)
fi->pc = FRAME_SAVED_PC (fi->next);
memset (fi->fsr.regs, '\000', sizeof fi->fsr.regs);
fi->status = 0;
fi->stack_size = 0;
mn10200_analyze_prologue (fi, 0);
}
void
_initialize_mn10200_tdep (void)
{
tm_print_insn = print_insn_mn10200;
}