This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [PATCH] new support for PPC64 architecture
- From: Andrew Cagney <ac131313 at redhat dot com>
- To: Will Schmidt <willschm at us dot ibm dot com>,Elena Zannoni <ezannoni at redhat dot com>
- Cc: gdb-patches at sources dot redhat dot com, will_schmidt at vnet dot ibm dot com
- Date: Wed, 07 May 2003 16:14:16 -0400
- Subject: Re: [PATCH] new support for PPC64 architecture
- References: <OF55D5107F.A2571F44-ON86256D0B.007B01F9-86256D0B.007CEFB6@rchland.ibm.com>
For the record. The software letter for this patch has been completed.
This making it possible for GDB developers to examine the actual changes.
From a quick exmination:
- the patch is against a very old code base [20021129], the actual
changes will most likely no longer be applicable. GDB's frame, register
and inferior-function-call code have, for instance, all been overhauled
- changes such as:
+void
+_initialize_ppc64_linux_tdep (void)
+{
+ /* hardware/kernel supports single stepping */
+ set_gdbarch_software_single_step (current_gdbarch, NULL);
+}
and:
+#if defined (SOLIB_BREAK_NAME)
+#ifdef DROP_TEXT_NAME_PREFIX_CHAR
+#ifdef SKIP_DATA_IN_OPD
+#undef SKIP_TRAMPOLINE_CODE
+#ifdef DEAD_CODE
are simply wrong wrong. With one exception related to shared libraries,
GDB only accepts strict multi-arch targets.
Someone has a lot of work ahead of them, sigh.
Andrew
diff -rupPN gdb-5.2.1/gdb/config/powerpc/ppc64linux.mh src.ppc64/gdb/config/powerpc/ppc64linux.mh
--- gdb-5.2.1/gdb/config/powerpc/ppc64linux.mh 1969-12-31 18:00:00.000000000 -0600
+++ src.ppc64/gdb/config/powerpc/ppc64linux.mh 2003-03-05 13:00:33.000000000 -0600
@@ -0,0 +1,14 @@
+# Host: PowerPC, running Linux
+
+XM_FILE= xm-linux.h
+XM_CLIBS=
+
+NAT_FILE= nm-linux.h
+NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o linux-proc.o \
+ core-regset.o ppc-linux-nat.o proc-service.o thread-db.o lin-lwp.o \
+ gcore.o ppc-sysv-tdep.o
+
+LOADLIBES = -ldl -lthread_db
+
+GDBSERVER_DEPFILES= low-linux.o
+GDBSERVER_LIBS= -lnss_dns -lnss_files -lresolv
diff -rupPN gdb-5.2.1/gdb/config/powerpc/ppc64linux.mt src.ppc64/gdb/config/powerpc/ppc64linux.mt
--- gdb-5.2.1/gdb/config/powerpc/ppc64linux.mt 1969-12-31 18:00:00.000000000 -0600
+++ src.ppc64/gdb/config/powerpc/ppc64linux.mt 2003-03-05 16:32:12.000000000 -0600
@@ -0,0 +1,4 @@
+# Target: PPC running Linux 64bit programs
+TDEPFILES= rs6000-tdep.o ppc-linux-tdep.o ppc64-linux-tdep.o solib.o solib-svr4.o solib-legacy.o
+TM_FILE= tm-ppc64linux.h
+
diff -rupPN gdb-5.2.1/gdb/solib-svr4.c src.ppc64/gdb/solib-svr4.c
--- gdb-5.2.1/gdb/solib-svr4.c 2002-02-05 17:28:13.000000000 -0600
+++ src.ppc64/gdb/solib-svr4.c 2003-01-28 13:28:24.000000000 -0600
@@ -75,6 +75,9 @@ struct lm_info
static char *solib_break_names[] =
{
+#if defined (SOLIB_BREAK_NAME)
+ SOLIB_BREAK_NAME,
+#endif
"r_debug_state",
"_r_debug_state",
"_dl_debug_state",
@@ -998,7 +1001,7 @@ enable_break (void)
the current pc (which should point at the entry point for the
dynamic linker) and subtracting the offset of the entry point. */
if (!load_addr_found)
- load_addr = read_pc () - tmp_bfd->start_address;
+ load_addr = read_pc () - CONVERT_FROM_FUNC_PTR_ADDR(tmp_bfd->start_address);
/* Record the relocated start and end address of the dynamic linker
text and plt section for svr4_in_dynsym_resolve_code. */
diff -rupPN gdb-5.2.1/gdb/config/powerpc/tm-linux.h src.ppc64/gdb/config/powerpc/tm-linux.h
--- gdb-5.2.1/gdb/config/powerpc/tm-linux.h 2002-02-24 16:56:06.000000000 -0600
+++ src.ppc64/gdb/config/powerpc/tm-linux.h 2003-01-28 13:28:24.000000000 -0600
@@ -67,4 +67,9 @@ extern int ppc_linux_in_sigtramp (CORE_A
to be relocated. */
#define SOFUN_ADDRESS_MAYBE_MISSING
+/* used for ppc64 only, but added here because code is common between ppc and ppc64 */
+struct link_map_offsets *ppc64_linux_svr4_fetch_link_map_offsets (void);
+extern CORE_ADDR ppc64_linux_convert_from_func_ptr_addr (CORE_ADDR addr);
+
+
#endif /* #ifndef TM_LINUX_H */
diff -rupPN gdb-5.2.1/gdb/config/powerpc/tm-ppc64linux.h src.ppc64/gdb/config/powerpc/tm-ppc64linux.h
--- gdb-5.2.1/gdb/config/powerpc/tm-ppc64linux.h 1969-12-31 18:00:00.000000000 -0600
+++ src.ppc64/gdb/config/powerpc/tm-ppc64linux.h 2003-01-28 13:28:24.000000000 -0600
@@ -0,0 +1,80 @@
+#ifndef TM_PPC64LINUX_H
+#define TM_PPC64LINUX_H
+
+#include "rs6000/tm-rs6000.h"
+
+/* Avoid warning from redefinition in tm-sysv4.h (included from tm-linux.h) */
+#undef SKIP_TRAMPOLINE_CODE
+#include "tm-linux.h"
+
+#include "gdbarch.h"
+/* Reset these back to the default. Should really fix this for other
+ powerpc tm.h so it can be chosen at runtime */
+#undef SOFTWARE_SINGLE_STEP_P
+#define SOFTWARE_SINGLE_STEP_P() (gdbarch_software_single_step_p (current_gdbarch))
+#undef SOFTWARE_SINGLE_STEP
+#define SOFTWARE_SINGLE_STEP(sig, insert_breakpoints_p) (gdbarch_software_single_step (current_gdbarch, sig, insert_breakpoints_p))
+
+#ifdef DEAD_CODE
+/* FIXME: tm-linux defines this which a dead interface, as far as I
+ can tell. The macro is unused and there is no definition for the
+ function the macro calls. It is here so we know to get rid of it
+ there. */
+/* 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();
+#endif /* DEAD_CODE */
+
+/* We _want_ the SVR4 section offset calculations (see syms_from_objfile()
+ in symfile.c) */
+#undef IBM6000_TARGET
+
+/* Default offset from SP where the LR is stored */
+#undef DEFAULT_LR_SAVE
+#define DEFAULT_LR_SAVE 16
+
+/* Say that we're using ELF, not XCOFF. */
+#define ELF_OBJECT_FORMAT 1
+
+/* Say that we're using ELF64 since ABI is closer to XCOFF64. */
+#define ELF64_OBJECT_FORMAT 1
+
+#undef PROCESS_LINENUMBER_HOOK
+
+#undef TEXT_SEGMENT_BASE
+#define TEXT_SEGMENT_BASE 1
+
+/* don't think it is but it can't hurt (can it?) */
+#define TARGET_BYTE_ORDER_SELECTABLE_P 1
+
+/* The value of symbols of type N_SO and N_FUN maybe null when
+ it shouldn't be. */
+#define SOFUN_ADDRESS_MAYBE_MISSING
+
+#undef CHILD_SPECIAL_WAITSTATUS
+
+/* Use generic shared library machinery. */
+#include "solib.h"
+
+/* function entrypoints have a '.' prepended to them (elfread.c) */
+#define DROP_TEXT_NAME_PREFIX_CHAR '.'
+/* skip data symbols if they are from the .opd section (elfread.c) */
+#define SKIP_DATA_IN_OPD
+
+/* define our own child_xfer_memory() ppc-linux-nat.c */
+#define CHILD_XFER_MEMORY
+
+#undef bfd_get_start_address
+#define bfd_get_start_address(abfd) ppc64_bfd_get_start_address (abfd)
+extern CORE_ADDR ppc64_bfd_get_start_address (bfd *);
+struct link_map_offsets *ppc64_linux_svr4_fetch_link_map_offsets (void);
+extern CORE_ADDR ppc64_linux_convert_from_func_ptr_addr (CORE_ADDR addr);
+
+/* define additional name for solib functions (solib-svr4.c) to hinge on. */
+#define SOLIB_BREAK_NAME "._dl_debug_state"
+
+
+#endif /* #ifndef TM_PPC64LINUX_H */
diff -rupPN gdb-5.2.1/gdb/configure.host src.ppc64/gdb/configure.host
--- gdb-5.2.1/gdb/configure.host 2002-03-01 12:35:23.000000000 -0600
+++ src.ppc64/gdb/configure.host 2003-01-28 13:28:24.000000000 -0600
@@ -136,6 +136,8 @@ powerpc-*-aix*) gdb_host=aix ;;
powerpc-*-linux*) gdb_host=linux ;;
powerpc-*-netbsd*) gdb_host=nbsd ;;
+powerpc64-*-linux*) gdb_host=ppc64linux ;;
+
rs6000-*-lynxos*) gdb_host=rs6000lynx ;;
rs6000-*-aix4*) gdb_host=aix4 ;;
rs6000-*-*) gdb_host=rs6000 ;;
diff -rupPN gdb-5.2.1/gdb/configure.tgt src.ppc64/gdb/configure.tgt
--- gdb-5.2.1/gdb/configure.tgt 2002-05-28 21:36:55.000000000 -0500
+++ src.ppc64/gdb/configure.tgt 2003-01-28 13:28:24.000000000 -0600
@@ -222,6 +222,15 @@ powerpcle-*-eabi* | powerpcle-*-sysv* |
powerpc-*-linux*) gdb_target=linux
build_gdbserver=yes
;;
+powerpc64-*-linux*) gdb_target=ppc64linux
+ ###HACK -JX
+ case "${host}" in
+ powerpc-*-linux*)
+ ## This host can treat target as native
+ nativefile=nm-linux.h
+ ;;
+ esac
+ ;;
powerpc-*-vxworks*) gdb_target=vxworks ;;
powerpc*-*-*) if test -f ../sim/ppc/Makefile; then
gdb_target=ppc-sim
diff -rupPN gdb-5.2.1/gdb/elfread.c src.ppc64/gdb/elfread.c
--- gdb-5.2.1/gdb/elfread.c 2002-03-25 10:50:20.000000000 -0600
+++ src.ppc64/gdb/elfread.c 2003-01-28 13:28:24.000000000 -0600
@@ -154,6 +154,12 @@ record_minimal_symbol_and_info (char *na
if (ms_type == mst_text || ms_type == mst_file_text)
address = SMASH_TEXT_ADDRESS (address);
+#ifdef DROP_TEXT_NAME_PREFIX_CHAR
+ if ((ms_type == mst_text || ms_type == mst_file_text)
+ && name[0] == DROP_TEXT_NAME_PREFIX_CHAR)
+ ++name;
+#endif /* DROP_TEXT_NAME_PREFIX_CHAR */
+
return prim_record_minimal_symbol_and_info
(name, address, ms_type, info, bfd_section->index, bfd_section, objfile);
}
@@ -376,6 +382,10 @@ elf_symtab_read (struct objfile *objfile
{
if (sym->section->flags & SEC_LOAD)
{
+#ifdef SKIP_DATA_IN_OPD
+ if (strcmp(sym->section->name, ".opd") == 0)
+ continue;
+#endif /* SKIP_DATA_IN_OPD */
ms_type = mst_data;
}
else
@@ -455,6 +465,10 @@ elf_symtab_read (struct objfile *objfile
symbol processing. */
if (sym->section->flags & SEC_LOAD)
{
+#ifdef SKIP_DATA_IN_OPD
+ if (strcmp(sym->section->name, ".opd") == 0)
+ continue;
+#endif /* SKIP_DATA_IN_OPD */
ms_type = mst_file_data;
}
else
diff -rupPN gdb-5.2.1/gdb/ppc-linux-nat.c src.ppc64/gdb/ppc-linux-nat.c
--- gdb-5.2.1/gdb/ppc-linux-nat.c 2002-02-21 16:04:46.000000000 -0600
+++ src.ppc64/gdb/ppc-linux-nat.c 2003-01-28 13:28:24.000000000 -0600
@@ -47,11 +47,108 @@
#define PT_WRITE_U PTRACE_POKEUSR
#endif
-/* Default the type of the ptrace transfer to int. */
+/* Default the type of the ptrace transfer to long. */
#ifndef PTRACE_XFER_TYPE
-#define PTRACE_XFER_TYPE int
+#define PTRACE_XFER_TYPE long
#endif
+/* Write DATA into location ADDR within the "user area" on a 64-bit
+ process from a 32-bit process. */
+#ifndef PPC_PTRACE_POKEUSR_3264
+#define PPC_PTRACE_POKEUSR_3264 0x90
+#endif
+
+/* Read a register (specified by ADDR) out of the "user area" on a
+ 64-bit process from a 32-bit process. */
+#ifndef PPC_PTRACE_PEEKUSR_3264
+#define PPC_PTRACE_PEEKUSR_3264 0x91
+#endif
+
+/* Write word at location ADDR on a 64-bit process from a 32-bit process. */
+#ifndef PPC_PTRACE_POKEDATA_3264
+#define PPC_PTRACE_POKEDATA_3264 0x92
+#endif
+
+/* Read word at location ADDR on a 64-bit process from a 32-bit
+ process. */
+#ifndef PPC_PTRACE_PEEKDATA_3264
+#define PPC_PTRACE_PEEKDATA_3264 0x94
+#endif
+
+#define ARCH64() (REGISTER_RAW_SIZE (0) == 8)
+
+/* REALLY SHAMELESS HACK:
+
+ 32 bit programs can exec 64 bit programs and so forth. GDB launches
+ the inferior process by lauching ${SHELL} -c <program and args>.
+ Fortunately, we know that it only tries to get the PC so we only
+ have to hack that.. I THINK.
+
+ At this time we are not ready to unify ppc32 and ppc64 as
+ rs/6000-aix is. and there is know easy way to find out if a process
+ is running 32 or 64 bits so we have this little hack.
+
+ EVEN MORE SHAMELESS HACK: rs6000-nat.c solves this problem by
+ expecting the first few ptracex() calls to fail.
+
+*/
+#include <sys/stat.h>
+#include "bfd/elf-bfd.h"
+static int
+ppc_wordsize_pid(pid_t pid)
+{
+ static ino_t fino = 0;
+ static int last = 0;
+ struct stat sb;
+ const char fmt[] = "/proc/%u/exe";
+ FILE *file;
+ char *fname = alloca (sizeof(fmt) + 10); /* 10 digit pid.. why not */
+ Elf_Internal_Ehdr elfh;
+
+ if ((gdbarch_tdep (current_gdbarch))->wordsize == 4)
+ return 4;
+
+ sprintf (fname, fmt, pid);
+
+ if (stat(fname, &sb) == -1)
+ {
+ internal_error (__FILE__, __LINE__,
+ "could not stat executable from /proc.");
+ return 0;
+ }
+
+ if (fino == sb.st_ino)
+ return last;
+
+ fino = sb.st_ino;
+
+ /* FIXME: could stat the file and check if inode changed. */
+ file = fopen (fname, "rb");
+ if (file == NULL)
+ {
+ internal_error (__FILE__, __LINE__,
+ "could not open executable from /proc.");
+ return 0;
+ }
+
+ if (fread (elfh.e_ident, EI_NIDENT, 1, file) == 1)
+ {
+ if (elfh.e_ident [EI_CLASS] == ELFCLASS64)
+ last = 8;
+ else
+ last = 4;
+ }
+ else
+ {
+ last = 0;
+ internal_error (__FILE__, __LINE__,
+ "could not read executable from /proc.");
+ }
+ fclose (file);
+
+ return last;
+}
+
/* Glibc's headers don't define PTRACE_GETVRREGS so we cannot use a
configure time check. Some older glibc's (for instance 2.2.1)
don't have a specific powerpc version of ptrace.h, and fall back on
@@ -105,7 +202,15 @@ int have_ptrace_getvrregs = 1;
int
kernel_u_size (void)
{
- return (sizeof (struct user));
+ if ((gdbarch_tdep (current_gdbarch))->wordsize == sizeof (PTRACE_XFER_TYPE))
+ return (sizeof (struct user));
+ else
+ {
+ /* with a 64-bit kernel, all members of struct user go from 32
+ to 64 bit except for the u_comm character array so we can
+ double everything and subtract sizeof u_comm. */
+ return ((sizeof (struct user) * 2) - sizeof (((struct user*)0)->u_comm));
+ }
}
/* *INDENT-OFF* */
@@ -125,33 +125,34 @@
ppc_register_u_addr (int regno)
{
int u_addr = -1;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ int wordsize = tdep->wordsize;
/* General purpose registers occupy 1 slot each in the buffer */
if (regno >= tdep->ppc_gp0_regnum && regno <= tdep->ppc_gplast_regnum )
- u_addr = ((PT_R0 + regno) * 4);
+ u_addr = ((PT_R0 + regno) * wordsize);
/* Floating point regs: 2 slots each */
if (regno >= FP0_REGNUM && regno <= FPLAST_REGNUM)
- u_addr = ((PT_FPR0 + (regno - FP0_REGNUM) * 2) * 4);
+ u_addr = ((PT_FPR0 + (regno - FP0_REGNUM) * 2) * wordsize);
/* UISA special purpose registers: 1 slot each */
if (regno == PC_REGNUM)
- u_addr = PT_NIP * 4;
+ u_addr = PT_NIP * wordsize;
if (regno == tdep->ppc_lr_regnum)
- u_addr = PT_LNK * 4;
+ u_addr = PT_LNK * wordsize;
if (regno == tdep->ppc_cr_regnum)
- u_addr = PT_CCR * 4;
+ u_addr = PT_CCR * wordsize;
if (regno == tdep->ppc_xer_regnum)
- u_addr = PT_XER * 4;
+ u_addr = PT_XER * wordsize;
if (regno == tdep->ppc_ctr_regnum)
- u_addr = PT_CTR * 4;
+ u_addr = PT_CTR * wordsize;
if (regno == tdep->ppc_mq_regnum)
- u_addr = PT_MQ * 4;
+ u_addr = PT_MQ * wordsize;
if (regno == tdep->ppc_ps_regnum)
- u_addr = PT_MSR * 4;
+ u_addr = PT_MSR * wordsize;
if (regno == tdep->ppc_fpscr_regnum)
- u_addr = PT_FPSCR * 4;
+ u_addr = PT_FPSCR * wordsize;
return u_addr;
}
@@ -205,6 +322,16 @@ fetch_register (int tid, int regno)
unsigned int offset; /* Offset of registers within the u area. */
char *buf = alloca (MAX_REGISTER_RAW_SIZE);
CORE_ADDR regaddr = ppc_register_u_addr (regno);
+ int wordsize = (gdbarch_tdep (current_gdbarch))->wordsize;
+
+ /* Do the easy thing for now which is to silently succeed if we are
+ attached to a 32-bit process when we are expecting 64-bits */
+ if (wordsize != ppc_wordsize_pid(tid))
+ {
+ /* supplying garbage.. but that's ok */
+ supply_register (regno, buf);
+ return;
+ }
if (altivec_register_p (regno))
{
@@ -232,8 +359,19 @@ fetch_register (int tid, int regno)
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
{
errno = 0;
- *(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid,
- (PTRACE_ARG3_TYPE) regaddr, 0);
+ if (wordsize != sizeof (PTRACE_XFER_TYPE))
+ {
+ PTRACE_XFER_TYPE reg;
+ ptrace (PPC_PTRACE_PEEKUSR_3264, tid,
+ (PTRACE_ARG3_TYPE) regaddr, ®);
+ *(PTRACE_XFER_TYPE *) & buf[i] = reg;
+ }
+ else
+ {
+ *(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid,
+ (PTRACE_ARG3_TYPE) regaddr, 0);
+ }
+
regaddr += sizeof (PTRACE_XFER_TYPE);
if (errno != 0)
{
@@ -364,6 +452,7 @@ store_register (int tid, int regno)
register int i;
unsigned int offset; /* Offset of registers within the u area. */
char *buf = alloca (MAX_REGISTER_RAW_SIZE);
+ int wordsize = (gdbarch_tdep (current_gdbarch))->wordsize;
if (altivec_register_p (regno))
{
@@ -378,8 +517,18 @@ store_register (int tid, int regno)
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
{
errno = 0;
- ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr,
- *(PTRACE_XFER_TYPE *) & buf[i]);
+ if (wordsize != sizeof (PTRACE_XFER_TYPE))
+ {
+ PTRACE_XFER_TYPE reg;
+ ptrace (PPC_PTRACE_POKEUSR_3264, tid, (PTRACE_ARG3_TYPE) regaddr,
+ *(PTRACE_XFER_TYPE *) & buf[i]);
+ }
+ else
+ {
+ ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr,
+ *(PTRACE_XFER_TYPE *) & buf[i]);
+ }
+
regaddr += sizeof (PTRACE_XFER_TYPE);
if (errno == EIO
@@ -533,3 +682,243 @@ fill_fpregset (gdb_fpregset_t *fpregsetp
if ((regno == -1) || regno == tdep->ppc_fpscr_regnum)
regcache_collect (tdep->ppc_fpscr_regnum, (char *) (*fpregsetp + regi));
}
+
+
+#ifdef CHILD_XFER_MEMORY
+
+/* this is a complete rip off from infptrace.c */
+
+#ifndef GDB_MAX_ALLOCA
+#define GDB_MAX_ALLOCA 0x1000
+#endif /* GDB_MAX_ALLOCA */
+
+/* Copy LEN bytes to or from inferior's memory starting at MEMADDR to
+ debugger memory starting at MYADDR. Copy to inferior if WRITE is
+ nonzero. TARGET is ignored.
+
+ Returns the length copied, which is either the LEN argument or
+ zero. This xfer function does not do partial moves, since
+ child_ops doesn't allow memory operations to cross below us in the
+ target stack anyway. */
+
+int
+child_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int i;
+ /* Round starting address down to longword boundary. */
+ CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
+ /* Round ending address up; get number of longwords that makes. */
+ int count = ((((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
+ / sizeof (PTRACE_XFER_TYPE));
+ int alloc = count * sizeof (PTRACE_XFER_TYPE);
+ PTRACE_XFER_TYPE *buffer;
+ struct cleanup *old_chain = NULL;
+ int wordsize = (gdbarch_tdep (current_gdbarch))->wordsize;
+ int arch64 = ARCH64();
+
+ /* Allocate buffer of that many longwords. */
+ if (len < GDB_MAX_ALLOCA)
+ {
+ buffer = (PTRACE_XFER_TYPE *) alloca (alloc);
+ }
+ else
+ {
+ buffer = (PTRACE_XFER_TYPE *) xmalloc (alloc);
+ old_chain = make_cleanup (xfree, buffer);
+ }
+
+ /* WARNING: from kernel source: "when I and D space are separate,
+ these will need to be fixed." */
+ if (write)
+ {
+ /* Fill start and end extra bytes of buffer with existing memory
+ data. */
+ if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE))
+ {
+ /* Need part of initial word -- fetch it. */
+ if (wordsize == sizeof (PTRACE_XFER_TYPE) && (!arch64))
+ {
+ buffer[0] = ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) addr, 0);
+ }
+ else
+ {
+ if (arch64) {
+ buffer[0] = ptrace (PTRACE_PEEKDATA, PIDGET (inferior_ptid),
+ (unsigned long) addr, 0);
+ }
+ else
+ {
+ ptrace (PPC_PTRACE_PEEKDATA_3264, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &addr, buffer);
+ }
+ }
+ }
+ if (count > 1) /* FIXME, avoid if even boundary. */
+ {
+ CORE_ADDR a64 = (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE));
+ if (wordsize == sizeof (PTRACE_XFER_TYPE) && (!arch64))
+ {
+ buffer[count - 1] = ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) a64, 0);
+ }
+ else
+ if (arch64) {
+ buffer[count-1] = ptrace (PTRACE_PEEKDATA, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &a64, 0);
+ }
+ else
+ {
+ ptrace (PPC_PTRACE_PEEKDATA_3264, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &a64, &buffer[count - 1]);
+ }
+ }
+
+ /* Copy data to be written over corresponding part of buffer. */
+ memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
+ myaddr, len);
+
+ /* Write the entire buffer. */
+ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ if (wordsize == sizeof (PTRACE_XFER_TYPE) && (!arch64))
+ {
+ ptrace (PT_WRITE_D, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) addr, buffer[i]);
+ }
+ else
+ if (arch64) {
+ ptrace (PT_WRITE_D, PIDGET (inferior_ptid),
+ (unsigned long) addr, buffer[i]);
+ }
+ else
+ {
+ ptrace (PPC_PTRACE_POKEDATA_3264, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &addr, buffer[i]);
+ }
+ if (errno)
+ {
+ errno = 0;
+ if (wordsize == sizeof (PTRACE_XFER_TYPE) && (!arch64))
+ {
+ ptrace (PT_WRITE_I, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) addr, buffer[i]);
+ }
+ else
+ if (arch64) {
+ ptrace (PTRACE_POKEDATA, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) addr, buffer[i]);
+ }
+ else
+ {
+ ptrace (PPC_PTRACE_POKEDATA_3264, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &addr, buffer[i]);
+ }
+ }
+ if (errno)
+ return 0;
+ }
+#ifdef CLEAR_INSN_CACHE
+ CLEAR_INSN_CACHE ();
+#endif
+ }
+ else
+ {
+ /* Read all the longwords. */
+ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+ {
+ errno = 0;
+ if (wordsize == sizeof (PTRACE_XFER_TYPE) && (!arch64))
+ {
+ buffer[i] = ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) addr, 0);
+ }
+ else
+ {
+ if (arch64) {
+ buffer[i] = ptrace (PTRACE_PEEKDATA, PIDGET (inferior_ptid),
+ (unsigned long) addr, 0);
+ }
+ else
+ {
+ ptrace (PPC_PTRACE_PEEKDATA_3264, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) &addr, &buffer[i]);
+ }
+ if (errno)
+ return 0;
+ QUIT;
+ }
+
+ /* Copy appropriate bytes out of the buffer. */
+ memcpy (myaddr,
+ (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
+ len);
+ }
+ }
+ if (old_chain != NULL)
+ do_cleanups (old_chain);
+ return len;
+ }
+
+
+/* Did not want to add this originally since the kernel will give us a
+ lot of gargabe (and would probably fail if it wasn't for the
+ FPU's). But at least you can get the other registers in struct
+ pt_regs. Perhaps we can get the kernels to co-operate. */
+static void
+udot_info (char *dummy1, int dummy2)
+{
+ int udot_off; /* Offset into user struct */
+ int udot_val; /* Value from user struct at udot_off */
+ char mess[128]; /* For messages */
+ int wordsize = (gdbarch_tdep (current_gdbarch))->wordsize;
+
+ if (!target_has_execution)
+ {
+ error ("The program is not being run.");
+ }
+
+ for (udot_off = 0; udot_off < KERNEL_U_SIZE; udot_off += sizeof (udot_val))
+ {
+ if ((udot_off % 24) == 0)
+ {
+ if (udot_off > 0)
+ {
+ printf_filtered ("\n");
+ }
+ printf_filtered ("%04x:", udot_off);
+ }
+ if (wordsize != sizeof (PTRACE_XFER_TYPE))
+ {
+ PTRACE_XFER_TYPE reg;
+ /* ptrace will place contents in "data" pointer */
+ ptrace (PPC_PTRACE_PEEKUSR_3264, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) udot_off, ®);
+ udot_val = reg;
+ }
+ else
+ udot_val = ptrace (PT_READ_U, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) udot_off, 0);
+ if (errno != 0)
+ {
+ sprintf (mess, "\nreading user struct at offset 0x%x", udot_off);
+ perror_with_name (mess);
+ }
+ /* Avoid using nonportable (?) "*" in print specs */
+ printf_filtered (sizeof (int) == 4 ? " 0x%08x" : " 0x%16x", udot_val);
+ }
+ printf_filtered ("\n");
+}
+#endif /* CHILD_XFER_MEMORY */
+
+#include "command.h"
+void
+_initialize_ppc_linux_nat (void)
+{
+#ifdef CHILD_XFER_MEMORY
+ add_info ("udot", udot_info,
+ "Print contents of kernel ``struct user'' for current child.");
+#endif
+}
diff -rupPN gdb-5.2.1/gdb/ppc-linux-tdep.c src.ppc64/gdb/ppc-linux-tdep.c
--- gdb-5.2.1/gdb/ppc-linux-tdep.c 2002-02-24 16:31:19.000000000 -0600
+++ src.ppc64/gdb/ppc-linux-tdep.c 2003-01-28 13:28:24.000000000 -0600
@@ -57,6 +57,8 @@
offsetof(struct sigcontext_struct, handler) == 0x14 */
#define PPC_LINUX_HANDLER_PTR_OFFSET (PPC_LINUX_SIGNAL_FRAMESIZE + 0x14)
+#define TDEP gdbarch_tdep (current_gdbarch)
+
/* 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
@@ -730,3 +732,64 @@ _initialize_ppc_linux_tdep (void)
ppc_linux_init_abi);
add_core_fns (&ppc_linux_regset_core_fns);
}
+
+struct link_map_offsets *
+ ppc64_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 = 16;/* The actual size is xx bytes, but
+ this is all we need. */
+ lmo.r_map_offset = 8;
+ lmo.r_map_size = 8;
+ lmo.link_map_size = 40; /* The actual size is xxx bytes, but
+ this is all we need. */
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 8;
+ lmo.l_name_offset = 8;
+ lmo.l_name_size = 8;
+ lmo.l_next_offset = 24;
+ lmo.l_next_size = 8;
+ lmo.l_prev_offset = 32;
+ lmo.l_prev_size = 8;
+ }
+
+ return lmp;
+}
+
+
+/* Support for CONVERT_FROM_FUNC_PTR_ADDR(ADDR).
+ Duplicate of RS6000 function, except ppc64_linux requires relocated address. */
+static CORE_ADDR
+read_memory_addr (CORE_ADDR memaddr, int len)
+{
+ return read_memory_unsigned_integer (memaddr, len);
+}
+
+
+CORE_ADDR
+ppc64_linux_convert_from_func_ptr_addr (CORE_ADDR addr)
+{
+ long long my_adder;
+ struct obj_section *s;
+ CORE_ADDR retval;
+ extern struct obj_section *find_pc_section(CORE_ADDR);
+
+ /* this should be the base address that the object (containing the func_ptr_addr) is loaded at. */
+ my_adder = 0x7fe0000000;
+
+ s = find_pc_section (my_adder + addr);
+ if (s && s->the_bfd_section->flags & SEC_CODE)
+ return addr;
+
+ /* ADDR is in the data space, so it's a special function pointer. */
+ retval = read_memory_addr (my_adder + addr, TDEP->wordsize);
+ /* printf("reading 0x%lx ",my_adder+addr); */
+ /* printf("ppc64...convert_func_ptr addr:0x%lx new:0x%lx\n",addr,retval); */
+ return retval;
+}
diff -rupPN gdb-5.2.1/gdb/ppc64-linux-tdep.c src.ppc64/gdb/ppc64-linux-tdep.c
--- gdb-5.2.1/gdb/ppc64-linux-tdep.c 1969-12-31 18:00:00.000000000 -0600
+++ src.ppc64/gdb/ppc64-linux-tdep.c 2003-01-28 13:28:24.000000000 -0600
@@ -0,0 +1,80 @@
+/* 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.
+
+ 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"
+
+
+/* These elfcore fuctions are defined in libbfd.a but only when host
+ == target, once we can convince the bfd to supply it these can go */
+#define _SYSCALL32
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#define ARCH_SIZE 0
+#include "elf-bfd.h"
+#include "libiberty.h"
+#include <sys/procfs.h>
+
+
+/*
+ * Initialization
+ */
+void
+_initialize_ppc64_linux_tdep (void)
+{
+ /* hardware/kernel supports single stepping */
+ set_gdbarch_software_single_step (current_gdbarch, NULL);
+}
+
+/* the start_address stored in the bfd is a function descriptor */
+#include "gdb/target.h"
+CORE_ADDR
+ppc64_bfd_get_start_address (bfd *abfd)
+{
+ extern struct target_ops exec_ops;
+ CORE_ADDR myaddr;
+ xfer_memory(abfd->start_address, (char *)&myaddr, 8, 0, 0, &exec_ops);
+ return myaddr;
+}
+
+/* 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).
+
+*/
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+#include "ppc-tdep.h"
+#define TDEP gdbarch_tdep (current_gdbarch)
+
+static CORE_ADDR
+read_memory_addr (CORE_ADDR memaddr, int len)
+{
+ return read_memory_unsigned_integer (memaddr, len);
+}
diff -rupPN gdb-5.2.1/gdb/rs6000-tdep.c src.ppc64/gdb/rs6000-tdep.c
--- gdb-5.2.1/gdb/rs6000-tdep.c 2002-04-01 00:01:46.000000000 -0600
+++ src.ppc64/gdb/rs6000-tdep.c 2003-01-28 13:28:24.000000000 -0600
@@ -513,13 +508,13 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
if ((op & 0xfc1fffff) == 0x7c0802a6)
{ /* mflr Rx */
- lr_reg = (op & 0x03e00000) | 0x90010000;
+ lr_reg = (op & 0x03e00000);
continue;
}
else if ((op & 0xfc1fffff) == 0x7c000026)
{ /* mfcr Rx */
- cr_reg = (op & 0x03e00000) | 0x90010000;
+ cr_reg = (op & 0x03e00000);
continue;
}
@@ -545,7 +540,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
{
fdata->saved_gpr = reg;
if ((op & 0xfc1f0003) == 0xf8010000)
- op = (op >> 1) << 1;
+ op &= ~3UL;
fdata->gpr_offset = SIGNED_SHORT (op) + offset;
}
continue;
@@ -577,19 +572,49 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
continue;
}
- else if (lr_reg != -1 && (op & 0xffff0000) == lr_reg)
- { /* st Rx,NUM(r1)
- where Rx == lr */
- fdata->lr_offset = SIGNED_SHORT (op) + offset;
+ else if (lr_reg != -1 &&
+ /* std Rx || stdu Rx */
+ (((op & 0xffff0000) == (lr_reg | 0xf8010000)) ||
+ /* stw Rx */
+ ((op & 0xffff0000) == (lr_reg | 0x90010000)) ||
+ /* stwu Rx */
+ ((op & 0xffff0000) == (lr_reg | 0x94010000))))
+ { /* where Rx == lr */
+ fdata->lr_offset = offset;
fdata->nosavedpc = 0;
lr_reg = 0;
+ if ((op & 0xfc000003) == 0xf8000000 || /* std Rx */
+ (op & 0xfc000000) == 0x90000000) /* stw Rx */
+ {
+ /* does not update r1 add d to lr_offset */
+ fdata->lr_offset = SIGNED_SHORT (op);
+ }
continue;
}
- else if (cr_reg != -1 && (op & 0xffff0000) == cr_reg)
- { /* st Rx,NUM(r1)
+ else if (cr_reg != -1 &&
+ /* std Rx || stdu Rx */
+ (((op & 0xffff0000) == (cr_reg | 0xf8010000)) ||
+ /* stw Rx */
+ ((op & 0xffff0000) == (cr_reg | 0x90010000)) ||
+ /* stwu Rx */
+ ((op & 0xffff0000) == (cr_reg | 0x94010000))))
+ { /* where Rx == cr */
+ fdata->cr_offset = offset;
+ cr_reg = 0;
+ if ((op & 0xfc000003) == 0xf8000000 ||
+ (op & 0xfc000000) == 0x90000000)
+ {
+ /* does not update r1 add d to cr_offset */
+ fdata->cr_offset += SIGNED_SHORT (op);
+ }
+ continue;
+
+ }
+ else if (cr_reg != -1 && (op & 0xffff0003) == cr_reg)
+ { /* std Rx,NUM(r1) || stdu Rx,NUM(r1)
where Rx == cr */
- fdata->cr_offset = SIGNED_SHORT (op) + offset;
+ fdata->cr_offset = SIGNED_SHORT (op & ~3UL) + offset;
cr_reg = 0;
continue;
@@ -634,30 +658,41 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
this branch */
continue;
- /* update stack pointer */
}
- else if ((op & 0xffff0000) == 0x94210000 || /* stu r1,NUM(r1) */
- (op & 0xffff0003) == 0xf8210001) /* stdu r1,NUM(r1) */
- {
+ /* update stack pointer */
+ else if ((op & 0xfc1f0000) == 0x94010000)
+ { /* stu rX,NUM(r1) || stwu rX,NUM(r1) */
fdata->frameless = 0;
- if ((op & 0xffff0003) == 0xf8210001)
- op = (op >> 1) << 1;
fdata->offset = SIGNED_SHORT (op);
offset = fdata->offset;
continue;
-
}
- else if (op == 0x7c21016e)
- { /* stwux 1,1,0 */
+ else if ((op & 0xfc1f016a) == 0x7c01016e)
+ { /* stwux rX,r1,rY */
+ /* no way to figure out what r1 is going to be */
+ fdata->frameless = 0;
+ offset = fdata->offset;
+ continue;
+ }
+ else if ((op & 0xfc1f0003) == 0xf8010001)
+ { /* stdu rX,NUM(r1) */
+ fdata->frameless = 0;
+ fdata->offset = SIGNED_SHORT (op & ~3UL);
+ offset = fdata->offset;
+ continue;
+ }
+ else if ((op & 0xfc1f016a) == 0x7c01016a)
+ { /* stdux rX,r1,rY */
+ /* no way to figure out what r1 is going to be */
fdata->frameless = 0;
offset = fdata->offset;
continue;
-
- /* Load up minimal toc pointer */
}
- else if ((op >> 22) == 0x20f
+ /* Load up minimal toc pointer */
+ else if (((op >> 22) == 0x20f || /* l r31,... or l r30,... */
+ (op >> 22) == 0x3af) /* ld r31,... or ld r30,... */
&& !minimal_toc_loaded)
- { /* l r31,... or l r30,... */
+ {
minimal_toc_loaded = 1;
continue;
@@ -2439,6 +2483,44 @@ static const struct reg registers_7400[]
/* FIXME? Add more registers? */
};
+
+/* PowerPC UISA - a PPC64 processor as viewed by user-level code. */
+/* Should be able to use the common registers_powerpc[] here, however
+ it does not define an fpscr, though both linux and aix get one from
+ ptrace(). Can only assume that there is a 32-bit core our there
+ that does not have an fpscr. I think we can assert that all 64-bit
+ cores do. */
+static const struct reg registers_powerpc64[] =
+{
+ COMMON_UISA_REGS,
+ /* SPRs */
+ /* 66 */ R4(cr), R(lr), R(ctr), R4(xer),
+ /* 70 */ R4(fpscr), R0 /* mq? */
+};
+
+static const struct reg registers_a35[] =
+{
+ COMMON_UISA_REGS,
+ /* SPRs */
+ /* 66 */ R4(cr), R(lr), R(ctr), R4(xer),
+ /* 70 */ R4(fpscr), R0 /* mq? */,
+ /* 72 */ R(dabr), R(iabr), R4(dsisr),
+ /* 75 */ R(dar), R4(dec), R(sdr1), R(srr0), R(srr1),
+ /* 80 */ R(sprg0), R(sprg1), R(sprg2), R(sprg3),
+ /* 84 */ R64(asr), R4(ear), R4(tbl), R4(tbu),
+ /* 88 */ R(ibat0u), R(ibat0l), R(ibat1u), R(ibat1l),
+ /* 92 */ R(ibat2u), R(ibat2l), R(ibat3u), R(ibat3l),
+ /* 96 */ R(dbat0u), R(dbat0l), R(dbat1u), R(dbat1l),
+ /* 100 */ R(dbat2u), R(dbat2l), R(dbat3u), R(dbat3l),
+ /* 104 */ R(pir), R4(mmcr0),
+ /* 106..121 segment regs 0..15 */
+ /* 106 */ R(sr0), R(sr1), R(sr2), R(sr3),
+ /* 110 */ R(sr4), R(sr5), R(sr6), R(sr7),
+ /* 114 */ R(sr8), R(sr9), R(sr10), R(sr11),
+ /* 118 */ R(sr12), R(sr13), R(sr14), R(sr15),
+ /* 122 */ R4(pvr) /* processor version register */
+};
+
/* Motorola e500. */
static const struct reg registers_e500[] =
{
@@ -2947,6 +3051,15 @@ rs6000_gdbarch_init (struct gdbarch_info
descriptors). */
set_gdbarch_convert_from_func_ptr_addr (gdbarch,
rs6000_convert_from_func_ptr_addr);
+
+ /* wordsize 8, ppc64 linux functions */
+ if (osabi == ELFOSABI_LINUX)
+ {
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, ppc64_linux_svr4_fetch_link_map_offsets);
+ set_gdbarch_convert_from_func_ptr_addr
+ (gdbarch, ppc64_linux_convert_from_func_ptr_addr);
+ }
}
set_gdbarch_frame_args_address (gdbarch, rs6000_frame_args_address);
set_gdbarch_frame_locals_address (gdbarch, rs6000_frame_args_address);