Re: [PATCH] new support for PPC64 architecture

Elena Zannoni
2003-05-07T20:37:36Z

Will Schmidt writes:
> All,
>
> This patch contains code that provides support for GDB on the PPC64
> architecture. This patch will apply clean on top of the RedHat
> gdb-5.3post-0.20021129.29.src.rpm. (A patch against CVS will
> happen, but not today.. )
>
>
> (See attached file: gdb-5.3post-ppc64-support.patch)
>
>
> -Will
>
>
> Will Schmidt
> willschm@us.ibm.com will_schmidt@vnet.ibm.com
> Linux on PowerPC-64 Development
> IBM Rochester

A few comments/questions. You need changelogs, and the proper
copyright verbiage in the new files you are adding. The code needs to
conform to gnu coding standards as fas as spaces, indentation,
etc. You can run the new files through gdb_indent.sh to get the right
format. Comments should start with a capital letter, be full
sentences, and end with a period followed by 2 spaces.

see below.....

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
+

this is the host makefile fragment, the *tdep.o files should be
included in the target makefile fragment, the .mt file, not here.
Actually if you exclude the .o's that ashould really be in the mt
file, then this file becomes almost identical to the linux.mh
file. Which makes me wonder if we really need a new file.

+LOADLIBES = -ldl -lthread_db
+

Why include thread_db? I don't see any other config files doing that.

+GDBSERVER_DEPFILES= low-linux.o

it is linux-low.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

corelow?

+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

Caouldn't the new name just be added to the list w/o this ifdef? All
of these names are looked for into the executable, if one is not
found, it will try the next.

"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))
+

why this? In the current tm-linux.h it is defined to generate an
internal_error.

+#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 */

delete this 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
+

hmm do we need this?

+/* don't think it is but it can't hurt (can it?) */
+#define TARGET_BYTE_ORDER_SELECTABLE_P 1
+

the above macro is gone from the gdb sources since Jan 2002.

+/* 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
+

Do we need to worry at all about 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
+

please explain the need for the above 2 macros.

+/* 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 */
+

can you explain why this is needed? Do we really have names starting
with '.', using gcc?

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
+

shouldn't these come from some include file? Should there be a
configure time check to see if the glibc include fles have such ptrace
flag?

+#define ARCH64() (REGISTER_RAW_SIZE (0) == 8)
+

ulgh, can't you use tdep->wordsize instead?

+/* 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;
+ }

maybe I am missing something here, but there is already an identical test in
rs6000 tdep.c (around line 2074):
else if (from_elf_exec)
{
if (elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
wordsize = 8;
else
wordsize = 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, &reg);
+ *(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;
+ }
+
+\f
+/* 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, &reg);
+ 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)
+

No, please! :-) I went through this file to get rid of the TDEP's not
too long ago.

/* 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)
+{

Don't add this at the end of the file. Probably right after the 32 bit
version of the function is better.

+ 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);

no 'extern's in .c files. Include the .h instead.

+
+ /* 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;
+}

can you expand a bit on why the above is needed?

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.
+

Copyright 2003 only, is enough, since this is a new file.

+ 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 */

can you explain what's going on here? I don't understand the comment.

+#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 _initialize functions should be at the bottom of the file.

+/* 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)
+

No. All includes go at the beginning of the file. No TDEP.

+static CORE_ADDR
+read_memory_addr (CORE_ADDR memaddr, int len)
+{
+ return read_memory_unsigned_integer (memaddr, len);
+}

????? what's this for???

this whole file is questionable.

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;

All these changes to skip_prologue worry me. Are you sure you are not
breaking other ppc variants? Did you test altivec? e500? eabi, etc etc?

@@ -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. */

how about using PPC_UISA_SPRS ?

+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 */
+};
+

what's the a35 stuff for?

/* 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);
+ }
}

why here? shouldn't this bit go in ppc_linux_init_abi()?

set_gdbarch_frame_args_address (gdbarch, rs6000_frame_args_address);
set_gdbarch_frame_locals_address (gdbarch, rs6000_frame_args_address);

Well, I think there are still a lot of things that need to be looked
at. Expecially the new PTRACE related changes. Maybe Kevin has some
more ideas on this.

elena