[patch] Fix 64-bit->32-bit vDSO reporting

Jan Kratochvil jan.kratochvil at redhat.com
Wed Oct 10 18:56:43 UTC 2012


Hi Roland,

jankratochvil/auxv32

the problem is obvious I think.  I do not see how to write an easy testcase.
It is tested on the jankratochvil/unwind branch but a more minimal testcase
would just be a partial duplication of that testcase also involving biarch
compilation and ptrace attachment.

FAIL->PASS

0xf7502000	0xf76b0000	/lib/libc-2.14.90.so
0xf76b3000	0xf76cc000	/lib/libpthread-2.14.90.so
0xf76ec000	0xf770f000	/lib/ld-2.14.90.so
0xf770f000	0xf7711000	/home/jkratoch/redhat/elfutils-clean/tests/backtrace-child-biarch
TID 29871:
# 0 0xf76eb430    	(null)
No DWARF information found
[...]
->
0xf74ff000	0xf76ad000	/lib/libc-2.14.90.so
0xf76b0000	0xf76c9000	/lib/libpthread-2.14.90.so
0xf76e8000	0xf76e9000	[vdso: 29682]
0xf76e9000	0xf770c000	/lib/ld-2.14.90.so
0xf770c000	0xf770e000	/home/jkratoch/redhat/elfutils-clean/tests/backtrace-child-biarch
TID 29683:
# 0 0xf76e8430    	__kernel_vsyscall
[...]

One can see [vdso: 29682] is not reported above at all.


Thanks,
Jan


commit 77d700999426dec7004ea41af89376580aab264c
Author: Jan Kratochvil <jan.kratochvil at redhat.com>
Date:   Wed Oct 10 20:42:30 2012 +0200

    libdwfl/
    2012-10-10  Jan Kratochvil  <jan.kratochvil at redhat.com>
    
    	* linux-proc-maps.c (PROCEXEFMT, get_pid_width): New.
    	(grovel_auxv): New parameter width.  Use it.
    	(dwfl_linux_proc_report): New variable width, initialize it by
    	get_pid_width, use it for grovel_auxv.
    
    Signed-off-by: Jan Kratochvil <jan.kratochvil at redhat.com>

diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c
index 4fbe90d..327eb32 100644
--- a/libdwfl/linux-proc-maps.c
+++ b/libdwfl/linux-proc-maps.c
@@ -44,12 +44,39 @@
 #define PROCMAPSFMT	"/proc/%d/maps"
 #define PROCMEMFMT	"/proc/%d/mem"
 #define PROCAUXVFMT	"/proc/%d/auxv"
+#define PROCEXEFMT	"/proc/%d/exe"
 
 
+/* Return 64 for 64-bit main ELF executable, 32 accordingly otherwise.
+   Return -1 for errors.  */
+
+static int
+get_pid_width (pid_t pid)
+{
+  char *fname;
+  if (asprintf (&fname, PROCEXEFMT, pid) < 0)
+    return -1;
+
+  int fd = open64 (fname, O_RDONLY);
+  free (fname);
+  if (fd < 0)
+    return -1;
+
+  unsigned char buf[5];
+  ssize_t nread = read (fd, &buf, sizeof buf);
+  close (fd);
+  if (nread != sizeof (buf) || buf[0] != ELFMAG0 || buf[1] != ELFMAG1
+      || buf[2] != ELFMAG2 || buf[3] != ELFMAG3
+      || (buf[4] != ELFCLASS64 && buf[4] != ELFCLASS32))
+    return -1;
+
+  return buf[4] == ELFCLASS64 ? 64 : 32;
+}
+
 /* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag.  */
 
 static int
-grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr)
+grovel_auxv (pid_t pid, Dwfl *dwfl, int width, GElf_Addr *sysinfo_ehdr)
 {
   char *fname;
   if (asprintf (&fname, PROCAUXVFMT, pid) < 0)
@@ -72,9 +99,9 @@ grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr)
       nread = read (fd, &d, sizeof d);
       if (nread > 0)
 	{
-	  switch (sizeof (long int))
+	  switch (width)
 	    {
-	    case 4:
+	    case 32:
 	      for (size_t i = 0; (char *) &d.a32[i] < &d.buffer[nread]; ++i)
 		if (d.a32[i].a_type == AT_SYSINFO_EHDR)
 		  {
@@ -89,7 +116,7 @@ grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr)
 			 && dwfl->segment_align <= 1)
 		  dwfl->segment_align = d.a32[i].a_un.a_val;
 	      break;
-	    case 8:
+	    case 64:
 	      for (size_t i = 0; (char *) &d.a64[i] < &d.buffer[nread]; ++i)
 		if (d.a64[i].a_type == AT_SYSINFO_EHDR)
 		  {
@@ -227,9 +254,13 @@ dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid)
   if (dwfl == NULL)
     return -1;
 
+  int width = get_pid_width (pid);
+  if (width == -1)
+    return -1;
+
   /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it.  */
   GElf_Addr sysinfo_ehdr = 0;
-  int result = grovel_auxv (pid, dwfl, &sysinfo_ehdr);
+  int result = grovel_auxv (pid, dwfl, width, &sysinfo_ehdr);
   if (result != 0)
     return result;
 


More information about the elfutils-devel mailing list