diff options
author | Rob Landley <rob@landley.net> | 2016-02-17 14:01:19 -0600 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2016-02-17 14:01:19 -0600 |
commit | cc4a1f4d520f090bd563647df2614d09b66bd54a (patch) | |
tree | 17864be3f289c3927a70328b4aba0d285c4927ad /toys/pending | |
parent | 782d2c17cac641c3c123cc284b219a01ef26e74f (diff) | |
download | toybox-cc4a1f4d520f090bd563647df2614d09b66bd54a.tar.gz |
Add dynamic/static checking to file (printing dynamic linker if found).
Diffstat (limited to 'toys/pending')
-rw-r--r-- | toys/pending/file.c | 103 |
1 files changed, 68 insertions, 35 deletions
diff --git a/toys/pending/file.c b/toys/pending/file.c index 2c2f2864..1d09471d 100644 --- a/toys/pending/file.c +++ b/toys/pending/file.c @@ -3,6 +3,8 @@ * Copyright 2016 The Android Open Source Project * * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/file.html + * + * TODO: ar USE_FILE(NEWTOY(file, "<1", TOYFLAG_USR|TOYFLAG_BIN)) @@ -22,9 +24,11 @@ GLOBALS( int max_name_len; ) -static void do_elf_file() +// We don't trust elf.h to be there, and two codepaths for 32/64 is awkward +// anyway, so calculate struct offsets manually. (It's a fixed ABI.) +static void do_elf_file(int fd) { - int elf_endian = toybuf[5], e_type, e_machine, i; + int endian = toybuf[5], bits = toybuf[4], i, j; int64_t (*elf_int)(void *ptr, unsigned size) = peek_le; // Values from include/linux/elf-em.h (plus arch/*/include/asm/elf.h) // Names are linux/arch/ directory name @@ -40,43 +44,74 @@ static void do_elf_file() xprintf("ELF "); // "64-bit" - if (toybuf[4] == 1) xprintf("32-bit "); - else if (toybuf[4] == 2) xprintf("64-bit "); - else xprintf("(bad class %d)", toybuf[4]); + if (bits == 1) xprintf("32-bit "); + else if (bits == 2) xprintf("64-bit "); + else { + xprintf("(bad class %d) ", bits); + bits = 0; + } + + // e_machine, ala "x86", from big table above + j = elf_int(toybuf+18, 2); + for (i = 0; i<ARRAY_LEN(type); i++) if (j==type[i].val) break; + if (i<ARRAY_LEN(type)) xprintf("%s ", type[i].name); + else xprintf("(unknown arch %d) ", j); // "LSB" - if (elf_endian == 1) xprintf("LSB "); - else if (elf_endian == 2) { + if (endian == 1) xprintf("LSB "); + else if (endian == 2) { xprintf("MSB "); elf_int = peek_be; } else { - xprintf("(bad endian %d)\n", elf_endian); - - // At this point we can't parse remaining fields. - return; + xprintf("(bad endian %d)\n", endian); + endian = 0; } // ", executable" - e_type = elf_int(&toybuf[0x10], 2); - if (e_type == 1) xprintf("relocatable"); - else if (e_type == 2) xprintf("executable"); - else if (e_type == 3) xprintf("shared object"); - else if (e_type == 4) xprintf("core dump"); - else xprintf("(invalid type %d)", e_type); - - // ", x86-64" - e_machine = elf_int(&toybuf[0x12], 2); - for (i = 0; i<ARRAY_LEN(type); i++) if (e_machine == type[i].val) break; - if (i<ARRAY_LEN(type)) xprintf(", %s", type[i].name); - else xprintf(", (unknown arch %d)", e_machine); - - // "version 1" - xprintf(", version %d", toybuf[6]); - - // " (SYSV)" - // TODO: will we ever meet any of the others in practice? - if (!toybuf[7]) xprintf(" (SYSV)"); - else xprintf(" (OS %d)", toybuf[7]); + i = elf_int(toybuf+16, 2); + if (i == 1) xprintf("relocatable"); + else if (i == 2) xprintf("executable"); + else if (i == 3) xprintf("shared object"); + else if (i == 4) xprintf("core dump"); + else xprintf("(bad type %d)", i); + + bits--; + // If we know our bits and endianness and phentsize agrees show dynamic linker + if ((bits&1)==bits && endian && + (i = elf_int(toybuf+42+12*bits, 2)) == 32+24*bits) + { + char *map, *phdr; + int phsize = i, phnum = elf_int(toybuf+44+12*bits, 2), + psz = sysconf(_SC_PAGE_SIZE), lib = 0; + off_t phoff = elf_int(toybuf+28+4*bits, 4+4*bits), + mapoff = phoff^(phoff&(psz-1)); + + // map e_phentsize*e_phnum bytes at e_phoff + map = mmap(0, phsize*phnum, PROT_READ, MAP_SHARED, fd, mapoff); + if (map) { + // Find PT_INTERP entry. (Not: fields got reordered for 64 bit) + for (i = 0; i<phnum; i++) { + long long dlpos, dllen; + + // skip non-PT_INTERP entries + j = elf_int(phdr = map+(phoff-mapoff)+i*phsize, 4); + if (j==2) lib++; + if (j!=3) continue; + + // Read p_offset and p_filesz + j = bits+1; + dlpos = elf_int(phdr+4*j, 4*j); + dllen = elf_int(phdr+16*j, 4*j); + if (dllen<0 || dllen>sizeof(toybuf)-128 + || dlpos!=lseek(fd, dlpos, SEEK_SET) + || dllen!=readall(fd, toybuf+128, dllen)) break; + printf(", dynamic (%.*s)", (int)dllen, toybuf+128); + } + if (!lib) printf(", static"); + else printf(", needs %d lib%s", lib, lib>1 ? "s" : ""); + munmap(map, phsize*phnum); + } + } // TODO: we'd need to actually parse the ELF file to report the rest... // ", dynamically linked" @@ -84,7 +119,6 @@ static void do_elf_file() // ", for Linux 2.6.24" // ", BuildID[sha1]=SHA" // ", stripped" - xputc('\n'); } @@ -95,9 +129,8 @@ static void do_regular_file(int fd, char *name) if (len<0) perror_msg("%s", name); - if (len>20 && strstart(&s, "\177ELF")) { - do_elf_file(len); - } else if (len>28 && strstart(&s, "\x89PNG\x0d\x0a\x1a\x0a")) { + if (len>40 && strstart(&s, "\177ELF")) do_elf_file(fd); + else if (len>28 && strstart(&s, "\x89PNG\x0d\x0a\x1a\x0a")) { // PNG is big-endian: https://www.w3.org/TR/PNG/#7Integers-and-byte-order int chunk_length = peek_be(s, 4); |