diff options
| author | Roland McGrath <[email protected]> | 2007-10-04 08:50:09 +0000 |
|---|---|---|
| committer | Roland McGrath <[email protected]> | 2007-10-04 08:50:09 +0000 |
| commit | 59ea7f33f781e6e3f8c9d81d457e5d99eee8f1ce (patch) | |
| tree | 10a3dd35d3b568876f0edc6dd903fe8715a507e1 /src | |
| parent | 057ec6b35ef97bd1cf6c1e96da3da399237e5224 (diff) | |
src/
2007-10-04 Roland McGrath <[email protected]>
* readelf.c (print_archive_index): New variable.
(options, parse_opt): Accept -c/--archive-index to set it.
(dump_archive_index): New function.
(process_file): Take new arg WILL_PRINT_ARCHIVE_INDEX.
Call dump_archive_index on archives if set.
(main): Update caller.
(any_control_option): Give it file scope, moved out of ...
(parse_opt): ... here.
tests/
2007-10-04 Roland McGrath <[email protected]>
* run-readelf-test4.sh: New file.
* Makefile.am (TESTS, EXTRA_DIST): Add it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 31 | ||||
| -rw-r--r-- | src/elflint.c | 253 | ||||
| -rw-r--r-- | src/readelf.c | 267 | ||||
| -rw-r--r-- | src/unstrip.c | 82 |
4 files changed, 407 insertions, 226 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 832c5b99..f4937cf0 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,34 @@ +2007-10-04 Roland McGrath <[email protected]> + + * readelf.c (print_archive_index): New variable. + (options, parse_opt): Accept -c/--archive-index to set it. + (dump_archive_index): New function. + (process_file): Take new arg WILL_PRINT_ARCHIVE_INDEX. + Call dump_archive_index on archives if set. + (main): Update caller. + (any_control_option): Give it file scope, moved out of ... + (parse_opt): ... here. + +2007-10-03 Roland McGrath <[email protected]> + + * unstrip.c (struct arg_info): Add `list' flag. + (options, parse_opt): Grok -n/--list to set it. + (list_module): New function. + (handle_implicit_modules): Call it under -n. + + * elflint.c (check_note_section): New function. + (check_sections): Call it for SHT_NOTE. + + * readelf.c (handle_notes): Use sections when available. + + * elflint.c (check_note_data): New function, broken out of ... + (check_note): ... here. Call it and elf_getdata_rawchunk. + + * readelf.c (handle_auxv_note): Take offset as argument, not buffer. + Use elf_getdata_rawchunk and gelf_getauxv. + (handle_notes_data): New function, broken out of ... + (handle_notes): ... here. Call it and elf_getdata_rawchunk. + 2007-10-01 Roland McGrath <[email protected]> * readelf.c (hex_dump): Fix transposed subtraction generating spaces. diff --git a/src/elflint.c b/src/elflint.c index 37936b1f..e855d483 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -96,6 +96,9 @@ static void process_file (int fd, Elf *elf, const char *prefix, bool only_one); static void process_elf_file (Elf *elf, const char *prefix, const char *suffix, const char *fname, size_t size, bool only_one); +static void check_note_section (Ebl *ebl, GElf_Ehdr *ehdr, + GElf_Shdr *shdr, int idx); + /* Report an error. */ #define ERROR(str, args...) \ @@ -3499,6 +3502,10 @@ section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"), check_group (ebl, ehdr, shdr, cnt); break; + case SHT_NOTE: + check_note_section (ebl, ehdr, shdr, cnt); + break; + case SHT_GNU_versym: /* We cannot process this section now since we have no guarantee that the verneed and verdef sections have already been read. @@ -3565,163 +3572,141 @@ no .gnu.versym section present but .gnu.versym_d or .gnu.versym_r section exist\ } -static void -check_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt) +static GElf_Off +check_note_data (Ebl *ebl, const GElf_Ehdr *ehdr, + Elf_Data *data, int shndx, int phndx, GElf_Off start) { - if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL - && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) - ERROR (gettext ("\ -phdr[%d]: no note entries defined for the type of file\n"), - cnt); - - if (is_debuginfo) - /* The p_offset values in a separate debug file are bogus. */ - return; - - char *notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz); - - /* ELF64 files often use note section entries in the 32-bit format. - The p_align field is set to 8 in case the 64-bit format is used. - In case the p_align value is 0 or 4 the 32-bit format is - used. */ - GElf_Xword align = phdr->p_align == 0 || phdr->p_align == 4 ? 4 : 8; -#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1)) - - GElf_Xword idx = 0; - while (idx < phdr->p_filesz) + size_t offset = 0; + size_t last_offset = 0; + GElf_Nhdr nhdr; + size_t name_offset; + size_t desc_offset; + while (offset < data->d_size + && (offset = gelf_getnote (data, offset, + &nhdr, &name_offset, &desc_offset)) > 0) { - uint64_t namesz; - uint64_t descsz; - uint64_t type; - uint32_t namesz32; - uint32_t descsz32; - - if (align == 4) - { - uint32_t *ptr = (uint32_t *) (notemem + idx); - - if ((__BYTE_ORDER == __LITTLE_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - || (__BYTE_ORDER == __BIG_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) - { - namesz32 = namesz = bswap_32 (*ptr); - ++ptr; - descsz32 = descsz = bswap_32 (*ptr); - ++ptr; - type = bswap_32 (*ptr); - } - else - { - namesz32 = namesz = *ptr++; - descsz32 = descsz = *ptr++; - type = *ptr; - } - } - else - { - uint64_t *ptr = (uint64_t *) (notemem + idx); - uint32_t *ptr32 = (uint32_t *) (notemem + idx); - - if ((__BYTE_ORDER == __LITTLE_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - || (__BYTE_ORDER == __BIG_ENDIAN - && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) - { - namesz = bswap_64 (*ptr); - ++ptr; - descsz = bswap_64 (*ptr); - ++ptr; - type = bswap_64 (*ptr); - - namesz32 = bswap_32 (*ptr32); - ++ptr32; - descsz32 = bswap_32 (*ptr32); - } - else - { - namesz = *ptr++; - descsz = *ptr++; - type = *ptr; - - namesz32 = *ptr32++; - descsz32 = *ptr32; - } - } - - if (idx + 3 * align > phdr->p_filesz - || (idx + 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz) - > phdr->p_filesz)) - { - if (ehdr->e_ident[EI_CLASS] == ELFCLASS64 - && idx + 3 * 4 <= phdr->p_filesz - && (idx + 3 * 4 + ALIGNED_LEN (namesz32) + ALIGNED_LEN (descsz32) - <= phdr->p_filesz)) - ERROR (gettext ("\ -phdr[%d]: note entries probably in form of a 32-bit ELF file\n"), cnt); - else - ERROR (gettext ("phdr[%d]: extra %zu bytes after last note\n"), - cnt, (size_t) (phdr->p_filesz - idx)); - break; - } + last_offset = offset; /* Make sure it is one of the note types we know about. */ if (ehdr->e_type == ET_CORE) - { - switch (type) - { - case NT_PRSTATUS: - case NT_FPREGSET: - case NT_PRPSINFO: - case NT_TASKSTRUCT: /* NT_PRXREG on Solaris. */ - case NT_PLATFORM: - case NT_AUXV: - case NT_GWINDOWS: - case NT_ASRS: - case NT_PSTATUS: - case NT_PSINFO: - case NT_PRCRED: - case NT_UTSNAME: - case NT_LWPSTATUS: - case NT_LWPSINFO: - case NT_PRFPXREG: - /* Known type. */ - break; + switch (nhdr.n_type) + { + case NT_PRSTATUS: + case NT_FPREGSET: + case NT_PRPSINFO: + case NT_TASKSTRUCT: /* NT_PRXREG on Solaris. */ + case NT_PLATFORM: + case NT_AUXV: + case NT_GWINDOWS: + case NT_ASRS: + case NT_PSTATUS: + case NT_PSINFO: + case NT_PRCRED: + case NT_UTSNAME: + case NT_LWPSTATUS: + case NT_LWPSINFO: + case NT_PRFPXREG: + /* Known type. */ + break; - default: + default: + if (shndx == 0) ERROR (gettext ("\ -phdr[%d]: unknown core file note type %" PRIu64 " at offset %" PRIu64 "\n"), - cnt, type, idx); - } - } +phdr[%d]: unknown core file note type %" PRIu32 " at offset %" PRIu64 "\n"), + phndx, (uint32_t) nhdr.n_type, start + offset); + else + ERROR (gettext ("\ +section [%2d] '%s': unknown core file note type %" PRIu32 + " at offset %Zu\n"), + shndx, section_name (ebl, shndx), + (uint32_t) nhdr.n_type, offset); + } else - switch (type) + switch (nhdr.n_type) { - case NT_GNU_ABI_TAG: /* aka NT_VERSION */ + case NT_GNU_ABI_TAG: case NT_GNU_HWCAP: case NT_GNU_BUILD_ID: - /* Known type. */ break; case 0: /* Linux vDSOs use a type 0 note for the kernel version word. */ - if (namesz == sizeof "Linux" - && !memcmp (notemem + idx + 3 * align, "Linux", sizeof "Linux")) + if (nhdr.n_namesz == sizeof "Linux" + && !memcmp (data->d_buf + name_offset, "Linux", sizeof "Linux")) break; default: - ERROR (gettext ("\ -phdr[%d]: unknown object file note type %" PRIu64 " at offset %" PRIu64 "\n"), - cnt, type, idx); + if (shndx == 0) + ERROR (gettext ("\ +phdr[%d]: unknown object file note type %" PRIu32 " at offset %Zu\n"), + phndx, (uint32_t) nhdr.n_type, offset); + else + ERROR (gettext ("\ +section [%2d] '%s': unknown object file note type %" PRIu32 + " at offset %Zu\n"), + shndx, section_name (ebl, shndx), + (uint32_t) nhdr.n_type, offset); } - - /* Move to the next entry. */ - idx += 3 * align + ALIGNED_LEN (namesz) + ALIGNED_LEN (descsz); } - gelf_freechunk (ebl->elf, notemem); + return last_offset; +} + +static void +check_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt) +{ + if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL + && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) + ERROR (gettext ("\ +phdr[%d]: no note entries defined for the type of file\n"), + cnt); + + if (is_debuginfo) + /* The p_offset values in a separate debug file are bogus. */ + return; + + GElf_Off notes_size = 0; + Elf_Data *data = elf_getdata_rawchunk (ebl->elf, + phdr->p_offset, phdr->p_filesz, + ELF_T_NHDR); + if (data != NULL) + notes_size = check_note_data (ebl, ehdr, data, 0, cnt, phdr->p_offset); + + if (notes_size == 0) + ERROR (gettext ("phdr[%d]: cannot get content of note section: %s\n"), + cnt, elf_errmsg (-1)); + else if (notes_size != phdr->p_filesz) + ERROR (gettext ("phdr[%d]: extra %" PRIu64 " bytes after last note\n"), + cnt, phdr->p_filesz - notes_size); } +static void +check_note_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) +{ + Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); + if (data == NULL) + { + ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), + idx, section_name (ebl, idx)); + return; + } + + if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL + && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) + ERROR (gettext ("\ +section [%2d] '%s': no note entries defined for the type of file\n"), + idx, section_name (ebl, idx)); + + GElf_Off notes_size = check_note_data (ebl, ehdr, data, idx, 0, 0); + + if (notes_size == 0) + ERROR (gettext ("section [%2d] '%s': cannot get content of note section\n"), + idx, section_name (ebl, idx)); + else if (notes_size != shdr->sh_size) + ERROR (gettext ("section [%2d] '%s': extra %" PRIu64 + " bytes after last note\n"), + idx, section_name (ebl, idx), shdr->sh_size - notes_size); +} static void check_program_header (Ebl *ebl, GElf_Ehdr *ehdr) diff --git a/src/readelf.c b/src/readelf.c index 823cf2b9..fee908e9 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -50,6 +50,7 @@ #include <sys/param.h> #include <system.h> +#include "../libelf/libelfP.h" #include "../libebl/libeblP.h" #include "../libdw/libdwP.h" #include "../libdw/memory-access.h" @@ -90,6 +91,8 @@ static const struct argp_option options[] = { "strings", 'p', "SECTION", OPTION_ARG_OPTIONAL, N_("Print string contents of sections"), 0 }, { "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 }, + { "archive-index", 'c', NULL, 0, + N_("Display the symbol index of an archive"), 0 }, { NULL, 0, NULL, 0, N_("Output control:"), 0 }, @@ -151,6 +154,12 @@ static bool print_notes; /* True if SHF_STRINGS section content should be printed. */ static bool print_string_sections; +/* True if archive index should be printed. */ +static bool print_archive_index; + +/* True if any of the control options except print_archive_index is set. */ +static bool any_control_option; + /* Select printing of debugging sections. */ static enum section_e { @@ -190,7 +199,8 @@ static size_t shnum; /* Declarations of local functions. */ static void process_file (int fd, Elf *elf, const char *prefix, - const char *fname, bool only_one); + const char *fname, bool only_one, + bool will_print_archive_index); static void process_elf_file (Elf *elf, const char *prefix, const char *fname, bool only_one); static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr); @@ -215,6 +225,7 @@ static void print_liblist (Ebl *ebl); static void dump_data (Ebl *ebl); static void dump_strings (Ebl *ebl); static void print_strings (Ebl *ebl); +static void dump_archive_index (Elf *, const char *); int @@ -252,7 +263,8 @@ main (int argc, char *argv[]) elf_errmsg (-1)); else { - process_file (fd, elf, NULL, argv[remaining], only_one); + process_file (fd, elf, NULL, argv[remaining], only_one, + print_archive_index); /* Now we can close the descriptor. */ if (elf_end (elf) != 0) @@ -273,9 +285,6 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state __attribute__ ((unused))) { - /* True if any of the control options is set. */ - static bool any_control_option; - switch (key) { case 'a': @@ -336,6 +345,9 @@ parse_opt (int key, char *arg, print_version_info = true; any_control_option = true; break; + case 'c': + print_archive_index = true; + break; case 'w': if (arg == NULL) print_debug_sections = section_all; @@ -393,7 +405,7 @@ parse_opt (int key, char *arg, fputs (gettext ("Missing file name.\n"), stderr); goto do_argp_help; case ARGP_KEY_FINI: - if (! any_control_option) + if (! any_control_option && ! print_archive_index) { fputs (gettext ("No operation specified.\n"), stderr); do_argp_help: @@ -426,7 +438,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ /* Process one file. */ static void process_file (int fd, Elf *elf, const char *prefix, const char *fname, - bool only_one) + bool only_one, bool will_print_archive_index) { /* We can handle two types of files: ELF files and archives. */ Elf_Kind kind = elf_kind (elf); @@ -435,8 +447,13 @@ process_file (int fd, Elf *elf, const char *prefix, const char *fname, switch (kind) { case ELF_K_ELF: + if (unlikely (will_print_archive_index)) + error (0, 0, + gettext ("'%s' is not an archive, cannot print archive index"), + fname); /* Yes! It's an ELF file. */ - process_elf_file (elf, prefix, fname, only_one); + if (any_control_option) + process_elf_file (elf, prefix, fname, only_one); break; case ELF_K_AR: @@ -454,6 +471,9 @@ process_file (int fd, Elf *elf, const char *prefix, const char *fname, } memcpy (cp, fname, fname_len); + if (will_print_archive_index) + dump_archive_index (elf, new_prefix); + /* It's an archive. We process each file in it. */ Elf *subelf; Elf_Cmd cmd = ELF_C_READ_MMAP; @@ -467,7 +487,8 @@ process_file (int fd, Elf *elf, const char *prefix, const char *fname, Elf_Arhdr *arhdr = elf_getarhdr (subelf); assert (arhdr != NULL); - process_file (fd, subelf, new_prefix, arhdr->ar_name, false); + process_file (fd, subelf, new_prefix, arhdr->ar_name, false, + kind == ELF_K_AR && will_print_archive_index); } /* Get next archive element. */ @@ -5493,12 +5514,21 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc, } static void -handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, const void *desc) +handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, GElf_Off desc_pos) { + Elf_Data *data = elf_getdata_rawchunk (core, desc_pos, descsz, ELF_T_AUXV); + if (data == NULL) + elf_error: + error (EXIT_FAILURE, 0, + gettext ("cannot convert core note data: %s"), elf_errmsg (-1)); + const size_t nauxv = descsz / gelf_fsize (core, ELF_T_AUXV, 1, EV_CURRENT); for (size_t i = 0; i < nauxv; ++i) { - const GElf_auxv_t *av = (const GElf_auxv_t *) desc + i; + GElf_auxv_t av_mem; + GElf_auxv_t *av = gelf_getauxv (data, i, &av_mem); + if (av == NULL) + goto elf_error; const char *name; const char *fmt; @@ -5578,16 +5608,101 @@ handle_core_note (Ebl *ebl, const GElf_Nhdr *nhdr, const void *desc) putchar_unlocked ('\n'); } +static void +handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr, + GElf_Off start, Elf_Data *data) +{ + fputs_unlocked (gettext (" Owner Data size Type\n"), stdout); + + if (data == NULL) + goto bad_note; + + size_t offset = 0; + GElf_Nhdr nhdr; + size_t name_offset; + size_t desc_offset; + while (offset < data->d_size + && (offset = gelf_getnote (data, offset, + &nhdr, &name_offset, &desc_offset)) > 0) + { + const char *name = data->d_buf + name_offset; + const char *desc = data->d_buf + desc_offset; + + char buf[100]; + char buf2[100]; + printf (gettext (" %-13.*s %9" PRId32 " %s\n"), + (int) nhdr.n_namesz, name, nhdr.n_descsz, + ehdr->e_type == ET_CORE + ? ebl_core_note_type_name (ebl, nhdr.n_type, + buf, sizeof (buf)) + : ebl_object_note_type_name (ebl, nhdr.n_type, + buf2, sizeof (buf2))); + + /* Filter out invalid entries. */ + if (memchr (name, '\0', nhdr.n_namesz) != NULL + /* XXX For now help broken Linux kernels. */ + || 1) + { + if (ehdr->e_type == ET_CORE) + { + if (nhdr.n_type == NT_AUXV) + handle_auxv_note (ebl, ebl->elf, nhdr.n_descsz, + start + desc_offset); + else + handle_core_note (ebl, &nhdr, desc); + } + else + ebl_object_note (ebl, name, nhdr.n_type, nhdr.n_descsz, desc); + } + } + + if (offset == data->d_size) + return; + + bad_note: + error (EXIT_FAILURE, 0, + gettext ("cannot get content of note section: %s"), + elf_errmsg (-1)); +} static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr) { - int class = gelf_getclass (ebl->elf); - size_t cnt; + /* If we have section headers, just look for SHT_NOTE sections. + In a debuginfo file, the program headers are not reliable. */ + if (shnum != 0) + { + /* Get the section header string table index. */ + size_t shstrndx; + if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr == NULL || shdr->sh_type != SHT_NOTE) + /* Not what we are looking for. */ + continue; + + printf (gettext ("\ +\nNote section [%2zu] '%s' of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"), + elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + shdr->sh_size, shdr->sh_offset); + + handle_notes_data (ebl, ehdr, shdr->sh_offset, + elf_getdata (scn, NULL)); + } + return; + } /* We have to look through the program header to find the note sections. There can be more than one. */ - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt) { GElf_Phdr mem; GElf_Phdr *phdr = gelf_getphdr (ebl->elf, cnt, &mem); @@ -5597,82 +5712,13 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr) continue; printf (gettext ("\ -\nNote segment of %" PRId64 " bytes at offset %#0" PRIx64 ":\n"), +\nNote segment of %" PRIu64 " bytes at offset %#0" PRIx64 ":\n"), phdr->p_filesz, phdr->p_offset); - char *notemem = gelf_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz); - if (notemem == NULL) - error (EXIT_FAILURE, 0, - gettext ("cannot get content of note section: %s"), - elf_errmsg (-1)); - - fputs_unlocked (gettext (" Owner Data size Type\n"), stdout); - - - /* Handle the note section content. It consists of one or more - entries each of which consists of five parts: - - - a 32-bit name length - - a 32-bit descriptor length - - a 32-bit type field - - the NUL-terminated name, length as specified in the first field - - the descriptor, length as specified in the second field - - The variable sized fields are padded to 32- or 64-bits - depending on whether the file is a 32- or 64-bit ELF file. - */ - // XXX Which 64-bit archs need 8-byte alignment? x86-64 does not. - size_t align = class == ELFCLASS32 ? 4 : 4; // XXX 8; -#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1)) - - size_t idx = 0; - while (idx < phdr->p_filesz) - { - const GElf_Nhdr *nhdr = (const GElf_Nhdr *) (notemem + idx); - const char *name = (const char *) (nhdr + 1); - const void *desc = &name[ALIGNED_LEN (nhdr->n_namesz)]; - - if (idx + 12 > phdr->p_filesz - || (idx + 12 + ALIGNED_LEN (nhdr->n_namesz) - + ALIGNED_LEN (nhdr->n_descsz) > phdr->p_filesz)) - /* This entry isn't completely contained in the note - section. Ignore it. */ - break; - - char buf[100]; - char buf2[100]; - printf (gettext (" %-13.*s %9" PRId32 " %s\n"), - (int) nhdr->n_namesz, name, - nhdr->n_descsz, - ehdr->e_type == ET_CORE - ? ebl_core_note_type_name (ebl, nhdr->n_type, - buf, sizeof (buf)) - : ebl_object_note_type_name (ebl, nhdr->n_type, - buf2, sizeof (buf2))); - - /* Filter out invalid entries. */ - if (memchr (name, '\0', nhdr->n_namesz) != NULL - /* XXX For now help broken Linux kernels. */ - || 1) - { - if (ehdr->e_type == ET_CORE) - { - if (nhdr->n_type == NT_AUXV) - handle_auxv_note (ebl, ebl->elf, nhdr->n_descsz, desc); - else - handle_core_note (ebl, nhdr, desc); - } - else - ebl_object_note (ebl, name, nhdr->n_type, - nhdr->n_descsz, desc); - } - - /* Move to the next entry. */ - idx += (12 + ALIGNED_LEN (nhdr->n_namesz) - + ALIGNED_LEN (nhdr->n_descsz)); - } - - gelf_freechunk (ebl->elf, notemem); + handle_notes_data (ebl, ehdr, phdr->p_offset, + elf_getdata_rawchunk (ebl->elf, + phdr->p_offset, phdr->p_filesz, + ELF_T_NHDR)); } } @@ -5866,3 +5912,48 @@ print_strings (Ebl *ebl) print_string_section (scn, &shdr_mem, name); } } + +static void +dump_archive_index (Elf *elf, const char *fname) +{ + size_t narsym; + const Elf_Arsym *arsym = elf_getarsym (elf, &narsym); + if (arsym == NULL) + { + int result = elf_errno (); + if (result != ELF_E_NO_INDEX) + error (EXIT_FAILURE, 0, + gettext ("cannot get symbol index of archive '%s': %s"), + fname, elf_errmsg (result)); + else + printf (gettext ("\nArchive '%s' has no symbol index\n"), fname); + return; + } + + printf (gettext ("\nIndex of archive '%s' has %Zu entries:\n"), + fname, narsym); + + size_t as_off = 0; + for (const Elf_Arsym *s = arsym; s < &arsym[narsym - 1]; ++s) + { + if (s->as_off != as_off) + { + as_off = s->as_off; + + Elf *subelf; + if (elf_rand (elf, as_off) == 0 + || (subelf = elf_begin (-1, ELF_C_READ_MMAP, elf)) == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot extract member at offset %Zu in '%s': %s"), + as_off, fname, elf_errmsg (-1)); + + const Elf_Arhdr *h = elf_getarhdr (subelf); + + printf (gettext ("Archive member '%s' contains:\n"), h->ar_name); + + elf_end (subelf); + } + + printf ("\t%s\n", s->as_name); + } +} diff --git a/src/unstrip.c b/src/unstrip.c index a8c30022..ec22aa91 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -53,6 +53,7 @@ #include <stdbool.h> #include <stdio.h> #include <stdio_ext.h> +#include <inttypes.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -90,6 +91,8 @@ static const struct argp_option options[] = { "all", 'a', NULL, 0, N_("Create output for modules that have no separate debug information"), 0 }, + { "list-only", 'n', NULL, 0, + N_("Only list module and file names, build IDs"), 0 }, { NULL, 0, NULL, 0, NULL, 0 } }; @@ -99,6 +102,7 @@ struct arg_info const char *output_dir; Dwfl *dwfl; char **args; + bool list; bool all; bool ignore; bool modnames; @@ -147,6 +151,9 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'i': info->ignore = true; break; + case 'n': + info->list = true; + break; case ARGP_KEY_ARGS: case ARGP_KEY_NO_ARGS: @@ -159,6 +166,15 @@ parse_opt (int key, char *arg, struct argp_state *state) return EINVAL; } + if (info->list && (info->dwfl == NULL + || info->output_dir != NULL + || info->output_file != NULL)) + { + argp_error (state, + _("-n cannot be used with explicit files or -o or -d")); + return EINVAL; + } + if (info->output_dir != NULL) { struct stat64 st; @@ -194,7 +210,8 @@ parse_opt (int key, char *arg, struct argp_state *state) from defaulting to "-e a.out". */ return ENOSYS; } - else if (info->output_file == NULL && info->output_dir == NULL) + else if (info->output_file == NULL && info->output_dir == NULL + && !info->list) { argp_error (state, _("-o or -d is required when using implicit files")); @@ -1947,6 +1964,47 @@ handle_output_dir_module (const char *output_dir, Dwfl_Module *mod, } +static void +list_module (Dwfl_Module *mod) +{ + /* Make sure we have searched for the files. */ + GElf_Addr bias; + bool have_elf = dwfl_module_getelf (mod, &bias) != NULL; + bool have_dwarf = dwfl_module_getdwarf (mod, &bias) != NULL; + + const char *file; + const char *debug; + Dwarf_Addr start; + Dwarf_Addr end; + const char *name = dwfl_module_info (mod, NULL, &start, &end, + NULL, NULL, &file, &debug); + if (file != NULL && debug != NULL && (debug == file || !strcmp (debug, file))) + debug = "."; + + const unsigned char *id; + GElf_Addr id_vaddr; + int id_len = dwfl_module_build_id (mod, &id, &id_vaddr); + + printf ("%#" PRIx64 "+%#" PRIx64 " ", start, end - start); + + if (id_len > 0) + { + do + printf ("%02" PRIx8, *id++); + while (--id_len > 0); + if (id_vaddr != 0) + printf ("@%#" PRIx64, id_vaddr); + } + else + putchar ('-'); + + printf (" %s %s %s\n", + file ?: have_elf ? "." : "-", + debug ?: have_dwarf ? "." : "-", + name); +} + + struct match_module_info { char **patterns; @@ -2006,7 +2064,11 @@ handle_implicit_modules (const struct arg_info *info) if (offset == 0) error (EXIT_FAILURE, 0, _("no matching modules found")); - if (info->output_dir == NULL) + if (info->list) + do + list_module (mmi.found); + while ((offset = next (offset)) > 0); + else if (info->output_dir == NULL) { if (next (offset) != 0) error (EXIT_FAILURE, 0, _("matched more than one module")); @@ -2068,7 +2130,19 @@ With no arguments, process all modules found.\n\ Multiple modules are written to files under OUTPUT-DIRECTORY, \ creating subdirectories as needed. \ With -m these files have simple module names, otherwise they have the \ -name of the main file complete with directory underneath OUTPUT-DIRECTORY.") +name of the main file complete with directory underneath OUTPUT-DIRECTORY.\n\ +\n\ +With -n no files are written, but one line to standard output for each module:\ +\n\tSTART+SIZE BUILDID FILE DEBUGFILE MODULENAME\n\ +START and SIZE are hexadecimal giving the address bounds of the module. \ +BUILDID is hexadecimal for the build ID bits, or - if no ID is known; \ +the hexadecimal may be followed by @0xADDR giving the address where the \ +ID resides if that is known. \ +FILE is the file name found for the module, or - if none was found, \ +or . if an ELF image is available but not from any named file. \ +DEBUGFILE is the separate debuginfo file name, \ +or - if no debuginfo was found, or . if FILE contains the debug information.\ +") }; int remaining; @@ -2102,7 +2176,7 @@ name of the main file complete with directory underneath OUTPUT-DIRECTORY.") else { /* parse_opt checked this. */ - assert (info.output_file != NULL || info.output_dir != NULL); + assert (info.output_file != NULL || info.output_dir != NULL || info.list); handle_implicit_modules (&info); |
