#include "defs.h"
#include "gdbcore.h"
#include "inferior.h"
#include "regcache.h"
#include "value.h"
#include "gdb_string.h"
#include "gdb_assert.h"
#include "ppc-tdep.h"
#include "target.h"
#include "objfiles.h"
#include "infcall.h"
#define ROUND_UP(x,s) ((((long) (x) - 1) & ~(long) ((s) - 1)) + (s))
struct ppc_stack_abi
{
int first_greg;
int last_greg;
int first_freg;
int last_freg;
int first_vreg;
int last_vreg;
int fregs_shadow_gregs;
int regs_shadow_stack;
int structs_with_args;
int min_argsize;
int backchain_size;
};
struct ppc_stack_context
{
int greg;
int freg;
int vreg;
int argoffset;
int structoffset;
CORE_ADDR sp;
};
static void
ppc_copy_into_greg (struct regcache *regcache, int regno, int wordsize,
int len, const gdb_byte *contents)
{
int reg_size = register_size (current_gdbarch, regno);
if (reg_size == wordsize)
{
regcache_raw_write (current_regcache, regno, contents);
}
else
{
int upper_half_size = reg_size - wordsize;
int num_regs = (len/wordsize);
int i;
if (num_regs == 0)
num_regs = 1;
for (i = 0; i < num_regs; i++)
{
char buf[8];
memset (buf, 0, 8);
memcpy (buf + upper_half_size, contents, wordsize);
regcache_cooked_write (regcache, regno + i,
(const bfd_byte *) buf);
contents += wordsize;
}
}
}
static void
ppc_copy_from_greg (struct regcache *regcache, int regno, int wordsize,
int len, bfd_byte *buf)
{
int reg_size = register_size (current_gdbarch, regno);
int num_regs = len / wordsize;
if (reg_size == wordsize)
{
int i;
for (i = 0; i < num_regs; i++)
regcache_cooked_read (regcache, regno + i, buf + i * wordsize);
}
else
{
gdb_byte tmpbuf[8];
int i;
for (i = 0; i < num_regs; i++)
{
regcache_cooked_read (regcache, regno + i, tmpbuf);
memcpy (buf + i * wordsize, tmpbuf + (reg_size - wordsize), wordsize);
}
}
}
static void
ppc_push_argument (struct ppc_stack_abi *abi,
struct ppc_stack_context *c, struct value *arg,
int argno, int do_copy, int floatonly)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
struct type *type = check_typedef (value_type (arg));
int len = TYPE_LENGTH (type);
gdb_byte buf[16];
c->argoffset = ROUND_UP (c->argoffset, 4);
switch (TYPE_CODE (type)) {
case TYPE_CODE_FLT:
{
if (c->freg <= abi->last_freg)
{
struct value *rval;
struct type *rtype;
int rlen;
if (strcmp (TYPE_NAME (type), "long double") != 0)
{
rval = value_cast (builtin_type_double, arg);
rtype = check_typedef (value_type (rval));
rlen = TYPE_LENGTH (rtype);
}
else
{
rval = arg;
rtype = type;
rlen = len;
}
if ((len != 4) && (len != 8) && (len != 16))
error ("floating point parameter had unexpected size");
if (rlen != 8 && rlen != 16)
error ("floating point parameter had unexpected size");
if (do_copy)
regcache_raw_write (current_regcache, FP0_REGNUM + c->freg,
value_contents (rval));
if (do_copy && ! floatonly && abi->fregs_shadow_gregs)
ppc_copy_into_greg (current_regcache, c->greg, tdep->wordsize, len, value_contents (arg));
if (do_copy && ! floatonly && abi->regs_shadow_stack)
write_memory (c->sp + c->argoffset, value_contents (arg), len);
c->freg++;
if (rlen == 16)
c->freg++;
if (! floatonly && (abi->fregs_shadow_gregs) && (c->greg <= abi->last_greg))
c->greg += len / 4;
if (! floatonly && abi->regs_shadow_stack)
c->argoffset += len;
}
else if (! floatonly)
{
if ((len != 4) && (len != 8) && (len != 16))
error ("floating point parameter had unexpected size");
c->argoffset = ROUND_UP (c->argoffset, len);
if (do_copy)
write_memory (c->sp + c->argoffset, value_contents (arg), len);
c->argoffset += len;
}
break;
}
case TYPE_CODE_INT:
case TYPE_CODE_ENUM:
case TYPE_CODE_PTR:
case TYPE_CODE_REF:
{
int nregs;
gdb_byte *val_contents;
if (floatonly)
break;
if (VALUE_REGNUM (arg) != -1 && len == 8 && tdep->wordsize == 4)
{
len = 4;
val_contents = value_contents (arg) + 4;
}
else
val_contents = value_contents (arg);
nregs = (len <= 4) ? 1 : 2;
if ((len != 1) && (len != 2) && (len != 4) && (len != 8))
error ("integer parameter had unexpected size");
if (c->greg <= abi->last_greg)
{
if (do_copy)
{
int regs_avaliable = abi->last_greg - c->greg + 1;
if (regs_avaliable >= nregs)
regs_avaliable = nregs;
ppc_copy_into_greg (current_regcache, c->greg,
tdep->wordsize, regs_avaliable * 4, val_contents);
}
if (do_copy && abi->regs_shadow_stack)
write_memory (c->sp + c->argoffset, val_contents, len);
c->greg += nregs;
if (abi->regs_shadow_stack)
c->argoffset += (nregs * 4);
}
else
{
if (do_copy)
write_memory (c->sp + c->argoffset, val_contents, len);
c->argoffset += (nregs * 4);
}
break;
}
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
{
if (! abi->structs_with_args)
{
if (floatonly)
break;
if (len > 4)
{
c->structoffset = ROUND_UP (c->structoffset, 8);
if (do_copy)
{
write_memory (c->sp + c->structoffset, value_contents (arg), len);
store_unsigned_integer (buf, 4, c->sp + c->structoffset);
}
c->structoffset += ROUND_UP (len, 8);
}
else
if (do_copy)
{
memset (buf, 0, 4);
memcpy (buf, value_contents (arg), len);
}
if (c->greg <= abi->last_greg)
{
if (do_copy)
ppc_copy_into_greg (current_regcache, c->greg, tdep->wordsize, 4, buf);
c->greg++;
}
else
{
if (do_copy)
write_memory (c->sp + c->argoffset, buf, 4);
c->argoffset += 4;
}
break;
}
else
{
int i;
int regspace = (abi->last_greg - c->greg + 1) * 4;
int stackspace = (len <= regspace) ? 0 : (len - regspace);
int writereg = (regspace > len) ? len : regspace;
int writestack = abi->regs_shadow_stack ? len : stackspace;
for (i = 0; i < TYPE_NFIELDS (type); i++)
{
struct value *subarg = value_field (arg, i);
ppc_push_argument (abi, c, subarg, argno, do_copy, 1);
}
if (floatonly)
break;
if (do_copy)
{
gdb_byte *ptr = value_contents (arg);
if (len < 4)
{
memset (buf, 0, 4);
if ((len == 1) || (len == 2))
memcpy (buf + 4 - len, ptr, len);
else
memcpy (buf, ptr, len);
ptr = buf;
}
ppc_copy_into_greg (current_regcache, c->greg,
tdep->wordsize, (writereg < 4) ? 4 : writereg, ptr);
write_memory (c->sp + c->argoffset, ptr,
(writestack < 4) ? 4 : writestack);
}
c->greg += ROUND_UP (writereg, 4) / 4;
c->argoffset += writestack;
}
break;
}
case TYPE_CODE_ARRAY:
{
if (floatonly)
break;
if (! TYPE_VECTOR (type))
error ("non-vector array type");
if (len != 16)
error ("unexpected vector length");
if (c->vreg <= abi->last_vreg)
{
if (do_copy)
regcache_raw_write (current_regcache, tdep->ppc_vr0_regnum + c->vreg,
value_contents (arg));
c->vreg++;
}
else
{
c->argoffset = ROUND_UP (c->argoffset, 16);
if (do_copy)
write_memory (c->sp + c->argoffset, value_contents (arg), len);
c->argoffset += len;
}
break;
}
default:
error ("argument %d has unknown type code 0x%x (%s)",
argno, TYPE_CODE (type),
type_code_name (TYPE_CODE (type)));
}
return;
}
static CORE_ADDR
ppc_push_arguments (struct ppc_stack_abi *abi, int nargs, struct value **args,
CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr)
{
int argno;
gdb_byte buf[4];
CORE_ADDR saved_sp;
struct ppc_stack_context preview;
struct ppc_stack_context write;
preview.greg = abi->first_greg;
preview.freg = abi->first_freg;
preview.vreg = abi->first_vreg;
preview.argoffset = 0;
preview.structoffset = 0;
preview.sp = 0;
if (struct_return)
{
preview.greg++;
if (abi->regs_shadow_stack)
preview.argoffset += 4;
}
for (argno = 0; argno < nargs; argno++)
{
ppc_push_argument (abi, &preview, args[argno], argno, 0, 0);
}
if (preview.argoffset < abi->min_argsize)
preview.argoffset = abi->min_argsize;
saved_sp = read_sp ();
sp -= preview.argoffset + preview.structoffset;
sp -= abi->backchain_size;
sp -= 32;
sp &= ~0x0f;
write_register (SP_REGNUM, sp);
store_unsigned_integer (buf, 4, saved_sp);
write_memory (sp, buf, 4);
write.greg = abi->first_greg;
write.freg = abi->first_freg;
write.vreg = abi->first_vreg;
write.argoffset = abi->backchain_size;
write.structoffset = write.argoffset + preview.argoffset;
write.sp = sp;
if (struct_return)
{
store_unsigned_integer (buf, 4, struct_addr);
ppc_copy_into_greg (current_regcache, write.greg,
gdbarch_tdep (current_gdbarch)->wordsize, 4, buf);
write.greg++;
if (abi->regs_shadow_stack)
write.argoffset += 4;
}
for (argno = 0; argno < nargs; argno++)
{
ppc_push_argument (abi, &write, args[argno], argno, 1, 0);
}
return sp;
}
CORE_ADDR
ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
struct ppc_stack_abi abi;
CORE_ADDR ret;
abi.first_greg = 3;
abi.last_greg = 10;
abi.first_freg = 1;
abi.last_freg = 8;
abi.first_vreg = 2;
abi.last_vreg = 13;
abi.fregs_shadow_gregs = 0;
abi.regs_shadow_stack = 0;
abi.structs_with_args = 0;
abi.min_argsize = 0;
abi.backchain_size = 8;
ret = ppc_push_arguments (&abi, nargs, args, sp, struct_return, struct_addr);
regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
target_store_registers (-1);
return ret;
}
CORE_ADDR
ppc_darwin_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
struct ppc_stack_abi abi;
CORE_ADDR ret;
abi.first_greg = 3;
abi.last_greg = 10;
abi.first_freg = 1;
abi.last_freg = 13;
abi.first_vreg = 2;
abi.last_vreg = 13;
abi.fregs_shadow_gregs = 1;
abi.regs_shadow_stack = 1;
abi.structs_with_args = 1;
abi.min_argsize = 32;
abi.backchain_size = 24;
ret = ppc_push_arguments (&abi, nargs, args, sp, struct_return, struct_addr);
regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
target_store_registers (-1);
return ret;
}
static enum return_value_convention
do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache, gdb_byte *readbuf,
const gdb_byte *writebuf, int broken_gcc)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_assert (tdep->wordsize == 4);
if (TYPE_CODE (type) == TYPE_CODE_FLT
&& TYPE_LENGTH (type) <= 8
&& ppc_floating_point_unit_p (gdbarch))
{
if (readbuf)
{
gdb_byte regval[MAX_REGISTER_SIZE];
struct type *regtype = register_type (gdbarch,
tdep->ppc_fp0_regnum + 1);
regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval);
convert_typed_floating (regval, regtype, readbuf, type);
}
if (writebuf)
{
gdb_byte regval[MAX_REGISTER_SIZE];
struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum);
convert_typed_floating (writebuf, type, regval, regtype);
regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, regval);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (type) == TYPE_CODE_FLT
&& (TYPE_LENGTH (type) == 16 || TYPE_LENGTH (type) == 32))
{
if (writebuf || readbuf != NULL)
{
int i;
for (i = 0; i < TYPE_LENGTH (type) / 8; i++)
{
if (writebuf != NULL)
regcache_cooked_write (regcache, FP0_REGNUM + 1 + i,
(const bfd_byte *) writebuf + i * 8);
if (readbuf != NULL)
regcache_cooked_read (regcache, FP0_REGNUM + 1 + i,
(bfd_byte *) readbuf + i * 8);
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if ((TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) == 8)
|| (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8))
{
if (readbuf)
{
ppc_copy_from_greg (regcache, tdep->ppc_gp0_regnum + 3,
tdep->wordsize, 8, (bfd_byte *) readbuf);
}
if (writebuf)
{
ppc_copy_into_greg (regcache, tdep->ppc_gp0_regnum + 3,
tdep->wordsize, 8, writebuf);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (type) == TYPE_CODE_INT
&& TYPE_LENGTH (type) <= tdep->wordsize)
{
if (readbuf)
{
ULONGEST regval;
regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
®val);
store_unsigned_integer (readbuf, TYPE_LENGTH (type), regval);
}
if (writebuf)
{
regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
unpack_long (type, writebuf));
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_LENGTH (type) == 16
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& TYPE_VECTOR (type) && tdep->ppc_vr0_regnum >= 0)
{
if (readbuf)
{
regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf);
}
if (writebuf)
{
regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, writebuf);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_LENGTH (type) == 8
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& TYPE_VECTOR (type) && tdep->ppc_ev0_regnum >= 0)
{
if (readbuf)
regcache_cooked_read (regcache, tdep->ppc_ev0_regnum + 3, readbuf);
if (writebuf)
regcache_cooked_write (regcache, tdep->ppc_ev0_regnum + 3, writebuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (broken_gcc && TYPE_LENGTH (type) <= 8)
{
if (readbuf)
{
int word = 0;
while (1)
{
ULONGEST reg;
int len = TYPE_LENGTH (type) - word * tdep->wordsize;
if (len <= 0)
break;
if (len > tdep->wordsize)
len = tdep->wordsize;
regcache_cooked_read_unsigned (regcache,
tdep->ppc_gp0_regnum + 3 + word,
®);
store_unsigned_integer (((bfd_byte *) readbuf
+ word * tdep->wordsize), len, reg);
word++;
}
}
if (writebuf)
{
int word = 0;
while (1)
{
ULONGEST reg;
int len = TYPE_LENGTH (type) - word * tdep->wordsize;
if (len <= 0)
break;
if (len > tdep->wordsize)
len = tdep->wordsize;
reg = extract_unsigned_integer (((const bfd_byte *) writebuf
+ word * tdep->wordsize), len);
regcache_cooked_write_unsigned (regcache,
tdep->ppc_gp0_regnum + 3 + word,
reg);
word++;
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_LENGTH (type) <= 8)
{
if (readbuf)
{
ppc_copy_from_greg (regcache, tdep->ppc_gp0_regnum + 3,
tdep->wordsize, TYPE_LENGTH (type), readbuf);
}
if (writebuf)
{
gdb_byte regvals[MAX_REGISTER_SIZE * 2];
memset (regvals, 0, sizeof regvals);
memcpy (regvals, writebuf, TYPE_LENGTH (type));
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3,
regvals + 0 * tdep->wordsize);
if (TYPE_LENGTH (type) > tdep->wordsize)
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4,
regvals + 1 * tdep->wordsize);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
return RETURN_VALUE_STRUCT_CONVENTION;
}
enum return_value_convention
ppc_darwin_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
struct regcache *regcache, gdb_byte *readbuf,
const gdb_byte *writebuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
|| TYPE_CODE (valtype) == TYPE_CODE_UNION)
{
if (readbuf != NULL)
{
ULONGEST addr;
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, (gdb_byte *) &addr);
read_memory (addr, readbuf, TYPE_LENGTH (valtype));
}
return RETURN_VALUE_ABI_RETURNS_ADDRESS;
}
else
return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
writebuf, 0);
}
enum return_value_convention
ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
struct regcache *regcache, gdb_byte *readbuf,
const gdb_byte *writebuf)
{
return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
writebuf, 0);
}
enum return_value_convention
ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
struct type *valtype,
struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
return do_ppc_sysv_return_value (gdbarch, valtype, regcache, readbuf,
writebuf, 1);
}
CORE_ADDR
ppc64_darwin_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
return ppc64_sysv_abi_push_dummy_call
(gdbarch, function, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr);
}
enum return_value_convention
ppc64_darwin_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
struct regcache *regcache, gdb_byte *readbuf,
const gdb_byte *writebuf)
{
return ppc64_sysv_abi_return_value (gdbarch, valtype, regcache, readbuf, writebuf);
}
static int
convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr)
{
struct obj_section *dot_fn_section;
struct minimal_symbol *dot_fn;
struct minimal_symbol *fn;
CORE_ADDR toc;
dot_fn = lookup_minimal_symbol_by_pc (code_addr);
if (dot_fn == NULL || SYMBOL_LINKAGE_NAME (dot_fn)[0] != '.')
return 0;
dot_fn_section = find_pc_section (code_addr);
if (dot_fn_section == NULL || dot_fn_section->objfile == NULL)
return 0;
fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL,
dot_fn_section->objfile);
if (fn == NULL)
return 0;
(*desc_addr) = SYMBOL_VALUE_ADDRESS (fn);
return 1;
}
CORE_ADDR
ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
CORE_ADDR func_addr = find_function_addr (function, NULL);
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
const CORE_ADDR back_chain = read_sp ();
int write_pass;
LONGEST vparam_size = 0;
LONGEST gparam_size = 0;
gdb_assert (tdep->wordsize == 8);
for (write_pass = 0; write_pass < 2; write_pass++)
{
int argno;
int freg = 1;
int greg = 3;
int vreg = 2;
CORE_ADDR gparam;
CORE_ADDR vparam;
if (!write_pass)
{
gparam = 0;
vparam = 0;
}
else
{
vparam = align_down (sp - vparam_size, 16);
gparam = align_down (vparam - gparam_size, 16);
sp = align_down (gparam - 48, 16);
}
if (struct_return)
{
if (write_pass)
regcache_cooked_write_signed (regcache,
tdep->ppc_gp0_regnum + greg,
struct_addr);
greg++;
gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
}
for (argno = 0; argno < nargs; argno++)
{
struct value *arg = args[argno];
struct type *type = check_typedef (value_type (arg));
const bfd_byte *val = value_contents (arg);
if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8)
{
if (write_pass)
{
if (ppc_floating_point_unit_p (current_gdbarch)
&& freg <= 13)
{
gdb_byte regval[MAX_REGISTER_SIZE];
struct type *regtype
= register_type (gdbarch, tdep->ppc_fp0_regnum);
convert_typed_floating (val, type, regval, regtype);
regcache_cooked_write (regcache,
tdep->ppc_fp0_regnum + freg,
regval);
}
if (greg <= 10)
{
gdb_byte regval[MAX_REGISTER_SIZE];
memset (regval, 0, sizeof regval);
memcpy (regval, val, TYPE_LENGTH (type));
regcache_cooked_write (regcache,
tdep->ppc_gp0_regnum + greg,
regval);
}
write_memory (gparam, val, TYPE_LENGTH (type));
}
freg++;
greg++;
gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
}
else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
&& TYPE_CODE (type) == TYPE_CODE_ARRAY
&& tdep->ppc_vr0_regnum >= 0)
{
if (vreg <= 13)
{
if (write_pass)
regcache_cooked_write (regcache,
tdep->ppc_vr0_regnum + vreg, val);
vreg++;
}
else
{
if (write_pass)
write_memory (vparam, val, TYPE_LENGTH (type));
vparam = align_up (vparam + TYPE_LENGTH (type), 16);
}
}
else if ((TYPE_CODE (type) == TYPE_CODE_INT
|| TYPE_CODE (type) == TYPE_CODE_ENUM
|| TYPE_CODE (type) == TYPE_CODE_PTR)
&& TYPE_LENGTH (type) <= 8)
{
if (write_pass)
{
ULONGEST word = unpack_long (type, val);
if (TYPE_CODE (type) == TYPE_CODE_PTR
&& TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)
{
CORE_ADDR desc = word;
convert_code_addr_to_desc_addr (word, &desc);
word = desc;
}
if (greg <= 10)
regcache_cooked_write_unsigned (regcache,
tdep->ppc_gp0_regnum +
greg, word);
write_memory_unsigned_integer (gparam, tdep->wordsize,
word);
}
greg++;
gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
}
else
{
int byte;
for (byte = 0; byte < TYPE_LENGTH (type);
byte += tdep->wordsize)
{
if (write_pass && greg <= 10)
{
gdb_byte regval[MAX_REGISTER_SIZE];
int len = TYPE_LENGTH (type) - byte;
if (len > tdep->wordsize)
len = tdep->wordsize;
memset (regval, 0, sizeof regval);
memcpy (regval, val + byte, len);
if (len == 1 || len == 2 || len == 4)
memcpy (regval + tdep->wordsize - len,
val + byte, len);
regcache_cooked_write (regcache, greg, regval);
}
greg++;
}
if (write_pass)
write_memory (gparam, val, TYPE_LENGTH (type));
if (write_pass)
gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
}
}
if (!write_pass)
{
vparam_size = vparam;
if (greg < 8)
gparam_size = 8 * tdep->wordsize;
else
gparam_size = gparam;
}
}
regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
write_memory_signed_integer (sp, tdep->wordsize, back_chain);
regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
{
CORE_ADDR desc_addr;
if (convert_code_addr_to_desc_addr (func_addr, &desc_addr))
{
CORE_ADDR toc =
read_memory_unsigned_integer (desc_addr + tdep->wordsize,
tdep->wordsize);
regcache_cooked_write_unsigned (regcache,
tdep->ppc_gp0_regnum + 2, toc);
}
}
return sp;
}
enum return_value_convention
ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *valtype,
struct regcache *regcache, gdb_byte *readbuf,
const gdb_byte *writebuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_assert (ppc_floating_point_unit_p (gdbarch));
if (TYPE_CODE (valtype) == TYPE_CODE_FLT && TYPE_LENGTH (valtype) <= 8)
{
gdb_byte regval[MAX_REGISTER_SIZE];
struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum);
if (writebuf != NULL)
{
convert_typed_floating (writebuf, valtype, regval, regtype);
regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, regval);
}
if (readbuf != NULL)
{
regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval);
convert_typed_floating (regval, regtype, readbuf, valtype);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if ((TYPE_CODE (valtype) == TYPE_CODE_INT
|| TYPE_CODE (valtype) == TYPE_CODE_ENUM)
&& TYPE_LENGTH (valtype) <= 8)
{
if (writebuf != NULL)
{
regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
unpack_long (valtype, writebuf));
}
if (readbuf != NULL)
{
ULONGEST regval;
regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
®val);
store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), regval);
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (valtype) == TYPE_CODE_PTR)
{
if (writebuf != NULL)
regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
if (readbuf != NULL)
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
&& TYPE_LENGTH (valtype) <= 8
&& TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
&& TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
{
int offset = (register_size (gdbarch, tdep->ppc_gp0_regnum + 3)
- TYPE_LENGTH (valtype));
if (writebuf != NULL)
regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3,
offset, TYPE_LENGTH (valtype), writebuf);
if (readbuf != NULL)
regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3,
offset, TYPE_LENGTH (valtype), readbuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (valtype) == TYPE_CODE_FLT
&& (TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 32))
{
if (writebuf || readbuf != NULL)
{
int i;
for (i = 0; i < TYPE_LENGTH (valtype) / 8; i++)
{
if (writebuf != NULL)
regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
(const bfd_byte *) writebuf + i * 8);
if (readbuf != NULL)
regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
(bfd_byte *) readbuf + i * 8);
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
&& (TYPE_LENGTH (valtype) == 8 || TYPE_LENGTH (valtype) == 16))
{
if (regcache != NULL)
{
int i;
for (i = 0; i < 2; i++)
{
gdb_byte regval[MAX_REGISTER_SIZE];
struct type *regtype =
register_type (current_gdbarch, tdep->ppc_fp0_regnum);
if (writebuf != NULL)
{
convert_typed_floating ((const bfd_byte *) writebuf +
i * (TYPE_LENGTH (valtype) / 2),
valtype, regval, regtype);
regcache_cooked_write (regcache,
tdep->ppc_fp0_regnum + 1 + i,
regval);
}
if (readbuf != NULL)
{
regcache_cooked_read (regcache,
tdep->ppc_fp0_regnum + 1 + i,
regval);
convert_typed_floating (regval, regtype,
(bfd_byte *) readbuf +
i * (TYPE_LENGTH (valtype) / 2),
valtype);
}
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX && TYPE_LENGTH (valtype) == 32)
{
if (regcache != NULL)
{
int i;
for (i = 0; i < 4; i++)
{
if (writebuf != NULL)
regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
(const bfd_byte *) writebuf + i * 8);
if (readbuf != NULL)
regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
(bfd_byte *) readbuf + i * 8);
}
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
return RETURN_VALUE_STRUCT_CONVENTION;
}
CORE_ADDR
ppc64_sysv_abi_adjust_breakpoint_address (struct gdbarch *gdbarch,
CORE_ADDR bpaddr)
{
return gdbarch_convert_from_func_ptr_addr (gdbarch, bpaddr, ¤t_target);
}