/* Target-dependent code for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 2000, 2001 Free Software Foundation, Inc.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GDB.
#include "regcache.h"
#include "value.h"
+#include "solib-svr4.h"
#include "ppc-tdep.h"
/* The following two instructions are used in the signal trampoline
- code on linux/ppc */
+ code on GNU/Linux PPC. */
#define INSTR_LI_R0_0x7777 0x38007777
#define INSTR_SC 0x44000002
/* Determine if pc is in a signal trampoline...
- Ha! That's not what this does at all. wait_for_inferior in infrun.c
- calls IN_SIGTRAMP in order to detect entry into a signal trampoline
- just after delivery of a signal. But on linux, signal trampolines
- are used for the return path only. The kernel sets things up so that
- the signal handler is called directly.
+ Ha! That's not what this does at all. wait_for_inferior in
+ infrun.c calls PC_IN_SIGTRAMP in order to detect entry into a
+ signal trampoline just after delivery of a signal. But on
+ GNU/Linux, signal trampolines are used for the return path only.
+ The kernel sets things up so that the signal handler is called
+ directly.
If we use in_sigtramp2() in place of in_sigtramp() (see below)
we'll (often) end up with stop_pc in the trampoline and prev_pc in
first instruction long after the fact, just in case the observed
behavior is ever fixed.)
- IN_SIGTRAMP is called from blockframe.c as well in order to set
+ PC_IN_SIGTRAMP is called from blockframe.c as well in order to set
the signal_handler_caller flag. Because of our strange definition
- of in_sigtramp below, we can't rely on signal_handler_caller getting
- set correctly from within blockframe.c. This is why we take pains
- to set it in init_extra_frame_info(). */
+ of in_sigtramp below, we can't rely on signal_handler_caller
+ getting set correctly from within blockframe.c. This is why we
+ take pains to set it in init_extra_frame_info(). */
int
ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
char buf[4];
CORE_ADDR handler;
- lr = read_register (PPC_LR_REGNUM);
+ lr = read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum);
if (!ppc_linux_at_sigtramp_return_path (lr))
return 0;
regs_addr =
read_memory_integer (fi->frame + PPC_LINUX_REGS_PTR_OFFSET, 4);
fi->saved_regs[PC_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_NIP;
- fi->saved_regs[PPC_PS_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_MSR;
- fi->saved_regs[PPC_CR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_CCR;
- fi->saved_regs[PPC_LR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_LNK;
- fi->saved_regs[PPC_CTR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_CTR;
- fi->saved_regs[PPC_XER_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_XER;
- fi->saved_regs[PPC_MQ_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_MQ;
+ fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_ps_regnum] =
+ regs_addr + 4 * PPC_LINUX_PT_MSR;
+ fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_cr_regnum] =
+ regs_addr + 4 * PPC_LINUX_PT_CCR;
+ fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_lr_regnum] =
+ regs_addr + 4 * PPC_LINUX_PT_LNK;
+ fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_ctr_regnum] =
+ regs_addr + 4 * PPC_LINUX_PT_CTR;
+ fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_xer_regnum] =
+ regs_addr + 4 * PPC_LINUX_PT_XER;
+ fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_mq_regnum] =
+ regs_addr + 4 * PPC_LINUX_PT_MQ;
for (i = 0; i < 32; i++)
- fi->saved_regs[PPC_GP0_REGNUM + i] = regs_addr + 4 * PPC_LINUX_PT_R0 + 4 * i;
+ fi->saved_regs[gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum + i] =
+ regs_addr + 4 * PPC_LINUX_PT_R0 + 4 * i;
for (i = 0; i < 32; i++)
fi->saved_regs[FP0_REGNUM + i] = regs_addr + 4 * PPC_LINUX_PT_FPR0 + 8 * i;
}
it may be used generically by ports which use either the SysV ABI or
the EABI */
+/* Until November 2001, gcc was not complying to the SYSV ABI for
+ returning structures less than or equal to 8 bytes in size. It was
+ returning everything in memory. When this was corrected, it wasn't
+ fixed for native platforms. */
+int
+ppc_sysv_abi_broken_use_struct_convention (int gcc_p, struct type *value_type)
+{
+ if (TYPE_LENGTH (value_type) == 16
+ && TYPE_VECTOR (value_type))
+ return 0;
+
+ return generic_use_struct_convention (gcc_p, value_type);
+}
+
+/* Structures 8 bytes or less long are returned in the r3 & r4
+ registers, according to the SYSV ABI. */
+int
+ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
+{
+ if (TYPE_LENGTH (value_type) == 16
+ && TYPE_VECTOR (value_type))
+ return 0;
+
+ return (TYPE_LENGTH (value_type) > 8);
+}
+
/* round2 rounds x up to the nearest multiple of s assuming that s is a
power of 2 */
int struct_return, CORE_ADDR struct_addr)
{
int argno;
- int greg, freg;
+ /* Next available general register for non-float, non-vector arguments. */
+ int greg;
+ /* Next available floating point register for float arguments. */
+ int freg;
+ /* Next available vector register for vector arguments. */
+ int vreg;
int argstkspace;
int structstkspace;
int argoffset;
greg = struct_return ? 4 : 3;
freg = 1;
+ vreg = 2;
argstkspace = 0;
structstkspace = 0;
greg += 2;
}
}
- else
- {
+ else if (!TYPE_VECTOR (type))
+ {
if (len > 4
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION)
{
/* Rounding to the nearest multiple of 8 may not be necessary,
- but it is safe. Particularly since we don't know the
- field types of the structure */
+ but it is safe. Particularly since we don't know the
+ field types of the structure */
structstkspace += round2 (len, 8);
}
if (greg <= 10)
greg++;
else
argstkspace += 4;
+ }
+ else
+ {
+ if (len == 16
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type))
+ {
+ if (vreg <= 13)
+ vreg++;
+ else
+ {
+ /* Vector arguments must be aligned to 16 bytes on
+ the stack. */
+ argstkspace += round2 (argstkspace, 16);
+ argstkspace += 16;
+ }
+ }
}
}
structoffset = argoffset + argstkspace;
freg = 1;
greg = 3;
+ vreg = 2;
/* Fill in r3 with the return structure, if any */
if (struct_return)
{
{
if (len > 8)
printf_unfiltered (
- "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
+ "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM + freg)],
VALUE_CONTENTS (arg), len);
freg++;
greg += 2;
}
}
- else
+ else if (!TYPE_VECTOR (type))
{
char val_buf[4];
if (len > 4
}
if (greg <= 10)
{
- *(int *) ®isters[REGISTER_BYTE (greg)] = 0;
memcpy (®isters[REGISTER_BYTE (greg)], val_buf, 4);
greg++;
}
argoffset += 4;
}
}
+ else
+ {
+ if (len == 16
+ && TYPE_CODE (type) == TYPE_CODE_ARRAY
+ && TYPE_VECTOR (type))
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ char *v_val_buf = alloca (16);
+ memset (v_val_buf, 0, 16);
+ memcpy (v_val_buf, VALUE_CONTENTS (arg), len);
+ if (vreg <= 13)
+ {
+ memcpy (®isters[REGISTER_BYTE (tdep->ppc_vr0_regnum
+ + vreg)],
+ v_val_buf, 16);
+ vreg++;
+ }
+ else
+ {
+ write_memory (sp + argoffset, v_val_buf, 16);
+ argoffset += 16;
+ }
+ }
+ }
}
target_store_registers (-1);
int
ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
{
- unsigned char *bp;
+ const unsigned char *bp;
int val;
int bplen;
char old_contents[BREAKPOINT_MAX];
return val;
}
+
+/* Fetch (and possibly build) an appropriate link_map_offsets
+ structure for GNU/Linux PPC targets using the struct offsets
+ defined in link.h (but without actual reference to that file).
+
+ This makes it possible to access GNU/Linux PPC shared libraries
+ from a GDB that was not built on an GNU/Linux PPC host (for cross
+ debugging). */
+
+struct link_map_offsets *
+ppc_linux_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 8; /* The actual size is 20 bytes, but
+ this is all we need. */
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 20; /* The actual size is 560 bytes, but
+ this is all we need. */
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 4;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 12;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 16;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}