[RFC,v2] Rebase executable to match relocated base address

Message ID 20191223140825.5378-1-ssbssa@yahoo.de
State New, archived
Headers

Commit Message

Terekhov, Mikhail via Gdb-patches Dec. 23, 2019, 2:08 p.m. UTC
  Windows executables linked with -dynamicbase get a new base address
when loaded, which makes debugging impossible if the executable isn't
also rebased in gdb.

solib_create_inferior_hook looked like the right place for rebasing,
since there is similar code in solib_aix_solib_create_inferior_hook
and darwin_solib_create_inferior_hook.

But I'm not at all sure about my approach to forward the image base
via auxv data, but I needed a solution that worked for gdbserver as well.

Also I just reused AT_ENTRY, which is not nice at all.
I guess a new define should be created (where?), and a new auxv print function
registered with set_gdbarch_print_auxv_entry, but since I'm not sure
if the auxv approach is even correct, I didn't bother with this (for now).

The first version of this patch didn't apply on master, this one does.
---
 gdb/gdbserver/win32-low.c | 32 +++++++++++++++++++++++++++++++-
 gdb/windows-nat.c         | 35 +++++++++++++++++++++++++++++++++++
 gdb/windows-tdep.c        | 20 ++++++++++++++++++++
 3 files changed, 86 insertions(+), 1 deletion(-)
  

Comments

Terekhov, Mikhail via Gdb-patches Jan. 16, 2020, 8:23 p.m. UTC | #1
Ping.

Am Montag, 23. Dezember 2019, 15:08:56 MEZ hat Hannes Domani via gdb-patches <gdb-patches@sourceware.org> Folgendes geschrieben:

> Windows executables linked with -dynamicbase get a new base address
> when loaded, which makes debugging impossible if the executable isn't
> also rebased in gdb.
>
> solib_create_inferior_hook looked like the right place for rebasing,
> since there is similar code in solib_aix_solib_create_inferior_hook
> and darwin_solib_create_inferior_hook.
>
> But I'm not at all sure about my approach to forward the image base
> via auxv data, but I needed a solution that worked for gdbserver as well.
>
> Also I just reused AT_ENTRY, which is not nice at all.
> I guess a new define should be created (where?), and a new auxv print function
> registered with set_gdbarch_print_auxv_entry, but since I'm not sure
> if the auxv approach is even correct, I didn't bother with this (for now).
>
> The first version of this patch didn't apply on master, this one does.
> ---
> gdb/gdbserver/win32-low.c | 32 +++++++++++++++++++++++++++++++-
> gdb/windows-nat.c        | 35 +++++++++++++++++++++++++++++++++++
> gdb/windows-tdep.c        | 20 ++++++++++++++++++++
> 3 files changed, 86 insertions(+), 1 deletion(-)
>
> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
> index 449ed5f462..d453b89cdd 100644
> --- a/gdb/gdbserver/win32-low.c
> +++ b/gdb/gdbserver/win32-low.c
> @@ -74,6 +74,7 @@ static int attaching = 0;
> static HANDLE current_process_handle = NULL;
> static DWORD current_process_id = 0;
> static DWORD main_thread_id = 0;
> +static CORE_ADDR current_exec_base;    /* Executable base address */
> static enum gdb_signal last_sig = GDB_SIGNAL_0;
>
> /* The current debug event from WaitForDebugEvent.  */
> @@ -1485,6 +1486,8 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
>
>       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
>       main_thread_id = current_event.dwThreadId;
> +      current_exec_base =
> +    (CORE_ADDR) current_event.u.CreateProcessInfo.lpBaseOfImage;
>
>       /* Add the main thread.  */
>       child_add_thread (current_event.dwProcessId,
> @@ -1695,6 +1698,33 @@ win32_request_interrupt (void)
>   soft_interrupt_requested = 1;
> }
>
> +static int
> +win32_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)
> +{
> +  size_t buf[4];
> +
> +  if (!myaddr)
> +    return -1;
> +
> +  if (offset > sizeof (buf))
> +    return -1;
> +
> +  if (offset == sizeof (buf))
> +    return 0;
> +
> +  if (offset + len > sizeof (buf))
> +    len = sizeof (buf) - offset;
> +
> +  buf[0] = 9; /* AT_ENTRY */
> +  buf[1] = current_exec_base;
> +  buf[2] = 0; /* AT_NULL */
> +  buf[3] = 0;
> +
> +  memcpy (myaddr, (char *) buf + offset, len);
> +
> +  return len;
> +}
> +
> #ifdef _WIN32_WCE
> int
> win32_error_to_fileio_error (DWORD err)
> @@ -1796,7 +1826,7 @@ static struct target_ops win32_target_ops = {
>   win32_write_inferior_memory,
>   NULL, /* lookup_symbols */
>   win32_request_interrupt,
> -  NULL, /* read_auxv */
> +  win32_read_auxv,
>   win32_supports_z_point_type,
>   win32_insert_point,
>   win32_remove_point,
> diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
> index 10d5c95d09..4a5d9230cc 100644
> --- a/gdb/windows-nat.c
> +++ b/gdb/windows-nat.c
> @@ -235,6 +235,7 @@ static DEBUG_EVENT current_event;    /* The current debug event from
>                       WaitForDebugEvent */
> static HANDLE current_process_handle;    /* Currently executing process */
> static windows_thread_info *current_thread;    /* Info on currently selected thread */
> +static CORE_ADDR current_exec_base;    /* Executable base address */
>
> /* Counts of things.  */
> static int exception_count = 0;
> @@ -1593,6 +1594,8 @@ get_windows_debug_event (struct target_ops *ops,
>     break;
>
>       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
> +      current_exec_base =
> +    (CORE_ADDR) current_event.u.CreateProcessInfo.lpBaseOfImage;
>       /* Add the main thread.  */
>       th = windows_add_thread
>         (ptid_t (current_event.dwProcessId, 0,
> @@ -2969,6 +2972,35 @@ windows_xfer_shared_libraries (struct target_ops *ops,
>   return len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF;
> }
>
> +static enum target_xfer_status
> +windows_xfer_auxv (gdb_byte *readbuf, ULONGEST offset, ULONGEST len,
> +          ULONGEST *xfered_len)
> +{
> +  CORE_ADDR buf[4];
> +
> +  if (!readbuf)
> +    return TARGET_XFER_E_IO;
> +
> +  if (offset > sizeof (buf))
> +    return TARGET_XFER_E_IO;
> +
> +  if (offset == sizeof (buf))
> +    return TARGET_XFER_EOF;
> +
> +  if (offset + len > sizeof (buf))
> +    len = sizeof (buf) - offset;
> +
> +  buf[0] = 9; /* AT_ENTRY */
> +  buf[1] = current_exec_base;
> +  buf[2] = 0; /* AT_NULL */
> +  buf[3] = 0;
> +
> +  memcpy (readbuf, (char *) buf + offset, len);
> +  *xfered_len = len;
> +
> +  return TARGET_XFER_OK;
> +}
> +
> enum target_xfer_status
> windows_nat_target::xfer_partial (enum target_object object,
>                   const char *annex, gdb_byte *readbuf,
> @@ -2984,6 +3016,9 @@ windows_nat_target::xfer_partial (enum target_object object,
>       return windows_xfer_shared_libraries (this, object, annex, readbuf,
>                         writebuf, offset, len, xfered_len);
>
> +    case TARGET_OBJECT_AUXV:
> +      return windows_xfer_auxv (readbuf, offset, len, xfered_len);
> +
>     default:
>       if (beneath () == NULL)
>     {
> diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
> index bb69a79996..03b69464db 100644
> --- a/gdb/windows-tdep.c
> +++ b/gdb/windows-tdep.c
> @@ -34,6 +34,10 @@
> #include "solib.h"
> #include "solib-target.h"
> #include "gdbcore.h"
> +#include "coff/internal.h"
> +#include "libcoff.h"
> +#include "solist.h"
> +#include "auxv.h"
>
> struct cmd_list_element *info_w32_cmdlist;
>
> @@ -461,6 +465,20 @@ init_w32_command_list (void)
>     }
> }
>
> +static void
> +windows_solib_create_inferior_hook (int from_tty)
> +{
> +  CORE_ADDR exec_base;
> +  /* 9 -> AT_ENTRY */
> +  if (target_auxv_search (current_top_target (), 9, &exec_base) == 1
> +      && exec_base && symfile_objfile)
> +    {
> +      CORE_ADDR vmaddr = pe_data (exec_bfd)->pe_opthdr.ImageBase;
> +      if (vmaddr != exec_base)
> +    objfile_rebase (symfile_objfile, exec_base - vmaddr);
> +    }
> +}
> +
> /* To be called from the various GDB_OSABI_CYGWIN handlers for the
>     various Windows architectures and machine types.  */
>
> @@ -477,6 +495,8 @@ windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>   set_gdbarch_iterate_over_objfiles_in_search_order
>     (gdbarch, windows_iterate_over_objfiles_in_search_order);
>
> +  solib_target_so_ops.solib_create_inferior_hook =
> +    windows_solib_create_inferior_hook;
>   set_solib_ops (gdbarch, &solib_target_so_ops);
> }
>
> --
> 2.24.1
  
Tom Tromey Jan. 21, 2020, 10:38 p.m. UTC | #2
>>>>> "Hannes" == Hannes Domani via gdb-patches <gdb-patches@sourceware.org> writes:

>> But I'm not at all sure about my approach to forward the image base
>> via auxv data, but I needed a solution that worked for gdbserver as well.

I don't know about this either :(.  Should it use the "library list
format" stuff instead?  Or, how does it work on Linux?

>> 
>> +static int
>> +win32_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)

New functions need an introductory comment.

>> 
>> +static enum target_xfer_status
>> +windows_xfer_auxv (gdb_byte *readbuf, ULONGEST offset, ULONGEST len,
>> +          ULONGEST *xfered_len)

Here too.

>> +  solib_target_so_ops.solib_create_inferior_hook =
>> +    windows_solib_create_inferior_hook;

"=" should be after the line break.

Tom
  

Patch

diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 449ed5f462..d453b89cdd 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -74,6 +74,7 @@  static int attaching = 0;
 static HANDLE current_process_handle = NULL;
 static DWORD current_process_id = 0;
 static DWORD main_thread_id = 0;
+static CORE_ADDR current_exec_base;	/* Executable base address */
 static enum gdb_signal last_sig = GDB_SIGNAL_0;
 
 /* The current debug event from WaitForDebugEvent.  */
@@ -1485,6 +1486,8 @@  get_child_debug_event (struct target_waitstatus *ourstatus)
 
       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
       main_thread_id = current_event.dwThreadId;
+      current_exec_base =
+	(CORE_ADDR) current_event.u.CreateProcessInfo.lpBaseOfImage;
 
       /* Add the main thread.  */
       child_add_thread (current_event.dwProcessId,
@@ -1695,6 +1698,33 @@  win32_request_interrupt (void)
   soft_interrupt_requested = 1;
 }
 
+static int
+win32_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)
+{
+  size_t buf[4];
+
+  if (!myaddr)
+    return -1;
+
+  if (offset > sizeof (buf))
+    return -1;
+
+  if (offset == sizeof (buf))
+    return 0;
+
+  if (offset + len > sizeof (buf))
+    len = sizeof (buf) - offset;
+
+  buf[0] = 9; /* AT_ENTRY */
+  buf[1] = current_exec_base;
+  buf[2] = 0; /* AT_NULL */
+  buf[3] = 0;
+
+  memcpy (myaddr, (char *) buf + offset, len);
+
+  return len;
+}
+
 #ifdef _WIN32_WCE
 int
 win32_error_to_fileio_error (DWORD err)
@@ -1796,7 +1826,7 @@  static struct target_ops win32_target_ops = {
   win32_write_inferior_memory,
   NULL, /* lookup_symbols */
   win32_request_interrupt,
-  NULL, /* read_auxv */
+  win32_read_auxv,
   win32_supports_z_point_type,
   win32_insert_point,
   win32_remove_point,
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 10d5c95d09..4a5d9230cc 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -235,6 +235,7 @@  static DEBUG_EVENT current_event;	/* The current debug event from
 					   WaitForDebugEvent */
 static HANDLE current_process_handle;	/* Currently executing process */
 static windows_thread_info *current_thread;	/* Info on currently selected thread */
+static CORE_ADDR current_exec_base;	/* Executable base address */
 
 /* Counts of things.  */
 static int exception_count = 0;
@@ -1593,6 +1594,8 @@  get_windows_debug_event (struct target_ops *ops,
 	break;
 
       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
+      current_exec_base =
+	(CORE_ADDR) current_event.u.CreateProcessInfo.lpBaseOfImage;
       /* Add the main thread.  */
       th = windows_add_thread
         (ptid_t (current_event.dwProcessId, 0,
@@ -2969,6 +2972,35 @@  windows_xfer_shared_libraries (struct target_ops *ops,
   return len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF;
 }
 
+static enum target_xfer_status
+windows_xfer_auxv (gdb_byte *readbuf, ULONGEST offset, ULONGEST len,
+		   ULONGEST *xfered_len)
+{
+  CORE_ADDR buf[4];
+
+  if (!readbuf)
+    return TARGET_XFER_E_IO;
+
+  if (offset > sizeof (buf))
+    return TARGET_XFER_E_IO;
+
+  if (offset == sizeof (buf))
+    return TARGET_XFER_EOF;
+
+  if (offset + len > sizeof (buf))
+    len = sizeof (buf) - offset;
+
+  buf[0] = 9; /* AT_ENTRY */
+  buf[1] = current_exec_base;
+  buf[2] = 0; /* AT_NULL */
+  buf[3] = 0;
+
+  memcpy (readbuf, (char *) buf + offset, len);
+  *xfered_len = len;
+
+  return TARGET_XFER_OK;
+}
+
 enum target_xfer_status
 windows_nat_target::xfer_partial (enum target_object object,
 				  const char *annex, gdb_byte *readbuf,
@@ -2984,6 +3016,9 @@  windows_nat_target::xfer_partial (enum target_object object,
       return windows_xfer_shared_libraries (this, object, annex, readbuf,
 					    writebuf, offset, len, xfered_len);
 
+    case TARGET_OBJECT_AUXV:
+      return windows_xfer_auxv (readbuf, offset, len, xfered_len);
+
     default:
       if (beneath () == NULL)
 	{
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index bb69a79996..03b69464db 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -34,6 +34,10 @@ 
 #include "solib.h"
 #include "solib-target.h"
 #include "gdbcore.h"
+#include "coff/internal.h"
+#include "libcoff.h"
+#include "solist.h"
+#include "auxv.h"
 
 struct cmd_list_element *info_w32_cmdlist;
 
@@ -461,6 +465,20 @@  init_w32_command_list (void)
     }
 }
 
+static void
+windows_solib_create_inferior_hook (int from_tty)
+{
+  CORE_ADDR exec_base;
+  /* 9 -> AT_ENTRY */
+  if (target_auxv_search (current_top_target (), 9, &exec_base) == 1
+      && exec_base && symfile_objfile)
+    {
+      CORE_ADDR vmaddr = pe_data (exec_bfd)->pe_opthdr.ImageBase;
+      if (vmaddr != exec_base)
+	objfile_rebase (symfile_objfile, exec_base - vmaddr);
+    }
+}
+
 /* To be called from the various GDB_OSABI_CYGWIN handlers for the
    various Windows architectures and machine types.  */
 
@@ -477,6 +495,8 @@  windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_iterate_over_objfiles_in_search_order
     (gdbarch, windows_iterate_over_objfiles_in_search_order);
 
+  solib_target_so_ops.solib_create_inferior_hook =
+    windows_solib_create_inferior_hook;
   set_solib_ops (gdbarch, &solib_target_so_ops);
 }