[PING] [PATCH] Rebase executable to match relocated base address

Luis Machado luis.machado@linaro.org
Tue Feb 11 00:29:00 GMT 2020


On 2/8/20 1:37 PM, Hannes Domani via gdb-patches wrote:
> Ping.
> 
> Am Samstag, 25. Januar 2020, 17:47:19 MEZ hat Hannes Domani via gdb-patches <gdb-patches@sourceware.org> Folgendes geschrieben:
> 
>> 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(-)
>>
>> 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 */

Set current_exec_base to 0 so it gets explicitly initialized?

>> 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;

Formatting of the second line looks funny. Should be moved forward.

Has the lpBaseOfImage member variable always been there and was never 
used? From what i looked at MSDN, it looks like it.

>>
>>         /* 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)

Missing documentation for this function.

This function is needed, but the question is how it should get the base 
address from the target.

The auxv trickery works, but that may have other implications. I'm not 
sure if GDB won't try to fetch more stuff given we now have an "auxv". 
And it is also a bit misleading.

Is there some other way one can fetch this data? Registers? Memory?

If not, then maybe we could create a new qxfer request to fetch this 
data for Windows, say, TARGET_OBJECT_WINDOWS_LOADBASE. It would be 
cleaner and would handle both gdbserver and gdb.

In case we want to make the request more generic, maybe call it 
TARGET_OBJECT_EXEC_LOADBASE or somesuch.



More information about the Gdb-patches mailing list