hurd: Add enough auxv support for AT_ENTRY for PIE binaries

Message ID 20171227154156.130174-1-samuel.thibault@ens-lyon.org
State New, archived
Headers

Commit Message

Samuel Thibault Dec. 27, 2017, 3:41 p.m. UTC
  gdb/ChangeLog:

	* gdb/gnu-nat.c: Include <elf.h> and <link.h>.
	(gnu_xfer_auxv): New function.
	(gnu_xfer_partial): Call gnu_xfer_auxv when `object' is
	TARGET_OBJECT_AUXV.
---
 gdb/ChangeLog |  7 +++++++
 gdb/gnu-nat.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)
  

Comments

Simon Marchi Dec. 28, 2017, 2:19 a.m. UTC | #1
On 2017-12-27 10:41 AM, Samuel Thibault wrote:
> gdb/ChangeLog:
> 
> 	* gdb/gnu-nat.c: Include <elf.h> and <link.h>.
> 	(gnu_xfer_auxv): New function.
> 	(gnu_xfer_partial): Call gnu_xfer_auxv when `object' is
> 	TARGET_OBJECT_AUXV.
> ---
>  gdb/ChangeLog |  7 +++++++
>  gdb/gnu-nat.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 65 insertions(+)
> 
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 4d85029b99..40d8e6e1cf 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,10 @@
> +2017-12-22  Samuel Thibault  <samuel.thibault@ens-lyon.org>
> +
> +	* gdb/gnu-nat.c: Include <elf.h> and <link.h>.
> +	(gnu_xfer_auxv): New function.
> +	(gnu_xfer_partial): Call gnu_xfer_auxv when `object' is
> +	TARGET_OBJECT_AUXV.
> +
>  2017-12-27  Franck Jullien  <franck.jullien@gmail.com>
>  	    Stafford Horne  <shorne@gmail.com>
>  
> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
> index 0d500ea38d..7d9c7d8dfa 100644
> --- a/gdb/gnu-nat.c
> +++ b/gdb/gnu-nat.c
> @@ -52,6 +52,8 @@ extern "C"
>  #include <setjmp.h>
>  #include <signal.h>
>  #include <sys/ptrace.h>
> +#include <elf.h>
> +#include <link.h>
>  
>  #include "inferior.h"
>  #include "symtab.h"
> @@ -2541,6 +2543,60 @@ gnu_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
>      }
>  }
>  
> +/* GNU does not have auxv, but we can at least fake the AT_ENTRY entry for PIE
> +   binaries.  */
> +static enum target_xfer_status
> +gnu_xfer_auxv (gdb_byte *readbuf, const gdb_byte *writebuf,
> +	       CORE_ADDR memaddr, ULONGEST len, ULONGEST *xfered_len)
> +{
> +  task_t task = (gnu_current_inf
> +		 ? (gnu_current_inf->task
> +		    ? gnu_current_inf->task->port : 0)
> +		 : 0);
> +  process_t proc;
> +  int res;
> +  kern_return_t err;
> +  vm_address_t entry;
> +  ElfW(auxv_t) auxv[2];
> +
> +  if (task == MACH_PORT_NULL)
> +    return TARGET_XFER_E_IO;
> +  if (writebuf != NULL)
> +    return TARGET_XFER_E_IO;
> +
> +  if (memaddr == sizeof (auxv))
> +    return TARGET_XFER_EOF;
> +  if (memaddr > sizeof (auxv))
> +    return TARGET_XFER_E_IO;
> +
> +  err = proc_task2proc (proc_server, task, &proc);
> +  if (err != 0)
> +    return TARGET_XFER_E_IO;
> +
> +  /* Get entry from proc server.  */
> +  err = proc_get_entry (proc, &entry);
> +  if (err != 0)
> +    return TARGET_XFER_E_IO;
> +
> +  /* Fake auxv entry.  */
> +  auxv[0].a_type = AT_ENTRY;
> +  auxv[0].a_un.a_val = entry;
> +  auxv[1].a_type = AT_NULL;
> +  auxv[1].a_un.a_val = 0;
> +
> +  inf_debug (gnu_current_inf, "reading auxv %s[%s] --> %s",
> +	     paddress (target_gdbarch (), memaddr), pulongest (len),
> +	     host_address_to_string (readbuf));
> +
> +  if (memaddr + len > sizeof (auxv))
> +    len = sizeof (auxv) - memaddr;
> +
> +  memcpy (readbuf, (gdb_byte *) &auxv + memaddr, len);
> +  *xfered_len = len;
> +
> +  return TARGET_XFER_OK;
> +}
> +
>  /* Target to_xfer_partial implementation.  */
>  
>  static enum target_xfer_status
> @@ -2553,6 +2609,8 @@ gnu_xfer_partial (struct target_ops *ops, enum target_object object,
>      {
>      case TARGET_OBJECT_MEMORY:
>        return gnu_xfer_memory (readbuf, writebuf, offset, len, xfered_len);
> +    case TARGET_OBJECT_AUXV:
> +      return gnu_xfer_auxv (readbuf, writebuf, offset, len, xfered_len);
>      default:
>        return TARGET_XFER_E_IO;
>      }
> 

Hi Samuel,

As I said in the previous thread, the patch looks good to me, but
I don't have a setup to test.  I would like to leave some time for
others to comment, especially because I don't expect people to be
very active these days.  If nobody has commented by the time we are
ready to create the 8.1 branch (supposed to be in January), we'll
merge it.  I'll add a note to the GDB 8.1 release wiki page [1] so
we don't forget.  Does that sound good to you?

In the mean time, I'd like to add some details to the commit message
about how this is expected to work.  The AT_ENTRY value set here
will be read by the svr4_exec_displacement function, is that right?

Thanks,

Simon

[1] https://sourceware.org/gdb/wiki/GDB_8.1_Release
  
Samuel Thibault Dec. 28, 2017, 9:27 p.m. UTC | #2
Hello,

Simon Marchi, on mer. 27 déc. 2017 21:19:12 -0500, wrote:
> If nobody has commented by the time we are
> ready to create the 8.1 branch (supposed to be in January), we'll
> merge it.  I'll add a note to the GDB 8.1 release wiki page [1] so
> we don't forget.  Does that sound good to you?

Sure.

> In the mean time, I'd like to add some details to the commit message
> about how this is expected to work.  The AT_ENTRY value set here
> will be read by the svr4_exec_displacement function, is that right?

Yes, here is the backtrace:

#0  gnu_xfer_partial (ops=0x867cb78, object=TARGET_OBJECT_AUXV, annex=0x0, readbuf=0x8787250 "", writebuf=0x0, offset=0, len=4096, xfered_len=0x28043e0) at ./gdb/gnu-nat.c:2615
#1  0x081f09a7 in target_xfer_partial (ops=0x863d440 <current_target>, object=TARGET_OBJECT_AUXV, annex=0x0, readbuf=0x8787250 "", writebuf=0x0, offset=0, len=<optimized out>, xfered_len=0x28043e0) at ./gdb/target.c:1374
#2  0x081f0e32 in target_read_partial (xfered_len=0x28043e0, len=4096, offset=0, buf=0x8787250 "", annex=0x0, object=TARGET_OBJECT_AUXV, ops=0x863d440 <current_target>) at ./gdb/target.c:1619
#3  target_read_alloc_1 (ops=0x863d440 <current_target>, object=TARGET_OBJECT_AUXV, annex=annex@entry=0x0, buf_p=0x87721e8, padding=0) at ./gdb/target.c:1988
#4  0x081f1f21 in target_read_alloc (ops=<optimized out>, object=<optimized out>, annex=0x0, buf_p=0x87721e8) at ./gdb/target.c:2029
#5  0x0812022f in get_auxv_inferior_data (ops=ops@entry=0x863d440 <current_target>) at ./gdb/auxv.c:362
#6  0x081206a1 in target_auxv_search (ops=0x863d440 <current_target>, match=9, valp=0x28044d0) at ./gdb/auxv.c:382
#7  0x08068c7f in svr4_exec_displacement (displacementp=<synthetic pointer>) at ./gdb/solib-svr4.c:2649
#8  svr4_relocate_main_executable () at ./gdb/solib-svr4.c:3031
#9  0x0806a828 in svr4_solib_create_inferior_hook (from_tty=0) at ./gdb/solib-svr4.c:3092
#10 0x0819490b in post_create_inferior (target=<optimized out>, from_tty=<optimized out>) at ./gdb/infcmd.c:445
#11 0x08194c5f in run_command_1 (args=<optimized out>, from_tty=1, tbreak_at_main=<optimized out>) at ./gdb/infcmd.c:631
...

Samuel
  
Simon Marchi Jan. 8, 2018, 3:41 p.m. UTC | #3
On 2017-12-28 16:27, Samuel Thibault wrote:
> Hello,
> 
> Simon Marchi, on mer. 27 déc. 2017 21:19:12 -0500, wrote:
>> If nobody has commented by the time we are
>> ready to create the 8.1 branch (supposed to be in January), we'll
>> merge it.  I'll add a note to the GDB 8.1 release wiki page [1] so
>> we don't forget.  Does that sound good to you?
> 
> Sure.
> 
>> In the mean time, I'd like to add some details to the commit message
>> about how this is expected to work.  The AT_ENTRY value set here
>> will be read by the svr4_exec_displacement function, is that right?
> 
> Yes, here is the backtrace:
> 
> #0  gnu_xfer_partial (ops=0x867cb78, object=TARGET_OBJECT_AUXV,
> annex=0x0, readbuf=0x8787250 "", writebuf=0x0, offset=0, len=4096,
> xfered_len=0x28043e0) at ./gdb/gnu-nat.c:2615
> #1  0x081f09a7 in target_xfer_partial (ops=0x863d440 <current_target>,
> object=TARGET_OBJECT_AUXV, annex=0x0, readbuf=0x8787250 "",
> writebuf=0x0, offset=0, len=<optimized out>, xfered_len=0x28043e0) at
> ./gdb/target.c:1374
> #2  0x081f0e32 in target_read_partial (xfered_len=0x28043e0, len=4096,
> offset=0, buf=0x8787250 "", annex=0x0, object=TARGET_OBJECT_AUXV,
> ops=0x863d440 <current_target>) at ./gdb/target.c:1619
> #3  target_read_alloc_1 (ops=0x863d440 <current_target>,
> object=TARGET_OBJECT_AUXV, annex=annex@entry=0x0, buf_p=0x87721e8,
> padding=0) at ./gdb/target.c:1988
> #4  0x081f1f21 in target_read_alloc (ops=<optimized out>,
> object=<optimized out>, annex=0x0, buf_p=0x87721e8) at
> ./gdb/target.c:2029
> #5  0x0812022f in get_auxv_inferior_data (ops=ops@entry=0x863d440
> <current_target>) at ./gdb/auxv.c:362
> #6  0x081206a1 in target_auxv_search (ops=0x863d440 <current_target>,
> match=9, valp=0x28044d0) at ./gdb/auxv.c:382
> #7  0x08068c7f in svr4_exec_displacement (displacementp=<synthetic
> pointer>) at ./gdb/solib-svr4.c:2649
> #8  svr4_relocate_main_executable () at ./gdb/solib-svr4.c:3031
> #9  0x0806a828 in svr4_solib_create_inferior_hook (from_tty=0) at
> ./gdb/solib-svr4.c:3092
> #10 0x0819490b in post_create_inferior (target=<optimized out>,
> from_tty=<optimized out>) at ./gdb/infcmd.c:445
> #11 0x08194c5f in run_command_1 (args=<optimized out>, from_tty=1,
> tbreak_at_main=<optimized out>) at ./gdb/infcmd.c:631
> ...
> 
> Samuel

Hi Samuel,

I pushed this patch to master and gdb-8.1-branch.

Thanks,

Simon
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4d85029b99..40d8e6e1cf 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@ 
+2017-12-22  Samuel Thibault  <samuel.thibault@ens-lyon.org>
+
+	* gdb/gnu-nat.c: Include <elf.h> and <link.h>.
+	(gnu_xfer_auxv): New function.
+	(gnu_xfer_partial): Call gnu_xfer_auxv when `object' is
+	TARGET_OBJECT_AUXV.
+
 2017-12-27  Franck Jullien  <franck.jullien@gmail.com>
 	    Stafford Horne  <shorne@gmail.com>
 
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 0d500ea38d..7d9c7d8dfa 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -52,6 +52,8 @@  extern "C"
 #include <setjmp.h>
 #include <signal.h>
 #include <sys/ptrace.h>
+#include <elf.h>
+#include <link.h>
 
 #include "inferior.h"
 #include "symtab.h"
@@ -2541,6 +2543,60 @@  gnu_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
     }
 }
 
+/* GNU does not have auxv, but we can at least fake the AT_ENTRY entry for PIE
+   binaries.  */
+static enum target_xfer_status
+gnu_xfer_auxv (gdb_byte *readbuf, const gdb_byte *writebuf,
+	       CORE_ADDR memaddr, ULONGEST len, ULONGEST *xfered_len)
+{
+  task_t task = (gnu_current_inf
+		 ? (gnu_current_inf->task
+		    ? gnu_current_inf->task->port : 0)
+		 : 0);
+  process_t proc;
+  int res;
+  kern_return_t err;
+  vm_address_t entry;
+  ElfW(auxv_t) auxv[2];
+
+  if (task == MACH_PORT_NULL)
+    return TARGET_XFER_E_IO;
+  if (writebuf != NULL)
+    return TARGET_XFER_E_IO;
+
+  if (memaddr == sizeof (auxv))
+    return TARGET_XFER_EOF;
+  if (memaddr > sizeof (auxv))
+    return TARGET_XFER_E_IO;
+
+  err = proc_task2proc (proc_server, task, &proc);
+  if (err != 0)
+    return TARGET_XFER_E_IO;
+
+  /* Get entry from proc server.  */
+  err = proc_get_entry (proc, &entry);
+  if (err != 0)
+    return TARGET_XFER_E_IO;
+
+  /* Fake auxv entry.  */
+  auxv[0].a_type = AT_ENTRY;
+  auxv[0].a_un.a_val = entry;
+  auxv[1].a_type = AT_NULL;
+  auxv[1].a_un.a_val = 0;
+
+  inf_debug (gnu_current_inf, "reading auxv %s[%s] --> %s",
+	     paddress (target_gdbarch (), memaddr), pulongest (len),
+	     host_address_to_string (readbuf));
+
+  if (memaddr + len > sizeof (auxv))
+    len = sizeof (auxv) - memaddr;
+
+  memcpy (readbuf, (gdb_byte *) &auxv + memaddr, len);
+  *xfered_len = len;
+
+  return TARGET_XFER_OK;
+}
+
 /* Target to_xfer_partial implementation.  */
 
 static enum target_xfer_status
@@ -2553,6 +2609,8 @@  gnu_xfer_partial (struct target_ops *ops, enum target_object object,
     {
     case TARGET_OBJECT_MEMORY:
       return gnu_xfer_memory (readbuf, writebuf, offset, len, xfered_len);
+    case TARGET_OBJECT_AUXV:
+      return gnu_xfer_auxv (readbuf, writebuf, offset, len, xfered_len);
     default:
       return TARGET_XFER_E_IO;
     }