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

Jan Kratochvil jan.kratochvil at redhat.com
Thu Oct 11 06:22:10 UTC 2012


Hi Roland,

jankratochvil/auxv32

On Thu, 11 Oct 2012 00:27:35 +0200, Roland McGrath wrote:
> The problem is indeed obvious.  I really wish there were a better way to
> detect the bit-width of the process than looking at /proc/PID/exe, but
> perhaps there really isn't.
> 
> What about just looking at the first 8 bytes of the auxv data?  The first
> element is never AT_NULL, so it will have a nonzero a_type.  No a_type
> value will ever be more than UINT32_MAX.  So for big-endian, the first four
> bytes being zero says it's 64-bit.  For little-endian, it's not so easy
> without assuming that the first a_val is nonzero.  That's actually reliable
> enough in practice, but it feels wrong.  Maybe there is something better
> for little-endian that I'm not thinking of.

I had similar concerns.


Done the other changes.


Thanks,
Jan


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

    libdwfl/
    linux-proc-maps.c: Include system.h.
    (PROCEXEFMT, get_pid_class): New.
    (grovel_auxv): New parameter pid_class.  Use it.
    (dwfl_linux_proc_report): New variable pid_class, initialize it by
    get_pid_class, use it for grovel_auxv.
    
    Signed-off-by: Jan Kratochvil <jan.kratochvil at redhat.com>

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 189d3b7..c18362c 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,11 @@
+2012-10-11  Jan Kratochvil  <jan.kratochvil at redhat.com>
+
+	* linux-proc-maps.c: Include system.h.
+	(PROCEXEFMT, get_pid_class): New.
+	(grovel_auxv): New parameter pid_class.  Use it.
+	(dwfl_linux_proc_report): New variable pid_class, initialize it by
+	get_pid_class, use it for grovel_auxv.
+
 2012-10-10  Jan Kratochvil  <jan.kratochvil at redhat.com>
 
 	* dwfl_segment_report_module.c (dwfl_segment_report_module):
diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c
index 4fbe90d..2ac0e3e 100644
--- a/libdwfl/linux-proc-maps.c
+++ b/libdwfl/linux-proc-maps.c
@@ -39,17 +39,47 @@
 #include <unistd.h>
 #include <assert.h>
 #include <endian.h>
+#include "system.h"
 
 
 #define PROCMAPSFMT	"/proc/%d/maps"
 #define PROCMEMFMT	"/proc/%d/mem"
 #define PROCAUXVFMT	"/proc/%d/auxv"
+#define PROCEXEFMT	"/proc/%d/exe"
 
 
+/* Return ELFCLASS64 or ELFCLASS32 for the main ELF executable.  Return
+   ELFCLASSNONE for an error.  */
+
+static unsigned char
+get_pid_class (pid_t pid)
+{
+  char *fname;
+  if (asprintf (&fname, PROCEXEFMT, pid) < 0)
+    return ELFCLASSNONE;
+
+  int fd = open64 (fname, O_RDONLY);
+  free (fname);
+  if (fd < 0)
+    return ELFCLASSNONE;
+
+  unsigned char buf[EI_CLASS + 1];
+  ssize_t nread = pread_retry (fd, &buf, sizeof buf, 0);
+  close (fd);
+  if (nread != sizeof (buf) || buf[EI_MAG0] != ELFMAG0
+      || buf[EI_MAG1] != ELFMAG1 || buf[EI_MAG2] != ELFMAG2
+      || buf[EI_MAG3] != ELFMAG3
+      || (buf[EI_CLASS] != ELFCLASS64 && buf[EI_CLASS] != ELFCLASS32))
+    return ELFCLASSNONE;
+
+  return buf[EI_CLASS];
+}
+
 /* 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, unsigned char pid_class,
+	     GElf_Addr *sysinfo_ehdr)
 {
   char *fname;
   if (asprintf (&fname, PROCAUXVFMT, pid) < 0)
@@ -72,9 +102,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 (pid_class)
 	    {
-	    case 4:
+	    case ELFCLASS32:
 	      for (size_t i = 0; (char *) &d.a32[i] < &d.buffer[nread]; ++i)
 		if (d.a32[i].a_type == AT_SYSINFO_EHDR)
 		  {
@@ -89,7 +119,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 ELFCLASS64:
 	      for (size_t i = 0; (char *) &d.a64[i] < &d.buffer[nread]; ++i)
 		if (d.a64[i].a_type == AT_SYSINFO_EHDR)
 		  {
@@ -227,9 +257,13 @@ dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid)
   if (dwfl == NULL)
     return -1;
 
+  unsigned char pid_class = get_pid_class (pid);
+  if (pid_class == ELFCLASSNONE)
+    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, pid_class, &sysinfo_ehdr);
   if (result != 0)
     return result;
 


More information about the elfutils-devel mailing list