This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

ppc32 debugging ppc64, part 1


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 <fcntl.h>
  #include <sys/procfs.h>
  #include <sys/ptrace.h>
+ #include <sys/syscall.h>
  
  /* 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);
  }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]