From: Roland McGrath Date: Fri, 3 Aug 2007 21:59:15 +0000 (+0000) Subject: 2007-08-03 Roland McGrath X-Git-Tag: elfutils-0.129~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=60fc84c4288cd6edda3a78dff95e52b5858bacb2;p=platform%2Fupstream%2Felfutils.git 2007-08-03 Roland McGrath * 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. --- diff --git a/NEWS b/NEWS index 95374f8..4eb1ead 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +Version 0.129: + +readelf: new options --hex-dump (or -x), --strings (or -p) + +addr2line: new option --symbols (or -S) + Version 0.128: new program: unstrip diff --git a/src/ChangeLog b/src/ChangeLog index c25db5b..d94dcfe 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,29 @@ +2007-08-03 Roland McGrath + + * 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 + + * 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 + + * 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 * addr2line.c: Update for latest autoconf header. diff --git a/src/addr2line.c b/src/addr2line.c index a112d34..394d065 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 6abf3e9..153176c 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); + } + } +}