summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2007-08-03 21:59:15 +0000
committerRoland McGrath <roland@redhat.com>2007-08-03 21:59:15 +0000
commit60fc84c4288cd6edda3a78dff95e52b5858bacb2 (patch)
tree53dc93ca398da24e8644488325e552d82e830b3a /src
parent87d4780beb37f265fa89ffd909e77513ef516180 (diff)
downloadelfutils-60fc84c4288cd6edda3a78dff95e52b5858bacb2.tar.gz
2007-08-03 Roland McGrath <roland@redhat.com>
* readelf.c (print_string_sections): New variable. (options, parse_opt): Handle --strings/-p to set it. (print_strings): New function. (process_elf_file): Call it under -p. * readelf.c (options): Add hidden aliases --segments, --sections, as taken by binutils readelf.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog26
-rw-r--r--src/addr2line.c36
-rw-r--r--src/readelf.c203
3 files changed, 264 insertions, 1 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index c25db5bb..d94dcfe1 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,29 @@
+2007-08-03 Roland McGrath <roland@redhat.com>
+
+ * readelf.c (print_string_sections): New variable.
+ (options, parse_opt): Handle --strings/-p to set it.
+ (print_strings): New function.
+ (process_elf_file): Call it under -p.
+
+ * readelf.c (options): Add hidden aliases --segments, --sections,
+ as taken by binutils readelf.
+
+2007-08-01 Roland McGrath <roland@redhat.com>
+
+ * readelf.c (dump_data_sections, dump_data_sections_tail):
+ New variables.
+ (options, parse_opt): Handle --hex-dump/-x, set them.
+ (hex_dump): New function.
+ (dump_data): New function, call it.
+ (process_elf_file): Call it.
+
+2007-07-25 Roland McGrath <roland@redhat.com>
+
+ * addr2line.c (show_symbols): New variable.
+ (print_addrsym): New function.
+ (handle_address): Call it.
+ (options, parse_opt): Handle -S/--symbols.
+
2007-06-05 Ulrich Drepper <drepper@redhat.com>
* addr2line.c: Update for latest autoconf header.
diff --git a/src/addr2line.c b/src/addr2line.c
index a112d348..394d0655 100644
--- a/src/addr2line.c
+++ b/src/addr2line.c
@@ -66,6 +66,7 @@ static const struct argp_option options[] =
{ "absolute", 'A', NULL, 0,
N_("Show absolute file names using compilation directory"), 0 },
{ "functions", 'f', NULL, 0, N_("Also show function names"), 0 },
+ { "symbols", 'S', NULL, 0, N_("Also show symbol or section names"), 0 },
{ NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
/* Unsupported options. */
@@ -107,6 +108,9 @@ static bool use_comp_dir;
/* True if function names should be shown. */
static bool show_functions;
+/* True if ELF symbol or section info should be shown. */
+static bool show_symbols;
+
int
main (int argc, char *argv[])
@@ -221,6 +225,10 @@ parse_opt (int key, char *arg __attribute__ ((unused)),
show_functions = true;
break;
+ case 'S':
+ show_symbols = true;
+ break;
+
default:
return ARGP_ERR_UNKNOWN;
}
@@ -298,6 +306,29 @@ print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
}
static void
+print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
+{
+ GElf_Sym s;
+ GElf_Word shndx;
+ const char *name = dwfl_module_addrsym (mod, addr, &s, &shndx);
+ if (name == NULL)
+ {
+ /* No symbol name. Get a section name instead. */
+ int i = dwfl_module_relocate_address (mod, &addr);
+ if (i >= 0)
+ name = dwfl_module_relocation_info (mod, i, NULL);
+ if (name == NULL)
+ puts ("??");
+ else
+ printf ("(%s)+%#" PRIx64 "\n", name, addr);
+ }
+ else if (addr == s.st_value)
+ puts (name);
+ else
+ printf ("%s+%#" PRIx64 "\n", name, addr - s.st_value);
+}
+
+static void
handle_address (GElf_Addr addr, Dwfl *dwfl)
{
Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr);
@@ -306,10 +337,13 @@ handle_address (GElf_Addr addr, Dwfl *dwfl)
{
/* First determine the function name. Use the DWARF information if
possible. */
- if (! print_dwarf_function (mod, addr))
+ if (! print_dwarf_function (mod, addr) && !show_symbols)
puts (dwfl_module_addrname (mod, addr) ?: "??");
}
+ if (show_symbols)
+ print_addrsym (mod, addr);
+
Dwfl_Line *line = dwfl_module_getsrc (mod, addr);
const char *src;
diff --git a/src/readelf.c b/src/readelf.c
index 6abf3e9f..153176c2 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -70,8 +70,10 @@ static const struct argp_option options[] =
{ "histogram", 'I', NULL, 0,
N_("Display histogram of bucket list lengths"), 0 },
{ "program-headers", 'l', NULL, 0, N_("Display the program headers"), 0 },
+ { "segments", 'l', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
{ "relocs", 'r', NULL, 0, N_("Display relocations"), 0 },
{ "section-headers", 'S', NULL, 0, N_("Display the sections' header"), 0 },
+ { "sections", 'S', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
{ "symbols", 's', NULL, 0, N_("Display the symbol table"), 0 },
{ "version-info", 'V', NULL, 0, N_("Display versioning information"), 0 },
{ "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL,
@@ -81,6 +83,10 @@ static const struct argp_option options[] =
{ "notes", 'n', NULL, 0, N_("Display the core notes"), 0 },
{ "arch-specific", 'A', NULL, 0,
N_("Display architecture specific information (if any)"), 0 },
+ { "hex-dump", 'x', "SECTION", 0,
+ N_("Dump the uninterpreted contents of SECTION, by number or name"), 0 },
+ { "strings", 'p', NULL, 0,
+ N_("Print contents of sections marked as containing only strings"), 0 },
{ NULL, 0, NULL, 0, N_("Output control:"), 0 },
@@ -139,6 +145,9 @@ static bool print_arch;
/* True if note section content should be printed. */
static bool print_notes;
+/* True if SHF_STRINGS section content should be printed. */
+static bool print_string_sections;
+
/* Select printing of debugging sections. */
static enum section_e
{
@@ -158,6 +167,16 @@ static enum section_e
| section_ranges)
} print_debug_sections;
+/* Select hex dumping of sections. */
+static struct section_argument *dump_data_sections;
+static struct section_argument **dump_data_sections_tail = &dump_data_sections;
+
+struct section_argument
+{
+ struct section_argument *next;
+ const char *arg;
+};
+
/* Number of sections in the file. */
static size_t shnum;
@@ -186,6 +205,8 @@ static void print_debug (Ebl *ebl, GElf_Ehdr *ehdr);
static void handle_hash (Ebl *ebl);
static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr);
static void print_liblist (Ebl *ebl);
+static void dump_data (Ebl *ebl);
+static void print_strings (Ebl *ebl);
int
@@ -303,6 +324,10 @@ parse_opt (int key, char *arg,
print_symbol_table = true;
any_control_option = true;
break;
+ case 'p':
+ print_string_sections = true;
+ any_control_option = true;
+ break;
case 'V':
print_version_info = true;
any_control_option = true;
@@ -340,6 +365,16 @@ parse_opt (int key, char *arg,
}
any_control_option = true;
break;
+ case 'x':
+ {
+ struct section_argument *a = xmalloc (sizeof *a);
+ a->arg = arg;
+ a->next = NULL;
+ *dump_data_sections_tail = a;
+ dump_data_sections_tail = &a->next;
+ }
+ any_control_option = true;
+ break;
case ARGP_KEY_NO_ARGS:
fputs (gettext ("Missing file name.\n"), stderr);
goto do_argp_help;
@@ -503,10 +538,14 @@ process_elf_file (Elf *elf, const char *prefix, const char *fname,
print_symtab (ebl, SHT_SYMTAB);
if (print_arch)
print_liblist (ebl);
+ if (dump_data_sections != NULL)
+ dump_data (ebl);
if (print_debug_sections != 0)
print_debug (ebl, ehdr);
if (print_notes)
handle_notes (ebl, ehdr);
+ if (print_string_sections)
+ print_strings (ebl);
ebl_closebackend (ebl);
}
@@ -5008,3 +5047,167 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
gelf_freechunk (ebl->elf, notemem);
}
}
+
+
+static void
+hex_dump (const uint8_t *data, size_t len)
+{
+ size_t pos = 0;
+ while (pos < len)
+ {
+ printf (" 0x%08Zu ", pos);
+
+ const size_t chunk = MIN (len - pos, 16);
+
+ for (size_t i = 0; i < chunk; ++i)
+ if (i % 4 == 3)
+ printf ("%02x ", data[pos + i]);
+ else
+ printf ("%02x", data[pos + i]);
+
+ if (chunk < 16)
+ printf ("%*s", (int) ((chunk - 16) * 2 + (chunk - 16) / 4), "");
+
+ for (size_t i = 0; i < chunk; ++i)
+ {
+ unsigned char b = data[pos + i];
+ printf ("%c", b > ' ' && b < 0x7f ? b : '.');
+ }
+
+ putchar ('\n');
+ pos += chunk;
+ }
+}
+
+static void
+dump_data (Ebl *ebl)
+{
+ /* 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"));
+
+ for (struct section_argument *a = dump_data_sections; a != NULL; a = a->next)
+ {
+ Elf_Scn *scn;
+ GElf_Shdr shdr_mem;
+ const char *name;
+
+ char *endp = NULL;
+ unsigned long int shndx = strtoul (a->arg, &endp, 0);
+ if (endp != NULL && endp != a->arg && *endp == '\0')
+ {
+ scn = elf_getscn (ebl->elf, shndx);
+ if (scn == NULL)
+ {
+ error (0, 0, gettext ("\nsection [%lu] does not exist"), shndx);
+ continue;
+ }
+
+ if (gelf_getshdr (scn, &shdr_mem) == NULL)
+ error (EXIT_FAILURE, 0, gettext ("cannot get section header: %s"),
+ elf_errmsg (-1));
+ name = elf_strptr (ebl->elf, shstrndx, shdr_mem.sh_name);
+ }
+ else
+ {
+ /* Need to look up the section by name. */
+ scn = NULL;
+ while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+ {
+ if (gelf_getshdr (scn, &shdr_mem) == NULL)
+ continue;
+ name = elf_strptr (ebl->elf, shstrndx, shdr_mem.sh_name);
+ if (name == NULL)
+ continue;
+ if (!strcmp (name, a->arg))
+ break;
+ }
+
+ if (scn == NULL)
+ {
+ error (0, 0, gettext ("\nsection '%s' does not exist"), a->arg);
+ continue;
+ }
+ }
+
+ if (shdr_mem.sh_size == 0 || shdr_mem.sh_type == SHT_NOBITS)
+ printf (gettext ("\nSection [%Zu] '%s' has no data to dump.\n"),
+ elf_ndxscn (scn), name);
+ else
+ {
+ Elf_Data *data = elf_rawdata (scn, NULL);
+ if (data == NULL)
+ error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
+ elf_ndxscn (scn), name, elf_errmsg (-1));
+ else
+ {
+ printf (gettext ("\nHex dump of section [%Zu] '%s', %" PRIu64
+ " bytes at offset %#0" PRIx64 ":\n"),
+ elf_ndxscn (scn), name,
+ shdr_mem.sh_size, shdr_mem.sh_offset);
+ hex_dump (data->d_buf, data->d_size);
+ }
+ }
+ }
+}
+
+static void
+print_strings (Ebl *ebl)
+{
+ /* 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;
+ GElf_Shdr shdr_mem;
+ const char *name;
+ scn = NULL;
+ while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+ {
+ if (gelf_getshdr (scn, &shdr_mem) == NULL)
+ continue;
+
+ if (shdr_mem.sh_type != SHT_PROGBITS
+ || !(shdr_mem.sh_flags & SHF_STRINGS))
+ continue;
+
+ name = elf_strptr (ebl->elf, shstrndx, shdr_mem.sh_name);
+ if (name == NULL)
+ continue;
+
+ if (shdr_mem.sh_size == 0)
+ printf (gettext ("\nSection [%Zu] '%s' is empty.\n"),
+ elf_ndxscn (scn), name);
+
+ Elf_Data *data = elf_rawdata (scn, NULL);
+ if (data == NULL)
+ error (0, 0, gettext ("cannot get data for section [%Zu] '%s': %s"),
+ elf_ndxscn (scn), name, elf_errmsg (-1));
+ else
+ {
+ printf (gettext ("\nString section [%Zu] '%s' contains %" PRIu64
+ " bytes at offset %#0" PRIx64 ":\n"),
+ elf_ndxscn (scn), name,
+ shdr_mem.sh_size, shdr_mem.sh_offset);
+
+ const char *start = data->d_buf;
+ const char *const limit = start + data->d_size;
+ do
+ {
+ const char *end = memchr (start, '\0', limit - start);
+ const size_t pos = start - (const char *) data->d_buf;
+ if (unlikely (end == NULL))
+ {
+ printf (" [%6Zx]- %.*s\n", pos, (int) (end - start), start);
+ break;
+ }
+ printf (" [%6Zx] %s\n", pos, start);
+ start = end + 1;
+ } while (start < limit);
+ }
+ }
+}