#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "symtab.h"
#include "target.h"
#include "gdbcore.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdbcmd.h"
#include "arch-utils.h"
#include "floatformat.h"
#include "gdbtypes.h"
#include "regcache.h"
#include "reggroups.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "dummy-frame.h"
#include "gdb_assert.h"
#include "complaints.h"
#include "user-regs.h"
#include "objfiles.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "dis-asm.h"
#include "ppc-tdep.h"
#include "gdbarch.h"
#include "osabi.h"
#include "ppc-macosx-tdep.h"
#include "ppc-macosx-regs.h"
#include "ppc-macosx-regnums.h"
#include "ppc-macosx-tdep.h"
#include "ppc-macosx-frameinfo.h"
#include <mach/mach.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#include <mach/machine.h>
void
rs6000_value_to_register (struct frame_info *frame,
int regnum,
struct type *type,
const gdb_byte *from);
void
rs6000_register_to_value (struct frame_info *frame,
int regnum,
struct type *type,
gdb_byte *to);
#undef XMALLOC
#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
const unsigned int PPC_FRAME_MAGIC = 0xfe30a3d7;
const unsigned int PPC_SIGCONTEXT_PC_OFFSET = 0x90;
const unsigned int PPC_SIGCONTEXT_SP_OFFSET = 0x9c;
static int ppc_debugflag = 0;
static unsigned int ppc_max_frame_size = UINT_MAX;
static void ppc_macosx_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch);
static void ppc_macosx_init_abi_64 (struct gdbarch_info info,
struct gdbarch *gdbarch);
static int ppc_macosx_get_longjmp_target (CORE_ADDR * pc);
static int ppc_64_macosx_get_longjmp_target (CORE_ADDR * pc);
static struct value *ppc_value_of_builtin_frame_fp_reg (struct frame_info *);
CORE_ADDR
ppc_frame_unwind_sp_for_dereferencing (struct frame_info *next_frame,
void **this_cache);
void
ppc_debug (const char *fmt, ...)
{
va_list ap;
if (ppc_debugflag)
{
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
}
}
void
ppc_print_extra_frame_info (struct frame_info *next_frame, void **this_cache)
{
struct ppc_frame_cache *cache;
struct ppc_function_boundaries *bounds;
struct ppc_function_properties *props;
if (get_frame_type (get_prev_frame (next_frame)) == DUMMY_FRAME)
return;
cache = ppc_frame_cache (next_frame, this_cache);
if (get_frame_type (next_frame) == SIGTRAMP_FRAME)
{
printf_filtered (" This function was called from a signal handler.\n");
}
else
{
printf_filtered
(" This function was not called from a signal handler.\n");
}
bounds = ppc_frame_function_boundaries (next_frame, this_cache);
if (bounds != NULL)
{
ppc_print_boundaries (bounds);
}
else
{
printf_filtered
(" Unable to determine function boundary information.\n");
}
props = ppc_frame_function_properties (next_frame, this_cache);
if (props != NULL)
{
ppc_print_properties (props);
}
else
{
printf_filtered
(" Unable to determine function property information.\n");
}
}
static struct ppc_frame_cache *
ppc_alloc_frame_cache (void)
{
struct ppc_frame_cache *cache;
int i;
cache = FRAME_OBSTACK_ZALLOC (struct ppc_frame_cache);
cache->magic = PPC_FRAME_MAGIC;
cache->saved_regs =
(CORE_ADDR *) frame_obstack_zalloc ((NUM_REGS) * sizeof (CORE_ADDR));
cache->prev_pc = (CORE_ADDR) -1;
cache->prev_sp = (CORE_ADDR) -1;
cache->sp = (CORE_ADDR) -1;
cache->fp = (CORE_ADDR) -1;
cache->pc = (CORE_ADDR) -1;
cache->sp_for_dereferencing = (CORE_ADDR) -1;
for (i = 0; i < NUM_REGS; i++)
cache->saved_regs[i] = -1;
cache->saved_regs_valid = 0;
cache->properties_valid = 0;
cache->boundaries_status = 0;
return cache;
}
struct ppc_frame_cache *
ppc_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct ppc_frame_cache *cache;
if (*this_cache)
{
cache = *this_cache;
gdb_assert (cache->magic == PPC_FRAME_MAGIC);
return cache;
}
cache = ppc_alloc_frame_cache ();
*this_cache = cache;
cache->sp = ppc_frame_unwind_sp (next_frame, this_cache);
if (cache->sp == 0)
return cache;
cache->fp = ppc_frame_unwind_fp (next_frame, this_cache);
cache->pc = frame_func_unwind (next_frame);
if (cache->pc == 0)
cache->pc = frame_pc_unwind (next_frame);
cache->sp_for_dereferencing = ppc_frame_unwind_sp_for_dereferencing (next_frame, this_cache);
extern int frame_debug;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "\
{{ ppc_frame_cache (nxframe=%d) ",
frame_relative_level (next_frame));
fprintf_unfiltered (gdb_stdlog, "->");
fprintf_unfiltered (gdb_stdlog, " pc=0x%s", paddr_nz (cache->pc));
fprintf_unfiltered (gdb_stdlog, " sp=0x%s", paddr_nz (cache->sp));
fprintf_unfiltered (gdb_stdlog, " fp=0x%s", paddr_nz (cache->fp));
fprintf_unfiltered (gdb_stdlog, " }}\n");
}
return cache;
}
CORE_ADDR
ppc_frame_find_prev_pc (struct frame_info *next_frame, void **this_cache)
{
struct ppc_frame_cache *cache;
ppc_function_properties *props = NULL;
CORE_ADDR prev_sp, this_pc;
cache = ppc_frame_cache (next_frame, this_cache);
props = ppc_frame_function_properties (next_frame, this_cache);
if (props == NULL)
return 0;
prev_sp = ppc_frame_find_prev_sp (next_frame, this_cache);
this_pc = frame_pc_unwind (next_frame);
if (props->lr_saved && props->lr_saved < this_pc)
{
return read_memory_unsigned_integer (prev_sp + props->lr_offset,
gdbarch_addr_bit (current_gdbarch) / 8);
}
else if (props->lr_reg >= 0
&& props->lr_invalid
&& this_pc > props->lr_invalid
&& this_pc <= props->lr_valid_again)
{
return frame_unwind_register_unsigned (next_frame, props->lr_reg);
}
else
{
return frame_unwind_register_unsigned (next_frame, PPC_MACOSX_LR_REGNUM);
}
}
CORE_ADDR
ppc_frame_unwind_fp (struct frame_info *next_frame, void **this_cache)
{
struct ppc_frame_cache *cache;
ppc_function_properties *props;
CORE_ADDR this_fp, this_pc, this_func, next_sp;
cache = ppc_frame_cache (next_frame, this_cache);
props = ppc_frame_function_properties (next_frame, this_cache);
if (props == NULL)
return frame_unwind_register_unsigned (next_frame, SP_REGNUM);
if (props->frameless)
return frame_unwind_register_unsigned (next_frame, SP_REGNUM);
this_pc = frame_pc_unwind (next_frame);
this_func = frame_func_unwind (next_frame);
if (props->stack_offset_pc != INVALID_ADDRESS
&& this_pc >= this_func
&& this_pc <= props->stack_offset_pc)
{
CORE_ADDR this_sp;
this_sp = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
return this_sp - props->offset;
}
if (props->frameptr_used == 0)
return frame_unwind_register_unsigned (next_frame, SP_REGNUM);
if (props->frameptr_used && props->frameptr_reg > 0
&& props->frameptr_pc != INVALID_ADDRESS
&& this_pc > props->stack_offset_pc
&& this_pc <= props->frameptr_pc)
{
return frame_unwind_register_unsigned (next_frame, SP_REGNUM);
}
if (props->frameptr_used && props->frameptr_reg > 0)
{
next_sp = get_frame_register_unsigned (next_frame, SP_REGNUM);
this_fp = frame_unwind_register_unsigned (next_frame,
props->frameptr_reg);
if (this_fp >= next_sp && this_fp - next_sp < 0xfffff)
return this_fp;
complaint (&symfile_complaints,
"sanity check failed in ppc_frame_unwind_fp");
}
return frame_unwind_register_unsigned (next_frame, SP_REGNUM);
}
CORE_ADDR
ppc_frame_unwind_sp_for_dereferencing (struct frame_info *next_frame,
void **this_cache)
{
return frame_unwind_register_unsigned (next_frame, SP_REGNUM);
}
CORE_ADDR
ppc_frame_unwind_sp (struct frame_info *next_frame, void **this_cache)
{
struct ppc_frame_cache *cache;
ppc_function_properties *props;
CORE_ADDR this_pc;
cache = ppc_frame_cache (next_frame, this_cache);
props = ppc_frame_function_properties (next_frame, this_cache);
if (props == NULL)
return frame_unwind_register_unsigned (next_frame, SP_REGNUM);
this_pc = frame_pc_unwind (next_frame);
if (this_pc >= frame_func_unwind (next_frame)
&& props->stack_offset_pc != INVALID_ADDRESS
&& this_pc <= props->stack_offset_pc)
{
return frame_unwind_register_unsigned
(next_frame, SP_REGNUM) - props->offset;
}
return frame_unwind_register_unsigned (next_frame, SP_REGNUM);
}
CORE_ADDR
ppc_frame_find_prev_sp (struct frame_info *next_frame, void **this_cache)
{
ppc_function_properties *props = NULL;
CORE_ADDR this_sp, this_pc, this_func;
this_sp = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
if (this_sp == 0)
return 0;
props = ppc_frame_function_properties (next_frame, this_cache);
if (props == NULL)
return 0;
if (props->frameless)
return this_sp;
this_pc = frame_pc_unwind (next_frame);
this_func = frame_func_unwind (next_frame);
if (this_pc >= this_func
&& props->stack_offset_pc != INVALID_ADDRESS
&& this_pc <= props->stack_offset_pc)
{
return this_sp;
}
return read_memory_unsigned_integer (this_sp,
gdbarch_addr_bit (current_gdbarch) /
8);
}
CORE_ADDR
ppc_skip_prologue (CORE_ADDR pc)
{
ppc_function_boundaries_request request;
ppc_function_boundaries bounds;
int ret;
ppc_clear_function_boundaries_request (&request);
ppc_clear_function_boundaries (&bounds);
request.prologue_start = pc;
ret = ppc_find_function_boundaries (&request, &bounds);
if (ret != 0)
{
return 0;
}
return bounds.body_start;
}
const char *gdb_register_names[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
"pc", "ps", "cr", "lr", "ctr", "xer", "mq",
"fpscr",
"vscr", "vrsave"
};
const char *
ppc_register_name (int reg_nr)
{
if (reg_nr < 0)
return NULL;
if (reg_nr >= (sizeof (gdb_register_names) / sizeof (*gdb_register_names)))
return NULL;
return gdb_register_names[reg_nr];
}
static const unsigned char *
ppc_breakpoint_from_pc (CORE_ADDR * addr, int *size)
{
static unsigned char big_breakpoint[] = { 0x7f, 0xe0, 0x00, 0x08 };
static unsigned char little_breakpoint[] = { 0x08, 0x00, 0xe0, 0x7f };
*size = 4;
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
return big_breakpoint;
else
return little_breakpoint;
}
static struct type *
ppc_register_virtual_type (struct gdbarch *gdbarch, int n)
{
if (((n >= PPC_MACOSX_FIRST_GP_REGNUM) && (n <= PPC_MACOSX_LAST_GP_REGNUM))
|| (n == PPC_MACOSX_PC_REGNUM)
|| (n == PPC_MACOSX_PS_REGNUM)
|| (n == PPC_MACOSX_LR_REGNUM)
|| (n == PPC_MACOSX_CTR_REGNUM)
|| (n == PPC_MACOSX_XER_REGNUM))
{
return builtin_type_unsigned_long_long;
}
if ((n >= PPC_MACOSX_FIRST_VP_REGNUM) && (n <= PPC_MACOSX_LAST_VP_REGNUM))
return builtin_type_vec128;
if ((n >= PPC_MACOSX_FIRST_FP_REGNUM) && (n <= PPC_MACOSX_LAST_FP_REGNUM))
return builtin_type_double;
return builtin_type_unsigned_int;
}
int
ppc_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
{
if ((regnum == PPC_MACOSX_VSCR_REGNUM)
|| (regnum == PPC_MACOSX_VRSAVE_REGNUM))
if (group == vector_reggroup)
return 1;
if (regnum == PPC_MACOSX_FPSCR_REGNUM)
if (group == float_reggroup)
return 1;
return default_register_reggroup_p (gdbarch, regnum, group);
}
int
ppc_use_struct_convention (int gccp, struct type *value_type)
{
if ((TYPE_LENGTH (value_type) == 16) && TYPE_VECTOR (value_type))
return 0;
return 1;
}
static CORE_ADDR
ppc_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
struct ppc_frame_cache *cache = ppc_frame_cache (next_frame, this_cache);
return cache->fp;
}
static CORE_ADDR
ppc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
return frame_unwind_register_unsigned (next_frame, PC_REGNUM);
}
static void
ppc_frame_prev_register (struct frame_info *next_frame, void **this_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *valuep)
{
struct ppc_frame_cache *cache = ppc_frame_cache (next_frame, this_cache);
CORE_ADDR *saved_regs = NULL;
ppc_function_properties *props;
props = ppc_frame_function_properties (next_frame, this_cache);
if (regnum == SP_REGNUM)
{
*optimizedp = opt_okay;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (valuep)
{
if (cache->prev_sp == (CORE_ADDR) - 1)
cache->prev_sp = ppc_frame_find_prev_sp (next_frame, this_cache);
store_unsigned_integer (valuep,
register_size (current_gdbarch, regnum),
cache->prev_sp);
}
return;
}
if (regnum == PC_REGNUM)
{
*optimizedp = opt_okay;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (valuep)
{
if (cache->prev_pc == (CORE_ADDR) - 1)
cache->prev_pc = ppc_frame_find_prev_pc (next_frame, this_cache);
store_unsigned_integer (valuep,
register_size (current_gdbarch, regnum),
cache->prev_pc);
}
return;
}
saved_regs = ppc_frame_saved_regs (next_frame, this_cache);
if ((saved_regs != NULL) && (saved_regs[regnum] != -1))
{
*optimizedp = opt_okay;
*lvalp = lval_memory;
*addrp = cache->saved_regs[regnum];
*realnump = -1;
if (valuep)
{
int wordsize;
int offset;
if (PPC_MACOSX_IS_FP_REGNUM (regnum)
|| PPC_MACOSX_IS_VP_REGNUM (regnum))
{
wordsize = register_size (current_gdbarch, regnum);
offset = 0;
}
else
{
wordsize = (gdbarch_tdep (current_gdbarch))->wordsize;
offset = register_size (current_gdbarch, regnum) - wordsize;
*((int *) valuep) = 0;
}
read_memory (*addrp, valuep + offset, wordsize);
}
return;
}
frame_register_unwind (next_frame, regnum,
optimizedp, lvalp, addrp, realnump, valuep);
}
static struct frame_id
ppc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
gdb_byte buf[8];
CORE_ADDR fp;
frame_unwind_register (next_frame, SP_REGNUM, buf);
fp =
extract_unsigned_integer (buf,
register_size (current_gdbarch, SP_REGNUM));
return frame_id_build (fp, frame_pc_unwind (next_frame));
}
static void
ppc_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
ULONGEST prev_frame_addr = 0;
struct ppc_frame_cache *cache = ppc_frame_cache (next_frame, this_cache);
if (cache->sp == 0 || cache->fp == 0)
{
*this_id = null_frame_id;
return;
}
if (safe_read_memory_unsigned_integer
(cache->sp_for_dereferencing, TARGET_PTR_BIT / 8, &prev_frame_addr))
{
if (safe_read_memory_unsigned_integer
(prev_frame_addr, TARGET_PTR_BIT / 8, &prev_frame_addr))
if (prev_frame_addr == 0)
{
*this_id = null_frame_id;
return;
}
}
(*this_id) = frame_id_build (cache->fp, cache->pc);
}
static struct ppc_frame_cache *
ppc_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
{
enum
{ EXCSTATE = 0x20, GPSTATE = 0xa0, GPSTATE64 = 0x130,
FPSTATE = 0x108, VPSTATE = 0x240
};
struct ppc_frame_cache *cache;
CORE_ADDR sigframe, context;
ULONGEST length = 0;
CORE_ADDR regs = 0, fpregs = 0, vpregs = 0;
unsigned int reglen = 4;
unsigned int i;
if (*this_cache)
return *this_cache;
cache = ppc_alloc_frame_cache ();
*this_cache = cache;
cache->sp = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
if (cache->sp == 0)
return cache;
cache->pc = frame_func_unwind (next_frame);
sigframe = read_memory_unsigned_integer (cache->sp, TARGET_PTR_BIT / 8);
context =
read_memory_unsigned_integer (sigframe + 0xd4, TARGET_PTR_BIT / 8);
length = read_memory_unsigned_integer (sigframe + 0xd0, TARGET_INT_BIT / 8);
switch (length)
{
case (EXCSTATE + GPSTATE + FPSTATE + VPSTATE):
vpregs = context + EXCSTATE + GPSTATE + FPSTATE;
case (EXCSTATE + GPSTATE + FPSTATE):
fpregs = context + EXCSTATE + GPSTATE;
case (EXCSTATE + GPSTATE):
regs = context + EXCSTATE;
reglen = 4;
break;
case (EXCSTATE + GPSTATE64 + FPSTATE + VPSTATE):
vpregs = context + EXCSTATE + GPSTATE64 + FPSTATE;
case (EXCSTATE + GPSTATE64 + FPSTATE):
fpregs = context + EXCSTATE + GPSTATE64;
case (EXCSTATE + GPSTATE64):
regs = context + EXCSTATE;
reglen = 8;
break;
default:
warning ("unrecognized length (0x%lx) for sigtramp context",
(unsigned long) length);
break;
}
cache->sigtramp_gp_store_size = reglen;
if (regs != 0)
{
int cr_offset = reglen - 4;
cache->saved_regs[PPC_MACOSX_PC_REGNUM] = regs;
cache->saved_regs[PPC_MACOSX_PS_REGNUM] = regs + (1 * reglen);
for (i = 0; i < 32; i++)
cache->saved_regs[PPC_MACOSX_FIRST_GP_REGNUM + i] =
regs + ((i + 2) * reglen);
cache->saved_regs[PPC_MACOSX_CR_REGNUM] = regs + (34 * reglen);
cache->saved_regs[PPC_MACOSX_XER_REGNUM] = regs + (35 * reglen) - cr_offset;
cache->saved_regs[PPC_MACOSX_LR_REGNUM] = regs + (36 * reglen) - cr_offset;
cache->saved_regs[PPC_MACOSX_CTR_REGNUM] = regs + (37 * reglen) - cr_offset;
cache->saved_regs[PPC_MACOSX_MQ_REGNUM] = regs + (38 * reglen) - cr_offset;
cache->saved_regs[PPC_MACOSX_VRSAVE_REGNUM] = regs + (39 * reglen) - cr_offset;
}
if (fpregs != 0)
{
for (i = 0; i < 32; i++)
cache->saved_regs[PPC_MACOSX_FIRST_FP_REGNUM + i] = fpregs + (i * 8);
cache->saved_regs[PPC_MACOSX_FPSCR_REGNUM] = fpregs + (i * 8) + 4;
}
if (vpregs != 0)
{
for (i = 0; i < 32; i++)
cache->saved_regs[PPC_MACOSX_FIRST_VP_REGNUM + i] = fpregs + (i * 16);
cache->saved_regs[PPC_MACOSX_VSCR_REGNUM] = vpregs + (i * 16);
}
cache->saved_regs_valid = 1;
return cache;
}
static void
ppc_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
struct ppc_frame_cache *cache =
ppc_sigtramp_frame_cache (next_frame, this_cache);
(*this_id) = frame_id_build (cache->fp, frame_pc_unwind (next_frame));
}
static void
ppc_sigtramp_frame_prev_register (struct frame_info *next_frame,
void **this_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR * addrp,
int *realnump, gdb_byte *valuep)
{
struct ppc_frame_cache *cache =
ppc_sigtramp_frame_cache (next_frame, this_cache);
CORE_ADDR *saved_regs = NULL;
saved_regs = ppc_frame_saved_regs (next_frame, this_cache);
if ((saved_regs != NULL) && (saved_regs[regnum] != -1))
{
int size;
int offset = 0;
*optimizedp = opt_okay;
*lvalp = lval_memory;
*addrp = cache->saved_regs[regnum];
*realnump = -1;
if (valuep)
{
int reg_size = register_size (current_gdbarch, regnum);
if (regnum == PPC_MACOSX_CR_REGNUM || regnum == PPC_MACOSX_MQ_REGNUM)
size = 4;
else if (PPC_MACOSX_IS_GP_REGNUM (regnum) || PPC_MACOSX_IS_GSP_REGNUM (regnum))
size = cache->sigtramp_gp_store_size;
else
size = reg_size;
gdb_assert (reg_size >= size);
offset = reg_size - size;
if (reg_size > size)
bzero ((char *) valuep, reg_size - size);
read_memory (*addrp, valuep + offset, size);
}
return;
}
frame_register_unwind (next_frame, regnum,
optimizedp, lvalp, addrp, realnump, valuep);
}
static const struct frame_unwind ppc_sigtramp_frame_unwind = {
SIGTRAMP_FRAME,
ppc_sigtramp_frame_this_id,
ppc_sigtramp_frame_prev_register
};
static const struct frame_unwind *
ppc_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
char *name;
find_pc_partial_function (pc, &name, NULL, NULL);
if (legacy_pc_in_sigtramp (pc, name))
return &ppc_sigtramp_frame_unwind;
return NULL;
}
static const struct frame_unwind ppc_frame_unwind = {
NORMAL_FRAME,
ppc_frame_this_id,
ppc_frame_prev_register
};
static const struct frame_unwind *
ppc_frame_sniffer (struct frame_info *next_frame)
{
return &ppc_frame_unwind;
}
static const struct frame_base ppc_frame_base = {
&ppc_frame_unwind,
ppc_frame_base_address,
ppc_frame_base_address,
ppc_frame_base_address
};
CORE_ADDR
ppc_fetch_pointer_argument (struct frame_info *frame, int argi,
struct type *type)
{
CORE_ADDR addr;
static unsigned long long mask = 0xffffffff;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
addr = get_frame_register_unsigned (frame, 3 + argi);
if (tdep->wordsize == 4)
addr &= mask;
return addr;
}
static CORE_ADDR
ppc_integer_to_address (struct gdbarch *gdbarch, struct type *type,
const gdb_byte *buf)
{
gdb_byte *tmp = alloca (TYPE_LENGTH (builtin_type_void_data_ptr));
LONGEST val = unpack_long (type, buf);
store_unsigned_integer (tmp, TYPE_LENGTH (builtin_type_void_data_ptr), val);
return extract_unsigned_integer (tmp,
TYPE_LENGTH (builtin_type_void_data_ptr));
}
static CORE_ADDR
ppc_macosx_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
{
return (addr & -16);
}
static struct gdbarch *
ppc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return arches->gdbarch;
tdep = XMALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
tdep->wordsize = -1;
tdep->regs = 0;
tdep->ppc_gp0_regnum = -1;
tdep->ppc_toc_regnum = -1;
tdep->ppc_ps_regnum = -1;
tdep->ppc_cr_regnum = -1;
tdep->ppc_lr_regnum = -1;
tdep->ppc_ctr_regnum = -1;
tdep->ppc_xer_regnum = -1;
tdep->ppc_fpscr_regnum = -1;
tdep->ppc_mq_regnum = -1;
tdep->ppc_vr0_regnum = -1;
tdep->ppc_vrsave_regnum = -1;
tdep->ppc_ev0_regnum = -1;
tdep->ppc_ev31_regnum = -1;
tdep->lr_frame_offset = -1;
tdep->wordsize = 4;
tdep->ppc_toc_regnum = 2;
tdep->ppc_cr_regnum = PPC_MACOSX_CR_REGNUM;
tdep->ppc_ctr_regnum = PPC_MACOSX_CTR_REGNUM;
tdep->ppc_xer_regnum = PPC_MACOSX_XER_REGNUM;
tdep->ppc_sr0_regnum = 71;
tdep->ppc_vr0_regnum = PPC_MACOSX_FIRST_VP_REGNUM;
tdep->ppc_vrsave_regnum = PPC_MACOSX_VRSAVE_REGNUM;
tdep->ppc_ev0_upper_regnum = -1;
tdep->ppc_ev0_regnum = -1;
tdep->ppc_ev31_regnum = -1;
tdep->ppc_acc_regnum = -1;
tdep->ppc_spefscr_regnum = -1;
tdep->ppc_fp0_regnum = PPC_MACOSX_FIRST_FP_REGNUM;
tdep->ppc_fpscr_regnum = PPC_MACOSX_FPSCR_REGNUM;
tdep->ppc_lr_regnum = PPC_MACOSX_LR_REGNUM;
tdep->ppc_gp0_regnum = PPC_MACOSX_FIRST_GP_REGNUM;
set_gdbarch_num_regs (gdbarch, PPC_MACOSX_NUM_REGS);
set_gdbarch_sp_regnum (gdbarch, PPC_MACOSX_SP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, PPC_MACOSX_PC_REGNUM);
set_gdbarch_ps_regnum (gdbarch, PPC_MACOSX_PS_REGNUM);
set_gdbarch_fp0_regnum (gdbarch, PPC_MACOSX_FIRST_FP_REGNUM);
set_gdbarch_register_name (gdbarch, ppc_register_name);
set_gdbarch_register_type (gdbarch, ppc_register_virtual_type);
set_gdbarch_addr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
switch (info.byte_order)
{
case BFD_ENDIAN_BIG:
set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
break;
case BFD_ENDIAN_LITTLE:
set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little);
set_gdbarch_long_double_format (gdbarch,
&floatformat_ieee_double_little);
break;
default:
internal_error (__FILE__, __LINE__,
"ppc_gdbarch_init: bad byte order for float format");
}
set_gdbarch_push_dummy_call (gdbarch, ppc_darwin_abi_push_dummy_call);
set_gdbarch_frame_align (gdbarch, ppc_macosx_frame_align);
set_gdbarch_frame_red_zone_size (gdbarch, 224);
set_gdbarch_stab_reg_to_regnum (gdbarch, ppc_macosx_stab_reg_to_regnum);
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, rs6000_dwarf2_reg_to_regnum);
set_gdbarch_return_value (gdbarch, ppc_darwin_abi_return_value);
set_gdbarch_deprecated_use_struct_convention (gdbarch, ppc_use_struct_convention);
set_gdbarch_skip_prologue (gdbarch, ppc_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_decr_pc_after_break (gdbarch, 0);
set_gdbarch_deprecated_function_start_offset (gdbarch, 0);
set_gdbarch_breakpoint_from_pc (gdbarch, ppc_breakpoint_from_pc);
set_gdbarch_unwind_dummy_id (gdbarch, ppc_unwind_dummy_id);
set_gdbarch_unwind_pc (gdbarch, ppc_unwind_pc);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_skip_trampoline_code (gdbarch, macosx_skip_trampoline_code);
set_gdbarch_in_solib_return_trampoline (gdbarch,
macosx_in_solib_return_trampoline);
set_gdbarch_print_insn (gdbarch, print_insn_big_powerpc);
set_gdbarch_register_reggroup_p (gdbarch, ppc_register_reggroup_p);
frame_unwind_append_sniffer (gdbarch, ppc_sigtramp_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, ppc_frame_sniffer);
set_gdbarch_integer_to_address (gdbarch, ppc_integer_to_address);
set_gdbarch_fetch_pointer_argument (gdbarch, ppc_fetch_pointer_argument);
gdbarch_init_osabi (info, gdbarch);
frame_base_set_default (gdbarch, &ppc_frame_base);
return gdbarch;
}
int
ppc_fast_show_stack (unsigned int count_limit, unsigned int print_limit,
unsigned int *count,
void (print_fun) (struct ui_out * uiout, int frame_num,
CORE_ADDR pc, CORE_ADDR fp))
{
CORE_ADDR fp = 0;
static CORE_ADDR sigtramp_start = 0;
static CORE_ADDR sigtramp_end = 0;
unsigned int i = 0;
int err = 0;
struct frame_info *fi;
int more_frames = 1;
ULONGEST prev_fp = 0;
ULONGEST next_fp = 0;
ULONGEST pc = 0;
int wordsize = gdbarch_tdep (current_gdbarch)->wordsize;
more_frames = fast_show_stack_trace_prologue (count_limit, print_limit, wordsize,
&sigtramp_start, &sigtramp_end,
&i, &fi, print_fun);
if (more_frames < 0)
{
err = 1;
goto ppc_count_finish;
}
if (i >= count_limit || !more_frames)
goto ppc_count_finish;
fp = get_frame_sp (fi);
if (!safe_read_memory_unsigned_integer (fp, wordsize, &next_fp))
goto ppc_count_finish;
while (1)
{
prev_fp = fp;
if ((sigtramp_start <= pc) && (pc <= sigtramp_end))
{
fp = next_fp + 0x70 + 0xc;
if (!safe_read_memory_unsigned_integer (fp, wordsize, &next_fp))
goto ppc_count_finish;
if (!safe_read_memory_unsigned_integer (fp - 0xc, wordsize, &pc))
goto ppc_count_finish;
fp = next_fp;
if (!safe_read_memory_unsigned_integer (fp, wordsize, &next_fp))
goto ppc_count_finish;
}
else
{
fp = next_fp;
if (!safe_read_memory_unsigned_integer (fp, wordsize, &next_fp))
goto ppc_count_finish;
if (next_fp == 0)
goto ppc_count_finish;
else if (fp == next_fp)
{
warning ("Frame pointer point back at the previous frame");
err = 1;
goto ppc_count_finish;
}
if (!safe_read_memory_unsigned_integer
(fp + PPC_MACOSX_DEFAULT_LR_SAVE * wordsize, wordsize, &pc))
goto ppc_count_finish;
}
pc_set_load_state (pc, OBJF_SYM_ALL, 0);
if (print_fun && (i < print_limit))
print_fun (uiout, i, pc, fp);
i++;
if (!backtrace_past_main && addr_inside_main_func (pc))
goto ppc_count_finish;
if (i >= count_limit)
goto ppc_count_finish;
}
ppc_count_finish:
if (print_fun)
ui_out_end (uiout, ui_out_type_list);
*count = i;
return (!err);
}
char *
ppc_throw_catch_find_typeinfo (struct frame_info *curr_frame,
int exception_type)
{
struct minimal_symbol *typeinfo_sym = NULL;
ULONGEST typeinfo_ptr;
char *typeinfo_str;
if (exception_type == EX_EVENT_THROW)
{
frame_unwind_unsigned_register (curr_frame,
PPC_MACOSX_FIRST_GP_REGNUM + 4,
&typeinfo_ptr);
typeinfo_sym = lookup_minimal_symbol_by_pc (typeinfo_ptr);
}
else
{
ULONGEST type_obj_addr = 0;
frame_unwind_unsigned_register (curr_frame,
PPC_MACOSX_FIRST_GP_REGNUM + 3,
&typeinfo_ptr);
if (safe_read_memory_unsigned_integer
(typeinfo_ptr - 48, 4, &type_obj_addr))
typeinfo_sym = lookup_minimal_symbol_by_pc (type_obj_addr);
}
if (!typeinfo_sym)
return NULL;
typeinfo_str =
typeinfo_sym->ginfo.language_specific.cplus_specific.demangled_name;
if ((typeinfo_str == NULL)
|| (strstr (typeinfo_str, "typeinfo for ") != typeinfo_str))
return NULL;
return typeinfo_str + strlen ("typeinfo for ");
}
static int
ppc_macosx_convert_register_p (int regno, struct type *type)
{
int wordsize = gdbarch_tdep (current_gdbarch)->wordsize;
if (PPC_MACOSX_IS_GP_REGNUM (regno)
&& (TYPE_LENGTH (type) > wordsize)
&& (register_size (current_gdbarch, regno) > wordsize))
return 1;
else
return 0;
}
static void
ppc_macosx_value_to_register (struct frame_info *frame, int regno,
struct type *type, const gdb_byte *buf)
{
int len = TYPE_LENGTH (type);
int wordsize = gdbarch_tdep (current_gdbarch)->wordsize;
int reg_size;
int upper_half_size;
int num_regs;
int i;
gdb_byte reg_buf[8] = { 0 };
if (len <= wordsize)
{
rs6000_value_to_register (frame, regno, type, buf);
return;
}
reg_size = register_size (current_gdbarch, regno);
upper_half_size = reg_size - wordsize;
num_regs = len / wordsize;
for (i = 0; i < num_regs; i++)
{
memcpy (reg_buf + upper_half_size, ((bfd_byte *) buf) + i * wordsize,
wordsize);
put_frame_register (frame, regno + i, reg_buf);
}
}
static void
ppc_macosx_register_to_value (struct frame_info *frame, int regno,
struct type *type, gdb_byte *buf)
{
int len = TYPE_LENGTH (type);
int wordsize = gdbarch_tdep (current_gdbarch)->wordsize;
int reg_size;
int upper_half_size;
int num_regs;
int i;
if (len <= wordsize)
{
rs6000_register_to_value (frame, regno, type, buf);
return;
}
reg_size = register_size (current_gdbarch, regno);
upper_half_size = reg_size - wordsize;
num_regs = len / wordsize;
for (i = 0; i < num_regs; i++)
{
gdb_byte reg_buf[8];
get_frame_register (frame, regno + i, reg_buf);
memcpy (((bfd_byte *) buf) + i * wordsize, reg_buf + upper_half_size,
wordsize);
}
}
static void
ppc_macosx_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_get_longjmp_target (gdbarch, ppc_macosx_get_longjmp_target);
set_gdbarch_register_to_value (gdbarch, ppc_macosx_register_to_value);
set_gdbarch_value_to_register (gdbarch, ppc_macosx_value_to_register);
set_gdbarch_convert_register_p (gdbarch, ppc_macosx_convert_register_p);
user_reg_replace (gdbarch, "fp", ppc_value_of_builtin_frame_fp_reg);
}
static void
ppc_macosx_init_abi_64 (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
tdep->wordsize = 8;
set_gdbarch_addr_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_ptr_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
set_gdbarch_push_dummy_call (gdbarch, ppc64_darwin_abi_push_dummy_call);
set_gdbarch_return_value (gdbarch, ppc64_darwin_abi_return_value);
set_gdbarch_frame_red_zone_size (gdbarch, 288);
set_gdbarch_frame_align (gdbarch, ppc_macosx_frame_align);
set_gdbarch_get_longjmp_target (gdbarch, ppc_64_macosx_get_longjmp_target);
user_reg_replace (gdbarch, "fp", ppc_value_of_builtin_frame_fp_reg);
}
static int
ppc_mach_o_query_64bit ()
{
host_basic_info_data_t info;
mach_msg_type_number_t count;
count = HOST_BASIC_INFO_COUNT;
host_info (mach_host_self (), HOST_BASIC_INFO, (host_info_t) & info,
&count);
return (info.cpu_type == CPU_TYPE_POWERPC &&
info.cpu_subtype == CPU_SUBTYPE_POWERPC_970);
}
static enum gdb_osabi
ppc_mach_o_osabi_sniffer (bfd *abfd)
{
return generic_mach_o_osabi_sniffer (abfd,
bfd_arch_powerpc,
bfd_mach_ppc, bfd_mach_ppc64,
ppc_mach_o_query_64bit);
}
#define PPC_JMP_LR 0x54
#define PPC_64_JMP_LR 0xa8
static int
ppc_macosx_get_longjmp_target_helper (unsigned int offset, CORE_ADDR *pc)
{
CORE_ADDR jmp_buf;
ULONGEST long_addr = 0;
jmp_buf = read_register (PPC_MACOSX_FIRST_GP_REGNUM + 3);
if (safe_read_memory_unsigned_integer
(jmp_buf + offset, TARGET_PTR_BIT / 8, &long_addr))
{
*pc = long_addr;
return 1;
}
else
return 0;
}
static int
ppc_64_macosx_get_longjmp_target (CORE_ADDR *pc)
{
return ppc_macosx_get_longjmp_target_helper (PPC_64_JMP_LR, pc);
}
static int
ppc_macosx_get_longjmp_target (CORE_ADDR *pc)
{
return ppc_macosx_get_longjmp_target_helper (PPC_JMP_LR, pc);
}
static struct value *
ppc_value_of_builtin_frame_fp_reg (struct frame_info *frame)
{
CORE_ADDR frame_pc;
ppc_function_properties *props;
props = ppc_frame_function_properties (frame_next_hack (frame),
frame_cache_hack (frame));
if (props)
{
frame_pc = get_frame_pc (frame);
if (props->frameptr_used && props->frameptr_reg > 0
&& props->frameptr_pc != INVALID_ADDRESS
&& props->frameptr_pc <= frame_pc)
{
return value_of_register (props->frameptr_reg, frame);
}
}
return value_of_register (PPC_MACOSX_SP_REGNUM, frame);
}
void
_initialize_ppc_tdep ()
{
register_gdbarch_init (bfd_arch_powerpc, ppc_gdbarch_init);
gdbarch_register_osabi_sniffer (bfd_arch_unknown, bfd_target_mach_o_flavour,
ppc_mach_o_osabi_sniffer);
gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_DARWIN,
ppc_macosx_init_abi);
gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64,
GDB_OSABI_DARWIN64, ppc_macosx_init_abi_64);
add_setshow_boolean_cmd ("ppc", class_obscure,
&ppc_debugflag, _("\
Set if printing PPC stack analysis debugging statements."), _("\
Show if printing PPC stack analysis debugging statements."), NULL,
NULL, NULL,
&setdebuglist, &showdebuglist);
add_setshow_uinteger_cmd ("ppc-maximum-frame-size", class_obscure,
&ppc_max_frame_size, _("\
Set the maximum size to expect for a valid PPC frame."), _("\
Show the maximum size to expect for a valid PPC frame."), NULL,
NULL, NULL,
&setlist, &showlist);
}