commit:     9b36cb0609e6553f2c89c0b5909aa8c6482f9c7f
Author:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
AuthorDate: Sun Jan  3 21:32:47 2016 +0000
Commit:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
CommitDate: Sun Jan  3 21:32:47 2016 +0000
URL:        https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=9b36cb06

dumpelf: improve decoding

- push down section header validity checks (previous one was too strict)
- fix section header walking (was missing braces in for loop)
- dump all of the pad bytes in the elf header
- expand program header output and decode/explain more fields
- use uintptr_t for doing pointer math
- handle SHT_NOBITS better

 dumpelf.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 76 insertions(+), 26 deletions(-)

diff --git a/dumpelf.c b/dumpelf.c
index 8abad61..d765164 100644
--- a/dumpelf.c
+++ b/dumpelf.c
@@ -111,10 +111,7 @@ static void dumpelf(const char *filename, long file_cnt)
                } \
                offset = EGET(strtbl->sh_offset); \
                for (i = 0; i < shnum; ++i, ++shdr) \
-                       if (!VALID_SHDR(elf, shdr)) { \
-                               printf(" /* corrupt section headers ! */ "); \
-                               break; \
-                       } \
+                       /* Don't use VALID_SHDR as we want to decode the fields 
*/ \
                        dump_shdr(elf, shdr, i, elf->vdata + offset + 
EGET(shdr->sh_name)); \
                }
                DUMP_SHDRS(32)
@@ -155,6 +152,7 @@ static void dumpelf(const char *filename, long file_cnt)
        /* get out of here */
        unreadelf(elf);
 }
+
 static void dump_ehdr(elfobj *elf, const void *ehdr_void)
 {
 #define DUMP_EHDR(B) \
@@ -168,8 +166,7 @@ static void dump_ehdr(elfobj *elf, const void *ehdr_void)
               "\t\t/* [%i] EI_VERSION:    */ %i , /* (%s) */\n" \
               "\t\t/* [%i] EI_OSABI:      */ %i , /* (%s) */\n" \
               "\t\t/* [%i] EI_ABIVERSION: */ %i ,\n" \
-              "\t\t/* [%i] EI_PAD:        */ 0x%02X /* x %i bytes */\n" \
-              /* "\t\t/ [%i] EI_BRAND:      / 0x%02X\n" */ \
+              "\t\t/* [%i-%i] EI_PAD:     */ 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 
0x%X, 0x%X,\n" \
               "\t},\n", \
               EI_MAG0, (unsigned int)ehdr->e_ident[EI_MAG0], 
ehdr->e_ident[EI_MAG1], ehdr->e_ident[EI_MAG2], ehdr->e_ident[EI_MAG3], \
               EI_CLASS, (int)ehdr->e_ident[EI_CLASS], get_elfeitype(EI_CLASS, 
ehdr->e_ident[EI_CLASS]), \
@@ -177,18 +174,25 @@ static void dump_ehdr(elfobj *elf, const void *ehdr_void)
               EI_VERSION, (int)ehdr->e_ident[EI_VERSION], 
get_elfeitype(EI_VERSION, ehdr->e_ident[EI_VERSION]), \
               EI_OSABI, (int)ehdr->e_ident[EI_OSABI], get_elfeitype(EI_OSABI, 
ehdr->e_ident[EI_OSABI]), \
               EI_ABIVERSION, (int)ehdr->e_ident[EI_ABIVERSION], \
-              EI_PAD, (unsigned int)ehdr->e_ident[EI_PAD], EI_NIDENT - EI_PAD \
-              /* EI_BRAND, ehdr->e_ident[EI_BRAND] */ \
+              EI_PAD, EI_NIDENT - 1, \
+                (unsigned int)ehdr->e_ident[EI_PAD + 0], \
+                (unsigned int)ehdr->e_ident[EI_PAD + 1], \
+                (unsigned int)ehdr->e_ident[EI_PAD + 2], \
+                (unsigned int)ehdr->e_ident[EI_PAD + 3], \
+                (unsigned int)ehdr->e_ident[EI_PAD + 4], \
+                (unsigned int)ehdr->e_ident[EI_PAD + 5], \
+                (unsigned int)ehdr->e_ident[EI_PAD + 6] \
        ); \
        printf("\t.e_type      = %-10i , /* (%s) */\n", 
(int)EGET(ehdr->e_type), get_elfetype(elf)); \
        printf("\t.e_machine   = %-10i , /* (%s) */\n", 
(int)EGET(ehdr->e_machine), get_elfemtype(elf)); \
-       printf("\t.e_version   = %-10i ,\n", (int)EGET(ehdr->e_version)); \
-       printf("\t.e_entry     = 0x%-8lX ,\n", (unsigned 
long)EGET(ehdr->e_entry)); \
+       printf("\t.e_version   = %-10i , /* (%s) */\n", 
(int)EGET(ehdr->e_version), get_elfeitype(EI_VERSION, EGET(ehdr->e_version))); \
+       printf("\t.e_entry     = 0x%-8lX , /* (start address at runtime) */\n", 
(unsigned long)EGET(ehdr->e_entry)); \
        printf("\t.e_phoff     = %-10li , /* (bytes into file) */\n", (unsigned 
long)EGET(ehdr->e_phoff)); \
        printf("\t.e_shoff     = %-10li , /* (bytes into file) */\n", (unsigned 
long)EGET(ehdr->e_shoff)); \
        printf("\t.e_flags     = 0x%-8X ,\n", (unsigned 
int)EGET(ehdr->e_flags)); \
        printf("\t.e_ehsize    = %-10i , /* (bytes) */\n", 
(int)EGET(ehdr->e_ehsize)); \
        printf("\t.e_phentsize = %-10i , /* (bytes) */\n", 
(int)EGET(ehdr->e_phentsize)); \
+       /* TODO: Handle PN_XNUM */ \
        printf("\t.e_phnum     = %-10i , /* (program headers) */\n", 
(int)EGET(ehdr->e_phnum)); \
        printf("\t.e_shentsize = %-10i , /* (bytes) */\n", 
(int)EGET(ehdr->e_shentsize)); \
        printf("\t.e_shnum     = %-10i , /* (section headers) */\n", 
(int)EGET(ehdr->e_shnum)); \
@@ -198,28 +202,63 @@ static void dump_ehdr(elfobj *elf, const void *ehdr_void)
        DUMP_EHDR(32)
        DUMP_EHDR(64)
 }
+
+static const char *dump_p_flags(uint32_t type, uint32_t flags)
+{
+       static char buf[1024];
+       char *p = buf;
+       p[0] = p[1] = p[2] = '\0';
+
+       if (flags & PF_R)
+               p = stpcpy(p, " | PF_R");
+       if (flags & PF_W)
+               p = stpcpy(p, " | PF_W");
+       if (flags & PF_X)
+               p = stpcpy(p, " | PF_X");
+       flags &= ~(PF_R | PF_W | PF_X);
+
+       switch (type) {
+       case PT_PAX_FLAGS:
+#define X(b) if (flags & b) { p = stpcpy(p, " | " #b); flags &= ~b; }
+               X(PF_PAGEEXEC) X(PF_NOPAGEEXEC)
+               X(PF_SEGMEXEC) X(PF_NOSEGMEXEC)
+               X(PF_MPROTECT) X(PF_NOMPROTECT)
+               X(PF_RANDEXEC) X(PF_NORANDEXEC)
+               X(PF_EMUTRAMP) X(PF_NOEMUTRAMP)
+               X(PF_RANDMMAP) X(PF_NORANDMMAP)
+#undef X
+               break;
+       }
+
+       if (flags)
+               sprintf(p, " | 0x%X", flags);
+
+       return buf + 3;
+}
 static void dump_phdr(elfobj *elf, const void *phdr_void, long phdr_cnt)
 {
 #define DUMP_PHDR(B) \
        if (elf->elf_class == ELFCLASS ## B) { \
        const Elf ## B ## _Phdr *phdr = PHDR ## B (phdr_void); \
-       switch (EGET(phdr->p_type)) { \
+       uint32_t p_type = EGET(phdr->p_type); \
+       switch (p_type) { \
        case PT_DYNAMIC: phdr_dynamic_void = phdr_void; break; \
        } \
-       printf("/* Program Header #%li 0x%lX */\n{\n", phdr_cnt, (unsigned 
long)phdr_void - (unsigned long)elf->data); \
-       printf("\t.p_type   = %-10li , /* [%s] */\n", (long)EGET(phdr->p_type), 
get_elfptype(EGET(phdr->p_type))); \
-       printf("\t.p_offset = %-10li ,\n", (long)EGET(phdr->p_offset)); \
-       printf("\t.p_vaddr  = 0x%-8lX ,\n", (unsigned 
long)EGET(phdr->p_vaddr)); \
-       printf("\t.p_paddr  = 0x%-8lX ,\n", (unsigned 
long)EGET(phdr->p_paddr)); \
-       printf("\t.p_filesz = %-10li ,\n", (long)EGET(phdr->p_filesz)); \
-       printf("\t.p_memsz  = %-10li ,\n", (long)EGET(phdr->p_memsz)); \
-       printf("\t.p_flags  = %-10li ,\n", (long)EGET(phdr->p_flags)); \
-       printf("\t.p_align  = %-10li\n", (long)EGET(phdr->p_align)); \
+       printf("/* Program Header #%li 0x%lX */\n{\n", phdr_cnt, 
(uintptr_t)phdr_void - (uintptr_t)elf->data); \
+       printf("\t.p_type   = %-10li , /* [%s] */\n", (long)p_type, 
get_elfptype(p_type)); \
+       printf("\t.p_offset = %-10li , /* (bytes into file) */\n", 
(long)EGET(phdr->p_offset)); \
+       printf("\t.p_vaddr  = 0x%-8lX , /* (virtual addr at runtime) */\n", 
(unsigned long)EGET(phdr->p_vaddr)); \
+       printf("\t.p_paddr  = 0x%-8lX , /* (physical addr at runtime) */\n", 
(unsigned long)EGET(phdr->p_paddr)); \
+       printf("\t.p_filesz = %-10li , /* (bytes in file) */\n", 
(long)EGET(phdr->p_filesz)); \
+       printf("\t.p_memsz  = %-10li , /* (bytes in mem at runtime) */\n", 
(long)EGET(phdr->p_memsz)); \
+       printf("\t.p_flags  = 0x%-8lX , /* %s */\n", (unsigned 
long)EGET(phdr->p_flags), dump_p_flags(p_type, EGET(phdr->p_flags))); \
+       printf("\t.p_align  = %-10li , /* (min mem alignment in bytes) */\n", 
(long)EGET(phdr->p_align)); \
        printf("},\n"); \
        }
        DUMP_PHDR(32)
        DUMP_PHDR(64)
 }
+
 static void dump_shdr(elfobj *elf, const void *shdr_void, long shdr_cnt, const 
char *name)
 {
        unsigned long i;
@@ -233,22 +272,31 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, 
long shdr_cnt, const c
 #define DUMP_SHDR(B) \
        if (elf->elf_class == ELFCLASS ## B) { \
        const Elf ## B ## _Shdr *shdr = SHDR ## B (shdr_void); \
+       Elf ## B ## _Off offset = EGET(shdr->sh_offset); \
        uint32_t type = EGET(shdr->sh_type); \
        uint ## B ## _t size = EGET(shdr->sh_size); \
+       \
        printf("/* Section Header #%li '%s' 0x%lX */\n{\n", \
-              shdr_cnt, name, (unsigned long)shdr_void - (unsigned 
long)elf->data); \
+              shdr_cnt, name, (uintptr_t)shdr_void - (uintptr_t)elf->data); \
        printf("\t.sh_name      = %-10i ,\n", (int)EGET(shdr->sh_name)); \
        printf("\t.sh_type      = %-10i , /* [%s] */\n", 
(int)EGET(shdr->sh_type), get_elfshttype(type)); \
        printf("\t.sh_flags     = %-10li ,\n", (long)EGET(shdr->sh_flags)); \
        printf("\t.sh_addr      = 0x%-8lX ,\n", (unsigned 
long)EGET(shdr->sh_addr)); \
-       printf("\t.sh_offset    = %-10i , /* (bytes) */\n", 
(int)EGET(shdr->sh_offset)); \
-       printf("\t.sh_size      = %-10li , /* (bytes) */\n", 
(long)EGET(shdr->sh_size)); \
+       printf("\t.sh_offset    = %-10li , /* (bytes) */\n", (long)offset); \
+       printf("\t.sh_size      = %-10lu , /* (bytes) */\n", (unsigned 
long)size); \
        printf("\t.sh_link      = %-10i ,\n", (int)EGET(shdr->sh_link)); \
        printf("\t.sh_info      = %-10i ,\n", (int)EGET(shdr->sh_info)); \
        printf("\t.sh_addralign = %-10li ,\n", (long)EGET(shdr->sh_addralign)); 
\
        printf("\t.sh_entsize   = %-10li\n", (long)EGET(shdr->sh_entsize)); \
-       if (size && be_verbose) { \
-               void *vdata = elf->vdata + EGET(shdr->sh_offset); \
+       \
+       if (type == SHT_NOBITS) { \
+               /* Special case so we can do valid check next. */ \
+               if (be_verbose) \
+                       printf("\t/* NOBITS sections do not occupy the file. 
*/\n"); \
+       } else if (!(offset < (uint64_t)elf->len && size < (uint64_t)elf->len 
&& offset <= elf->len - size)) { \
+               printf(" /* corrupt section header ! */ "); \
+       } else if (size && be_verbose) { \
+               void *vdata = elf->vdata + offset; \
                unsigned char *data = vdata; \
                switch (type) { \
                case SHT_PROGBITS: { \
@@ -258,6 +306,7 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, 
long shdr_cnt, const c
                        } \
                        if (strcmp(name, ".comment") != 0) \
                                break; \
+                       break; \
                } \
                case SHT_STRTAB: { \
                        char b; \
@@ -315,6 +364,7 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, 
long shdr_cnt, const c
        DUMP_SHDR(32)
        DUMP_SHDR(64)
 }
+
 static void dump_dyn(elfobj *elf, const void *dyn_void, long dyn_cnt)
 {
 #define DUMP_DYN(B) \
@@ -322,7 +372,7 @@ static void dump_dyn(elfobj *elf, const void *dyn_void, 
long dyn_cnt)
        const Elf ## B ## _Dyn *dyn = dyn_void; \
        unsigned long tag = EGET(dyn->d_tag); \
        printf("/* Dynamic tag #%li '%s' 0x%lX */\n{\n", \
-              dyn_cnt, get_elfdtype(tag), (unsigned long)dyn_void - (unsigned 
long)elf->data); \
+              dyn_cnt, get_elfdtype(tag), (uintptr_t)dyn_void - 
(uintptr_t)elf->data); \
        printf("\t.d_tag     = 0x%-8lX ,\n", tag); \
        printf("\t.d_un      = {\n"); \
        printf("\t\t.d_val = 0x%-8lX ,\n", (unsigned 
long)EGET(dyn->d_un.d_val)); \

Reply via email to