summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRoland McGrath <[email protected]>2007-08-23 08:10:54 +0000
committerRoland McGrath <[email protected]>2007-08-23 08:10:54 +0000
commitcb6d865011ad98a8ac2018f072f396a2268739ca (patch)
treec497c4dacb592f9da5f5740a8b9fa8d362468079 /src
parent50c6a2f8b9621ae01c8943e80c39bc859c9d5c22 (diff)
readelf register printing sort order tweak
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog46
-rw-r--r--src/nm.c53
-rw-r--r--src/readelf.c659
-rw-r--r--src/unstrip.c129
4 files changed, 785 insertions, 102 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 77c98381..2c51f472 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,49 @@
+2007-08-23 Roland McGrath <[email protected]>
+
+ * readelf.c (printf_with_wrap): Function removed.
+ (REGISTER_WRAP_COLUMN): New macro.
+ (handle_core_register): Use print_core_item instead.
+ (struct register_info): New type.
+ (compare_registers, compare_register_sets): New functions.
+ (register_bitpos, compare_sets_by_info): New functions.
+ (handle_core_registers): Use those to segregate and sort registers
+ for display.
+
+ * readelf.c (ITEM_WRAP_COLUMN): New macro.
+ (print_core_item): New function.
+ (handle_core_item): Use it instead of printf_with_wrap.
+ (compare_core_items, compare_core_item_groups): New functions.
+ (handle_core_items): Use them. Sort by group and force line breaks
+ between groups.
+
+ * readelf.c (handle_core_registers, handle_core_items): New functions,
+ broken out of ...
+ (handle_core_note): ... here. Call them.
+
+2007-08-22 Roland McGrath <[email protected]>
+
+ * unstrip.c (new_shstrtab): New function, broken out of ...
+ (copy_elided_sections): ... here.
+
+2007-08-20 Roland McGrath <[email protected]>
+
+ Avoid local function trampolines in nm binary.
+ * nm.c (sort_by_address): Move to a static function instead of local
+ inside show_symbols.
+ (sort_by_name_strtab): New static variable.
+ (sort_by_name): Use it. Move to a static function instead of local
+ inside show_symbols.
+ (show_symbols): Set sort_by_name_strtab.
+
+2007-08-19 Roland McGrath <[email protected]>
+
+ * readelf.c (handle_auxv_note): New function.
+ (handle_notes): Call it.
+
+ * readelf.c (printf_with_wrap, convert): New functions.
+ (handle_core_item, (handle_core_register): New functions.
+ (handle_notes): Call those with details from ebl_core_note.
+
2007-08-12 Roland McGrath <[email protected]>
* elflint.c (check_note): Accept type 0 with name "Linux".
diff --git a/src/nm.c b/src/nm.c
index d79b0058..48f08aca 100644
--- a/src/nm.c
+++ b/src/nm.c
@@ -938,34 +938,39 @@ show_symbols_posix (Elf *elf, GElf_Word strndx, const char *prefix,
/* Maximum size of memory we allocate on the stack. */
#define MAX_STACK_ALLOC 65536
-static void
-show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn,
- GElf_Shdr *shdr, const char *prefix, const char *fname,
- const char *fullname)
+static int
+sort_by_address (const void *p1, const void *p2)
{
- int sort_by_name (const void *p1, const void *p2)
- {
- GElf_SymX *s1 = (GElf_SymX *) p1;
- GElf_SymX *s2 = (GElf_SymX *) p2;
- int result;
+ GElf_SymX *s1 = (GElf_SymX *) p1;
+ GElf_SymX *s2 = (GElf_SymX *) p2;
- result = strcmp (elf_strptr (ebl->elf, shdr->sh_link, s1->sym.st_name),
- elf_strptr (ebl->elf, shdr->sh_link, s2->sym.st_name));
+ int result = (s1->sym.st_value < s2->sym.st_value
+ ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1));
- return reverse_sort ? -result : result;
- }
+ return reverse_sort ? -result : result;
+}
- int sort_by_address (const void *p1, const void *p2)
- {
- GElf_SymX *s1 = (GElf_SymX *) p1;
- GElf_SymX *s2 = (GElf_SymX *) p2;
+static Elf_Data *sort_by_name_strtab;
+
+static int
+sort_by_name (const void *p1, const void *p2)
+{
+ GElf_SymX *s1 = (GElf_SymX *) p1;
+ GElf_SymX *s2 = (GElf_SymX *) p2;
- int result = (s1->sym.st_value < s2->sym.st_value
- ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1));
+ const char *n1 = sort_by_name_strtab->d_buf + s1->sym.st_name;
+ const char *n2 = sort_by_name_strtab->d_buf + s2->sym.st_name;
- return reverse_sort ? -result : result;
- }
+ int result = strcmp (n1, n2);
+
+ return reverse_sort ? -result : result;
+}
+static void
+show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn,
+ GElf_Shdr *shdr, const char *prefix, const char *fname,
+ const char *fullname)
+{
/* Get the section header string table index. */
size_t shstrndx;
if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
@@ -1142,7 +1147,11 @@ show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn,
/* Sort the entries according to the users wishes. */
if (sort == sort_name)
- qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name);
+ {
+ sort_by_name_strtab = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link),
+ NULL);
+ qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name);
+ }
else if (sort == sort_numeric)
qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address);
diff --git a/src/readelf.c b/src/readelf.c
index e8b0bb4a..74730959 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -41,6 +41,7 @@
#include <libdw.h>
#include <libintl.h>
#include <locale.h>
+#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -4949,6 +4950,621 @@ print_debug (Ebl *ebl, GElf_Ehdr *ehdr)
}
+#define ITEM_INDENT 4
+#define ITEM_WRAP_COLUMN 150
+#define REGISTER_WRAP_COLUMN 75
+
+/* Print "NAME: FORMAT", wrapping when FORMAT_MAX chars of FORMAT would
+ make the line exceed ITEM_WRAP_COLUMN. Unpadded numbers look better
+ for the core items. But we do not want the line breaks to depend on
+ the particular values. */
+static unsigned int
+__attribute__ ((format (printf, 7, 8)))
+print_core_item (unsigned int colno, char sep, unsigned int wrap,
+ size_t name_width, const char *name,
+ size_t format_max, const char *format, ...)
+{
+ size_t len = strlen (name);
+ if (name_width < len)
+ name_width = len;
+
+ size_t n = name_width + sizeof ": " - 1 + format_max;
+
+ if (colno == 0)
+ {
+ printf ("%*s", ITEM_INDENT, "");
+ colno = ITEM_INDENT + n;
+ }
+ else if (colno + 2 + n < wrap)
+ {
+ printf ("%c ", sep);
+ colno += 2 + n;
+ }
+ else
+ {
+ printf ("\n%*s", ITEM_INDENT, "");
+ colno = ITEM_INDENT + n;
+ }
+
+ printf ("%s: %*s", name, (int) (name_width - len), "");
+
+ va_list ap;
+ va_start (ap, format);
+ vprintf (format, ap);
+ va_end (ap);
+
+ return colno;
+}
+
+static const void *
+convert (Elf *core, Elf_Type type, uint_fast16_t count,
+ void *value, const void *data)
+{
+ Elf_Data valuedata =
+ {
+ .d_type = type,
+ .d_buf = value,
+ .d_size = gelf_fsize (core, type, count, EV_CURRENT),
+ .d_version = EV_CURRENT,
+ };
+ Elf_Data indata =
+ {
+ .d_type = type,
+ .d_buf = (void *) data,
+ .d_size = valuedata.d_size,
+ .d_version = EV_CURRENT,
+ };
+
+ Elf_Data *d = (gelf_getclass (core) == ELFCLASS32
+ ? elf32_xlatetom : elf64_xlatetom)
+ (&valuedata, &indata, elf_getident (core, NULL)[EI_DATA]);
+ if (d == NULL)
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot convert core note data: %s"), elf_errmsg (-1));
+
+ return data + indata.d_size;
+}
+
+typedef uint8_t GElf_Byte;
+
+static unsigned int
+handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
+ unsigned int colno)
+{
+ uint_fast16_t count = item->count ?: 1;
+
+#define TYPES \
+ DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8, 4); \
+ DO_TYPE (HALF, Half, "0x%.4" PRIx16, "%" PRId16, 6); \
+ DO_TYPE (WORD, Word, "0x%.8" PRIx32, "%" PRId32, 11); \
+ DO_TYPE (SWORD, Sword, "%" PRId32, "%" PRId32, 11); \
+ DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64, 20); \
+ DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64, 20)
+
+#define DO_TYPE(NAME, Name, hex, dec, max) GElf_##Name Name[count]
+ union { TYPES; } value;
+#undef DO_TYPE
+
+ desc = convert (core, item->type, count, &value, desc + item->offset);
+
+ switch (item->format)
+ {
+ case 'd':
+ assert (count == 1);
+ switch (item->type)
+ {
+#define DO_TYPE(NAME, Name, hex, dec, max) \
+ case ELF_T_##NAME: \
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, \
+ 0, item->name, max, dec, value.Name[0]); \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ break;
+
+ case 'x':
+ assert (count == 1);
+ switch (item->type)
+ {
+#define DO_TYPE(NAME, Name, hex, dec, max) \
+ case ELF_T_##NAME: \
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, \
+ 0, item->name, max, hex, value.Name[0]); \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ break;
+
+ case 'b':
+ assert (count == 1);
+ Dwarf_Word bits = 0;
+ Dwarf_Word bit = 0;
+ switch (item->type)
+ {
+#define DO_TYPE(NAME, Name, hex, dec, max) \
+ case ELF_T_##NAME: \
+ bits = value.Name[0]; \
+ bit = (Dwarf_Word) 1 << ((sizeof value.Name[0] * 8) - 1); \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ char printed[sizeof (Dwarf_Word) * 8 + 1];
+ int i = 0;
+ while (bit != 0)
+ {
+ printed[i++] = (bits & bit) ? '1' : '0';
+ bit >>= 1;
+ }
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
+ sizeof printed - 1, "%.*s", i, printed);
+ break;
+
+ case 'T':
+ assert (count == 2);
+ Dwarf_Word sec;
+ Dwarf_Word usec;
+ size_t maxfmt = 7;
+ switch (item->type)
+ {
+#define DO_TYPE(NAME, Name, hex, dec, max) \
+ case ELF_T_##NAME: \
+ sec = value.Name[0]; \
+ usec = value.Name[1]; \
+ maxfmt += max; \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
+ maxfmt, "%" PRIu64 ".%.6" PRIu64, sec, usec);
+ break;
+
+ case 'c':
+ assert (count == 1);
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
+ 1, "%c", value.Byte[0]);
+ break;
+
+ case 's':
+ colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
+ count, "%.*s", (int) count, value.Byte);
+ break;
+
+ default:
+ error (0, 0, "XXX not handling format '%c' for %s",
+ item->format, item->name);
+ break;
+ }
+
+#undef TYPES
+
+ return colno;
+}
+
+
+/* Sort items by group, and by layout offset within each group. */
+static int
+compare_core_items (const void *a, const void *b)
+{
+ const Ebl_Core_Item *const *p1 = a;
+ const Ebl_Core_Item *const *p2 = b;
+ const Ebl_Core_Item *item1 = *p1;
+ const Ebl_Core_Item *item2 = *p2;
+
+ return ((item1->group == item2->group ? 0
+ : strcmp (item1->group, item2->group))
+ ?: (int) item1->offset - (int) item2->offset);
+}
+
+/* Sort item groups by layout offset of the first item in the group. */
+static int
+compare_core_item_groups (const void *a, const void *b)
+{
+ const Ebl_Core_Item *const *const *p1 = a;
+ const Ebl_Core_Item *const *const *p2 = b;
+ const Ebl_Core_Item *const *group1 = *p1;
+ const Ebl_Core_Item *const *group2 = *p2;
+ const Ebl_Core_Item *item1 = *group1;
+ const Ebl_Core_Item *item2 = *group2;
+
+ return (int) item1->offset - (int) item2->offset;
+}
+
+static unsigned int
+handle_core_items (Elf *core, const void *desc,
+ const Ebl_Core_Item *items, size_t nitems)
+{
+ if (nitems == 0)
+ return 0;
+
+ /* Sort to collect the groups together. */
+ const Ebl_Core_Item *sorted_items[nitems];
+ for (size_t i = 0; i < nitems; ++i)
+ sorted_items[i] = &items[i];
+ qsort (sorted_items, nitems, sizeof sorted_items[0], &compare_core_items);
+
+ /* Collect the unique groups and sort them. */
+ const Ebl_Core_Item **groups[nitems];
+ groups[0] = &sorted_items[0];
+ size_t ngroups = 1;
+ for (size_t i = 1; i < nitems; ++i)
+ if (sorted_items[i]->group != sorted_items[i - 1]->group
+ && strcmp (sorted_items[i]->group, sorted_items[i - 1]->group))
+ groups[ngroups++] = &sorted_items[i];
+ qsort (groups, ngroups, sizeof groups[0], &compare_core_item_groups);
+
+ /* Write out all the groups. */
+ unsigned int colno = 0;
+ for (size_t i = 0; i < ngroups; ++i)
+ {
+ for (const Ebl_Core_Item **item = groups[i];
+ (item < &sorted_items[nitems]
+ && ((*item)->group == groups[i][0]->group
+ || !strcmp ((*item)->group, groups[i][0]->group)));
+ ++item)
+ colno = handle_core_item (core, *item, desc, colno);
+
+ /* Force a line break at the end of the group. */
+ colno = ITEM_WRAP_COLUMN;
+ }
+
+ return colno;
+}
+
+static unsigned int
+handle_bit_registers (const Ebl_Register_Location *regloc, const void *desc,
+ unsigned int colno)
+{
+ desc += regloc->offset;
+
+ abort (); /* XXX */
+ return colno;
+}
+
+
+static unsigned int
+handle_core_register (Ebl *ebl, Elf *core, int maxregname,
+ const Ebl_Register_Location *regloc, const void *desc,
+ unsigned int colno)
+{
+ if (regloc->bits % 8 != 0)
+ return handle_bit_registers (regloc, desc, colno);
+
+ desc += regloc->offset;
+
+ for (int reg = regloc->regno; reg < regloc->regno + regloc->count; ++reg)
+ {
+ const char *pfx;
+ const char *set;
+ char name[16];
+ int bits;
+ int type;
+ ssize_t n = ebl_register_info (ebl, reg, name, sizeof name,
+ &pfx, &set, &bits, &type);
+ if (n <= 0)
+ error (EXIT_FAILURE, 0,
+ gettext ("unable to handle register number %d"),
+ regloc->regno);
+
+#define TYPES \
+ BITS (8, BYTE, "%4" PRId8, "0x%.2" PRIx8, 4); \
+ BITS (16, HALF, "%6" PRId16, "0x%.4" PRIx16, 6); \
+ BITS (32, WORD, "%11" PRId32, " 0x%.8" PRIx32, 11); \
+ BITS (64, XWORD, "%20" PRId64, " 0x%.16" PRIx64, 20)
+
+#define BITS(bits, xtype, sfmt, ufmt, max) \
+ uint##bits##_t b##bits; int##bits##_t b##bits##s
+ union { TYPES; uint64_t b128[2]; } value;
+#undef BITS
+
+ switch (type)
+ {
+ case DW_ATE_unsigned:
+ case DW_ATE_signed:
+ case DW_ATE_address:
+ switch (bits)
+ {
+#define BITS(bits, xtype, sfmt, ufmt, max) \
+ case bits: \
+ desc = convert (core, ELF_T_##xtype, 1, &value, desc); \
+ if (type == DW_ATE_signed) \
+ colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, \
+ maxregname, name, \
+ max, sfmt, value.b##bits##s); \
+ else \
+ colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, \
+ maxregname, name, \
+ max, ufmt, value.b##bits); \
+ break
+
+ TYPES;
+
+ case 128:
+ assert (type == DW_ATE_unsigned);
+ desc = convert (core, ELF_T_XWORD, 2, &value, desc);
+ int be = elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB;
+ colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN,
+ maxregname, name,
+ 34, "0x%.16" PRIx64 "%.16" PRIx64,
+ value.b128[!be], value.b128[be]);
+ break;
+
+ default:
+ abort ();
+#undef BITS
+ }
+ break;
+
+ default:
+ /* Print each byte in hex, the whole thing in native byte order. */
+ assert (bits % 8 == 0);
+ const uint8_t *bytes = desc;
+ desc += bits / 8;
+ char hex[bits / 4 + 1];
+ hex[bits / 4] = '\0';
+ int incr = 1;
+ if (elf_getident (core, NULL)[EI_DATA] == ELFDATA2LSB)
+ {
+ bytes += bits / 8 - 1;
+ incr = -1;
+ }
+ size_t idx = 0;
+ for (char *h = hex; bits > 0; bits -= 8, idx += incr)
+ {
+ *h++ = "0123456789abcdef"[bytes[idx] >> 4];
+ *h++ = "0123456789abcdef"[bytes[idx] & 0xf];
+ }
+ colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN,
+ maxregname, name,
+ 2 + sizeof hex - 1, "0x%s", hex);
+ break;
+ }
+ desc += regloc->pad;
+
+#undef TYPES
+ }
+
+ return colno;
+}
+
+
+struct register_info
+{
+ const Ebl_Register_Location *regloc;
+ const char *set;
+ char name[16];
+ Dwarf_Half regno;
+ uint8_t bits;
+ uint8_t type;
+};
+
+static int
+register_bitpos (const struct register_info *r)
+{
+ return (r->regloc->offset * 8
+ + ((r->regno - r->regloc->regno)
+ * (r->regloc->bits + r->regloc->pad * 8)));
+}
+
+static int
+compare_sets_by_info (const struct register_info *r1,
+ const struct register_info *r2)
+{
+ return ((int) r2->bits - (int) r1->bits
+ ?: register_bitpos (r1) - register_bitpos (r2));
+}
+
+/* Sort registers by set, and by size and layout offset within each set. */
+static int
+compare_registers (const void *a, const void *b)
+{
+ const struct register_info *r1 = a;
+ const struct register_info *r2 = b;
+
+ /* Unused elements sort last. */
+ if (r1->regloc == NULL)
+ return r2->regloc == NULL ? 0 : 1;
+ if (r2->regloc == NULL)
+ return -1;
+
+ return ((r1->set == r2->set ? 0 : strcmp (r1->set, r2->set))
+ ?: compare_sets_by_info (r1, r2));
+}
+
+/* Sort register sets by layout offset of the first register in the set. */
+static int
+compare_register_sets (const void *a, const void *b)
+{
+ const struct register_info *const *p1 = a;
+ const struct register_info *const *p2 = b;
+ return compare_sets_by_info (*p1, *p2);
+}
+
+static unsigned int
+handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
+ const Ebl_Register_Location *reglocs, size_t nregloc)
+{
+ if (nregloc == 0)
+ return 0;
+
+ ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL);
+ if (maxnreg <= 0)
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot register info: %s"), elf_errmsg (-1));
+
+ struct register_info regs[maxnreg];
+ memset (regs, 0, sizeof regs);
+
+ /* Sort to collect the sets together. */
+ int maxreg = 0;
+ for (size_t i = 0; i < nregloc; ++i)
+ for (int reg = reglocs[i].regno;
+ reg < reglocs[i].regno + reglocs[i].count;
+ ++reg)
+ {
+ assert (reg < maxnreg);
+ if (reg > maxreg)
+ maxreg = reg;
+ struct register_info *info = &regs[reg];
+
+ const char *pfx;
+ int bits;
+ int type;
+ ssize_t n = ebl_register_info (ebl, reg, info->name, sizeof info->name,
+ &pfx, &info->set, &bits, &type);
+ if (n <= 0)
+ error (EXIT_FAILURE, 0,
+ gettext ("cannot register info: %s"), elf_errmsg (-1));
+
+ info->regloc = &reglocs[i];
+ info->regno = reg;
+ info->bits = bits;
+ info->type = type;
+ }
+ qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers);
+
+ /* Collect the unique sets and sort them. */
+ inline bool same_set (const struct register_info *a,
+ const struct register_info *b)
+ {
+ return (a < &regs[maxnreg] && a->regloc != NULL
+ && b < &regs[maxnreg] && b->regloc != NULL
+ && a->bits == b->bits
+ && (a->set == b->set || !strcmp (a->set, b->set)));
+ }
+ struct register_info *sets[maxreg + 1];
+ sets[0] = &regs[0];
+ size_t nsets = 1;
+ for (int i = 1; i <= maxreg; ++i)
+ if (regs[i].regloc != NULL && !same_set (&regs[i], &regs[i - 1]))
+ sets[nsets++] = &regs[i];
+ qsort (sets, nsets, sizeof sets[0], &compare_register_sets);
+
+ /* Write out all the sets. */
+ unsigned int colno = 0;
+ for (size_t i = 0; i < nsets; ++i)
+ {
+ /* Find the longest name of a register in this set. */
+ size_t maxname = 0;
+ const struct register_info *end;
+ for (end = sets[i]; same_set (sets[i], end); ++end)
+ {
+ size_t len = strlen (end->name);
+ if (len > maxname)
+ maxname = len;
+ }
+
+ for (const struct register_info *reg = sets[i];
+ reg < end;
+ reg += reg->regloc->count ?: 1)
+ colno = handle_core_register (ebl, core, maxname,
+ reg->regloc, desc, colno);
+
+ /* Force a line break at the end of the group. */
+ colno = REGISTER_WRAP_COLUMN;
+ }
+
+ return colno;
+}
+
+static void
+handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, const void *desc)
+{
+ 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;
+
+ const char *name;
+ const char *fmt;
+ if (ebl_auxv_info (ebl, av->a_type, &name, &fmt) == 0)
+ {
+ /* Unknown type. */
+ if (av->a_un.a_val == 0)
+ printf (" %" PRIu64 "\n", av->a_type);
+ else
+ printf (" %" PRIu64 ": %#" PRIx64 "\n",
+ av->a_type, av->a_un.a_val);
+ }
+ else
+ switch (fmt[0])
+ {
+ case '\0': /* Normally zero. */
+ if (av->a_un.a_val == 0)
+ {
+ printf (" %s\n", name);
+ break;
+ }
+ /* Fall through */
+ case 'x': /* hex */
+ case 'p': /* address */
+ case 's': /* address of string */
+ printf (" %s: %#" PRIx64 "\n", name, av->a_un.a_val);
+ break;
+ case 'u':
+ printf (" %s: %" PRIu64 "\n", name, av->a_un.a_val);
+ break;
+ case 'd':
+ printf (" %s: %" PRId64 "\n", name, av->a_un.a_val);
+ break;
+
+ case 'b':
+ printf (" %s: %#" PRIx64 " ", name, av->a_un.a_val);
+ GElf_Xword bit = 1;
+ const char *pfx = "<";
+ for (const char *p = fmt + 1; *p != 0; p = strchr (p, '\0') + 1)
+ {
+ if (av->a_un.a_val & bit)
+ {
+ printf ("%s%s", pfx, p);
+ pfx = " ";
+ }
+ bit <<= 1;
+ }
+ printf (">\n");
+ break;
+
+ default:
+ abort ();
+ }
+ }
+}
+
+static void
+handle_core_note (Ebl *ebl, const GElf_Nhdr *nhdr, const void *desc)
+{
+ GElf_Word regs_offset;
+ size_t nregloc;
+ const Ebl_Register_Location *reglocs;
+ size_t nitems;
+ const Ebl_Core_Item *items;
+
+ if (! ebl_core_note (ebl, nhdr->n_type, nhdr->n_descsz,
+ &regs_offset, &nregloc, &reglocs, &nitems, &items))
+ return;
+
+ unsigned int colno = handle_core_items (ebl->elf, desc, items, nitems);
+ if (colno != 0)
+ putchar_unlocked ('\n');
+
+ colno = handle_core_registers (ebl, ebl->elf, desc + regs_offset,
+ reglocs, nregloc);
+ if (colno != 0)
+ putchar_unlocked ('\n');
+}
+
+
static void
handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
{
@@ -4998,18 +5614,13 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
size_t idx = 0;
while (idx < phdr->p_filesz)
{
- /* XXX Handle 64-bit note section entries correctly. */
- struct
- {
- uint32_t namesz;
- uint32_t descsz;
- uint32_t type;
- char name[0];
- } *noteentry = (__typeof (noteentry)) (notemem + idx);
+ 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 (noteentry->namesz)
- + ALIGNED_LEN (noteentry->descsz) > 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;
@@ -5017,32 +5628,34 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
char buf[100];
char buf2[100];
printf (gettext (" %-13.*s %9" PRId32 " %s\n"),
- (int) noteentry->namesz, noteentry->name,
- noteentry->descsz,
+ (int) nhdr->n_namesz, name,
+ nhdr->n_descsz,
ehdr->e_type == ET_CORE
- ? ebl_core_note_type_name (ebl, noteentry->type,
+ ? ebl_core_note_type_name (ebl, nhdr->n_type,
buf, sizeof (buf))
- : ebl_object_note_type_name (ebl, noteentry->type,
+ : ebl_object_note_type_name (ebl, nhdr->n_type,
buf2, sizeof (buf2)));
/* Filter out invalid entries. */
- if (memchr (noteentry->name, '\0', noteentry->namesz) != NULL
+ if (memchr (name, '\0', nhdr->n_namesz) != NULL
/* XXX For now help broken Linux kernels. */
|| 1)
{
if (ehdr->e_type == ET_CORE)
- ebl_core_note (ebl, noteentry->name, noteentry->type,
- noteentry->descsz,
- &noteentry->name[ALIGNED_LEN (noteentry->namesz)]);
+ {
+ 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, noteentry->name, noteentry->type,
- noteentry->descsz,
- &noteentry->name[ALIGNED_LEN (noteentry->namesz)]);
+ ebl_object_note (ebl, name, nhdr->n_type,
+ nhdr->n_descsz, desc);
}
/* Move to the next entry. */
- idx += (12 + ALIGNED_LEN (noteentry->namesz)
- + ALIGNED_LEN (noteentry->descsz));
+ idx += (12 + ALIGNED_LEN (nhdr->n_namesz)
+ + ALIGNED_LEN (nhdr->n_descsz));
}
gelf_freechunk (ebl->elf, notemem);
diff --git a/src/unstrip.c b/src/unstrip.c
index c1d40f1c..a8c30022 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -1094,6 +1094,73 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
return split_bss;
}
+/* Create new .shstrtab contents, subroutine of copy_elided_sections.
+ This can't be open coded there and still use variable-length auto arrays,
+ since the end of our block would free other VLAs too. */
+static Elf_Data *
+new_shstrtab (Elf *unstripped, size_t unstripped_shnum,
+ Elf_Data *shstrtab, size_t unstripped_shstrndx,
+ struct section *sections, size_t stripped_shnum,
+ struct Ebl_Strtab *strtab)
+{
+ if (strtab == NULL)
+ return NULL;
+
+ struct Ebl_Strent *unstripped_strent[unstripped_shnum - 1];
+ memset (unstripped_strent, 0, sizeof unstripped_strent);
+ for (struct section *sec = sections;
+ sec < &sections[stripped_shnum - 1];
+ ++sec)
+ if (sec->outscn != NULL)
+ {
+ if (sec->strent == NULL)
+ {
+ sec->strent = ebl_strtabadd (strtab, sec->name, 0);
+ ELF_CHECK (sec->strent != NULL,
+ _("cannot add section name to string table: %s"));
+ }
+ unstripped_strent[elf_ndxscn (sec->outscn) - 1] = sec->strent;
+ }
+
+ /* Add names of sections we aren't touching. */
+ for (size_t i = 0; i < unstripped_shnum - 1; ++i)
+ if (unstripped_strent[i] == NULL)
+ {
+ Elf_Scn *scn = elf_getscn (unstripped, i + 1);
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ const char *name = get_section_name (i + 1, shdr, shstrtab);
+ unstripped_strent[i] = ebl_strtabadd (strtab, name, 0);
+ ELF_CHECK (unstripped_strent[i] != NULL,
+ _("cannot add section name to string table: %s"));
+ }
+ else
+ unstripped_strent[i] = NULL;
+
+ /* Now finalize the string table so we can get offsets. */
+ Elf_Data *strtab_data = elf_getdata (elf_getscn (unstripped,
+ unstripped_shstrndx), NULL);
+ ELF_CHECK (elf_flagdata (strtab_data, ELF_C_SET, ELF_F_DIRTY),
+ _("cannot update section header string table data: %s"));
+ ebl_strtabfinalize (strtab, strtab_data);
+
+ /* Update the sh_name fields of sections we aren't modifying later. */
+ for (size_t i = 0; i < unstripped_shnum - 1; ++i)
+ if (unstripped_strent[i] != NULL)
+ {
+ Elf_Scn *scn = elf_getscn (unstripped, i + 1);
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ shdr->sh_name = ebl_strtaboffset (unstripped_strent[i]);
+ if (i + 1 == unstripped_shstrndx)
+ shdr->sh_size = strtab_data->d_size;
+ ELF_CHECK (gelf_update_shdr (scn, shdr),
+ _("cannot update section header: %s"));
+ }
+
+ return strtab_data;
+}
+
/* Fill in any SHT_NOBITS sections in UNSTRIPPED by
copying their contents and sh_type from STRIPPED. */
static void
@@ -1310,63 +1377,11 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
ndx_section[secndx - 1] = elf_ndxscn (sec->outscn);
}
- Elf_Data *strtab_data = NULL;
- if (strtab != NULL)
- {
- /* We added some sections, so we need a new shstrtab. */
-
- struct Ebl_Strent *unstripped_strent[unstripped_shnum - 1];
- memset (unstripped_strent, 0, sizeof unstripped_strent);
- for (struct section *sec = sections;
- sec < &sections[stripped_shnum - 1];
- ++sec)
- if (sec->outscn != NULL)
- {
- if (sec->strent == NULL)
- {
- sec->strent = ebl_strtabadd (strtab, sec->name, 0);
- ELF_CHECK (sec->strent != NULL,
- _("cannot add section name to string table: %s"));
- }
- unstripped_strent[elf_ndxscn (sec->outscn) - 1] = sec->strent;
- }
-
- /* Add names of sections we aren't touching. */
- for (size_t i = 0; i < unstripped_shnum - 1; ++i)
- if (unstripped_strent[i] == NULL)
- {
- scn = elf_getscn (unstripped, i + 1);
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- const char *name = get_section_name (i + 1, shdr, shstrtab);
- unstripped_strent[i] = ebl_strtabadd (strtab, name, 0);
- ELF_CHECK (unstripped_strent[i] != NULL,
- _("cannot add section name to string table: %s"));
- }
- else
- unstripped_strent[i] = NULL;
-
- /* Now finalize the string table so we can get offsets. */
- strtab_data = elf_getdata (elf_getscn (unstripped, unstripped_shstrndx),
- NULL);
- ELF_CHECK (elf_flagdata (strtab_data, ELF_C_SET, ELF_F_DIRTY),
- _("cannot update section header string table data: %s"));
- ebl_strtabfinalize (strtab, strtab_data);
-
- /* Update the sh_name fields of sections we aren't modifying later. */
- for (size_t i = 0; i < unstripped_shnum - 1; ++i)
- if (unstripped_strent[i] != NULL)
- {
- scn = elf_getscn (unstripped, i + 1);
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- shdr->sh_name = ebl_strtaboffset (unstripped_strent[i]);
- if (i + 1 == unstripped_shstrndx)
- shdr->sh_size = strtab_data->d_size;
- ELF_CHECK (gelf_update_shdr (scn, shdr),
- _("cannot update section header: %s"));
- }
- }
+ /* We added some sections, so we need a new shstrtab. */
+ Elf_Data *strtab_data = new_shstrtab (unstripped, unstripped_shnum,
+ shstrtab, unstripped_shstrndx,
+ sections, stripped_shnum,
+ strtab);
/* Get the updated section count. */
ELF_CHECK (elf_getshnum (unstripped, &unstripped_shnum) == 0,