/* 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 "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;
}
return rs6000_frame_chain (thisframe);
}
-/* FIXME: Move the following to rs6000-tdep.c (or some other file where
- it may be used generically by ports which use either the SysV ABI or
- the EABI */
-
-/* round2 rounds x up to the nearest multiple of s assuming that s is a
- power of 2 */
-
-#undef round2
-#define round2(x,s) ((((long) (x) - 1) & ~(long)((s)-1)) + (s))
-
-/* Pass the arguments in either registers, or in the stack. Using the
- ppc sysv ABI, 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..r10 registers. float and double parameters are
- passed in fpr's, in addition to that. Rest of the parameters if any
- are passed in user stack.
-
- If the function is returning a structure, then the return address is passed
- in r3, then the first 7 words of the parametes can be passed in registers,
- starting from r4. */
-
-CORE_ADDR
-ppc_sysv_abi_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
-{
- int argno;
- int greg, freg;
- int argstkspace;
- int structstkspace;
- int argoffset;
- int structoffset;
- struct value *arg;
- struct type *type;
- int len;
- char old_sp_buf[4];
- CORE_ADDR saved_sp;
-
- greg = struct_return ? 4 : 3;
- freg = 1;
- argstkspace = 0;
- structstkspace = 0;
-
- /* Figure out how much new stack space is required for arguments
- which don't fit in registers. Unlike the PowerOpen ABI, the
- SysV ABI doesn't reserve any extra space for parameters which
- are put in registers. */
- for (argno = 0; argno < nargs; argno++)
- {
- arg = args[argno];
- type = check_typedef (VALUE_TYPE (arg));
- len = TYPE_LENGTH (type);
-
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
- {
- if (freg <= 8)
- freg++;
- else
- {
- /* SysV ABI converts floats to doubles when placed in
- memory and requires 8 byte alignment */
- if (argstkspace & 0x4)
- argstkspace += 4;
- argstkspace += 8;
- }
- }
- else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8) /* long long */
- {
- if (greg > 9)
- {
- greg = 11;
- if (argstkspace & 0x4)
- argstkspace += 4;
- argstkspace += 8;
- }
- else
- {
- if ((greg & 1) == 0)
- greg++;
- greg += 2;
- }
- }
- else
- {
- 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 */
- structstkspace += round2 (len, 8);
- }
- if (greg <= 10)
- greg++;
- else
- argstkspace += 4;
- }
- }
-
- /* Get current SP location */
- saved_sp = read_sp ();
-
- sp -= argstkspace + structstkspace;
-
- /* Allocate space for backchain and callee's saved lr */
- sp -= 8;
-
- /* Make sure that we maintain 16 byte alignment */
- sp &= ~0x0f;
-
- /* Update %sp before proceeding any further */
- write_register (SP_REGNUM, sp);
-
- /* write the backchain */
- store_address (old_sp_buf, 4, saved_sp);
- write_memory (sp, old_sp_buf, 4);
-
- argoffset = 8;
- structoffset = argoffset + argstkspace;
- freg = 1;
- greg = 3;
- /* Fill in r3 with the return structure, if any */
- if (struct_return)
- {
- char val_buf[4];
- store_address (val_buf, 4, struct_addr);
- memcpy (®isters[REGISTER_BYTE (greg)], val_buf, 4);
- greg++;
- }
- /* Now fill in the registers and stack... */
- for (argno = 0; argno < nargs; argno++)
- {
- arg = args[argno];
- type = check_typedef (VALUE_TYPE (arg));
- len = TYPE_LENGTH (type);
-
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
- {
- if (freg <= 8)
- {
- 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 + freg)],
- VALUE_CONTENTS (arg), len);
- freg++;
- }
- else
- {
- /* SysV ABI converts floats to doubles when placed in
- memory and requires 8 byte alignment */
- /* FIXME: Convert floats to doubles */
- if (argoffset & 0x4)
- argoffset += 4;
- write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
- argoffset += 8;
- }
- }
- else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8) /* long long */
- {
- if (greg > 9)
- {
- greg = 11;
- if (argoffset & 0x4)
- argoffset += 4;
- write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
- argoffset += 8;
- }
- else
- {
- if ((greg & 1) == 0)
- greg++;
-
- memcpy (®isters[REGISTER_BYTE (greg)],
- VALUE_CONTENTS (arg), 4);
- memcpy (®isters[REGISTER_BYTE (greg + 1)],
- VALUE_CONTENTS (arg) + 4, 4);
- greg += 2;
- }
- }
- else
- {
- char val_buf[4];
- if (len > 4
- || TYPE_CODE (type) == TYPE_CODE_STRUCT
- || TYPE_CODE (type) == TYPE_CODE_UNION)
- {
- write_memory (sp + structoffset, VALUE_CONTENTS (arg), len);
- store_address (val_buf, 4, sp + structoffset);
- structoffset += round2 (len, 8);
- }
- else
- {
- memset (val_buf, 0, 4);
- memcpy (val_buf, VALUE_CONTENTS (arg), len);
- }
- if (greg <= 10)
- {
- *(int *) ®isters[REGISTER_BYTE (greg)] = 0;
- memcpy (®isters[REGISTER_BYTE (greg)], val_buf, 4);
- greg++;
- }
- else
- {
- write_memory (sp + argoffset, val_buf, 4);
- argoffset += 4;
- }
- }
- }
-
- target_store_registers (-1);
- return sp;
-}
-
/* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint
in much the same fashion as memory_remove_breakpoint in mem-break.c,
but is careful not to write back the previous contents if the code
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];
}
/* Fetch (and possibly build) an appropriate link_map_offsets
- structure for Linux/PPC targets using the struct 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 Linux/PPC shared libraries from a
- GDB that was not built on an Linux/PPC host (for cross debugging). */
+ 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)
return lmp;
}
+
+static void
+ppc_linux_init_abi (struct gdbarch_info info,
+ struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* 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. */
+ set_gdbarch_use_struct_convention (gdbarch,
+ ppc_sysv_abi_broken_use_struct_convention);
+
+ if (tdep->wordsize == 4)
+ {
+ /* Note: kevinb/2002-04-12: See note in rs6000_gdbarch_init regarding
+ *_push_arguments(). The same remarks hold for the methods below. */
+ set_gdbarch_frameless_function_invocation (gdbarch,
+ ppc_linux_frameless_function_invocation);
+ set_gdbarch_frame_chain (gdbarch, ppc_linux_frame_chain);
+ set_gdbarch_frame_saved_pc (gdbarch, ppc_linux_frame_saved_pc);
+
+ set_gdbarch_frame_init_saved_regs (gdbarch,
+ ppc_linux_frame_init_saved_regs);
+ set_gdbarch_init_extra_frame_info (gdbarch,
+ ppc_linux_init_extra_frame_info);
+
+ set_gdbarch_memory_remove_breakpoint (gdbarch,
+ ppc_linux_memory_remove_breakpoint);
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, ppc_linux_svr4_fetch_link_map_offsets);
+ }
+}
+
+void
+_initialize_ppc_linux_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_powerpc, GDB_OSABI_LINUX,
+ ppc_linux_init_abi);
+}