mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-23 11:39:26 +08:00
Better support V.4 calling sequences.
This commit is contained in:
@ -1,3 +1,27 @@
|
||||
Wed Jul 26 23:33:34 1995 Michael Meissner <meissner@cygnus.com>
|
||||
|
||||
* config/rs6000/tm-rs6000.h (rs6000_framedata): Add offsets the
|
||||
gprs, fprs, lr, and cr is stored at.
|
||||
(FRAME_FIND_SAVED_REGS): Use new fields in rs6000_framedata.
|
||||
(function_frame_info): Delete declaration.
|
||||
(SKIP_PROLOGUE): Skip_prologue is now passed a rs6000_framedata
|
||||
structure to fill in.
|
||||
(FRAMELESS_FUNCTION_INVOCATION): Function now longer takes a
|
||||
second argument.
|
||||
(FRAME_SAVED_PC): Call frame_saved_pc.
|
||||
|
||||
* rs6000-tdep.c (skip_prologue): Recognize V.4 prologues as well
|
||||
as AIX style. Fill in rs6000_framedata structure. Remember where
|
||||
the gprs, fprs, cr, and lr are saved.
|
||||
(pop_frame): Use skip_prologue, not function_frame_info, and use
|
||||
new rs6000_framedata fields.
|
||||
(function_frame_info): Function deleted.
|
||||
(frameless_function_invocation): Separate frame_saved_pc support
|
||||
to new function. Recognize V.4 frames.
|
||||
(frame_saved_pc): New function.
|
||||
(frame_get_cache_fsr): Use skip_prologue, not function_frame_info.
|
||||
(frame_initial_stack_address): Ditto.
|
||||
|
||||
Wed Jul 26 01:00:37 1995 Jeff Law (law@snake.cs.utah.edu)
|
||||
|
||||
* remote.c: Add documentation for extended protocol operations
|
||||
|
@ -56,7 +56,7 @@ struct fp_status {
|
||||
};
|
||||
|
||||
|
||||
/* To be used by function_frame_info. */
|
||||
/* To be used by skip_prologue. */
|
||||
|
||||
struct rs6000_framedata {
|
||||
int offset; /* # of bytes in gpr's and fpr's are saved */
|
||||
@ -65,11 +65,12 @@ struct rs6000_framedata {
|
||||
int alloca_reg; /* alloca register number (frame ptr) */
|
||||
char frameless; /* true if frameless functions. */
|
||||
char nosavedpc; /* true if pc not saved. */
|
||||
int gpr_offset; /* offset of saved gprs */
|
||||
int fpr_offset; /* offset of saved fprs */
|
||||
int lr_offset; /* offset of saved lr */
|
||||
int cr_offset; /* offset of saved cr */
|
||||
};
|
||||
|
||||
void
|
||||
function_frame_info PARAMS ((CORE_ADDR, struct rs6000_framedata *));
|
||||
|
||||
/* Define the byte order of the machine. */
|
||||
|
||||
#define TARGET_BYTE_ORDER BIG_ENDIAN
|
||||
@ -87,7 +88,14 @@ function_frame_info PARAMS ((CORE_ADDR, struct rs6000_framedata *));
|
||||
/* Advance PC across any function entry prologue instructions
|
||||
to reach some "real" code. */
|
||||
|
||||
#define SKIP_PROLOGUE(pc) pc = skip_prologue (pc)
|
||||
#define SKIP_PROLOGUE(pc) \
|
||||
do { \
|
||||
struct rs6000_framedata _frame; \
|
||||
pc = skip_prologue (pc, &_frame); \
|
||||
} while (0)
|
||||
|
||||
extern CORE_ADDR skip_prologue PARAMS((CORE_ADDR, struct rs6000_framedata *));
|
||||
|
||||
|
||||
/* If PC is in some function-call trampoline code, return the PC
|
||||
where the function itself actually starts. If not, return NULL. */
|
||||
@ -386,7 +394,9 @@ CORE_ADDR rs6000_frame_chain PARAMS ((struct frame_info *));
|
||||
does not, FRAMELESS is set to 1, else 0. */
|
||||
|
||||
#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \
|
||||
FRAMELESS = frameless_function_invocation (FI, 0)
|
||||
FRAMELESS = frameless_function_invocation (FI)
|
||||
|
||||
extern int frameless_function_invocation PARAMS((struct frame_info *));
|
||||
|
||||
/* Functions calling alloca() change the value of the stack pointer. We
|
||||
need to use initial stack pointer (which is saved in r31 by gcc) in
|
||||
@ -424,17 +434,10 @@ CORE_ADDR rs6000_frame_chain PARAMS ((struct frame_info *));
|
||||
#define SIG_FRAME_PC_OFFSET 96
|
||||
#define SIG_FRAME_FP_OFFSET 284
|
||||
|
||||
/* Frameless function invocation in IBM RS/6000 is sometimes
|
||||
half-done. It perfectly sets up a new frame, e.g. a new frame (in
|
||||
fact stack) pointer, etc, but it doesn't save the %pc. We call
|
||||
frameless_function_invocation to tell us how to get the %pc. */
|
||||
/* Return saved PC from a frame */
|
||||
#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME)
|
||||
|
||||
#define FRAME_SAVED_PC(FRAME) \
|
||||
(frameless_function_invocation (FRAME, 1) \
|
||||
? SAVED_PC_AFTER_CALL (FRAME) \
|
||||
: (FRAME)->signal_handler_caller \
|
||||
? read_memory_integer ((FRAME)->frame + SIG_FRAME_PC_OFFSET, 4) \
|
||||
: read_memory_integer (rs6000_frame_chain (FRAME) + 8, 4))
|
||||
extern unsigned long frame_saved_pc PARAMS ((struct frame_info *));
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(FI) \
|
||||
(((struct frame_info*)(FI))->initial_sp ? \
|
||||
@ -471,40 +474,57 @@ CORE_ADDR rs6000_frame_chain PARAMS ((struct frame_info *));
|
||||
CORE_ADDR frame_addr, func_start; \
|
||||
struct rs6000_framedata fdata; \
|
||||
\
|
||||
/* find the start of the function and collect info about its frame. */\
|
||||
/* find the start of the function and collect info about its frame. */ \
|
||||
\
|
||||
func_start = get_pc_function_start ((FRAME_INFO)->pc) + FUNCTION_START_OFFSET; \
|
||||
function_frame_info (func_start, &fdata); \
|
||||
memset (&(FRAME_SAVED_REGS), '\0', sizeof (FRAME_SAVED_REGS)); \
|
||||
(void) skip_prologue (func_start, &fdata); \
|
||||
memset (&(FRAME_SAVED_REGS), '\0', sizeof (FRAME_SAVED_REGS)); \
|
||||
\
|
||||
/* if there were any saved registers, figure out parent's stack pointer. */ \
|
||||
frame_addr = 0; \
|
||||
/* the following is true only if the frame doesn't have a call to alloca(), \
|
||||
FIXME. */ \
|
||||
if (fdata.saved_fpr >= 0 || fdata.saved_gpr >= 0) { \
|
||||
if ((FRAME_INFO)->prev && (FRAME_INFO)->prev->frame) \
|
||||
frame_addr = (FRAME_INFO)->prev->frame; \
|
||||
else \
|
||||
frame_addr = read_memory_integer ((FRAME_INFO)->frame, 4); \
|
||||
if (fdata.saved_fpr == 0 && fdata.saved_gpr == 0 && \
|
||||
fdata.lr_offset == 0 && fdata.cr_offset == 0) { \
|
||||
frame_addr = 0; \
|
||||
\
|
||||
} else if ((FRAME_INFO)->prev && (FRAME_INFO)->prev->frame) { \
|
||||
frame_addr = (FRAME_INFO)->prev->frame; \
|
||||
\
|
||||
} else { \
|
||||
frame_addr = read_memory_integer ((FRAME_INFO)->frame, 4); \
|
||||
} \
|
||||
\
|
||||
/* if != -1, fdata.saved_fpr is the smallest number of saved_fpr. All fpr's \
|
||||
from saved_fpr to fp31 are saved right underneath caller stack pointer, \
|
||||
starting from fp31 first. */ \
|
||||
\
|
||||
/* if != -1, fdata.saved_fpr is the smallest number of saved_fpr. All \
|
||||
fpr's from saved_fpr to f31 are saved. */ \
|
||||
if (fdata.saved_fpr >= 0) { \
|
||||
for (ii=31; ii >= fdata.saved_fpr; --ii) \
|
||||
(FRAME_SAVED_REGS).regs [FP0_REGNUM + ii] = frame_addr - ((32 - ii) * 8); \
|
||||
frame_addr -= (32 - fdata.saved_fpr) * 8; \
|
||||
int fpr_offset = frame_addr + fdata.fpr_offset; \
|
||||
for (ii = fdata.saved_fpr; ii < 32; ii++) { \
|
||||
(FRAME_SAVED_REGS).regs [FP0_REGNUM + ii] = fpr_offset; \
|
||||
fpr_offset += 8; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* if != -1, fdata.saved_gpr is the smallest number of saved_gpr. All gpr's \
|
||||
from saved_gpr to gpr31 are saved right under saved fprs, starting \
|
||||
from r31 first. */ \
|
||||
/* if != -1, fdata.saved_gpr is the smallest number of saved_gpr. All \
|
||||
gpr's from saved_gpr to r31 are saved. */ \
|
||||
if (fdata.saved_gpr >= 0) { \
|
||||
int gpr_offset = frame_addr + fdata.gpr_offset; \
|
||||
for (ii = fdata.saved_gpr; ii < 32; ii++) { \
|
||||
(FRAME_SAVED_REGS).regs [ii] = gpr_offset; \
|
||||
gpr_offset += 4; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (fdata.saved_gpr >= 0) \
|
||||
for (ii=31; ii >= fdata.saved_gpr; --ii) \
|
||||
(FRAME_SAVED_REGS).regs [ii] = frame_addr - ((32 - ii) * 4); \
|
||||
/* If != 0, fdata.cr_offset is the offset from the frame that holds \
|
||||
the CR */ \
|
||||
if (fdata.cr_offset != 0) { \
|
||||
(FRAME_SAVED_REGS).regs [CR_REGNUM] = frame_addr + fdata.cr_offset; \
|
||||
} \
|
||||
\
|
||||
/* If != 0, fdata.cr_offset is the offset from the frame that holds \
|
||||
the LR */ \
|
||||
if (fdata.lr_offset != 0) { \
|
||||
(FRAME_SAVED_REGS).regs [LR_REGNUM] = frame_addr + fdata.lr_offset; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,104 +177,181 @@ single_step (signal)
|
||||
}
|
||||
|
||||
|
||||
/* return pc value after skipping a function prologue. */
|
||||
/* return pc value after skipping a function prologue and also return
|
||||
information about a function frame.
|
||||
|
||||
skip_prologue (pc)
|
||||
CORE_ADDR pc;
|
||||
in struct rs6000_frameinfo fdata:
|
||||
- frameless is TRUE, if function does not have a frame.
|
||||
- nosavedpc is TRUE, if function does not save %pc value in its frame.
|
||||
- offset is the number of bytes used in the frame to save registers.
|
||||
- saved_gpr is the number of the first saved gpr.
|
||||
- saved_fpr is the number of the first saved fpr.
|
||||
- alloca_reg is the number of the register used for alloca() handling.
|
||||
Otherwise -1.
|
||||
- gpr_offset is the offset of the saved gprs
|
||||
- fpr_offset is the offset of the saved fprs
|
||||
- lr_offset is the offset of the saved lr
|
||||
- cr_offset is the offset of the saved cr
|
||||
*/
|
||||
|
||||
#define SIGNED_SHORT(x) \
|
||||
((sizeof (short) == 2) \
|
||||
? ((int)(short)(x)) \
|
||||
: ((int)((((x) & 0xffff) ^ 0x8000) - 0x8000)))
|
||||
|
||||
#define GET_SRC_REG(x) (((x) >> 21) & 0x1f)
|
||||
|
||||
CORE_ADDR
|
||||
skip_prologue (pc, fdata)
|
||||
CORE_ADDR pc;
|
||||
struct rs6000_framedata *fdata;
|
||||
{
|
||||
CORE_ADDR orig_pc = pc;
|
||||
char buf[4];
|
||||
unsigned int tmp;
|
||||
unsigned long op;
|
||||
int lr_reg = 0;
|
||||
int cr_reg = 0;
|
||||
int reg;
|
||||
static struct rs6000_framedata zero_frame;
|
||||
|
||||
*fdata = zero_frame;
|
||||
fdata->saved_gpr = -1;
|
||||
fdata->saved_fpr = -1;
|
||||
fdata->alloca_reg = -1;
|
||||
fdata->frameless = 1;
|
||||
fdata->nosavedpc = 1;
|
||||
|
||||
if (target_read_memory (pc, buf, 4))
|
||||
return pc; /* Can't access it -- assume no prologue. */
|
||||
op = extract_unsigned_integer (buf, 4);
|
||||
|
||||
/* Assume that subsequent fetches can fail with low probability. */
|
||||
pc -= 4;
|
||||
for (;;)
|
||||
{
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
|
||||
if (op == 0x7c0802a6) { /* mflr r0 */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
if ((op & 0xfc1fffff) == 0x7c0802a6) { /* mflr Rx */
|
||||
lr_reg = (op & 0x03e00000) | 0x90010000;
|
||||
continue;
|
||||
|
||||
if ((op & 0xfc00003e) == 0x7c000026) { /* mfcr Rx */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
} else if ((op & 0xfc1fffff) == 0x7c000026) { /* mfcr Rx */
|
||||
cr_reg = (op & 0x03e00000) | 0x90010000;
|
||||
continue;
|
||||
|
||||
if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
|
||||
pc += 4;
|
||||
} else if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */
|
||||
reg = GET_SRC_REG (op);
|
||||
if (fdata->saved_fpr == -1 || fdata->saved_fpr > reg) {
|
||||
fdata->saved_fpr = reg;
|
||||
fdata->fpr_offset = SIGNED_SHORT (op);
|
||||
}
|
||||
continue;
|
||||
|
||||
} else if (((op & 0xfc1f0000) == 0xbc010000) || /* stm Rx, NUM(r1) */
|
||||
((op & 0xfc1f0000) == 0x90010000 && /* st rx,NUM(r1), rx >= r13 */
|
||||
(op & 0x03e00000) >= 0x01a00000)) {
|
||||
|
||||
reg = GET_SRC_REG (op);
|
||||
if (fdata->saved_gpr == -1 || fdata->saved_gpr > reg) {
|
||||
fdata->saved_gpr = reg;
|
||||
fdata->gpr_offset = SIGNED_SHORT (op);
|
||||
}
|
||||
continue;
|
||||
|
||||
} else if ((op & 0xffff0000) == 0x3c000000) { /* addis 0,0,NUM, used for >= 32k frames */
|
||||
fdata->offset = (op & 0x0000ffff) << 16;
|
||||
continue;
|
||||
|
||||
} else if ((op & 0xffff0000) == 0x60000000) { /* ori 0,0,NUM, 2nd half of >= 32k frames */
|
||||
fdata->offset |= (op & 0x0000ffff);
|
||||
continue;
|
||||
|
||||
} else if ((op & 0xffff0000) == lr_reg) { /* st Rx,NUM(r1) where Rx == lr */
|
||||
fdata->lr_offset = SIGNED_SHORT (op);
|
||||
fdata->nosavedpc = 0;
|
||||
lr_reg = 0;
|
||||
continue;
|
||||
|
||||
} else if ((op & 0xffff0000) == cr_reg) { /* st Rx,NUM(r1) where Rx == cr */
|
||||
fdata->cr_offset = SIGNED_SHORT (op);
|
||||
cr_reg = 0;
|
||||
continue;
|
||||
|
||||
} else if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
|
||||
op = read_memory_integer (pc+4, 4);
|
||||
|
||||
/* At this point, make sure this is not a trampoline function
|
||||
(a function that simply calls another functions, and nothing else).
|
||||
If the next is not a nop, this branch was part of the function
|
||||
prologue. */
|
||||
|
||||
if (op == 0x4def7b82 || op == 0) /* crorc 15, 15, 15 */
|
||||
return pc; /* don't skip over this branch */
|
||||
|
||||
continue;
|
||||
|
||||
} else if ((op & 0xffff0000) == 0x94210000) { /* stu r1,NUM(r1) */
|
||||
fdata->offset = - SIGNED_SHORT (op);
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
break;
|
||||
|
||||
} else if (op == 0x7c21016e) { /* stwux 1,1,0 */
|
||||
pc += 4; /* offset set above */
|
||||
op = read_memory_integer (pc, 4);
|
||||
break;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip -mreloctable (V.4/eabi) load up the toc case */
|
||||
if (op == 0x48000005 && /* bl .+4 */
|
||||
read_memory_integer (pc+4, 4) == 0x7fc802a6 && /* mflr r30 */
|
||||
(read_memory_integer (pc+8, 4) & 0xffff) == 0x801e0000 && /* lwz 0,NUM(r30) */
|
||||
read_memory_integer (pc+12, 4) == 0x7fc0f214) { /* add r30,r0,r30 */
|
||||
pc += 16;
|
||||
op = read_memory_integer (pc, 4);
|
||||
|
||||
/* At this point, make sure this is not a trampoline function
|
||||
(a function that simply calls another functions, and nothing else).
|
||||
If the next is not a nop, this branch was part of the function
|
||||
prologue. */
|
||||
|
||||
if (op == 0x4def7b82 || /* crorc 15, 15, 15 */
|
||||
op == 0x0)
|
||||
return pc - 4; /* don't skip over this branch */
|
||||
/* And -mminimal-toc code on V.4 */
|
||||
} else if ((op & 0xffff0000) == 0x3fc00000 && /* addis 30,0,foo@ha */
|
||||
/* addi 30,30,foo@l */
|
||||
((read_memory_integer (pc+4, 4) & 0xffff0000) == 0x3bde0000)) {
|
||||
pc += 8;
|
||||
op = read_memory_integer (pc, 8);
|
||||
}
|
||||
|
||||
if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */
|
||||
pc += 4; /* store floating register double */
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
if ((op & 0xfc1f0000) == 0xbc010000) { /* stm Rx, NUM(r1) */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
while ((op & 0xfc1f0000) == 0x90010000 && /* st rx,NUM(r1), rx >= r13 */
|
||||
(op & 0x03e00000) >= 0x01a00000) {
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
if (op == 0x90010008) { /* st r0,8(r1) */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
if (op == 0x91810004) { /* st r12,4(r1) */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
if ((op & 0xffff0000) == 0x94210000) { /* stu r1,NUM(r1) */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
while ((tmp = (op >> 22)) == 0x20f) { /* l r31, ... or */
|
||||
pc += 4; /* l r30, ... */
|
||||
while ((op >> 22) == 0x20f) { /* l r31, ... or */
|
||||
pc += 4; /* l r30, ... */
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
/* store parameters into stack */
|
||||
while(
|
||||
(op & 0xfc1f0000) == 0xd8010000 || /* stfd Rx,NUM(r1) */
|
||||
(op & 0xfc1f0000) == 0x90010000 || /* st r?, NUM(r1) */
|
||||
(op & 0xfc000000) == 0xfc000000 || /* frsp, fp?, .. */
|
||||
(op & 0xd0000000) == 0xd0000000) /* stfs, fp?, .. */
|
||||
{
|
||||
pc += 4; /* store fpr double */
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
(op & 0xfc1f0000) == 0x90010000 || /* st rx,NUM(r1) */
|
||||
(op & 0xfc1f0000) == 0xd8010000 || /* stfd Rx,NUM(r1) */
|
||||
(op & 0xfc1f0000) == 0xfc010000) { /* frsp, fp?,NUM(r1) */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
}
|
||||
|
||||
if (op == 0x603f0000 /* oril r31, r1, 0x0 */
|
||||
|| op == 0x7c3f0b78) { /* mr r31, r1 */
|
||||
pc += 4; /* this happens if r31 is used as */
|
||||
op = read_memory_integer (pc, 4); /* frame ptr. (gcc does that) */
|
||||
/* Set up frame pointer */
|
||||
if (op == 0x603f0000 /* oril r31, r1, 0x0 */
|
||||
|| op == 0x7c3f0b78) { /* mr r31, r1 */
|
||||
pc += 4; /* this happens if r31 is used as */
|
||||
op = read_memory_integer (pc, 4); /* frame ptr. (gcc does that) */
|
||||
|
||||
tmp = 0;
|
||||
while ((op >> 16) == (0x907f + tmp)) { /* st r3, NUM(r31) */
|
||||
pc += 4; /* st r4, NUM(r31), ... */
|
||||
/* store parameters into frame */
|
||||
while (
|
||||
(op & 0xfc1f0000) == 0x901f0000 || /* st rx,NUM(r1) */
|
||||
(op & 0xfc1f0000) == 0xd81f0000 || /* stfd Rx,NUM(r1) */
|
||||
(op & 0xfc1f0000) == 0xfc1f0000) { /* frsp, fp?,NUM(r1) */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
tmp += 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* I have problems with skipping over __main() that I need to address
|
||||
* sometime. Previously, I used to use misc_function_vector which
|
||||
@ -302,6 +379,7 @@ CORE_ADDR pc;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
fdata->frameless = (pc == orig_pc);
|
||||
return pc;
|
||||
}
|
||||
|
||||
@ -496,16 +574,16 @@ pop_frame ()
|
||||
saved %pc value in the previous frame. */
|
||||
|
||||
addr = get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET;
|
||||
function_frame_info (addr, &fdata);
|
||||
(void) skip_prologue (addr, &fdata);
|
||||
|
||||
if (fdata.frameless)
|
||||
prev_sp = sp;
|
||||
else
|
||||
prev_sp = read_memory_integer (sp, 4);
|
||||
if (fdata.nosavedpc)
|
||||
if (fdata.lr_offset == 0)
|
||||
lr = read_register (LR_REGNUM);
|
||||
else
|
||||
lr = read_memory_integer (prev_sp+8, 4);
|
||||
lr = read_memory_integer (prev_sp + fdata.lr_offset, 4);
|
||||
|
||||
/* reset %pc value. */
|
||||
write_register (PC_REGNUM, lr);
|
||||
@ -568,147 +646,6 @@ fix_call_dummy(dummyname, pc, fun, nargs, type)
|
||||
*(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4) = ii;
|
||||
}
|
||||
|
||||
|
||||
/* return information about a function frame.
|
||||
in struct rs6000_frameinfo fdata:
|
||||
- frameless is TRUE, if function does not have a frame.
|
||||
- nosavedpc is TRUE, if function does not save %pc value in its frame.
|
||||
- offset is the number of bytes used in the frame to save registers.
|
||||
- saved_gpr is the number of the first saved gpr.
|
||||
- saved_fpr is the number of the first saved fpr.
|
||||
- alloca_reg is the number of the register used for alloca() handling.
|
||||
Otherwise -1.
|
||||
*/
|
||||
void
|
||||
function_frame_info (pc, fdata)
|
||||
CORE_ADDR pc;
|
||||
struct rs6000_framedata *fdata;
|
||||
{
|
||||
unsigned int tmp;
|
||||
register unsigned int op;
|
||||
char buf[4];
|
||||
|
||||
fdata->offset = 0;
|
||||
fdata->saved_gpr = fdata->saved_fpr = fdata->alloca_reg = -1;
|
||||
fdata->frameless = 1;
|
||||
|
||||
/* Do not error out if we can't access the instructions. */
|
||||
if (target_read_memory (pc, buf, 4))
|
||||
return;
|
||||
op = extract_unsigned_integer (buf, 4);
|
||||
if (op == 0x7c0802a6) { /* mflr r0 */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
fdata->nosavedpc = 0;
|
||||
fdata->frameless = 0;
|
||||
}
|
||||
else /* else, pc is not saved */
|
||||
fdata->nosavedpc = 1;
|
||||
|
||||
if ((op & 0xfc00003e) == 0x7c000026) { /* mfcr Rx */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
fdata->frameless = 0;
|
||||
}
|
||||
|
||||
if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
/* At this point, make sure this is not a trampoline function
|
||||
(a function that simply calls another functions, and nothing else).
|
||||
If the next is not a nop, this branch was part of the function
|
||||
prologue. */
|
||||
|
||||
if (op == 0x4def7b82 || /* crorc 15, 15, 15 */
|
||||
op == 0x0)
|
||||
return; /* prologue is over */
|
||||
fdata->frameless = 0;
|
||||
}
|
||||
|
||||
if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */
|
||||
pc += 4; /* store floating register double */
|
||||
op = read_memory_integer (pc, 4);
|
||||
fdata->frameless = 0;
|
||||
}
|
||||
|
||||
if ((op & 0xfc1f0000) == 0xbc010000) { /* stm Rx, NUM(r1) */
|
||||
int tmp2;
|
||||
fdata->saved_gpr = (op >> 21) & 0x1f;
|
||||
tmp2 = op & 0xffff;
|
||||
if (tmp2 > 0x7fff)
|
||||
tmp2 = (~0 &~ 0xffff) | tmp2;
|
||||
|
||||
if (tmp2 < 0) {
|
||||
tmp2 = tmp2 * -1;
|
||||
fdata->saved_fpr = (tmp2 - ((32 - fdata->saved_gpr) * 4)) / 8;
|
||||
if ( fdata->saved_fpr > 0)
|
||||
fdata->saved_fpr = 32 - fdata->saved_fpr;
|
||||
else
|
||||
fdata->saved_fpr = -1;
|
||||
}
|
||||
fdata->offset = tmp2;
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
fdata->frameless = 0;
|
||||
}
|
||||
|
||||
while (((tmp = op >> 16) == 0x9001) || /* st r0, NUM(r1) */
|
||||
(tmp == 0x9421) || /* stu r1, NUM(r1) */
|
||||
(tmp == 0x93e1)) /* st r31, NUM(r1) */
|
||||
{
|
||||
int tmp2;
|
||||
|
||||
/* gcc takes a short cut and uses this instruction to save r31 only. */
|
||||
|
||||
if (tmp == 0x93e1) {
|
||||
if (fdata->offset)
|
||||
/* fatal ("Unrecognized prolog."); */
|
||||
printf_unfiltered ("Unrecognized prolog!\n");
|
||||
|
||||
fdata->saved_gpr = 31;
|
||||
tmp2 = op & 0xffff;
|
||||
if (tmp2 > 0x7fff) {
|
||||
tmp2 = - ((~0 &~ 0xffff) | tmp2);
|
||||
fdata->saved_fpr = (tmp2 - ((32 - 31) * 4)) / 8;
|
||||
if ( fdata->saved_fpr > 0)
|
||||
fdata->saved_fpr = 32 - fdata->saved_fpr;
|
||||
else
|
||||
fdata->saved_fpr = -1;
|
||||
}
|
||||
fdata->offset = tmp2;
|
||||
}
|
||||
pc += 4;
|
||||
op = read_memory_integer (pc, 4);
|
||||
fdata->frameless = 0;
|
||||
}
|
||||
|
||||
while ((tmp = (op >> 22)) == 0x20f) { /* l r31, ... or */
|
||||
pc += 4; /* l r30, ... */
|
||||
op = read_memory_integer (pc, 4);
|
||||
fdata->frameless = 0;
|
||||
}
|
||||
|
||||
/* store parameters into stack */
|
||||
while(
|
||||
(op & 0xfc1f0000) == 0xd8010000 || /* stfd Rx,NUM(r1) */
|
||||
(op & 0xfc1f0000) == 0x90010000 || /* st r?, NUM(r1) */
|
||||
(op & 0xfc000000) == 0xfc000000 || /* frsp, fp?, .. */
|
||||
(op & 0xd0000000) == 0xd0000000) /* stfs, fp?, .. */
|
||||
{
|
||||
pc += 4; /* store fpr double */
|
||||
op = read_memory_integer (pc, 4);
|
||||
fdata->frameless = 0;
|
||||
}
|
||||
|
||||
if (op == 0x603f0000 /* oril r31, r1, 0x0 */
|
||||
|| op == 0x7c3f0b78) /* mr r31, r1 */
|
||||
{
|
||||
fdata->alloca_reg = 31;
|
||||
fdata->frameless = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Pass the arguments in either registers, or in the stack. In RS6000, the first
|
||||
eight words of the argument list (that might be less than eight parameters if
|
||||
some parameters occupy more than one word) are passed in r3..r11 registers.
|
||||
@ -964,15 +901,10 @@ CORE_ADDR pc;
|
||||
}
|
||||
|
||||
|
||||
/* Determines whether the function FI has a frame on the stack or not.
|
||||
Called from the FRAMELESS_FUNCTION_INVOCATION macro in tm.h with a
|
||||
second argument of 0, and from the FRAME_SAVED_PC macro with a
|
||||
second argument of 1. */
|
||||
|
||||
/* Determines whether the function FI has a frame on the stack or not. */
|
||||
int
|
||||
frameless_function_invocation (fi, pcsaved)
|
||||
struct frame_info *fi;
|
||||
int pcsaved;
|
||||
frameless_function_invocation (fi)
|
||||
struct frame_info *fi;
|
||||
{
|
||||
CORE_ADDR func_start;
|
||||
struct rs6000_framedata fdata;
|
||||
@ -991,10 +923,35 @@ int pcsaved;
|
||||
if (!func_start)
|
||||
return 0;
|
||||
|
||||
function_frame_info (func_start, &fdata);
|
||||
return pcsaved ? fdata.nosavedpc : fdata.frameless;
|
||||
(void) skip_prologue (func_start, &fdata);
|
||||
return fdata.frameless;
|
||||
}
|
||||
|
||||
/* Return the PC saved in a frame */
|
||||
unsigned long
|
||||
frame_saved_pc (fi)
|
||||
struct frame_info *fi;
|
||||
{
|
||||
CORE_ADDR func_start;
|
||||
struct rs6000_framedata fdata;
|
||||
int frameless;
|
||||
|
||||
func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
|
||||
|
||||
/* If we failed to find the start of the function, it is a mistake
|
||||
to inspect the instructions. */
|
||||
if (!func_start)
|
||||
return 0;
|
||||
|
||||
(void) skip_prologue (func_start, &fdata);
|
||||
if (fdata.lr_offset == 0)
|
||||
return read_register (LR_REGNUM);
|
||||
|
||||
if (fi->signal_handler_caller)
|
||||
return read_memory_integer (fi->frame + SIG_FRAME_PC_OFFSET, 4);
|
||||
|
||||
return read_memory_integer (rs6000_frame_chain (fi) + fdata.lr_offset, 4);
|
||||
}
|
||||
|
||||
/* If saved registers of frame FI are not known yet, read and cache them.
|
||||
&FDATAP contains rs6000_framedata; TDATAP can be NULL,
|
||||
@ -1014,7 +971,7 @@ frame_get_cache_fsr (fi, fdatap)
|
||||
|
||||
if (fdatap == NULL) {
|
||||
fdatap = &work_fdata;
|
||||
function_frame_info (get_pc_function_start (fi->pc), fdatap);
|
||||
(void) skip_prologue (get_pc_function_start (fi->pc), fdatap);
|
||||
}
|
||||
|
||||
fi->cache_fsr = (struct frame_saved_regs *)
|
||||
@ -1065,7 +1022,7 @@ frame_initial_stack_address (fi)
|
||||
|
||||
/* find out if this function is using an alloca register.. */
|
||||
|
||||
function_frame_info (get_pc_function_start (fi->pc), &fdata);
|
||||
(void) skip_prologue (get_pc_function_start (fi->pc), &fdata);
|
||||
|
||||
/* if saved registers of this frame are not known yet, read and cache them. */
|
||||
|
||||
|
Reference in New Issue
Block a user