vdso handling

Message ID 53357B30.6040006@redhat.com
State Not applicable
Headers

Commit Message

Pedro Alves March 28, 2014, 1:37 p.m. UTC
  On 03/28/2014 06:13 AM, Alan Modra wrote:
> On Fri, Mar 21, 2014 at 03:48:48PM +0000, Pedro Alves wrote:
>> I just tried pointing add-symbol-file-from-memory at an already
>> mapped DSO's elf header, but it doesn't work as is unfortunately:
>>
>>  (gdb) info shared curses
>>  0x000000324d006d20  0x000000324d01df58  Yes         /lib64/libncurses.so.5
>>  (gdb) x /4b 0x000000324d000000
>>  0x324d000000:   127     69      76      70
>>  (gdb) add-symbol-file-from-memory 0x000000324d000000
>>  Failed to read a valid object file image from memory.
>>
>> I single stepped a little through
>> bfd_elf_bfd_from_remote_memory - something goes wrong with the
>> reading of the load segment contents, probably something wrong
>> with the address computations.
> 
> readelf -a --wide on my x86_64 libncurses.so.5 shows
> 
> [snip]
>   Start of section headers:          132144 (bytes into file)
> [snip]
>   [25] .shstrtab         STRTAB          0000000000000000 02034c 0000de 00      0   0  1
> [snip]
>   LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x01efe4 0x01efe4 R E 0x200000
>   LOAD           0x01fd50 0x000000000021fd50 0x000000000021fd50 0x0005e4 0x000770 RW  0x200000
> 
> So .shstrtab and the section headers might have been loaded by the
> second PT_LOAD header, *but* the second PT_LOAD has a bss area.
> Anything past 0x220334 will be cleared out by ld.so.  No chance of
> getting at section headers then, and this will be true for most
> in-memory images.

Indeed.

> bfd_from_remote_memory should take note of p_memsz..  Hmm, and there
> are quite a few other issues there too, most notably that p_align
> on x86_64 these days tends to be *much* larger than the page size used
> by ld.so.

Hmm.  Indeed.  With current mainline, and with your patch as is,
the command still fails for me.  In fact, it turns out
exactly related to p_align vs page size.

$ cat /proc/30669/maps | grep ncurses
324d000000-324d023000 r-xp 00000000 fd:01 315662                         /usr/lib64/libncurses.so.5.9
324d023000-324d222000 ---p 00023000 fd:01 315662                         /usr/lib64/libncurses.so.5.9
324d222000-324d223000 r--p 00022000 fd:01 315662                         /usr/lib64/libncurses.so.5.9
324d223000-324d224000 rw-p 00023000 fd:01 315662                         /usr/lib64/libncurses.so.5.9

So when trying to read the second PT_LOAD with p_vmaddr 324d222cf8
and p_vmaddr+p_filesz 324d2236b4, (the 3rd and 4th region above),
we'd end up reading from 324d200000 to 324d2236b4:

(top-gdb) p /x loadbase + vaddr
$5 = 0x324d200000
(top-gdb) p /x end
$6 = 0x236b4
(top-gdb) p /x loadbase + vaddr + end
$8 = 0x324d2236b4

which fails as it hits the (324d023000-324d222000) region,
which has no permissions.

This patch on top of yours makes things work for me:

---
 bfd/elfcode.h | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
  

Patch

diff --git a/bfd/elfcode.h b/bfd/elfcode.h
index 31f67a8..974c8b4 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -1622,6 +1622,7 @@  NAME(_bfd_elf,bfd_from_remote_memory)
   bfd_vma shdr_end;
   bfd_vma loadbase;
   bfd_boolean loadbase_set;
+  bfd_vma page_size;

   /* Read in the ELF header in external format.  */
   err = target_read_memory (ehdr_vma, (bfd_byte *) &x_ehdr, sizeof x_ehdr);
@@ -1693,6 +1694,7 @@  NAME(_bfd_elf,bfd_from_remote_memory)
     }
   i_phdrs = (Elf_Internal_Phdr *) &x_phdrs[i_ehdr.e_phnum];

+  page_size = get_elf_backend_data (templ)->minpagesize;
   high_offset = 0;
   last_phdr = NULL;
   loadbase = 0;
@@ -1753,7 +1755,6 @@  NAME(_bfd_elf,bfd_from_remote_memory)
 	high_offset = shdr_end;
       else
 	{
-	  bfd_vma page_size = get_elf_backend_data (templ)->minpagesize;
 	  bfd_vma segment_end = last_phdr->p_offset + last_phdr->p_filesz;

 	  /* Assume we loaded full pages, allowing us to sometimes see
@@ -1781,15 +1782,14 @@  NAME(_bfd_elf,bfd_from_remote_memory)
     if (i_phdrs[i].p_type == PT_LOAD)
       {
 	bfd_vma start = i_phdrs[i].p_offset;
-	bfd_vma end = start + i_phdrs[i].p_filesz;
 	bfd_vma vaddr = i_phdrs[i].p_vaddr;
+	bfd_vma end = start + i_phdrs[i].p_filesz;

-	if (i_phdrs[i].p_align > 1)
-	  {
-	    start &= -i_phdrs[i].p_align;
-	    end = (end + i_phdrs[i].p_align - 1) & -i_phdrs[i].p_align;
-	    vaddr &= -i_phdrs[i].p_align;
-	  }
+	/* Assume we loaded full pages, allowing us to sometimes see
+	   section headers.  */
+	start &= -page_size;
+	vaddr &= -page_size;
+	end = (end + page_size - 1) & -page_size;
 	if (end > high_offset)
 	  end = high_offset;
 	err = target_read_memory (loadbase + vaddr,