[win32] wrong solib from/to addresses

Joel Brobecker
2007-06-12T20:47:41Z

[-- Attachment #1: Type: text/plain, Size: 1781 bytes --]

Hello,

We are working on porting our product to Vista, and we have noticed
an issue that this version of the MS OS makes more apparent: The from/to
addresses printed in the "info shared" listing are correct only when
the DLL was loaded at the prefered load address (which is in the
ImageBase field of the COFF/PE header).

I collegue of mine told me that, for security reasons, system DLLs
on Vista are now always rebased, and thus, the information printed
by info based is off by a certain offset.

The core of the attached patch is to implement the target_so_ops
method relocate_section_addresses. For that, I needed to compute
the offset between the load address and the image_base, and store
it for later use (during the call of our routine above). There
were two challenges:

1. Compute this image base. Rather than dig into the COFF/PE
data, I took a simpler route that I think has already been
taken: Use the start address of the .text section. I think
this is already used to do the symbol relocation.

2. Make that information available: I found that the lm_info
field was not allocated, so I had to add its initialization.

With all these changes, the address are correct again.

2007-06-12 Joel Brobecker <brobecker@adacore.com>

* win32-nat.c (struct lm_info): Add new field image_base.
(solib_symbols_add): Compute the prefered load address
and save it in the lm_info.
(register_loaded_dll): Initialize new field image_base.
(win32_relocate_section_addresses): Implement this routine.
(win32_current_sos): Allocate and set lm_info data.

Tested on x86-windows, no regression. Dejagnu on Vista is not working
at all for me, so I ran the testsuite on XP instead.

OK to apply?

Thanks,
--
Joel

[-- Attachment #2: win32-solib-fsf.diff --]
[-- Type: text/plain, Size: 3057 bytes --]

Index: gdb/win32-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/win32-nat.c,v
retrieving revision 1.131
diff -u -p -r1.131 win32-nat.c
--- gdb/win32-nat.c 31 May 2007 17:32:21 -0000 1.131
+++ gdb/win32-nat.c 12 Jun 2007 20:17:19 -0000
@@ -541,6 +541,9 @@ struct safe_symbol_file_add_args
struct lm_info
{
DWORD load_addr;
+
+ /* The ImageBase, aka the prefered load address. */
+ CORE_ADDR image_base;
};

static struct so_list solib_start, *solib_end;
@@ -659,6 +662,7 @@ solib_symbols_add (struct so_list *so, C
static struct objfile *result = NULL;
char *name = so->so_name;
bfd *abfd = NULL;
+ asection *text = NULL;
char *p;

/* The symbols in a dll are offset by 0x1000, which is the
@@ -701,10 +705,19 @@ solib_symbols_add (struct so_list *so, C
do_cleanups (my_cleanups);
}

+ if (abfd != NULL)
+ text = bfd_get_section_by_name (abfd, ".text");
+
+ /* Compute the ImageBase of our DLL. For that, we assume that
+ it is identical to the VMA of the ".text" section. This is
+ an assumption that is being made in other places already,
+ so this should be ok. */
+ if (text != NULL)
+ so->lm_info->image_base = bfd_section_vma (abfd, text);
+
p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
if (p >= so->so_name && strcasecmp (p, "/cygwin1.dll") == 0)
{
- asection *text = bfd_get_section_by_name (abfd, ".text");
cygwin_load_start = bfd_section_vma (abfd, text);
cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text);
}
@@ -752,6 +765,7 @@ register_loaded_dll (const char *name, D
so = XZALLOC (struct so_list);
so->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info));
so->lm_info->load_addr = load_addr;
+ so->lm_info->image_base = 0; /* Will be filled in later. */
cygwin_conv_to_posix_path (buf, so->so_name);
strcpy (so->so_original_name, so->so_name);

@@ -842,8 +856,18 @@ static void
win32_relocate_section_addresses (struct so_list *so,
struct section_table *sec)
{
- /* FIXME */
- return;
+ const DWORD load_addr = so->lm_info->load_addr;
+ const CORE_ADDR image_base = so->lm_info->image_base;
+
+ /* If we couldn't determine the DLL prefered load address (image base),
+ then we can't adjust the section addresses. Assume that the DLL was
+ loaded at the prefered load address, which means that the second
+ addresses do not need to be adjusted. */
+ if (image_base == 0)
+ return;
+
+ sec->addr = sec->addr - image_base + load_addr;
+ sec->endaddr = sec->endaddr - image_base + load_addr;
}

static void
@@ -2231,6 +2255,8 @@ win32_current_sos (void)
struct so_list *new = XZALLOC (struct so_list);
strcpy (new->so_name, sop->so_name);
strcpy (new->so_original_name, sop->so_original_name);
+ new->lm_info = xmalloc (sizeof (struct lm_info));
+ memcpy (new->lm_info, sop->lm_info, sizeof (struct lm_info));
if (!start)
last = start = new;
else