diff options
-rw-r--r-- | gdb/ChangeLog | 49 | ||||
-rw-r--r-- | gdb/config/powerpc/ppc64linux.mh | 14 | ||||
-rw-r--r-- | gdb/config/powerpc/ppc64linux.mt | 4 | ||||
-rw-r--r-- | gdb/config/powerpc/tm-linux.h | 5 | ||||
-rw-r--r-- | gdb/config/powerpc/tm-ppc64linux.h | 80 | ||||
-rw-r--r-- | gdb/configure.host | 2 | ||||
-rw-r--r-- | gdb/configure.tgt | 9 | ||||
-rw-r--r-- | gdb/elfread.c | 14 | ||||
-rw-r--r-- | gdb/ppc-linux-nat.c | 412 | ||||
-rw-r--r-- | gdb/ppc-linux-tdep.c | 63 | ||||
-rw-r--r-- | gdb/ppc64-linux-tdep.c | 80 | ||||
-rw-r--r-- | gdb/rs6000-tdep.c | 134 | ||||
-rw-r--r-- | gdb/solib-svr4.c | 5 |
13 files changed, 830 insertions, 41 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 9c58b41..9bd5f9d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,52 @@ +2003-05-12 Will Schmidt <willschm@us.ibm.com> + + These changes enable support of PPC64 architecture. + * config/powerpc/ppc64linux.mh: New file. + * config/powerpc/ppc64linux.mt: New file. + * config/powerpc/tm-ppc64linux.h: New file. + * ppc64-linux-tdep.c: New file. + * configure.host: Add clause for powerpc64-*-linux* + * configure.tgt: Add clause for powerpc64-*-linux* + * elfread.c (record_minimal_symbol_and_info): If + DROP_TEXT_NAME_PREFIX_CHAR is #defined, then drop a leading + instance of that char from the names of text symbols. + (elf_symtab_read): If SKIP_DATA_IN_OPD is #defined, ignore data + symbols in the .opd section. + * ppc-linux-nat.c (PTRACE_XFER_TYPE): Change the default for this + to 'long'. + (PPC_PTRACE_POKEUSR_3264, PPC_PTRACE_PEEKUSR_3264, + PPC_PTRACE_POKEDATA_3264, PPC_PTRACE_PEEKDATA_3264): Provide + default definitions for these. + (ARCH64): New macro. + (ppc_wordsize_pid): New function. + (kernel_u_size): Handle 64-bit case. + (ppc_register_u_addr): Same. + (fetch_register): Use the *_3264 requests when + debugging a 64-bit process from a 32-bit GDB. + (store_register): Same. + (GDB_MAX_ALLOCA, child_xfer_memory, udot_info): Copied from + infptrace.c. + (_initialize_ppc_linux_nat): New function, to register our copy of + the udot_info command. + * ppc-linux-tdep.c (TDEP): New macro. + (ppc64_linux_svr4_fetch_link_map_offsets): New function. + (read_memory_addr): Copied from rs6000-tdep.c. + (ppc64_linux_convert_from_func_ptr_addr): New function. + * rs6000-tdep.c (skip_prologue): Recognize more instructions for + saving the 'lr' and 'cr' registers; don't just pre-emptively mask + in the 'st' opcode as soon as we see an 'mflr' or 'mfcr' opcode. + Recognize more instructions for updating the stack pointer, and + loading the TOC pointer. + (registers_powerpc64, registers_a35): New register tables. + (rs6000_gdbarch_init): Register the 64-bit solib functions. + * solib-svr4.c (solib_break_names): If SOLIB_BREAK_NAME is + #defined, include an entry for it. + (enable_break): Call CONVERT_FROM_FUNC_PTR_ADDR when trying to + guess the linker's base address. + * config/powerpc/tm-linux.h + (ppc64_linux_svr4_fetch_link_map_offsets, + ppc64_linux_convert_from_func_ptr_addr): New declarations. + 2003-05-08 Andrew Cagney <cagney@redhat.com> * regcache.h (max_register_size): Delete declaration. diff --git a/gdb/config/powerpc/ppc64linux.mh b/gdb/config/powerpc/ppc64linux.mh new file mode 100644 index 0000000..e18a188 --- /dev/null +++ b/gdb/config/powerpc/ppc64linux.mh @@ -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 --git a/gdb/config/powerpc/ppc64linux.mt b/gdb/config/powerpc/ppc64linux.mt new file mode 100644 index 0000000..878eb15 --- /dev/null +++ b/gdb/config/powerpc/ppc64linux.mt @@ -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 --git a/gdb/config/powerpc/tm-linux.h b/gdb/config/powerpc/tm-linux.h index d69dfc1..9d72374 100644 --- a/gdb/config/powerpc/tm-linux.h +++ b/gdb/config/powerpc/tm-linux.h @@ -67,4 +67,9 @@ extern int ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name); 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 --git a/gdb/config/powerpc/tm-ppc64linux.h b/gdb/config/powerpc/tm-ppc64linux.h new file mode 100644 index 0000000..4b30c18 --- /dev/null +++ b/gdb/config/powerpc/tm-ppc64linux.h @@ -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 --git a/gdb/configure.host b/gdb/configure.host index 8f96b0a..ab5c2b7 100644 --- a/gdb/configure.host +++ b/gdb/configure.host @@ -120,6 +120,8 @@ powerpc-*-aix*) gdb_host=aix432 ;; 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 --git a/gdb/configure.tgt b/gdb/configure.tgt index fe4cc5d..2f5c909 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -193,6 +193,15 @@ powerpc-*-aix*) gdb_target=aix ;; 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 --git a/gdb/elfread.c b/gdb/elfread.c index 7aee37c..fd4c956 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -141,6 +141,12 @@ record_minimal_symbol_and_info (char *name, CORE_ADDR address, 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); } @@ -363,6 +369,10 @@ elf_symtab_read (struct objfile *objfile, int dynamic) { 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 @@ -444,6 +454,10 @@ elf_symtab_read (struct objfile *objfile, int dynamic) 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 --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index 20c8add..aff1f73 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -48,11 +48,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 @@ -106,7 +203,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* */ @@ -127,32 +232,33 @@ 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; } @@ -206,6 +312,16 @@ fetch_register (int tid, int regno) unsigned int offset; /* Offset of registers within the u area. */ char buf[MAX_REGISTER_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)) { @@ -233,8 +349,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) { @@ -365,6 +492,7 @@ store_register (int tid, int regno) register int i; unsigned int offset; /* Offset of registers within the u area. */ char buf[MAX_REGISTER_SIZE]; + int wordsize = (gdbarch_tdep (current_gdbarch))->wordsize; if (altivec_register_p (regno)) { @@ -379,8 +507,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 @@ -534,3 +672,243 @@ fill_fpregset (gdb_fpregset_t *fpregsetp, int regno) 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 --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 9284751..5993039 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -63,6 +63,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 @@ -755,3 +757,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 --git a/gdb/ppc64-linux-tdep.c b/gdb/ppc64-linux-tdep.c new file mode 100644 index 0000000..f7e0a2a --- /dev/null +++ b/gdb/ppc64-linux-tdep.c @@ -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 --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index 0b239bd..cd59cd4 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -529,13 +529,13 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata) 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; } @@ -561,7 +561,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata) { fdata->saved_gpr = reg; if ((op & 0xfc1f0003) == 0xf8010000) - op = (op >> 1) << 1; + op &= ~3UL; fdata->gpr_offset = SIGNED_SHORT (op) + offset; } continue; @@ -593,19 +593,49 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata) 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 && + /* 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 & 0xffff0000) == cr_reg) - { /* st Rx,NUM(r1) + 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; @@ -650,30 +680,41 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata) 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; @@ -2456,6 +2497,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[] = { @@ -2956,6 +3035,15 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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); diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 6c4c10a..2b453c9 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -76,6 +76,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", @@ -1015,7 +1018,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. */ |