#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 ? get_frame_pc (fi) : 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 && get_frame_pc (fi) + 1 == func_end)
{
status = target_read_memory (get_frame_pc (fi), buf, 1);
if (status != 0)
{
if (get_next_frame (fi) == NULL)
deprecated_update_frame_base_hack (fi, read_sp ());
return get_frame_pc (fi);
}
if (buf[0] == 0xfe)
{
if (get_next_frame (fi) == NULL)
deprecated_update_frame_base_hack (fi, read_sp ());
return get_frame_pc (fi);
}
}
if (fi && get_frame_pc (fi) == func_addr)
{
if (get_next_frame (fi) == NULL)
deprecated_update_frame_base_hack (fi, read_sp ());
return get_frame_pc (fi);
}
stop = fi ? get_frame_pc (fi) : func_end;
stop = stop > func_end ? func_end : stop;
addr = func_addr;
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
if (fi && get_next_frame (fi) == NULL && fi->status & MY_FRAME_IN_SP)
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL)
deprecated_update_frame_base_hack (fi, read_sp ());
return addr;
}
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
if (fi && get_next_frame (fi) == NULL)
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL)
deprecated_update_frame_base_hack (fi, read_sp ());
return addr;
}
}
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
if (fi && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, read_sp ());
return addr;
}
out_of_line_prologue = (strcmp (name, "__prologue") == 0);
if (out_of_line_prologue)
addr += 3;
if (addr >= stop)
{
if (fi && get_next_frame (fi) == NULL)
{
fi->stack_size -= 16;
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
deprecated_update_frame_base_hack (fi, read_sp ());
return addr;
}
out_of_line_prologue = (strcmp (name, "__prologue") == 0);
if (out_of_line_prologue)
addr += 5;
if (addr >= stop)
{
if (fi && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP))
{
fi->stack_size -= 16;
deprecated_update_frame_base_hack (fi, 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 && get_next_frame (fi) == NULL)
deprecated_update_frame_base_hack (fi, read_sp () - fi->stack_size);
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
if (fi)
{
fi->fsr.regs[2] = get_frame_base (fi) + fi->stack_size + 4;
fi->fsr.regs[3] = get_frame_base (fi) + fi->stack_size + 8;
fi->fsr.regs[5] = get_frame_base (fi) + fi->stack_size + 12;
fi->fsr.regs[6] = get_frame_base (fi) + 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] = get_frame_base (fi) + fi->stack_size + 4;
fi->fsr.regs[3] = get_frame_base (fi) + fi->stack_size + 8;
fi->fsr.regs[5] = get_frame_base (fi) + fi->stack_size + 12;
fi->fsr.regs[6] = get_frame_base (fi) + 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 && get_next_frame (fi) == NULL)
{
fi->fsr.regs[2] = get_frame_base (fi) + fi->stack_size + 4;
fi->fsr.regs[3] = get_frame_base (fi) + fi->stack_size + 8;
fi->fsr.regs[5] = get_frame_base (fi) + fi->stack_size + 12;
fi->fsr.regs[6] = get_frame_base (fi) + fi->stack_size + 16;
}
return addr;
}
outgoing_args_size = extract_signed_integer (buf, 3);
addr += 5;
}
else
outgoing_args_size = 0;
if (fi && get_next_frame (fi) == NULL)
deprecated_update_frame_base_hack (fi, get_frame_base (fi) - outgoing_args_size);
if (fi)
{
fi->fsr.regs[2] = get_frame_base (fi) + fi->stack_size + 4;
fi->fsr.regs[3] = get_frame_base (fi) + fi->stack_size + 8;
fi->fsr.regs[5] = get_frame_base (fi) + fi->stack_size + 12;
fi->fsr.regs[6] = get_frame_base (fi) + fi->stack_size + 16;
fi->stack_size += outgoing_args_size;
}
return addr;
}
if (fi && get_next_frame (fi) == NULL && (fi->status & MY_FRAME_IN_SP) != 0)
deprecated_update_frame_base_hack (fi, 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] = (get_frame_base (fi) + 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] = (get_frame_base (fi) + 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] = (get_frame_base (fi) + 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] = (get_frame_base (fi) + 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 = deprecated_frame_xmalloc ();
struct cleanup *old_chain = make_cleanup (xfree, dummy_frame);
CORE_ADDR ret;
if (fi->status == 0)
mn10200_analyze_prologue (fi, (CORE_ADDR) 0);
if (fi->status & NO_MORE_FRAMES)
return 0;
deprecated_update_frame_pc_hack (dummy_frame, FRAME_SAVED_PC (fi));
deprecated_update_frame_base_hack (dummy_frame, get_frame_base (fi));
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])
ret = (read_memory_integer (fi->fsr.regs[FP_REGNUM], REGISTER_SIZE)
& 0xffffff);
else if (fi->status & CALLER_A2_IN_A0)
ret = read_register (4);
else
ret = read_register (FP_REGNUM);
}
else
{
ret = get_frame_base (fi) + -dummy_frame->stack_size + 4;
}
do_cleanups (old_chain);
return ret;
}
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 (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame),
get_frame_base (frame),
get_frame_base (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, get_frame_base (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 (get_frame_base (fi), REGISTER_SIZE) & 0xffffff);
}
void
mn10200_init_extra_frame_info (struct frame_info *fi)
{
if (get_next_frame (fi))
deprecated_update_frame_pc_hack (fi, FRAME_SAVED_PC (get_next_frame (fi)));
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;
}