mov fp,a0
mov sp,fp
add <size>,sp
- Register saves for d2, d3, a3 as needed. Saves start
- at fp - <size> and work towards higher addresses. Note
- that the saves are actually done off the stack pointer
- in the prologue! This makes for smaller code and easier
- prologue scanning as the displacement fields will never
+ Register saves for d2, d3, a1, a2 as needed. Saves start
+ at fp - <size> + <outgoing_args_size> and work towards higher
+ addresses. Note that the saves are actually done off the stack
+ pointer in the prologue! This makes for smaller code and easier
+ prologue scanning as the displacement fields will unlikely
be more than 8 bits!
Without frame pointer:
add <size>,sp
- Register saves for d2, d3, a3 as needed. Saves start
- at sp and work towards higher addresses.
+ Register saves for d2, d3, a1, a2 as needed. Saves start
+ at sp + <outgoing_args_size> and work towards higher addresses.
+ Out of line prologue:
+ add <local size>,sp -- optional
+ jsr __prologue
+ add <outgoing_size>,sp -- optional
+
+ The stack pointer remains constant throughout the life of most
+ functions. As a result the compiler will usually omit the
+ frame pointer, so we must handle frame pointerless functions. */
- One day we might keep the stack pointer constant, that won't
- change the code for prologues, but it will make the frame
- pointerless case much more common. */
-
/* Analyze the prologue to determine where registers are saved,
the end of the prologue, etc etc. Return the end of the prologue
scanned.
unsigned char buf[4];
int status;
char *name;
+ int out_of_line_prologue = 0;
/* Use the PC in the frame if it's provided to look up the
start of this function. */
/* If we're in start, then give up. */
if (strcmp (name, "start") == 0)
{
- fi->status = NO_MORE_FRAMES;
+ if (fi)
+ fi->status = NO_MORE_FRAMES;
return pc;
}
status = target_read_memory (fi->pc, buf, 1);
if (status != 0)
{
- fi->frame = read_sp ();
+ if (fi->next == NULL)
+ fi->frame = read_sp ();
return fi->pc;
}
if (buf[0] == 0xfe)
{
- fi->frame = read_sp ();
+ if (fi->next == NULL)
+ fi->frame = read_sp ();
return fi->pc;
}
}
frame hasn't been allocated yet. */
if (fi && fi->pc == func_addr)
{
- fi->frame = read_sp ();
+ if (fi->next == NULL)
+ fi->frame = read_sp ();
return fi->pc;
}
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
- if (fi && fi->status & MY_FRAME_IN_SP)
+ if (fi && fi->next == NULL && fi->status & MY_FRAME_IN_SP)
fi->frame = read_sp ();
return addr;
}
{
/* We still haven't allocated our local stack. Handle this
as if we stopped on the first or last insn of a function. */
- if (fi)
+ if (fi && fi->next == NULL)
fi->frame = read_sp ();
return addr;
}
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
- if (fi)
+ if (fi && fi->next == NULL)
fi->frame = read_sp ();
return addr;
}
}
else
{
- if (fi)
+ if (fi && fi->next == NULL)
fi->frame = read_sp ();
return addr;
}
status = target_read_memory (addr, buf, 2);
if (status != 0)
{
- if (fi && (fi->status & MY_FRAME_IN_SP))
+ if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
addr += 2;
if (addr >= stop)
{
- if (fi && (fi->status & MY_FRAME_IN_SP))
- fi->frame = read_sp () + stack_size;
+ if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
+ fi->frame = read_sp () - stack_size;
return addr;
}
}
status = target_read_memory (addr + 2, buf, 2);
if (status != 0)
{
- if (fi && (fi->status & MY_FRAME_IN_SP))
+ if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
addr += 4;
if (addr >= stop)
{
- if (fi && (fi->status & MY_FRAME_IN_SP))
- fi->frame = read_sp () + stack_size;
+ if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
+ fi->frame = read_sp () - stack_size;
return addr;
}
}
status = target_read_memory (addr + 2, buf, 3);
if (status != 0)
{
- if (fi && (fi->status & MY_FRAME_IN_SP))
+ if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
fi->frame = read_sp ();
return addr;
}
addr += 5;
if (addr >= stop)
{
- if (fi && (fi->status & MY_FRAME_IN_SP))
- fi->frame = read_sp () + stack_size;
+ if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP))
+ fi->frame = read_sp () - stack_size;
return addr;
}
}
- else
+
+ /* Now see if we have a call to __prologue for an out of line
+ prologue. */
+ status = target_read_memory (addr, buf, 2);
+ if (status != 0)
+ return addr;
+
+ /* First check for 16bit pc-relative call to __prologue. */
+ if (buf[0] == 0xfd)
{
- if (fi && (fi->status & MY_FRAME_IN_SP))
- fi->frame = read_sp ();
+ 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;
+ }
+
+ /* Get the PC this instruction will branch to. */
+ temp = (extract_signed_integer (buf, 2) + addr + 3) & 0xffffff;
+
+ /* Get the name of the function at the target address. */
+ 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;
+ }
+
+ /* Note if it is an out of line prologue. */
+ out_of_line_prologue = (strcmp (name, "__prologue") == 0);
+
+ /* This sucks up 3 bytes of instruction space. */
+ 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;
+ }
+ }
+ /* Now check for the 24bit pc-relative call to __prologue. */
+ 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;
+ }
+
+ /* Get the PC this instruction will branch to. */
+ temp = (extract_signed_integer (buf, 3) + addr + 5) & 0xffffff;
+
+ /* Get the name of the function at the target address. */
+ 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;
+ }
+
+ /* Note if it is an out of line prologue. */
+ out_of_line_prologue = (strcmp (name, "__prologue") == 0);
+
+ /* This sucks up 5 bytes of instruction space. */
+ 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;
+ }
+ }
+
+ /* Now actually handle the out of line prologue. */
+ if (out_of_line_prologue)
+ {
+ int outgoing_args_size = 0;
+
+ /* First adjust the stack size for this function. The out of
+ line prologue saves 4 registers (16bytes of data). */
+ if (fi)
+ fi->stack_size -= 16;
+
+ /* Update fi->frame if necessary. */
+ if (fi && fi->next == NULL)
+ fi->frame = read_sp () - fi->stack_size;
+
+ /* After the out of line prologue, there may be another
+ stack adjustment for the outgoing arguments.
+
+ Search for add imm8,a3 (0xd3XX)
+ or add imm16,a3 (0xf70bXXXX)
+ or add imm24,a3 (0xf467XXXXXX). */
+
+ 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;
+
+ /* Now that we know the size of the outgoing arguments, fix
+ fi->frame again if this is the innermost frame. */
+ if (fi && fi->next == NULL)
+ fi->frame -= outgoing_args_size;
+
+ /* Note the register save information and update the stack
+ size for this frame too. */
+ 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;
+ }
+ /* There can be no more prologue insns, so return now. */
return addr;
}
/* At this point fi->frame needs to be correct.
- If MY_FRAME_IN_SP is set, then we need to fix fi->frame so
- that backtracing, find_frame_saved_regs, etc work correctly. */
- if (fi && (fi->status & MY_FRAME_IN_SP) != 0)
+ If MY_FRAME_IN_SP is set and we're the innermost frame, then we
+ need to fix fi->frame so that backtracing, find_frame_saved_regs,
+ etc work correctly. */
+ if (fi && fi->next == NULL && (fi->status & MY_FRAME_IN_SP) != 0)
fi->frame = read_sp () - fi->stack_size;
/* And last we have the register saves. These are relatively
Search for movx d2,(X,a3) (0xf55eXX)
then movx d3,(X,a3) (0xf55fXX)
+ then mov a1,(X,a3) (0x5dXX) No frame pointer case
then mov a2,(X,a3) (0x5eXX) No frame pointer case
or mov a0,(X,a3) (0x5cXX) Frame pointer case. */
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)
Else it's still in $a2.
If our caller does not have a frame pointer, then his
- frame base is fi->frame + caller's stack size + 4. */
+ frame base is fi->frame + -caller's stack size + 4. */
/* The easiest way to get that info is to analyze our caller's frame.
{
/* Our caller does not have a frame pointer. So his frame starts
at the base of our frame (fi->frame) + <his size> + 4 (saved pc). */
- return fi->frame + dummy_frame.stack_size + 4;
+ return fi->frame + -dummy_frame.stack_size + 4;
}
}
mn10200_skip_prologue (pc)
CORE_ADDR pc;
{
- CORE_ADDR func_addr, func_end;
-
- /* First check the symbol table. That'll be faster than scanning
- the prologue instructions if we have debug sybmols. */
- if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
- {
- struct symtab_and_line sal;
-
- sal = find_pc_line (func_addr, 0);
-
- if (sal.line != 0 && sal.end < func_end)
- return sal.end;
-
- return mn10200_analyze_prologue (NULL, pc);
- }
-
- /* We couldn't find the start of this function, do nothing. */
- return pc;
+ /* We used to check the debug symbols, but that can lose if
+ we have a null prologue. */
+ return mn10200_analyze_prologue (NULL, pc);
}
/* Function: pop_frame
int argnum = 0;
int len = 0;
int stack_offset = 0;
+ int regsused = struct_return ? 1 : 0;
/* This should be a nop, but align the stack just in case something
went wrong. Stacks are two byte aligned on the mn10200. */
XXX This doesn't appear to handle pass-by-invisible reference
arguments. */
for (argnum = 0; argnum < nargs; argnum++)
- len += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 1) & ~1);
+ {
+ int arg_length = (TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 1) & ~1;
+
+ /* If we've used all argument registers, then this argument is
+ pushed. */
+ if (regsused >= 2 || arg_length > 4)
+ {
+ regsused = 2;
+ len += arg_length;
+ }
+ /* We know we've got some arg register space left. If this argument
+ will fit entirely in regs, then put it there. */
+ 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;
+ }
+ }
/* Allocate stack space. */
sp -= len;
+ regsused = struct_return ? 1 : 0;
/* Push all arguments onto the stack. */
for (argnum = 0; argnum < nargs; argnum++)
{
int len;
char *val;
- /* XXX Check this. What about UNIONS? Size check looks
- wrong too. */
+ /* XXX Check this. What about UNIONS? */
if (TYPE_CODE (VALUE_TYPE (*args)) == TYPE_CODE_STRUCT
&& TYPE_LENGTH (VALUE_TYPE (*args)) > 8)
{
val = (char *)VALUE_CONTENTS (*args);
}
- while (len > 0)
+ 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)
{
- /* XXX This looks wrong; we can have one and two byte args. */
- write_memory (sp + stack_offset, val, 2);
+ 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;
+ len -= 2;
+ val += 2;
+ stack_offset += 2;
+ }
}
args++;
}
write_memory (sp - 4, buf, 4);
return sp - 4;
}
+
+/* Function: store_struct_return (addr,sp)
+ Store the structure value return address for an inferior function
+ call. */
+
+CORE_ADDR
+mn10200_store_struct_return (addr, sp)
+ CORE_ADDR addr;
+ CORE_ADDR sp;
+{
+ /* The structure return address is passed as the first argument. */
+ write_register (0, addr);
+ return sp;
+}
/* Function: frame_saved_pc
Find the caller of this frame. We do this by seeing if RP_REGNUM