Changes for GNU/Linux PPC native port of gdb.
authorKevin Buettner <kevinb@redhat.com>
Tue, 22 Feb 2000 01:20:32 +0000 (01:20 +0000)
committerKevin Buettner <kevinb@redhat.com>
Tue, 22 Feb 2000 01:20:32 +0000 (01:20 +0000)
gdb/config/powerpc/linux.mt [new file with mode: 0644]
gdb/config/powerpc/nm-linux.h [new file with mode: 0644]
gdb/config/powerpc/tm-linux.h [new file with mode: 0644]
gdb/config/powerpc/xm-linux.h
gdb/config/rs6000/tm-rs6000.h
gdb/ppc-linux-nat.c [new file with mode: 0644]
gdb/ppc-linux-tdep.c [new file with mode: 0644]
gdb/rs6000-tdep.c

diff --git a/gdb/config/powerpc/linux.mt b/gdb/config/powerpc/linux.mt
new file mode 100644 (file)
index 0000000..a7c1bed
--- /dev/null
@@ -0,0 +1,3 @@
+# Target: Motorola PPC on Linux
+TDEPFILES= rs6000-tdep.o ppc-linux-tdep.o
+TM_FILE= tm-linux.h
diff --git a/gdb/config/powerpc/nm-linux.h b/gdb/config/powerpc/nm-linux.h
new file mode 100644 (file)
index 0000000..78b78b9
--- /dev/null
@@ -0,0 +1,64 @@
+/* IBM PowerPC native-dependent macros for GDB, the GNU debugger.
+   Copyright 1995 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef NM_LINUX_H
+#define NM_LINUX_H
+
+/* Return sizeof user struct to callers in less machine dependent routines */
+
+#define KERNEL_U_SIZE kernel_u_size()
+extern int kernel_u_size PARAMS ((void));
+
+/* Tell gdb that we can attach and detach other processes */
+#define ATTACH_DETACH
+
+#define U_REGS_OFFSET 0
+
+#define REGISTER_U_ADDR(addr, blockend, regno) \
+        (addr) = ppc_register_u_addr ((blockend),(regno));
+
+/* No <sys/reg.h> */
+
+#define NO_SYS_REG_H
+
+#ifdef HAVE_LINK_H
+#include "solib.h"             /* Support for shared libraries. */
+#define SVR4_SHARED_LIBS
+#endif
+
+/* Support for Linuxthreads. */
+
+#ifdef __STDC__
+struct objfile;
+#endif
+
+extern void
+linuxthreads_new_objfile PARAMS ((struct objfile *objfile));
+#define target_new_objfile(OBJFILE) linuxthreads_new_objfile (OBJFILE)
+
+extern char *
+linuxthreads_pid_to_str PARAMS ((int pid));
+#define target_pid_to_str(PID) linuxthreads_pid_to_str (PID)
+
+extern int
+linuxthreads_prepare_to_proceed PARAMS ((int step));
+#define PREPARE_TO_PROCEED(select_it) linuxthreads_prepare_to_proceed (1)
+
+
+#endif /* #ifndef NM_LINUX_H */
diff --git a/gdb/config/powerpc/tm-linux.h b/gdb/config/powerpc/tm-linux.h
new file mode 100644 (file)
index 0000000..13a5327
--- /dev/null
@@ -0,0 +1,113 @@
+/* Definitions to target GDB to Linux on 386.
+   Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef TM_LINUX_H
+#define TM_LINUX_H
+
+#include "powerpc/tm-ppc-eabi.h"
+
+#undef PUSH_ARGUMENTS
+
+/* We can single step on linux */
+#undef  SOFTWARE_SINGLE_STEP
+#define SOFTWARE_SINGLE_STEP(p,q) abort() /* Will never execute! */
+#undef  SOFTWARE_SINGLE_STEP_P
+#define SOFTWARE_SINGLE_STEP_P 0
+
+/* Make sure nexti gets the help it needs for debugging assembly code
+   without symbols */
+
+#define AT_SUBROUTINE_CALL_INSTRUCTION_TARGET(prevpc,stoppc) \
+   at_subroutine_call_instruction_target(prevpc,stoppc)
+extern int at_subroutine_call_instruction_target();
+
+/* We _want_ the SVR4 section offset calculations (see syms_from_objfile()
+   in symfile.c) */
+#undef IBM6000_TARGET
+
+/* Offset to saved PC in sigcontext, from <linux/signal.h>.  */
+#define SIGCONTEXT_PC_OFFSET 184
+
+/* Avoid warning from redefinition in tm-sysv4.h */
+#undef SKIP_TRAMPOLINE_CODE
+
+/* We need this file for the SOLIB_TRAMPOLINE stuff. */
+#include "tm-sysv4.h"
+
+extern CORE_ADDR ppc_linux_skip_trampoline_code (CORE_ADDR pc);
+#undef SKIP_TRAMPOLINE_CODE
+#define        SKIP_TRAMPOLINE_CODE(pc) ppc_linux_skip_trampoline_code (pc)
+
+extern int ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name);
+#undef IN_SIGTRAMP
+#define IN_SIGTRAMP(pc,func_name) ppc_linux_in_sigtramp (pc,func_name)
+
+extern unsigned long ppc_linux_frame_saved_pc (struct frame_info *);
+#undef FRAME_SAVED_PC
+#define FRAME_SAVED_PC(FRAME) ppc_linux_frame_saved_pc (FRAME)
+
+extern void ppc_linux_init_extra_frame_info (int fromleaf, struct frame_info *);
+#undef  INIT_EXTRA_FRAME_INFO
+#define        INIT_EXTRA_FRAME_INFO(fromleaf, fi) \
+  ppc_linux_init_extra_frame_info (fromleaf, fi)
+
+extern int ppc_linux_frameless_function_invocation (struct frame_info *);
+#undef FRAMELESS_FUNCTION_INVOCATION
+#define FRAMELESS_FUNCTION_INVOCATION(FI) \
+  (ppc_linux_frameless_function_invocation (FI))
+
+extern void ppc_linux_frame_init_saved_regs (struct frame_info *);
+#undef FRAME_INIT_SAVED_REGS
+#define FRAME_INIT_SAVED_REGS(FI) ppc_linux_frame_init_saved_regs (FI)
+
+CORE_ADDR ppc_linux_frame_chain (struct frame_info *);
+#undef FRAME_CHAIN
+#define FRAME_CHAIN(thisframe) ppc_linux_frame_chain (thisframe)
+
+CORE_ADDR ppc_sysv_abi_push_arguments PARAMS ((int, struct value **, CORE_ADDR, int, CORE_ADDR));
+#undef PUSH_ARGUMENTS
+#define        PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
+  (ppc_sysv_abi_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr)))
+
+#define CANNOT_FETCH_REGISTER(regno) ((regno) >= MQ_REGNUM)
+#define CANNOT_STORE_REGISTER(regno) ((regno) >= MQ_REGNUM)
+
+/* Linux doesn't use the PowerOpen ABI for function pointer representation */
+#undef CONVERT_FROM_FUNC_PTR_ADDR
+
+#if 0 /* If skip_prologue() isn't too greedy, we don't need this */
+/* There is some problem with the debugging symbols generated by the
+   compiler such that the debugging symbol for the first line of a
+   function overlap with the function prologue.  */
+#define PROLOGUE_FIRSTLINE_OVERLAP
+#endif
+
+/* Some versions of Linux have real-time signal support in the C library, and
+   some don't.  We have to include this file to find out.  */
+#include <signal.h>
+
+#ifdef __SIGRTMIN
+#define REALTIME_LO __SIGRTMIN
+#define REALTIME_HI (__SIGRTMAX + 1)
+#else
+#define REALTIME_LO 32
+#define REALTIME_HI 64
+#endif
+
+#endif  /* #ifndef TM_LINUX_H */
index 754f8589ae56c504f3272f4bd20f864a3a936070..0ca4c609d67c5681731abd3b8505261449514a77 100644 (file)
@@ -1,3 +1,49 @@
+/* Native support for linux, for GDB, the GNU debugger.
+   Copyright (C) 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef XM_LINUX_H
+#define XM_LINUX_H
+
+#define HOST_BYTE_ORDER BIG_ENDIAN
+
+#define HAVE_TERMIOS
+
+/* This is the amount to subtract from u.u_ar0
+   +   to get the offset in the core file of the register values.  */
+#define KERNEL_U_ADDR 0x0
+
+#define NEED_POSIX_SETPGID
+
+/* Need R_OK etc, but USG isn't defined.  */
+#include <unistd.h>
+
+/* If you expect to use the mmalloc package to obtain mapped symbol files,
+   for now you have to specify some parameters that determine how gdb places
+   the mappings in it's address space.  See the comments in map_to_address()
+   for details.  This is expected to only be a short term solution.  Yes it
+   is a kludge.
+   FIXME:  Make this more automatic. */
+
+#define MMAP_BASE_ADDRESS      0x20000000      /* First mapping here */
+#define MMAP_INCREMENT         0x01000000      /* Increment to next mapping */
+
+#endif /* #ifndef XM_LINUX_H */
 /* Host definitions for a Sun 4, for GDB, the GNU debugger.
    Copyright 1996
    Free Software Foundation, Inc.
index 3c344311da7e26bd434af3067a7910232d9092eb..89a0bd1cfeba7e5c37b4bf30438919c923c1a4de 100644 (file)
@@ -380,10 +380,9 @@ CORE_ADDR rs6000_frame_chain PARAMS ((struct frame_info *));
    by FI does not have a frame on the stack associated with it.  If it
    does not, FRAMELESS is set to 1, else 0.  */
 
+extern int rs6000_frameless_function_invocation (struct frame_info *);
 #define FRAMELESS_FUNCTION_INVOCATION(FI) \
-  (frameless_function_invocation (FI))
-
-extern int frameless_function_invocation PARAMS ((struct frame_info *));
+  (rs6000_frameless_function_invocation (FI))
 
 #define INIT_FRAME_PC_FIRST(fromleaf, prev) \
   prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \
@@ -407,9 +406,9 @@ extern void rs6000_init_extra_frame_info (int fromleaf, struct frame_info *);
 #define        DEFAULT_LR_SAVE 8
 
 /* Return saved PC from a frame */
-#define FRAME_SAVED_PC(FRAME)  frame_saved_pc (FRAME)
+#define FRAME_SAVED_PC(FRAME)  rs6000_frame_saved_pc (FRAME)
 
-extern unsigned long frame_saved_pc PARAMS ((struct frame_info *));
+extern unsigned long rs6000_frame_saved_pc (struct frame_info *);
 
 extern CORE_ADDR rs6000_frame_args_address PARAMS ((struct frame_info *));
 #define FRAME_ARGS_ADDRESS(FI) rs6000_frame_args_address (FI)
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
new file mode 100644 (file)
index 0000000..1522f96
--- /dev/null
@@ -0,0 +1,76 @@
+/* PPC linux native support.
+   Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcore.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>
+
+int
+kernel_u_size ()
+{
+  return (sizeof (struct user));
+}
+
+static int regmap[] =
+{PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7,
+ PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_R13, PT_R14, PT_R15,
+ PT_R16, PT_R17, PT_R18, PT_R19, PT_R20, PT_R21, PT_R22, PT_R23,
+ PT_R24, PT_R25, PT_R26, PT_R27, PT_R28, PT_R29, PT_R30, PT_R31,
+ PT_FPR0, PT_FPR0 + 2, PT_FPR0 + 4, PT_FPR0 + 6, PT_FPR0 + 8, PT_FPR0 + 10, PT_FPR0 + 12, PT_FPR0 + 14,
+ PT_FPR0 + 16, PT_FPR0 + 18, PT_FPR0 + 20, PT_FPR0 + 22, PT_FPR0 + 24, PT_FPR0 + 26, PT_FPR0 + 28, PT_FPR0 + 30,
+ PT_FPR0 + 32, PT_FPR0 + 34, PT_FPR0 + 36, PT_FPR0 + 38, PT_FPR0 + 40, PT_FPR0 + 42, PT_FPR0 + 44, PT_FPR0 + 46,
+ PT_FPR0 + 48, PT_FPR0 + 50, PT_FPR0 + 52, PT_FPR0 + 54, PT_FPR0 + 56, PT_FPR0 + 58, PT_FPR0 + 60, PT_FPR0 + 62,
+ PT_NIP, PT_MSR, PT_CCR, PT_LNK, PT_CTR, PT_XER, PT_MQ};
+
+int 
+ppc_register_u_addr (int ustart, int regnum)
+{
+  return (ustart + 4 * regmap[regnum]);
+}
+
+supply_gregset (gregset_t * gregsetp)
+{
+  int regi;
+  register greg_t *regp = (greg_t *) gregsetp;
+
+  for (regi = 0; regi < 32; regi++)
+    supply_register (regi, (char *) (regp + regi));
+
+  for (regi = FIRST_UISA_SP_REGNUM; regi <= LAST_UISA_SP_REGNUM; regi++)
+    supply_register (regi, (char *) (regp + regmap[regi]));
+}
+
+supply_fpregset (fpregset_t * fpregsetp)
+{
+  int regi;
+  for (regi = 0; regi < 32; regi++)
+    {
+      supply_register (FP0_REGNUM + regi, (char *) (*fpregsetp + regi));
+    }
+}
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
new file mode 100644 (file)
index 0000000..c9a6812
--- /dev/null
@@ -0,0 +1,599 @@
+/* Target-dependent code for GDB, the GNU debugger.
+   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+/* The following two instructions are used in the signal trampoline
+   code on linux/ppc */
+#define INSTR_LI_R0_0x7777     0x38007777
+#define INSTR_SC               0x44000002
+
+/* Since the *-tdep.c files are platform independent (i.e, they may be
+   used to build cross platform debuggers), we can't include system
+   headers.  Therefore, details concerning the sigcontext structure
+   must be painstakingly rerecorded.  What's worse, if these details
+   ever change in the header files, they'll have to be changed here
+   as well. */
+
+/* __SIGNAL_FRAMESIZE from <asm/ptrace.h> */
+#define PPC_LINUX_SIGNAL_FRAMESIZE 64
+
+/* From <asm/sigcontext.h>, offsetof(struct sigcontext_struct, regs) == 0x1c */
+#define PPC_LINUX_REGS_PTR_OFFSET (PPC_LINUX_SIGNAL_FRAMESIZE + 0x1c)
+
+/* From <asm/sigcontext.h>, 
+   offsetof(struct sigcontext_struct, handler) == 0x14 */
+#define PPC_LINUX_HANDLER_PTR_OFFSET (PPC_LINUX_SIGNAL_FRAMESIZE + 0x14)
+
+/* From <asm/ptrace.h>, values for PT_NIP, PT_R1, and PT_LNK */
+#define PPC_LINUX_PT_R0                0
+#define PPC_LINUX_PT_R1                1
+#define PPC_LINUX_PT_R2                2
+#define PPC_LINUX_PT_R3                3
+#define PPC_LINUX_PT_R4                4
+#define PPC_LINUX_PT_R5                5
+#define PPC_LINUX_PT_R6                6
+#define PPC_LINUX_PT_R7                7
+#define PPC_LINUX_PT_R8                8
+#define PPC_LINUX_PT_R9                9
+#define PPC_LINUX_PT_R10       10
+#define PPC_LINUX_PT_R11       11
+#define PPC_LINUX_PT_R12       12
+#define PPC_LINUX_PT_R13       13
+#define PPC_LINUX_PT_R14       14
+#define PPC_LINUX_PT_R15       15
+#define PPC_LINUX_PT_R16       16
+#define PPC_LINUX_PT_R17       17
+#define PPC_LINUX_PT_R18       18
+#define PPC_LINUX_PT_R19       19
+#define PPC_LINUX_PT_R20       20
+#define PPC_LINUX_PT_R21       21
+#define PPC_LINUX_PT_R22       22
+#define PPC_LINUX_PT_R23       23
+#define PPC_LINUX_PT_R24       24
+#define PPC_LINUX_PT_R25       25
+#define PPC_LINUX_PT_R26       26
+#define PPC_LINUX_PT_R27       27
+#define PPC_LINUX_PT_R28       28
+#define PPC_LINUX_PT_R29       29
+#define PPC_LINUX_PT_R30       30
+#define PPC_LINUX_PT_R31       31
+#define PPC_LINUX_PT_NIP       32
+#define PPC_LINUX_PT_MSR       33
+#define PPC_LINUX_PT_CTR       35
+#define PPC_LINUX_PT_LNK       36
+#define PPC_LINUX_PT_XER       37
+#define PPC_LINUX_PT_CCR       38
+#define PPC_LINUX_PT_MQ                39
+#define PPC_LINUX_PT_FPR0      48      /* each FP reg occupies 2 slots in this space */
+#define PPC_LINUX_PT_FPR31 (PPC_LINUX_PT_FPR0 + 2*31)
+#define PPC_LINUX_PT_FPSCR (PPC_LINUX_PT_FPR0 + 2*32 + 1)
+
+/* 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.
+
+   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
+   the (now exited) handler.  The code there will cause a temporary
+   breakpoint to be set on prev_pc which is not very likely to get hit
+   again.
+
+   If this is confusing, think of it this way...  the code in
+   wait_for_inferior() needs to be able to detect entry into a signal
+   trampoline just after a signal is delivered, not after the handler
+   has been run.
+
+   So, we define in_sigtramp() below to return 1 if the following is
+   true:
+
+   1) The previous frame is a real signal trampoline.
+
+   - and -
+
+   2) pc is at the first or second instruction of the corresponding
+   handler.
+
+   Why the second instruction?  It seems that wait_for_inferior()
+   never sees the first instruction when single stepping.  When a
+   signal is delivered while stepping, the next instruction that
+   would've been stepped over isn't, instead a signal is delivered and
+   the first instruction of the handler is stepped over instead.  That
+   puts us on the second instruction.  (I added the test for the
+   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
+   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().  */
+
+int
+ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+  CORE_ADDR lr;
+  CORE_ADDR sp;
+  CORE_ADDR tramp_sp;
+  char buf[4];
+  CORE_ADDR handler;
+
+  lr = read_register (LR_REGNUM);
+  if (!ppc_linux_at_sigtramp_return_path (lr))
+    return 0;
+
+  sp = read_register (SP_REGNUM);
+
+  if (target_read_memory (sp, buf, sizeof (buf)) != 0)
+    return 0;
+
+  tramp_sp = extract_unsigned_integer (buf, 4);
+
+  if (target_read_memory (tramp_sp + PPC_LINUX_HANDLER_PTR_OFFSET, buf,
+                         sizeof (buf)) != 0)
+    return 0;
+
+  handler = extract_unsigned_integer (buf, 4);
+
+  return (pc == handler || pc == handler + 4);
+}
+
+/*
+ * The signal handler trampoline is on the stack and consists of exactly
+ * two instructions.  The easiest and most accurate way of determining
+ * whether the pc is in one of these trampolines is by inspecting the
+ * instructions.  It'd be faster though if we could find a way to do this
+ * via some simple address comparisons.
+ */
+int
+ppc_linux_at_sigtramp_return_path (CORE_ADDR pc)
+{
+  char buf[12];
+  unsigned long pcinsn;
+  if (target_read_memory (pc - 4, buf, sizeof (buf)) != 0)
+    return 0;
+
+  /* extract the instruction at the pc */
+  pcinsn = extract_unsigned_integer (buf + 4, 4);
+
+  return (
+          (pcinsn == INSTR_LI_R0_0x7777
+           && extract_unsigned_integer (buf + 8, 4) == INSTR_SC)
+          ||
+          (pcinsn == INSTR_SC
+           && extract_unsigned_integer (buf, 4) == INSTR_LI_R0_0x7777));
+}
+
+CORE_ADDR
+ppc_linux_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;
+  long symidx;
+  char symname[1024];
+  struct minimal_symbol *msymbol;
+
+  /* Find the section pc is in; return if not in .plt */
+  sect = find_pc_section (pc);
+  if (!sect || strcmp (sect->the_bfd_section->name, ".plt") != 0)
+    return 0;
+
+  objfile = sect->objfile;
+
+  /* Pick up the instruction at pc.  It had better be of the
+     form
+     li r11, IDX
+
+     where IDX is an index into the plt_table.  */
+
+  if (target_read_memory (pc, buf, 4) != 0)
+    return 0;
+  insn = extract_unsigned_integer (buf, 4);
+
+  if ((insn & 0xffff0000) != 0x39600000 /* li r11, VAL */ )
+    return 0;
+
+  reloc_index = (insn << 16) >> 16;
+
+  /* Find the objfile that pc is in and obtain the information
+     necessary for finding the symbol name. */
+  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;
+    }
+
+  /* Make sure we have all the information we need. */
+  if (plt_start == 0 || num_slots == -1 || symtab == 0 || strtab == 0)
+    return 0;
+
+  /* Compute the value of the plt table */
+  plt_table = plt_start + 72 + 8 * num_slots;
+
+  /* Get address of the relocation entry (Elf32_Rela) */
+  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;
+
+  /* Now get the r_info field which is the relocation type and symbol
+     index. */
+  if (target_read_memory (reloc + 4, buf, 4) != 0)
+    return 0;
+  symidx = extract_unsigned_integer (buf, 4);
+
+  /* Shift out the relocation type leaving just the symbol index */
+  /* symidx = ELF32_R_SYM(symidx); */
+  symidx = symidx >> 8;
+
+  /* compute the address of the symbol */
+  sym = symtab + symidx * 4;
+
+  /* Fetch the string table index */
+  if (target_read_memory (sym, buf, 4) != 0)
+    return 0;
+  symidx = extract_unsigned_integer (buf, 4);
+
+  /* Fetch the string; we don't know how long it is.  Is it possible
+     that the following will fail because we're trying to fetch too
+     much? */
+  if (target_read_memory (strtab + symidx, symname, sizeof (symname)) != 0)
+    return 0;
+
+  /* This might not work right if we have multiple symbols with the
+     same name; the only way to really get it right is to perform
+     the same sort of lookup as the dynamic linker. */
+  msymbol = lookup_minimal_symbol_text (symname, NULL, NULL);
+  if (!msymbol)
+    return 0;
+
+  return SYMBOL_VALUE_ADDRESS (msymbol);
+}
+
+/* The rs6000 version of FRAME_SAVED_PC will almost work for us.  The
+   signal handler details are different, so we'll handle those here
+   and call the rs6000 version to do the rest. */
+unsigned long
+ppc_linux_frame_saved_pc (struct frame_info *fi)
+{
+  if (fi->signal_handler_caller)
+    {
+      CORE_ADDR regs_addr =
+      read_memory_integer (fi->frame + PPC_LINUX_REGS_PTR_OFFSET, 4);
+      /* return the NIP in the regs array */
+      return read_memory_integer (regs_addr + 4 * PPC_LINUX_PT_NIP, 4);
+    }
+
+  return rs6000_frame_saved_pc (fi);
+}
+
+void
+ppc_linux_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+{
+  rs6000_init_extra_frame_info (fromleaf, fi);
+
+  if (fi->next != 0)
+    {
+      /* We're called from get_prev_frame_info; check to see if
+         this is a signal frame by looking to see if the pc points
+         at trampoline code */
+      if (ppc_linux_at_sigtramp_return_path (fi->pc))
+       fi->signal_handler_caller = 1;
+      else
+       fi->signal_handler_caller = 0;
+    }
+}
+
+int
+ppc_linux_frameless_function_invocation (struct frame_info *fi)
+{
+  /* We'll find the wrong thing if we let 
+     rs6000_frameless_function_invocation () search for a signal trampoline */
+  if (ppc_linux_at_sigtramp_return_path (fi->pc))
+    return 0;
+  else
+    return rs6000_frameless_function_invocation (fi);
+}
+
+void
+ppc_linux_frame_init_saved_regs (struct frame_info *fi)
+{
+  if (fi->signal_handler_caller)
+    {
+      CORE_ADDR regs_addr;
+      int i;
+      if (fi->saved_regs)
+       return;
+
+      frame_saved_regs_zalloc (fi);
+
+      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[PS_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_MSR;
+      fi->saved_regs[CR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_CCR;
+      fi->saved_regs[LR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_LNK;
+      fi->saved_regs[CTR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_CTR;
+      fi->saved_regs[XER_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_XER;
+      fi->saved_regs[MQ_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_MQ;
+      for (i = 0; i < 32; i++)
+       fi->saved_regs[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;
+    }
+  else
+    rs6000_frame_init_saved_regs (fi);
+}
+
+CORE_ADDR
+ppc_linux_frame_chain (struct frame_info *thisframe)
+{
+  /* Kernel properly constructs the frame chain for the handler */
+  if (thisframe->signal_handler_caller)
+    return read_memory_integer ((thisframe)->frame, 4);
+  else
+    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 (nargs, args, sp, struct_return, struct_addr)
+     int nargs;
+     value_ptr *args;
+     CORE_ADDR sp;
+     int struct_return;
+     CORE_ADDR struct_addr;
+{
+  int argno;
+  int greg, freg;
+  int argstkspace;
+  int structstkspace;
+  int argoffset;
+  int structoffset;
+  value_ptr 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;
+  /* 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 (&registers[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 (&registers[REGISTER_BYTE (greg)],
+                     VALUE_CONTENTS (arg), 4);
+             memcpy (&registers[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 *) &registers[REGISTER_BYTE (greg)] = 0;
+             memcpy (&registers[REGISTER_BYTE (greg)], val_buf, 4);
+             greg++;
+           }
+         else
+           {
+             write_memory (sp + argoffset, val_buf, 4);
+             argoffset += 4;
+           }
+       }
+    }
+
+  target_store_registers (-1);
+  return sp;
+}
index 5b6dcad08481b8229a1f95cc1717a2d2abffd049..29ca4ca6b9444d385ec9b2940e1258df635a78b6 100644 (file)
@@ -1,5 +1,5 @@
 /* Target-dependent code for GDB, the GNU debugger.
-   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -1238,8 +1238,7 @@ skip_trampoline_code (pc)
 /* Determines whether the function FI has a frame on the stack or not.  */
 
 int
-frameless_function_invocation (fi)
-     struct frame_info *fi;
+rs6000_frameless_function_invocation (struct frame_info *fi)
 {
   CORE_ADDR func_start;
   struct rs6000_framedata fdata;
@@ -1273,8 +1272,7 @@ frameless_function_invocation (fi)
 /* Return the PC saved in a frame */
 
 unsigned long
-frame_saved_pc (fi)
-     struct frame_info *fi;
+rs6000_frame_saved_pc (struct frame_info *fi)
 {
   CORE_ADDR func_start;
   struct rs6000_framedata fdata;
@@ -1302,14 +1300,13 @@ frame_saved_pc (fi)
       if (fi->next->signal_handler_caller)
        return read_memory_integer (fi->next->frame + SIG_FRAME_LR_OFFSET, 4);
       else
-       return read_memory_integer (rs6000_frame_chain (fi) + DEFAULT_LR_SAVE,
-                                   4);
+       return read_memory_integer (FRAME_CHAIN (fi) + DEFAULT_LR_SAVE, 4);
     }
 
   if (fdata.lr_offset == 0)
     return read_register (LR_REGNUM);
 
-  return read_memory_integer (rs6000_frame_chain (fi) + fdata.lr_offset, 4);
+  return read_memory_integer (FRAME_CHAIN (fi) + fdata.lr_offset, 4);
 }
 
 /* If saved registers of frame FI are not known yet, read and cache them.
@@ -1480,7 +1477,7 @@ rs6000_frame_chain (thisframe)
     fp = read_memory_integer (thisframe->frame + SIG_FRAME_FP_OFFSET, 4);
   else if (thisframe->next != NULL
           && thisframe->next->signal_handler_caller
-          && frameless_function_invocation (thisframe))
+          && FRAMELESS_FUNCTION_INVOCATION (thisframe))
     /* A frameless function interrupted by a signal did not change the
        frame pointer.  */
     fp = FRAME_FP (thisframe);