From 02d61ee510a4fab8b2860505e3a8fb3b32779670 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Wed, 10 Oct 2012 20:42:30 +0200 Subject: libdwfl/ linux-proc-maps.c: Include system.h. (PROCEXEFMT, get_pid_class): New. (grovel_auxv): Detect 32-bit vs. 64-bit auxv, possibly call get_pid_class. Signed-off-by: Jan Kratochvil --- libdwfl/ChangeLog | 7 +++ libdwfl/linux-proc-maps.c | 129 ++++++++++++++++++++++++++++++---------------- 2 files changed, 93 insertions(+), 43 deletions(-) diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index bdd9440f..824daf19 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,10 @@ +2012-10-27 Jan Kratochvil + + * linux-proc-maps.c: Include system.h. + (PROCEXEFMT, get_pid_class): New. + (grovel_auxv): Detect 32-bit vs. 64-bit auxv, possibly call + get_pid_class. + 2012-10-17 Jan Kratochvil * dwfl_module_getdwarf.c (mod_verify_build_id): New function with code diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c index 4fbe90d1..feed6a11 100644 --- a/libdwfl/linux-proc-maps.c +++ b/libdwfl/linux-proc-maps.c @@ -39,13 +39,42 @@ #include #include #include +#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 @@ -60,61 +89,75 @@ grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr) if (fd < 0) return errno == ENOENT ? 0 : errno; + GElf_Addr sysinfo_ehdr64 = 0, sysinfo_ehdr32 = 0; + GElf_Addr segment_align64 = dwfl->segment_align; + GElf_Addr segment_align32 = dwfl->segment_align; + off_t offset = 0; ssize_t nread; + union + { + Elf64_auxv_t a64[64]; + Elf32_auxv_t a32[128]; + } d; do { - union - { - char buffer[sizeof (long int) * 2 * 64]; - Elf64_auxv_t a64[sizeof (long int) * 2 * 64 / sizeof (Elf64_auxv_t)]; - Elf32_auxv_t a32[sizeof (long int) * 2 * 32 / sizeof (Elf32_auxv_t)]; - } d; - nread = read (fd, &d, sizeof d); - if (nread > 0) + eu_static_assert (sizeof d.a64 == sizeof d.a32); + nread = pread_retry (fd, d.a64, sizeof d.a64, offset); + if (nread < 0) + return errno; + for (unsigned a32i = 0; a32i < nread / sizeof d.a32[0]; a32i++) { - switch (sizeof (long int)) - { - case 4: - for (size_t i = 0; (char *) &d.a32[i] < &d.buffer[nread]; ++i) - if (d.a32[i].a_type == AT_SYSINFO_EHDR) - { - *sysinfo_ehdr = d.a32[i].a_un.a_val; - if (dwfl->segment_align > 1) - { - nread = 0; - break; - } - } - else if (d.a32[i].a_type == AT_PAGESZ - && dwfl->segment_align <= 1) - dwfl->segment_align = d.a32[i].a_un.a_val; + const Elf32_auxv_t *a32 = d.a32 + a32i; + switch (a32->a_type) + { + case AT_SYSINFO_EHDR: + sysinfo_ehdr32 = a32->a_un.a_val; break; - case 8: - for (size_t i = 0; (char *) &d.a64[i] < &d.buffer[nread]; ++i) - if (d.a64[i].a_type == AT_SYSINFO_EHDR) - { - *sysinfo_ehdr = d.a64[i].a_un.a_val; - if (dwfl->segment_align > 1) - { - nread = 0; - break; - } - } - else if (d.a64[i].a_type == AT_PAGESZ - && dwfl->segment_align <= 1) - dwfl->segment_align = d.a64[i].a_un.a_val; + case AT_PAGESZ: + segment_align32 = a32->a_un.a_val; break; - default: - abort (); + } + } + for (unsigned a64i = 0; a64i < nread / sizeof d.a64[0]; a64i++) + { + const Elf64_auxv_t *a64 = d.a64 + a64i; + switch (a64->a_type) + { + case AT_SYSINFO_EHDR: + sysinfo_ehdr64 = a64->a_un.a_val; break; - } + case AT_PAGESZ: + segment_align64 = a64->a_un.a_val; + break; + } } + offset += nread; } - while (nread > 0); + while (nread == sizeof d.a64); close (fd); - return nread < 0 ? errno : 0; + bool valid64 = sysinfo_ehdr64 || segment_align64 != dwfl->segment_align; + bool valid32 = sysinfo_ehdr32 || segment_align32 != dwfl->segment_align; + + if (! valid64 && ! valid32) + return 0; + + unsigned char pid_class = ELFCLASSNONE; + if (valid64 && valid32) + pid_class = get_pid_class (pid); + + if (pid_class == ELFCLASS64 || (valid64 && ! valid32)) + { + *sysinfo_ehdr = sysinfo_ehdr64; + dwfl->segment_align = segment_align64; + } + if (pid_class == ELFCLASS32 || (! valid64 && valid32)) + { + *sysinfo_ehdr = sysinfo_ehdr32; + dwfl->segment_align = segment_align32; + } + return 0; } static int -- cgit v1.2.3