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

Hannes Domani via gdb-patches gdb-patches@sourceware.org
Tue Feb 11 11:34:00 GMT 2020


 Am Dienstag, 11. Februar 2020, 01:29:44 MEZ hat Luis Machado <luis.machado@linaro.org> Folgendes geschrieben:

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

OK.


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

OK.


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

Yes.


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

Right.


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

I've used this approach for a while now, and never had any problem with it.
Also, gnu-nat.c creates a fake auxv entry as well.


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

I'm not sure how that would work.


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

I agree that this would be the cleanest solution, but I thought touching
the gdbserver interface isn't the best idea when it can be avoided.


Regards
Hannes Domani



More information about the Gdb-patches mailing list