#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "symtab.h"
#include "target.h"
#include "language.h"
#include "gdbcore.h"
#include "symfile.h"
#include "objfiles.h"
#include <sys/types.h>
#include <sys/param.h>
#include <signal.h>
#include <sys/user.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/procfs.h>
#include <link.h>
#include <elf.h>
#include <asm/ptrace.h>
#include <asm/sigcontext.h>
#define PT_REGS_PTR_OFFSET \
(STACK_FRAME_OVERHEAD + offsetof(struct sigcontext_struct, regs))
extern struct obstack frame_cache_obstack;
static void frame_get_cache_fsr PARAMS ((struct frame_info *fi,
struct rs6000_framedata *fdatap));
int
at_subroutine_call_instruction_target(prevpc,stoppc)
CORE_ADDR prevpc;
CORE_ADDR stoppc;
{
int instr;
int opcode, ext_op, lk;
instr = read_memory_unsigned_integer (prevpc, 4);
opcode = (instr >> 26) & 0x1f;
ext_op = (instr >> 1) & 0x3ff;
lk = instr & 1;
return ((prevpc+4 != stoppc)
&& lk == 1
&& (opcode == 18
|| opcode == 16
|| (opcode == 19 && (ext_op == 16 || ext_op == 528))));
}
#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 long op;
long offset = 0;
int lr_reg = 0;
int cr_reg = 0;
int reg;
int framep = 0;
int minimal_toc_loaded = 0;
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;
pc -= 4;
for (;;)
{
pc += 4;
op = read_memory_unsigned_integer (pc, 4);
if ((op & 0xfc1fffff) == 0x7c0802a6) {
lr_reg = (op & 0x03e00000) | 0x90010000;
continue;
} else if ((op & 0xfc1fffff) == 0x7c000026) {
cr_reg = (op & 0x03e00000) | 0x90010000;
continue;
} else if ((op & 0xfc1f0000) == 0xd8010000) {
reg = GET_SRC_REG (op);
if (fdata->saved_fpr == -1 || fdata->saved_fpr > reg) {
fdata->saved_fpr = reg;
fdata->fpr_offset = SIGNED_SHORT (op) + offset;
}
continue;
} else if (((op & 0xfc1f0000) == 0xbc010000) ||
((op & 0xfc1f0000) == 0x90010000 &&
(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) + offset;
}
continue;
} else if ((op & 0xffff0000) == 0x3c000000) {
fdata->offset = (op & 0x0000ffff) << 16;
fdata->frameless = 0;
continue;
} else if ((op & 0xffff0000) == 0x60000000) {
fdata->offset |= (op & 0x0000ffff);
fdata->frameless = 0;
continue;
} else if (lr_reg && (op & 0xffff0000) == lr_reg) {
fdata->lr_offset = SIGNED_SHORT (op) + offset;
fdata->nosavedpc = 0;
lr_reg = 0;
continue;
} else if (cr_reg && (op & 0xffff0000) == cr_reg) {
fdata->cr_offset = SIGNED_SHORT (op) + offset;
cr_reg = 0;
continue;
} else if (op == 0x48000005) {
continue;
} else if (op == 0x48000004) {
break;
} else if (((op & 0xffff0000) == 0x801e0000 ||
op == 0x7fc0f214) &&
lr_reg == 0x901e0000) {
continue;
} else if ((op & 0xffff0000) == 0x3fc00000 ||
(op & 0xffff0000) == 0x3bde0000) {
continue;
} else if ((op & 0xfc000000) == 0x48000000
&& read_memory_unsigned_integer(pc+(((((long) op)<<6)>>6) & ~3), 4)
== 0x4e800021
&& (read_memory_unsigned_integer(pc+4,4) & 0xfc1fffff) == 0x7c0802a6 ) {
pc += 4;
continue;
} else if ((op & 0xfc000000) == 0x48000000) {
fdata->frameless = 0;
if ((pc - orig_pc) > 8)
break;
op = read_memory_unsigned_integer (pc+4, 4);
if (op == 0x4def7b82 || op == 0)
break;
continue;
} else if ((op & 0xffff0000) == 0x94210000) {
fdata->frameless = 0;
fdata->offset = SIGNED_SHORT (op);
offset = fdata->offset;
continue;
} else if (op == 0x7c21016e) {
fdata->frameless = 0;
offset = fdata->offset;
continue;
} else if ((op >> 22) == 0x20f
&& ! minimal_toc_loaded) {
minimal_toc_loaded = 1;
continue;
} else if ((op & 0xfc1f0000) == 0x90010000 ||
(op & 0xfc1f0000) == 0xd8010000 ||
(op & 0xfc1f0000) == 0xfc010000) {
continue;
} else if (framep &&
(op & 0xfc1f0000) == 0x901f0000 ||
(op & 0xfc1f0000) == 0xd81f0000 ||
(op & 0xfc1f0000) == 0xfc1f0000) {
continue;
} else if (op == 0x603f0000
|| op == 0x7c3f0b78) {
fdata->frameless = 0;
framep = 1;
fdata->alloca_reg = 31;
continue;
} else if ((op & 0xfc1fffff) == 0x38010000) {
fdata->frameless = 0;
framep = 1;
fdata->alloca_reg = (op & ~0x38010000) >> 21;
continue;
} else {
break;
}
}
fdata->offset = - fdata->offset;
return pc;
}
#define DUMMY_FRAME_SIZE 436
#define DUMMY_FRAME_ADDR_SIZE 10
static int dummy_frame_count = 0;
static int dummy_frame_size = 0;
static CORE_ADDR *dummy_frame_addr = 0;
extern int stop_stack_dummy;
void
push_dummy_frame ()
{
CORE_ADDR sp;
char sp_targ[4];
CORE_ADDR pc;
char pc_targ[4];
struct rs6000_framedata fdata;
int ii;
target_fetch_registers (-1);
if (dummy_frame_count >= dummy_frame_size) {
dummy_frame_size += DUMMY_FRAME_ADDR_SIZE;
if (dummy_frame_addr)
dummy_frame_addr = (CORE_ADDR*) xrealloc
(dummy_frame_addr, sizeof(CORE_ADDR) * (dummy_frame_size));
else
dummy_frame_addr = (CORE_ADDR*)
xmalloc (sizeof(CORE_ADDR) * (dummy_frame_size));
}
sp = read_register(SP_REGNUM);
pc = read_register(PC_REGNUM);
store_address (pc_targ, 4, pc);
(void) skip_prologue (get_pc_function_start (pc) + FUNCTION_START_OFFSET, &fdata);
dummy_frame_addr [dummy_frame_count++] = sp;
write_register (SP_REGNUM, sp-DUMMY_FRAME_SIZE);
flush_cached_frames ();
write_memory (sp + (fdata.lr_offset ? fdata.lr_offset : DEFAULT_LR_SAVE),
pc_targ, 4);
for (ii = 0; ii < 32; ++ii)
write_memory (sp-8-(ii*8), ®isters[REGISTER_BYTE (31-ii+FP0_REGNUM)], 8);
for (ii=1; ii <=32; ++ii)
write_memory (sp-256-(ii*4), ®isters[REGISTER_BYTE (32-ii)], 4);
for (ii=1; ii <= (LAST_SP_REGNUM-FIRST_SP_REGNUM+1); ++ii) {
write_memory (sp-384-(ii*4),
®isters[REGISTER_BYTE (FPLAST_REGNUM + ii)], 4);
}
store_address (sp_targ, 4, sp);
write_memory (sp-DUMMY_FRAME_SIZE, sp_targ, 4);
sp -= DUMMY_FRAME_SIZE;
write_memory (sp+8, pc_targ, 4);
}
pop_dummy_frame ()
{
CORE_ADDR sp, pc;
int ii;
sp = dummy_frame_addr [--dummy_frame_count];
for (ii = 1; ii <= 32; ++ii)
read_memory (sp-(ii*8), ®isters[REGISTER_BYTE (32-ii+FP0_REGNUM)], 8);
for (ii=1; ii <= 32; ++ii) {
read_memory (sp-256-(ii*4), ®isters[REGISTER_BYTE (32-ii)], 4);
}
for (ii=1; ii <=(LAST_SP_REGNUM-FIRST_SP_REGNUM+1); ++ii)
read_memory (sp-384-(ii*4),
®isters[REGISTER_BYTE (FPLAST_REGNUM + ii)], 4);
read_memory (sp-(DUMMY_FRAME_SIZE-8),
®isters [REGISTER_BYTE(PC_REGNUM)], 4);
*(int*)®isters [REGISTER_BYTE(FP_REGNUM)] = sp;
target_store_registers (-1);
pc = read_pc ();
flush_cached_frames ();
}
void
pop_frame ()
{
CORE_ADDR pc, lr, sp, prev_sp;
struct rs6000_framedata fdata;
struct frame_info *frame = get_current_frame ();
int addr, ii;
pc = read_pc ();
sp = FRAME_FP (frame);
if (stop_stack_dummy && dummy_frame_count) {
pop_dummy_frame ();
return;
}
read_register_bytes (0, NULL, REGISTER_BYTES);
addr = get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET;
(void) skip_prologue (addr, &fdata);
if (fdata.frameless)
prev_sp = sp;
else
prev_sp = read_memory_unsigned_integer (sp, 4);
if (fdata.lr_offset == 0)
lr = read_register (LR_REGNUM);
else
lr = read_memory_unsigned_integer (prev_sp + fdata.lr_offset, 4);
write_register (PC_REGNUM, lr);
addr = prev_sp - fdata.offset;
if (fdata.saved_gpr != -1)
for (ii = fdata.saved_gpr; ii <= 31; ++ii) {
read_memory (addr, ®isters [REGISTER_BYTE (ii)], 4);
addr += 4;
}
if (fdata.saved_fpr != -1)
for (ii = fdata.saved_fpr; ii <= 31; ++ii) {
read_memory (addr, ®isters [REGISTER_BYTE (ii+FP0_REGNUM)], 8);
addr += 8;
}
write_register (SP_REGNUM, prev_sp);
target_store_registers (-1);
flush_cached_frames ();
}
void
fix_call_dummy (dummyname, pc, fun, nargs, type)
char *dummyname;
CORE_ADDR pc;
CORE_ADDR fun;
int nargs;
int type;
{
#define TOC_ADDR_OFFSET 20
#define TARGET_ADDR_OFFSET 28
int ii;
CORE_ADDR target_addr;
CORE_ADDR tocvalue = 0;
target_addr = fun;
#if 0
tocvalue = find_toc_address (target_addr);
#endif
ii = *(int*)((char*)dummyname + TOC_ADDR_OFFSET);
ii = (ii & 0xffff0000) | (tocvalue >> 16);
*(int*)((char*)dummyname + TOC_ADDR_OFFSET) = ii;
ii = *(int*)((char*)dummyname + TOC_ADDR_OFFSET+4);
ii = (ii & 0xffff0000) | (tocvalue & 0x0000ffff);
*(int*)((char*)dummyname + TOC_ADDR_OFFSET+4) = ii;
ii = *(int*)((char*)dummyname + TARGET_ADDR_OFFSET);
ii = (ii & 0xffff0000) | (target_addr >> 16);
*(int*)((char*)dummyname + TARGET_ADDR_OFFSET) = ii;
ii = *(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4);
ii = (ii & 0xffff0000) | (target_addr & 0x0000ffff);
*(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4) = ii;
}
CORE_ADDR
push_arguments (nargs, args, sp, struct_return, struct_addr)
int nargs;
value_ptr *args;
CORE_ADDR sp;
int struct_return;
CORE_ADDR struct_addr;
{
int ii, len;
int argno;
int argbytes;
char tmp_buffer [50];
int f_argno = 0;
value_ptr arg;
struct type *type;
CORE_ADDR saved_sp, pc;
if ( dummy_frame_count <= 0)
printf_unfiltered ("FATAL ERROR -push_arguments()! frame not found!!\n");
ii = struct_return ? 1 : 0;
for (argno=0, argbytes=0; argno < nargs && ii<8; ++ii) {
arg = args[argno];
type = check_typedef (VALUE_TYPE (arg));
len = TYPE_LENGTH (type);
if (TYPE_CODE (type) == TYPE_CODE_FLT) {
if (len > 8)
printf_unfiltered (
"Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
memcpy (®isters[REGISTER_BYTE(FP0_REGNUM + 1 + f_argno)], VALUE_CONTENTS (arg),
len);
++f_argno;
}
if (len > 4) {
while (argbytes < len) {
*(int*)®isters[REGISTER_BYTE(ii+3)] = 0;
memcpy (®isters[REGISTER_BYTE(ii+3)],
((char*)VALUE_CONTENTS (arg))+argbytes,
(len - argbytes) > 4 ? 4 : len - argbytes);
++ii, argbytes += 4;
if (ii >= 8)
goto ran_out_of_registers_for_arguments;
}
argbytes = 0;
--ii;
}
else {
*(int*)®isters[REGISTER_BYTE(ii+3)] = 0;
memcpy (®isters[REGISTER_BYTE(ii+3)], VALUE_CONTENTS (arg), len);
}
++argno;
}
ran_out_of_registers_for_arguments:
sp -= 4 * 8;
sp -= 24;
if ((argno < nargs) || argbytes) {
int space = 0, jj;
if (argbytes) {
space += ((len - argbytes + 3) & -4);
jj = argno + 1;
}
else
jj = argno;
for (; jj < nargs; ++jj) {
value_ptr val = args[jj];
space += ((TYPE_LENGTH (VALUE_TYPE (val))) + 3) & -4;
}
space = (space + 7) & -8;
sp -= space;
write_register (SP_REGNUM, sp);
if (argbytes) {
write_memory (
sp+24+(ii*4), ((char*)VALUE_CONTENTS (arg))+argbytes, len - argbytes);
++argno;
ii += ((len - argbytes + 3) & -4) / 4;
}
for (; argno < nargs; ++argno) {
arg = args[argno];
type = check_typedef (VALUE_TYPE (arg));
len = TYPE_LENGTH (type);
if (TYPE_CODE (type) == TYPE_CODE_FLT && f_argno < 13) {
if (len > 8)
printf_unfiltered (
"Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
memcpy (®isters[REGISTER_BYTE(FP0_REGNUM + 1 + f_argno)], VALUE_CONTENTS (arg),
len);
++f_argno;
}
write_memory (sp+24+(ii*4), (char *) VALUE_CONTENTS (arg), len);
ii += ((len + 3) & -4) / 4;
}
}
else
write_register (SP_REGNUM, sp);
saved_sp = dummy_frame_addr [dummy_frame_count - 1];
read_memory (saved_sp, tmp_buffer, 24);
write_memory (sp, tmp_buffer, 24);
store_address (tmp_buffer, 4, saved_sp);
write_memory (sp, tmp_buffer, 4);
target_store_registers (-1);
return sp;
}
void
extract_return_value (valtype, regbuf, valbuf)
struct type *valtype;
char regbuf[REGISTER_BYTES];
char *valbuf;
{
int offset = 0;
if (TYPE_CODE (valtype) == TYPE_CODE_FLT) {
double dd; float ff;
if (TYPE_LENGTH (valtype) > 4)
memcpy (valbuf, ®buf[REGISTER_BYTE (FP0_REGNUM + 1)],
TYPE_LENGTH (valtype));
else {
memcpy (&dd, ®buf[REGISTER_BYTE (FP0_REGNUM + 1)], 8);
ff = (float)dd;
memcpy (valbuf, &ff, sizeof(float));
}
}
else {
if (TARGET_BYTE_ORDER == BIG_ENDIAN
&& TYPE_LENGTH (valtype) < REGISTER_RAW_SIZE (3))
offset = REGISTER_RAW_SIZE (3) - TYPE_LENGTH (valtype);
memcpy (valbuf, regbuf + REGISTER_BYTE (3) + offset,
TYPE_LENGTH (valtype));
}
}
CORE_ADDR rs6000_struct_return_address;
int
frameless_function_invocation (fi)
struct frame_info *fi;
{
CORE_ADDR func_start;
struct rs6000_framedata fdata;
if (fi->next != NULL && !fi->next->signal_handler_caller)
return 0;
func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
if (!func_start)
return 0;
(void) skip_prologue (func_start, &fdata);
return fdata.frameless;
}
unsigned long
frame_saved_pc (fi)
struct frame_info *fi;
{
CORE_ADDR func_start;
struct rs6000_framedata fdata;
int frameless;
if (fi->signal_handler_caller)
{
CORE_ADDR pt_regs_addr = read_memory_unsigned_integer (fi->frame + PT_REGS_PTR_OFFSET, 4);
return read_memory_unsigned_integer(pt_regs_addr + offsetof(struct pt_regs, nip), 4);
}
func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
if (!func_start)
return 0;
(void) skip_prologue (func_start, &fdata);
if (fdata.lr_offset == 0 && fi->next != NULL)
return read_memory_unsigned_integer (rs6000_frame_chain (fi) + DEFAULT_LR_SAVE, 4);
if (fdata.lr_offset == 0)
return read_register (LR_REGNUM);
return read_memory_unsigned_integer (rs6000_frame_chain (fi) + fdata.lr_offset, 4);
}
static void
frame_get_cache_fsr (fi, fdatap)
struct frame_info *fi;
struct rs6000_framedata *fdatap;
{
int ii;
CORE_ADDR frame_addr;
struct rs6000_framedata work_fdata;
if (fi->cache_fsr)
return;
if (fdatap == NULL) {
fdatap = &work_fdata;
(void) skip_prologue (get_pc_function_start (fi->pc), fdatap);
}
fi->cache_fsr = (struct frame_saved_regs *)
obstack_alloc (&frame_cache_obstack, sizeof (struct frame_saved_regs));
memset (fi->cache_fsr, '\0', sizeof (struct frame_saved_regs));
if (fi->prev && fi->prev->frame)
frame_addr = fi->prev->frame;
else
frame_addr = read_memory_unsigned_integer (fi->frame, 4);
if (fdatap->saved_fpr >= 0) {
int fpr_offset = frame_addr + fdatap->fpr_offset;
for (ii = fdatap->saved_fpr; ii < 32; ii++) {
fi->cache_fsr->regs [FP0_REGNUM + ii] = fpr_offset;
fpr_offset += 8;
}
}
if (fdatap->saved_gpr >= 0) {
int gpr_offset = frame_addr + fdatap->gpr_offset;
for (ii = fdatap->saved_gpr; ii < 32; ii++) {
fi->cache_fsr->regs [ii] = gpr_offset;
gpr_offset += 4;
}
}
if (fdatap->cr_offset != 0)
fi->cache_fsr->regs [CR_REGNUM] = frame_addr + fdatap->cr_offset;
if (fdatap->lr_offset != 0)
fi->cache_fsr->regs [LR_REGNUM] = frame_addr + fdatap->lr_offset;
}
CORE_ADDR
frame_initial_stack_address (fi)
struct frame_info *fi;
{
CORE_ADDR tmpaddr;
struct rs6000_framedata fdata;
struct frame_info *callee_fi;
if (fi->initial_sp)
return fi->initial_sp;
if (fi->signal_handler_caller) {
fi->initial_sp = fi->frame;
return fi->initial_sp;
}
(void) skip_prologue (get_pc_function_start (fi->pc), &fdata);
if (!fi->cache_fsr)
frame_get_cache_fsr (fi, &fdata);
if (fdata.alloca_reg < 0) {
fi->initial_sp = fi->frame;
return fi->initial_sp;
}
if (!fi->next)
return fi->initial_sp = read_register (fdata.alloca_reg);
for (callee_fi = fi->next; callee_fi; callee_fi = callee_fi->next) {
if (!callee_fi->cache_fsr)
frame_get_cache_fsr (callee_fi, NULL);
tmpaddr = callee_fi->cache_fsr->regs [fdata.alloca_reg];
if (tmpaddr) {
fi->initial_sp = read_memory_unsigned_integer (tmpaddr, 4);
return fi->initial_sp;
}
}
return fi->initial_sp = read_register (fdata.alloca_reg);
}
CORE_ADDR
rs6000_frame_chain (thisframe)
struct frame_info *thisframe;
{
CORE_ADDR fp;
if (inside_entry_file ((thisframe)->pc))
return 0;
if (thisframe->signal_handler_caller)
{
CORE_ADDR pt_regs_addr;
pt_regs_addr = read_memory_unsigned_integer (thisframe->frame + PT_REGS_PTR_OFFSET, 4);
fp = read_memory_unsigned_integer(pt_regs_addr + offsetof(struct pt_regs, gpr[1]), 4);
}
else
fp = read_memory_unsigned_integer ((thisframe)->frame, 4);
return fp;
}
int
gdb_print_insn_powerpc (memaddr, info)
bfd_vma memaddr;
disassemble_info *info;
{
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
return print_insn_big_powerpc (memaddr, info);
else
return print_insn_little_powerpc (memaddr, info);
}
void
init_extra_frame_info (fromleaf, fi)
int fromleaf;
struct frame_info *fi;
{
fi->initial_sp = 0;
fi->cache_fsr = 0;
if (fi->next != 0) {
char buf[8];
if (target_read_memory(fi->pc, buf, sizeof(buf)) != 0)
return;
if ( extract_unsigned_integer(buf,4) == 0x38007777
|| extract_unsigned_integer(buf+4,4) == 0x44000002 ) {
fi->signal_handler_caller = 1;
}
}
}
void
frame_find_saved_regs(struct frame_info *fi, struct frame_saved_regs *fsr)
{
int ii;
CORE_ADDR frame_addr, func_start;
struct rs6000_framedata fdata;
if (fi->signal_handler_caller) {
CORE_ADDR pt_regs_addr = read_memory_unsigned_integer (fi->frame + PT_REGS_PTR_OFFSET, 4);
memset (fsr, '\0', sizeof (*fsr));
fsr->regs[PC_REGNUM] = pt_regs_addr + offsetof(struct pt_regs, nip);
fsr->regs[PS_REGNUM] = pt_regs_addr + offsetof(struct pt_regs, msr);
fsr->regs[CR_REGNUM] = pt_regs_addr + offsetof(struct pt_regs, ccr);
fsr->regs[LR_REGNUM] = pt_regs_addr + offsetof(struct pt_regs, link);
fsr->regs[CTR_REGNUM] = pt_regs_addr + offsetof(struct pt_regs, ctr);
fsr->regs[XER_REGNUM] = pt_regs_addr + offsetof(struct pt_regs, xer);
#if 0
fsr->regs[MQ_REGNUM] = pt_regs_addr + offsetof(struct pt_regs, mq);
#endif
for (ii=0; ii<32; ii++) {
fsr->regs[GP0_REGNUM+ii] = pt_regs_addr + offsetof(struct pt_regs, gpr[0]) + 4*ii;
}
#if 0
for (ii=0; ii<4; ii++) {
fsr->regs[FP0_REGNUM+ii] = pt_regs_addr + offsetof(struct pt_regs, fpr[0]) + 4*ii;
}
#endif
return;
}
func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET;
(void) skip_prologue (func_start, &fdata);
memset (fsr, '\0', sizeof (*fsr));
if (fdata.saved_fpr == 0 && fdata.saved_gpr == 0 &&
fdata.lr_offset == 0 && fdata.cr_offset == 0) {
frame_addr = 0;
} else if (fi->prev && fi->prev->frame) {
frame_addr = fi->prev->frame;
} else {
frame_addr = read_memory_unsigned_integer (fi->frame, 4);
}
if (fdata.saved_fpr >= 0) {
int fpr_offset = frame_addr + fdata.fpr_offset;
for (ii = fdata.saved_fpr; ii < 32; ii++) {
fsr->regs [FP0_REGNUM + ii] = fpr_offset;
fpr_offset += 8;
}
}
if (fdata.saved_gpr >= 0) {
int gpr_offset = frame_addr + fdata.gpr_offset;
for (ii = fdata.saved_gpr; ii < 32; ii++) {
fsr->regs [ii] = gpr_offset;
gpr_offset += 4;
}
}
if (fdata.cr_offset != 0) {
fsr->regs [CR_REGNUM] = frame_addr + fdata.cr_offset;
}
if (fdata.lr_offset != 0) {
fsr->regs [LR_REGNUM] = frame_addr + fdata.lr_offset;
}
}
void
init_frame_pc_first(int fromleaf, struct frame_info *fi)
{
if (fromleaf) {
if ( fi->next
&& fi->next->next
&& fi->next->next->signal_handler_caller) {
CORE_ADDR pt_regs_addr =
read_memory_unsigned_integer (fi->next->next->frame + PT_REGS_PTR_OFFSET, 4);
fi->pc = read_memory_unsigned_integer(pt_regs_addr + offsetof(struct pt_regs, link), 4);
}
else {
fi->pc = SAVED_PC_AFTER_CALL(fi->next);
}
}
else {
if (fi->next) {
fi->pc = FRAME_SAVED_PC(fi->next);
}
else {
fi->pc = read_pc();
}
}
}
CORE_ADDR
skip_trampoline_code (CORE_ADDR pc)
{
char buf[4];
struct obj_section *sect;
struct objfile *objfile;
unsigned long insn;
CORE_ADDR plt_start = 0;
CORE_ADDR symtab = 0;
CORE_ADDR strtab = 0;
int num_slots = -1;
int reloc_index = -1;
CORE_ADDR plt_table;
CORE_ADDR reloc;
CORE_ADDR sym;
Elf32_Word symidx;
char symname[1024];
struct minimal_symbol *msymbol;
sect = find_pc_section(pc);
if (!sect || strcmp(sect->the_bfd_section->name, ".plt") != 0)
return 0;
objfile = sect->objfile;
if (target_read_memory(pc, buf, 4) != 0)
return 0;
insn = extract_unsigned_integer(buf, 4);
if ( (insn & 0xffff0000) != 0x39600000 )
return 0;
reloc_index = (insn << 16) >> 16;
for (sect = objfile->sections; sect < objfile->sections_end; ++sect) {
const char *secname = sect->the_bfd_section->name;
if (strcmp(secname, ".plt") == 0) {
plt_start = sect->addr;
}
else if (strcmp(secname, ".rela.plt") == 0) {
num_slots = ((int) sect->endaddr - (int) sect->addr) / 12;
}
else if (strcmp(secname, ".dynsym") == 0) {
symtab = sect->addr;
}
else if (strcmp(secname, ".dynstr") == 0) {
strtab = sect->addr;
}
}
if (plt_start == 0 || num_slots == -1 || symtab == 0 || strtab == 0)
return 0;
plt_table = plt_start + 72 + 8*num_slots;
if (target_read_memory(plt_table + reloc_index, buf, 4) != 0)
return 0;
reloc = extract_address(buf, 4);
sect = find_pc_section(reloc);
if (!sect)
return 0;
if (strcmp(sect->the_bfd_section->name, ".text") == 0) {
return reloc;
}
if (target_read_memory(reloc+4, buf, 4) != 0)
return 0;
symidx = extract_unsigned_integer(buf, 4);
symidx = ELF32_R_SYM(symidx);
sym = symtab + symidx * sizeof(Elf32_Sym);
if (target_read_memory(sym, buf, 4) != 0)
return 0;
symidx = extract_unsigned_integer(buf, 4);
if (target_read_memory(strtab+symidx, symname, sizeof(symname)) != 0)
return 0;
msymbol = lookup_minimal_symbol_text(symname, NULL, NULL);
if (!msymbol)
return 0;
return SYMBOL_VALUE_ADDRESS (msymbol);
}
void
_initialize_ppclinux_tdep ()
{
tm_print_insn = gdb_print_insn_powerpc;
}