Rebase executable to match relocated base address

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

Commit Message

Terekhov, Mikhail via Gdb-patches Jan. 25, 2020, 4:42 p.m. UTC
  Compared to the [RFC], only Tom's noticed coding style problems were
fixed.

binutils 2.34 will have an improved -dynamicbase (so far this only
worked with some workarounds for executables), so the rebasing problem
might get more relevant in the future.


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.

The transfer of the new base address is done via a fake auxv entry,
so it's working with gdbserver as well.

gdb/ChangeLog:

2020-01-25  Hannes Domani  <ssbssa@yahoo.de>

	* windows-nat.c (windows_nat_target::get_windows_debug_event):
	Set current_exec_base.
	(windows_xfer_auxv): New function.
	(windows_nat_target::xfer_partial): Call windows_xfer_auxv.
	* windows-tdep.c (windows_solib_create_inferior_hook): New function.
	(windows_init_abi): Use windows_solib_create_inferior_hook.

gdb/gdbserver/ChangeLog:

2020-01-25  Hannes Domani  <ssbssa@yahoo.de>

	* win32-low.c (get_child_debug_event): Set current_exec_base.
	(win32_read_auxv): New function.
---
 gdb/gdbserver/win32-low.c | 35 ++++++++++++++++++++++++++++++++++-
 gdb/windows-nat.c         | 38 ++++++++++++++++++++++++++++++++++++++
 gdb/windows-tdep.c        | 20 ++++++++++++++++++++
 3 files changed, 92 insertions(+), 1 deletion(-)
  

Patch

diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 2c4a9b1074..2f6fe5785e 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -75,6 +75,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.  */
@@ -1486,6 +1487,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,
@@ -1713,6 +1716,36 @@  win32_request_interrupt (void)
   soft_interrupt_requested = 1;
 }
 
+/* Windows does not have auxv, but this creates a fake AT_ENTRY entry
+   which is the base address of the executable.  */
+
+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)
@@ -1814,7 +1847,7 @@  static process_stratum_target 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 366c98fbf3..459bb10fe9 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -236,6 +236,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;
@@ -1604,6 +1605,8 @@  windows_nat_target::get_windows_debug_event (int pid,
 	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,
@@ -2996,6 +2999,38 @@  windows_xfer_shared_libraries (struct target_ops *ops,
   return len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF;
 }
 
+/* Windows does not have auxv, but this creates a fake AT_ENTRY entry
+   which is the base address of the executable.  */
+
+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,
@@ -3011,6 +3046,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 6c9632d035..fd491e8e67 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"
 
 /* Windows signal numbers differ between MinGW flavors and between
    those and Cygwin.  The below enumeration was gleaned from the
@@ -656,6 +660,20 @@  windows_gdb_signal_to_target (struct gdbarch *gdbarch, enum gdb_signal signal)
   return -1;
 }
 
+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.  */
 
@@ -674,6 +692,8 @@  windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   set_gdbarch_gdb_signal_to_target (gdbarch, windows_gdb_signal_to_target);
 
+  solib_target_so_ops.solib_create_inferior_hook
+    = windows_solib_create_inferior_hook;
   set_solib_ops (gdbarch, &solib_target_so_ops);
 }