From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8808 invoked by alias); 12 Sep 2005 12:52:28 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 8400 invoked by uid 22791); 12 Sep 2005 12:51:10 -0000 Received: from are.twiddle.net (HELO are.twiddle.net) (64.81.246.98) by sourceware.org (qpsmtpd/0.30-dev) with ESMTP; Mon, 12 Sep 2005 12:51:10 +0000 Received: from owl.twiddle.home (owl.twiddle.home [172.31.0.8]) by are.twiddle.net (8.12.11/8.12.11) with ESMTP id j8CCosHc032710; Mon, 12 Sep 2005 05:50:54 -0700 Received: from owl.twiddle.home (localhost.localdomain [127.0.0.1]) by owl.twiddle.home (8.13.4/8.13.4) with ESMTP id j8CCosGu007304; Mon, 12 Sep 2005 05:50:54 -0700 Received: (from rth@localhost) by owl.twiddle.home (8.13.4/8.13.4/Submit) id j8CCol1A006876; Mon, 12 Sep 2005 05:50:47 -0700 Date: Mon, 12 Sep 2005 12:52:00 -0000 From: Richard Henderson To: amodra@bigpond.net.au, gdb-patches@gcc.gnu.org Cc: Richard Henderson Subject: ppc32 debugging ppc64, part 1 Message-ID: <20050912125047.GA5411@twiddle.net> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.2.1i X-SW-Source: 2005-09/txt/msg00082.txt.bz2 This is just enough modifications to not immediately fail debugging a 64-bit process from a 32-bit debugger. We don't get very far in the actual debugging: (gdb) b main warning: Breakpoint address adjusted from 0x10093aa0 to 0x10000370. Breakpoint 1 at 0x10000370 (gdb) run Starting program: /home/rth/work/gcc/bld-binu64/gdb/z warning: Breakpoint address adjusted from 0x10093a40 to 0x100001c0. warning: Breakpoint 1 address previously adjusted from 0x10093aa0 to 0x10000370. Breakpoint 1, 0x0000000010000370 in ?? () (gdb) ppc 0x10000370 <__libc_tsd_CTYPE_B+268436264>: std r31,-8(r1) But this is better than the original: Starting program: /home/rth/work/gcc/bld-binu64/gdb/z warning: Breakpoint address adjusted from 0x10093a40 to 0x100001c0. Failed to read a valid object file image from memory. Program received signal SIGTRAP, Trace/breakpoint trap. 0x100001c00002d932 in ?? () Comments? r~ * ppc-linux-nat.c (PTRACE_XFER_TYPE): Set to long. (ppc_register_u_addr): Compute wordsize correctly for 64-bit target. (ptrace_read_u, ptrace_write_u): New. (fetch_register): Simplify. Use PPC_PTRACE_PEEKUSR_3264 when needed. (store_register): Similarly with PPC_PTRACE_POKEUSR_3264. (default_xfer_partial, ppc32_linux_xfer_partial): New. (_initialize_ppc_linux_nat): Use them. Index: ppc-linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/ppc-linux-nat.c,v retrieving revision 1.55 diff -u -p -c -r1.55 ppc-linux-nat.c *** ppc-linux-nat.c 10 Sep 2005 18:11:04 -0000 1.55 --- ppc-linux-nat.c 12 Sep 2005 12:37:40 -0000 *************** *** 39,44 **** --- 39,45 ---- #include #include #include + #include /* Prototypes for supply_gregset etc. */ #include "gregset.h" *************** *** 51,59 **** #define PT_WRITE_U PTRACE_POKEUSR #endif - /* Default the type of the ptrace transfer to int. */ #ifndef PTRACE_XFER_TYPE ! #define PTRACE_XFER_TYPE int #endif /* Glibc's headers don't define PTRACE_GETVRREGS so we cannot use a --- 52,59 ---- #define PT_WRITE_U PTRACE_POKEUSR #endif #ifndef PTRACE_XFER_TYPE ! #define PTRACE_XFER_TYPE long #endif /* Glibc's headers don't define PTRACE_GETVRREGS so we cannot use a *************** ppc_register_u_addr (int regno) *** 180,186 **** struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace interface, and not the wordsize of the program's ABI. */ ! int wordsize = sizeof (PTRACE_XFER_TYPE); /* General purpose registers occupy 1 slot each in the buffer */ if (regno >= tdep->ppc_gp0_regnum --- 180,194 ---- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace interface, and not the wordsize of the program's ABI. */ ! /* NOTE: rth/2005-09-12: Which is complicated by the fact that there ! are in fact two ptrace interfaces: the normal one, and a different ! one for 32-bit gdb debugging 64-bit target. */ ! int wordsize; ! ! if (sizeof (PTRACE_XFER_TYPE) == 8) ! wordsize = sizeof (PTRACE_XFER_TYPE); ! else ! wordsize = tdep->wordsize; /* General purpose registers occupy 1 slot each in the buffer */ if (regno >= tdep->ppc_gp0_regnum *************** fetch_spe_register (int tid, int regno) *** 337,350 **** } static void fetch_register (int tid, int regno) { struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); /* This isn't really an address. But ptrace thinks of it as one. */ CORE_ADDR regaddr = ppc_register_u_addr (regno); ! int bytes_transferred; ! unsigned int offset; /* Offset of registers within the u area. */ char buf[MAX_REGISTER_SIZE]; if (altivec_register_p (regno)) { --- 345,364 ---- } static void + ptrace_read_u (int cmd, int tid, CORE_ADDR regaddr, char *buf) + { + syscall (SYS_ptrace, cmd, tid, (PTRACE_ARG3_TYPE)(size_t)regaddr, buf); + } + + static void fetch_register (int tid, int regno) { struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); /* This isn't really an address. But ptrace thinks of it as one. */ CORE_ADDR regaddr = ppc_register_u_addr (regno); ! int regsize = register_size (current_gdbarch, regno); char buf[MAX_REGISTER_SIZE]; + int bytes_transferred; if (altivec_register_p (regno)) { *************** fetch_register (int tid, int regno) *** 369,397 **** if (regaddr == -1) { ! memset (buf, '\0', register_size (current_gdbarch, regno)); /* Supply zeroes */ regcache_raw_supply (current_regcache, regno, buf); return; } ! /* Read the raw register using PTRACE_XFER_TYPE sized chunks. On a ! 32-bit platform, 64-bit floating-point registers will require two ! transfers. */ ! for (bytes_transferred = 0; ! bytes_transferred < register_size (current_gdbarch, regno); ! bytes_transferred += sizeof (PTRACE_XFER_TYPE)) { ! errno = 0; ! *(PTRACE_XFER_TYPE *) & buf[bytes_transferred] ! = ptrace (PT_READ_U, tid, (PTRACE_ARG3_TYPE) regaddr, 0); ! regaddr += sizeof (PTRACE_XFER_TYPE); ! if (errno != 0) ! { ! char message[128]; ! sprintf (message, "reading register %s (#%d)", ! REGISTER_NAME (regno), regno); ! perror_with_name (message); ! } } /* Now supply the register. Keep in mind that the regcache's idea --- 383,424 ---- if (regaddr == -1) { ! /* Supply zeroes */ ! memset (buf, '\0', register_size (current_gdbarch, regno)); regcache_raw_supply (current_regcache, regno, buf); return; } ! /* We need to distinguish between 32/64-bit gdb and 32/64-bit target. */ ! ! errno = 0; ! memset (buf, '\0', register_size (current_gdbarch, regno)); ! if (regsize <= sizeof (PTRACE_XFER_TYPE)) { ! ptrace_read_u (PT_READ_U, tid, regaddr, buf); ! bytes_transferred = sizeof (PTRACE_XFER_TYPE); ! } ! else ! { ! int cmd; ! ! gdb_assert (sizeof (PTRACE_XFER_TYPE) == 4 && regsize == 8); ! bytes_transferred = 2 * sizeof (PTRACE_XFER_TYPE); ! ! if (tdep->wordsize == 8) ! cmd = PPC_PTRACE_PEEKUSR_3264; ! else ! cmd = PT_READ_U; ! ! ptrace_read_u (cmd, tid, regaddr, buf); ! ptrace_read_u (cmd, tid, regaddr + 4, buf + 4); ! } ! if (errno != 0) ! { ! char message[128]; ! sprintf (message, "reading register %s (#%d)", ! REGISTER_NAME (regno), regno); ! perror_with_name (message); } /* Now supply the register. Keep in mind that the regcache's idea *************** fetch_register (int tid, int regno) *** 407,414 **** { /* Big-endian values are found at the right end of the bytes transferred. */ ! size_t padding = (bytes_transferred ! - register_size (current_gdbarch, regno)); regcache_raw_supply (current_regcache, regno, buf + padding); } else --- 434,440 ---- { /* Big-endian values are found at the right end of the bytes transferred. */ ! size_t padding = bytes_transferred - regsize; regcache_raw_supply (current_regcache, regno, buf + padding); } else *************** fetch_ppc_registers (int tid) *** 466,476 **** --- 492,504 ---- int i; struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + /* ??? Use PPC_PTRACE_GETREGS / PPC_PTRACE_GETFPREGS. */ for (i = 0; i < ppc_num_gprs; i++) fetch_register (tid, tdep->ppc_gp0_regnum + i); if (tdep->ppc_fp0_regnum >= 0) for (i = 0; i < ppc_num_fprs; i++) fetch_register (tid, tdep->ppc_fp0_regnum + i); + fetch_register (tid, PC_REGNUM); if (tdep->ppc_ps_regnum != -1) fetch_register (tid, tdep->ppc_ps_regnum); *************** store_spe_register (int tid, int regno) *** 633,646 **** } static void store_register (int tid, int regno) { struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); /* This isn't really an address. But ptrace thinks of it as one. */ CORE_ADDR regaddr = ppc_register_u_addr (regno); ! int i; ! size_t bytes_to_transfer; char buf[MAX_REGISTER_SIZE]; if (altivec_register_p (regno)) { --- 661,681 ---- } static void + ptrace_write_u (int cmd, int tid, CORE_ADDR regaddr, char *buf) + { + syscall (SYS_ptrace, cmd, tid, (PTRACE_ARG3_TYPE)(size_t)regaddr, + *(PTRACE_XFER_TYPE *)buf); + } + + static void store_register (int tid, int regno) { struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); /* This isn't really an address. But ptrace thinks of it as one. */ CORE_ADDR regaddr = ppc_register_u_addr (regno); ! int regsize = register_size (current_gdbarch, regno); char buf[MAX_REGISTER_SIZE]; + int bytes_to_transfer; if (altivec_register_p (regno)) { *************** store_register (int tid, int regno) *** 660,667 **** idea of the register's size may not be a multiple of sizeof (PTRACE_XFER_TYPE). */ memset (buf, 0, sizeof buf); ! bytes_to_transfer = align_up (register_size (current_gdbarch, regno), ! sizeof (PTRACE_XFER_TYPE)); if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE) { /* Little-endian values always sit at the left end of the buffer. */ --- 695,701 ---- idea of the register's size may not be a multiple of sizeof (PTRACE_XFER_TYPE). */ memset (buf, 0, sizeof buf); ! bytes_to_transfer = align_up (regsize, sizeof (PTRACE_XFER_TYPE)); if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE) { /* Little-endian values always sit at the left end of the buffer. */ *************** store_register (int tid, int regno) *** 670,701 **** else if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) { /* Big-endian values sit at the right end of the buffer. */ ! size_t padding = (bytes_to_transfer ! - register_size (current_gdbarch, regno)); regcache_raw_collect (current_regcache, regno, buf + padding); } ! for (i = 0; i < bytes_to_transfer; i += sizeof (PTRACE_XFER_TYPE)) { ! errno = 0; ! ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr, ! *(PTRACE_XFER_TYPE *) & buf[i]); ! regaddr += sizeof (PTRACE_XFER_TYPE); ! if (errno == EIO ! && regno == tdep->ppc_fpscr_regnum) ! { ! /* Some older kernel versions don't allow fpscr to be written. */ ! continue; ! } ! if (errno != 0) ! { ! char message[128]; ! sprintf (message, "writing register %s (#%d)", ! REGISTER_NAME (regno), regno); ! perror_with_name (message); ! } } } --- 704,740 ---- else if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) { /* Big-endian values sit at the right end of the buffer. */ ! size_t padding = bytes_to_transfer - regsize; regcache_raw_collect (current_regcache, regno, buf + padding); } ! /* We need to distinguish between 32/64-bit gdb and 32/64-bit target. */ ! ! errno = 0; ! if (regsize <= sizeof (PTRACE_XFER_TYPE)) ! ptrace_write_u (PT_WRITE_U, tid, regaddr, buf); ! else { ! int cmd; ! gdb_assert (sizeof (PTRACE_XFER_TYPE) == 4 && regsize == 8); ! if (regsize == tdep->wordsize) ! cmd = PPC_PTRACE_POKEUSR_3264; ! else ! cmd = PT_WRITE_U; ! ! ptrace_write_u (cmd, tid, regaddr, buf); ! ptrace_write_u (cmd, tid, regaddr + 4, buf + 4); ! } ! if (errno == EIO && regno == tdep->ppc_fpscr_regnum) ! /* Some older kernel versions don't allow fpscr to be written. */; ! else if (errno != 0) ! { ! char message[128]; ! sprintf (message, "writing register %s (#%d)", ! REGISTER_NAME (regno), regno); ! perror_with_name (message); } } *************** store_ppc_registers (int tid) *** 750,760 **** --- 789,801 ---- int i; struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + /* ??? Use PPC_PTRACE_SETREGS / PPC_PTRACE_SETFPREGS. */ for (i = 0; i < ppc_num_gprs; i++) store_register (tid, tdep->ppc_gp0_regnum + i); if (tdep->ppc_fp0_regnum >= 0) for (i = 0; i < ppc_num_fprs; i++) store_register (tid, tdep->ppc_fp0_regnum + i); + store_register (tid, PC_REGNUM); if (tdep->ppc_ps_regnum != -1) store_register (tid, tdep->ppc_ps_regnum); *************** fill_fpregset (gdb_fpregset_t *fpregsetp *** 886,891 **** --- 927,1014 ---- } } + /* Hold a pointer to inf_ptrace_xfer_partial. */ + static LONGEST (*default_xfer_partial) (struct target_ops *ops, + enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, LONGEST len); + + static LONGEST + ppc32_linux_xfer_partial (struct target_ops *ops, enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) + { + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + pid_t pid; + CORE_ADDR rounded_offset; + LONGEST partial_len; + PTRACE_XFER_TYPE buf; + + /* If the target is also 32-bit, we can avoid double indirection by + using the default implementation. Plus, the PTRACE_*_3264 commands + are only present on 64-bit kernels. */ + if (tdep->wordsize == 4) + return default_xfer_partial (ops, object, annex, readbuf, + writebuf, offset, len); + + if (object != TARGET_OBJECT_MEMORY) + return -1; + + gdb_assert (sizeof (CORE_ADDR) == 8); + + pid = ptid_get_pid (inferior_ptid); + + /* Round the start offset down to the next long word boundary. */ + rounded_offset = offset & -(ULONGEST) sizeof (PTRACE_XFER_TYPE); + + /* Since ptrace will transfer a single word starting at that + rounded_offset the partial_len needs to be adjusted down to + that (remember this function only does a single transfer). + Should the required length be even less, adjust it down again. */ + partial_len = rounded_offset + sizeof (PTRACE_XFER_TYPE) - offset; + if (partial_len > len) + partial_len = len; + + if (writebuf) + { + /* If OFFSET:PARTIAL_LEN is smaller than ROUNDED_OFFSET:WORDSIZE + then a read/modify write will be needed. Read in the entire word. */ + if (rounded_offset < offset + || (offset + partial_len + < rounded_offset + sizeof (PTRACE_XFER_TYPE))) + { + /* Need part of initial word -- fetch it. */ + syscall (SYS_ptrace, PPC_PTRACE_PEEKDATA_3264, pid, + &rounded_offset, &buf); + } + + /* Copy data to be written over corresponding part of buffer. */ + memcpy ((char *)&buf + offset - rounded_offset, writebuf, partial_len); + + errno = 0; + syscall (SYS_ptrace, PPC_PTRACE_POKEDATA_3264, pid, + &rounded_offset, buf); + if (errno) + return 0; + } + + if (readbuf) + { + errno = 0; + syscall (SYS_ptrace, PPC_PTRACE_PEEKDATA_3264, pid, + &rounded_offset, &buf); + if (errno) + return 0; + + /* Copy appropriate bytes out of the buffer. */ + memcpy (readbuf, (char *)&buf + offset - rounded_offset, partial_len); + } + + return partial_len; + } + void _initialize_ppc_linux_nat (void); void *************** _initialize_ppc_linux_nat (void) *** 900,905 **** --- 1023,1036 ---- t->to_fetch_registers = ppc_linux_fetch_inferior_registers; t->to_store_registers = ppc_linux_store_inferior_registers; + /* We need a special version of xfer_partial to handle 32-bit gdb + debugging a 64-bit process. */ + if (sizeof (PTRACE_XFER_TYPE) == 4) + { + default_xfer_partial = t->to_xfer_partial; + t->to_xfer_partial = ppc32_linux_xfer_partial; + } + /* Register the target. */ add_target (t); }