summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRoland McGrath <[email protected]>2007-10-04 08:50:09 +0000
committerRoland McGrath <[email protected]>2007-10-04 08:50:09 +0000
commit59ea7f33f781e6e3f8c9d81d457e5d99eee8f1ce (patch)
tree10a3dd35d3b568876f0edc6dd903fe8715a507e1 /src
parent057ec6b35ef97bd1cf6c1e96da3da399237e5224 (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/ChangeLog31
-rw-r--r--src/elflint.c253
-rw-r--r--src/readelf.c267
-rw-r--r--src/unstrip.c82
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);