summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRoland McGrath <[email protected]>2007-10-23 13:07:39 +0000
committerRoland McGrath <[email protected]>2007-10-23 13:07:39 +0000
commite4c22ea004c02a58f5db5eb53794275344c17958 (patch)
treeec3713d305f8e9f05b15d29240accc71e98998c5 /src
parent98c5ead4ad9fbf96ad3b54d8ca26e354ddc3398d (diff)
2007-10-23 Roland McGrath <[email protected]>
* linux-kernel-modules.c (report_kernel_archive): Reorder the kernel module to appear first.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog28
-rw-r--r--src/readelf.c112
-rw-r--r--src/unstrip.c80
3 files changed, 177 insertions, 43 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index ebd729fe..df4305c2 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,31 @@
+2007-10-20 Roland McGrath <[email protected]>
+
+ * unstrip.c (options): Update -R description.
+ (struct symbol): Put symbol details a union with a size_t pointer
+ `duplicate'.
+ (compare_symbols_output): Use null ->name as marker for discard
+ symbols, not zero *->map.
+ (copy_elided_sections): Record forwarding pointers for discarded
+ duplicates and fill SYMNDX_MAP elements through them.
+
+ * readelf.c (process_file): Set offline_next_address to 0 at start.
+ (struct process_dwflmod_args): New type.
+ (process_dwflmod): Take args in it, pass fd to process_elf_file.
+ (process_file): Update caller; dup FD for passing to libdwfl.
+ (process_elf_file): Take new arg FD. For ET_REL file when
+ displaying data affected by libdwfl relocation, open a new Elf handle.
+
+2007-10-17 Roland McGrath <[email protected]>
+
+ * readelf.c (print_debug_line_section): For invalid data inside a
+ unit with plausible length, keep printing at the next unit boundary.
+
+ * readelf.c (attr_callback): Use dwarf_formref_die, not dwarf_formref.
+
+2007-10-16 Roland McGrath <[email protected]>
+
+ * readelf.c (hex_dump): Fix rounding error in whitespace calculation.
+
2007-10-15 Roland McGrath <[email protected]>
* make-debug-archive.in: New file.
diff --git a/src/readelf.c b/src/readelf.c
index c591b322..2197d840 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -54,6 +54,7 @@
#include "../libelf/libelfP.h"
#include "../libebl/libeblP.h"
#include "../libdw/libdwP.h"
+#include "../libdwfl/libdwflP.h"
#include "../libdw/memory-access.h"
@@ -200,7 +201,7 @@ static size_t shnum;
/* Declarations of local functions. */
static void process_file (int fd, const char *fname, bool only_one);
-static void process_elf_file (Dwfl_Module *dwflmod);
+static void process_elf_file (Dwfl_Module *dwflmod, int fd);
static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr);
static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
@@ -460,6 +461,12 @@ count_dwflmod (Dwfl_Module *dwflmod __attribute__ ((unused)),
return DWARF_CB_ABORT;
}
+struct process_dwflmod_args
+{
+ int fd;
+ bool only_one;
+};
+
static int
process_dwflmod (Dwfl_Module *dwflmod,
void **userdata __attribute__ ((unused)),
@@ -467,10 +474,10 @@ process_dwflmod (Dwfl_Module *dwflmod,
Dwarf_Addr base __attribute__ ((unused)),
void *arg)
{
- bool only_one = *(bool *) arg;
+ const struct process_dwflmod_args *a = arg;
/* Print the file name. */
- if (!only_one)
+ if (!a->only_one)
{
const char *fname;
dwfl_module_info (dwflmod, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
@@ -478,7 +485,7 @@ process_dwflmod (Dwfl_Module *dwflmod,
printf ("\n%s:\n\n", fname);
}
- process_elf_file (dwflmod);
+ process_elf_file (dwflmod, a->fd);
return DWARF_CB_OK;
}
@@ -507,6 +514,11 @@ process_file (int fd, const char *fname, bool only_one)
if (!any_control_option)
return;
+ /* Duplicate an fd for dwfl_report_offline to swallow. */
+ int dwfl_fd = dup (fd);
+ if (unlikely (dwfl_fd < 0))
+ error (EXIT_FAILURE, errno, "dup");
+
/* Use libdwfl in a trivial way to open the libdw handle for us.
This takes care of applying relocations to DWARF data in ET_REL files. */
static const Dwfl_Callbacks callbacks =
@@ -515,7 +527,10 @@ process_file (int fd, const char *fname, bool only_one)
.find_debuginfo = find_no_debuginfo
};
Dwfl *dwfl = dwfl_begin (&callbacks);
- if (dwfl_report_offline (dwfl, fname, fname, fd) == NULL)
+ if (likely (dwfl != NULL))
+ /* Let 0 be the logical address of the file (or first in archive). */
+ dwfl->offline_next_address = 0;
+ if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) == NULL)
{
struct stat64 st;
if (fstat64 (fd, &st) != 0)
@@ -535,7 +550,8 @@ process_file (int fd, const char *fname, bool only_one)
dwfl_getmodules (dwfl, &count_dwflmod, &only_one, 1);
/* Process the one or more modules gleaned from this file. */
- dwfl_getmodules (dwfl, &process_dwflmod, &only_one, 0);
+ struct process_dwflmod_args a = { .fd = fd, .only_one = only_one };
+ dwfl_getmodules (dwfl, &process_dwflmod, &a, 0);
}
dwfl_end (dwfl);
}
@@ -543,7 +559,7 @@ process_file (int fd, const char *fname, bool only_one)
/* Process one ELF file. */
static void
-process_elf_file (Dwfl_Module *dwflmod)
+process_elf_file (Dwfl_Module *dwflmod, int fd)
{
GElf_Addr dwflbias;
Elf *elf = dwfl_module_getelf (dwflmod, &dwflbias);
@@ -553,6 +569,7 @@ process_elf_file (Dwfl_Module *dwflmod)
if (ehdr == NULL)
{
+ elf_error:
error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1));
return;
}
@@ -560,6 +577,7 @@ process_elf_file (Dwfl_Module *dwflmod)
Ebl *ebl = ebl_openbackend (elf);
if (ebl == NULL)
{
+ ebl_error:
error (0, errno, gettext ("cannot create EBL handle"));
return;
}
@@ -570,10 +588,40 @@ process_elf_file (Dwfl_Module *dwflmod)
gettext ("cannot determine number of sections: %s"),
elf_errmsg (-1));
+ /* For an ET_REL file, libdwfl has adjusted the in-core shdrs
+ and may have applied relocation to some sections.
+ So we need to get a fresh Elf handle on the file to display those. */
+ bool print_unrelocated = (print_section_header
+ || print_relocations
+ || dump_data_sections != NULL
+ || print_notes);
+
+ Elf *pure_elf = NULL;
+ Ebl *pure_ebl = ebl;
+ if (ehdr->e_type == ET_REL && print_unrelocated)
+ {
+ /* Read the file afresh. */
+ pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+ off64_t aroff = elf_getaroff (elf);
+ if (aroff > 0)
+ {
+ /* Archive member. */
+ (void) elf_rand (pure_elf, aroff);
+ Elf *armem = elf_begin (-1, ELF_C_READ_MMAP, pure_elf);
+ elf_end (pure_elf);
+ pure_elf = armem;
+ }
+ if (pure_elf == NULL)
+ goto elf_error;
+ pure_ebl = ebl_openbackend (pure_elf);
+ if (pure_ebl == NULL)
+ goto ebl_error;
+ }
+
if (print_file_header)
print_ehdr (ebl, ehdr);
if (print_section_header)
- print_shdr (ebl, ehdr);
+ print_shdr (pure_ebl, ehdr);
if (print_program_header)
print_phdr (ebl, ehdr);
if (print_section_groups)
@@ -581,7 +629,7 @@ process_elf_file (Dwfl_Module *dwflmod)
if (print_dynamic_table)
print_dynamic (ebl, ehdr);
if (print_relocations)
- print_relocs (ebl);
+ print_relocs (pure_ebl);
if (print_histogram)
handle_hash (ebl);
if (print_symbol_table)
@@ -593,17 +641,23 @@ process_elf_file (Dwfl_Module *dwflmod)
if (print_arch)
print_liblist (ebl);
if (dump_data_sections != NULL)
- dump_data (ebl);
+ dump_data (pure_ebl);
if (string_sections != NULL)
dump_strings (ebl);
if (print_debug_sections != 0)
print_debug (dwflmod, ebl, ehdr);
if (print_notes)
- handle_notes (ebl, ehdr);
+ handle_notes (pure_ebl, ehdr);
if (print_string_sections)
print_strings (ebl);
ebl_closebackend (ebl);
+
+ if (pure_ebl != ebl)
+ {
+ ebl_closebackend (pure_ebl);
+ elf_end (pure_elf);
+ }
}
@@ -4027,13 +4081,13 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
case DW_FORM_ref4:
case DW_FORM_ref2:
case DW_FORM_ref1:;
- Dwarf_Off ref;
- if (unlikely (dwarf_formref (attrp, &ref) != 0))
+ Dwarf_Die ref;
+ if (unlikely (dwarf_formref_die (attrp, &ref) == NULL))
goto attrval_out;
printf (" %*s%-20s [%6" PRIxMAX "]\n",
(int) (level * 2), "", dwarf_attr_string (attr),
- (uintmax_t) (ref + cbargs->cu_offset));
+ (uintmax_t) dwarf_dieoffset (&ref));
break;
case DW_FORM_udata:
@@ -4384,7 +4438,15 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
line_range, opcode_base);
if (unlikely (linep + opcode_base - 1 >= lineendp))
- goto invalid_data;
+ {
+ invalid_unit:
+ error (0, 0,
+ gettext ("invalid data at offset %tu in section [%zu] '%s'"),
+ linep - (const unsigned char *) data->d_buf,
+ elf_ndxscn (scn), ".debug_line");
+ linep = lineendp;
+ continue;
+ }
int opcode_base_l10 = 1;
unsigned int tmp = opcode_base;
while (tmp > 10)
@@ -4400,14 +4462,14 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
opcode_base_l10, cnt, linep[cnt - 1]);
linep += opcode_base - 1;
if (unlikely (linep >= lineendp))
- goto invalid_data;
+ goto invalid_unit;
puts (gettext ("\nDirectory table:"));
while (*linep != 0)
{
unsigned char *endp = memchr (linep, '\0', lineendp - linep);
if (endp == NULL)
- goto invalid_data;
+ goto invalid_unit;
printf (" %s\n", (char *) linep);
@@ -4417,7 +4479,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
++linep;
if (unlikely (linep >= lineendp))
- goto invalid_data;
+ goto invalid_unit;
puts (gettext ("\nFile name table:\n"
" Entry Dir Time Size Name"));
for (unsigned int cnt = 1; *linep != 0; ++cnt)
@@ -4426,7 +4488,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
char *fname = (char *) linep;
unsigned char *endp = memchr (fname, '\0', lineendp - linep);
if (endp == NULL)
- goto invalid_data;
+ goto invalid_unit;
linep = endp + 1;
/* Then the index. */
@@ -4517,13 +4579,13 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
{
/* This an extended opcode. */
if (unlikely (linep + 2 > lineendp))
- goto invalid_data;
+ goto invalid_unit;
/* The length. */
unsigned int len = *linep++;
if (unlikely (linep + len > lineendp))
- goto invalid_data;
+ goto invalid_unit;
/* The sub-opcode. */
opcode = *linep++;
@@ -4559,7 +4621,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
unsigned char *endp = memchr (linep, '\0',
lineendp - linep);
if (endp == NULL)
- goto invalid_data;
+ goto invalid_unit;
linep = endp + 1;
unsigned int diridx;
@@ -4626,7 +4688,7 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
case DW_LNS_set_column:
/* Takes one uleb128 parameter which is stored in column. */
if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
+ goto invalid_unit;
get_uleb128 (u128, linep);
printf (gettext (" set column to %" PRIu64 "\n"),
@@ -4662,7 +4724,7 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
/* Takes one 16 bit parameter which is added to the
address. */
if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
+ goto invalid_unit;
u128 = read_2ubyte_unaligned_inc (dbg, linep);
address += u128;
@@ -5888,7 +5950,7 @@ hex_dump (const uint8_t *data, size_t len)
printf ("%02x", data[pos + i]);
if (chunk < 16)
- printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk) / 4), "");
+ printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk + 3) / 4), "");
for (size_t i = 0; i < chunk; ++i)
{
diff --git a/src/unstrip.c b/src/unstrip.c
index d19ad27e..2670835a 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -87,7 +87,7 @@ static const struct argp_option options[] =
N_("Create output for modules that have no separate debug information"),
0 },
{ "relocate", 'R', NULL, 0,
- N_("Apply relocations to DWARF sections in ET_REL files"), 0 },
+ N_("Apply relocations to section contents in ET_REL files"), 0 },
{ "list-only", 'n', NULL, 0,
N_("Only list module and file names, build IDs"), 0 },
{ NULL, 0, NULL, 0, NULL, 0 }
@@ -719,17 +719,27 @@ struct symbol
const char *name;
struct Ebl_Strent *strent;
};
- GElf_Addr value;
- GElf_Xword size;
- GElf_Word shndx;
union
{
struct
{
- uint8_t info;
- uint8_t other;
- } info;
- int16_t compare;
+ GElf_Addr value;
+ GElf_Xword size;
+ GElf_Word shndx;
+ union
+ {
+ struct
+ {
+ uint8_t info;
+ uint8_t other;
+ } info;
+ int16_t compare;
+ };
+ };
+
+ /* For a symbol discarded after first sort, this matches its better's
+ map pointer. */
+ size_t *duplicate;
};
};
@@ -819,7 +829,7 @@ compare_symbols_output (const void *a, const void *b)
int cmp;
/* Sort discarded symbols last. */
- cmp = (*s1->map == 0) - (*s2->map == 0);
+ cmp = (s1->name == NULL) - (s2->name == NULL);
if (cmp == 0)
/* Local symbols must come first. */
@@ -1605,31 +1615,65 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
new slots, collecting a map from old indices to new. */
size_t nsym = 0;
for (struct symbol *s = symbols; s < &symbols[total_syms]; ++s)
- /* Skip a section symbol for a removed section, or a duplicate. */
- *s->map = (((s->shndx == SHN_UNDEF
- && GELF_ST_TYPE (s->info.info) == STT_SECTION)
- || (s + 1 < &symbols[total_syms]
- && !compare_symbols (s, s + 1))) ? 0
- /* Allocate the next slot. */
- : ++nsym);
+ {
+ /* Skip a section symbol for a removed section. */
+ if (s->shndx == SHN_UNDEF
+ && GELF_ST_TYPE (s->info.info) == STT_SECTION)
+ {
+ s->name = NULL; /* Mark as discarded. */
+ *s->map = STN_UNDEF;
+ s->duplicate = NULL;
+ continue;
+ }
+
+ struct symbol *n = s;
+ while (n + 1 < &symbols[total_syms] && !compare_symbols (s, n + 1))
+ ++n;
+
+ while (s < n)
+ {
+ /* This is a duplicate. Its twin will get the next slot. */
+ s->name = NULL; /* Mark as discarded. */
+ s->duplicate = n->map;
+ ++s;
+ }
+
+ /* Allocate the next slot. */
+ *s->map = ++nsym;
+ }
/* Now we sort again, to determine the order in the output. */
qsort (symbols, total_syms, sizeof symbols[0], compare_symbols_output);
if (nsym < total_syms)
/* The discarded symbols are now at the end of the table. */
- assert (*symbols[nsym].map == 0);
+ assert (symbols[nsym].name == NULL);
/* Now a final pass updates the map with the final order,
and builds up the new string table. */
symstrtab = ebl_strtabinit (true);
for (size_t i = 0; i < nsym; ++i)
{
+ assert (symbols[i].name != NULL);
assert (*symbols[i].map != 0);
- *symbols[i].map = i;
+ *symbols[i].map = 1 + i;
symbols[i].strent = ebl_strtabadd (symstrtab, symbols[i].name, 0);
}
+ /* Scan the discarded symbols too, just to update their slots
+ in SYMNDX_MAP to refer to their live duplicates. */
+ for (size_t i = nsym; i < total_syms; ++i)
+ {
+ assert (symbols[i].name == NULL);
+ if (symbols[i].duplicate == NULL)
+ assert (*symbols[i].map == STN_UNDEF);
+ else
+ {
+ assert (*symbols[i].duplicate != STN_UNDEF);
+ *symbols[i].map = *symbols[i].duplicate;
+ }
+ }
+
/* Now we are ready to write the new symbol table. */
symdata = elf_getdata (unstripped_symtab, NULL);
symstrdata = elf_getdata (unstripped_strtab, NULL);