diff options
-rw-r--r-- | binutils/ChangeLog | 22 | ||||
-rw-r--r-- | binutils/Makefile.am | 2 | ||||
-rw-r--r-- | binutils/Makefile.in | 10 | ||||
-rw-r--r-- | binutils/NEWS | 2 | ||||
-rw-r--r-- | binutils/doc/Makefile.in | 4 | ||||
-rw-r--r-- | binutils/doc/binutils.texi | 7 | ||||
-rw-r--r-- | binutils/readelf.c | 180 | ||||
-rw-r--r-- | binutils/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | binutils/testsuite/binutils-all/dumptest.s | 2 | ||||
-rw-r--r-- | binutils/testsuite/binutils-all/readelf.exp | 66 |
10 files changed, 244 insertions, 56 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 430b954..0f6b075 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,25 @@ +2007-08-30 Nick Clifton <nickc@redhat.com> + + * readelf.c (dump_type): New type used to classify the kinds of + dump requested by the user. + (dump_sects, cmdline_dump_sects): Use the new type. + (options): Add --string-dump option. + (request_dump): Rename to request_dump_bynumber. Use dump_type. + (request_dump_byname): Use dump_type. + (parse_args): Parse --string-dump option. + (process_section_headers): Fix calls to request_dump. + (initialise_dumps_byname): Likewise. + (dump_section): Rename to dump_section_as_bytes. + (dump_section_as_strings): New function. Display the contents of + a section as printable strings. + (process_section_contents): String dump the section if requested. + (process_object): Use dump_type. + (main): Likewise. + * Makefile.am: Add dependency for readelf.c on safe-ctype.h. + * Makefile.in: Regenerate. + * NEWS: Mention the new feature. + * doc/binutils.texi: Document the new feature. + 2007-08-30 Nathan Sidwell <nathan@codesourcery.com> * bucomm.c (bfd_nonfatal_message): New. diff --git a/binutils/Makefile.am b/binutils/Makefile.am index 047622c..9590b18 100644 --- a/binutils/Makefile.am +++ b/binutils/Makefile.am @@ -593,7 +593,7 @@ readelf.o: readelf.c sysdep.h $(INCDIR)/ansidecl.h \ $(INCDIR)/elf/spu.h $(INCDIR)/elf/v850.h $(INCDIR)/elf/vax.h \ $(INCDIR)/elf/x86-64.h $(INCDIR)/elf/xstormy16.h $(INCDIR)/elf/xtensa.h \ $(INCDIR)/aout/ar.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h \ - unwind-ia64.h + unwind-ia64.h $(INCDIR)/safe-ctype.h rename.o: rename.c sysdep.h $(INCDIR)/ansidecl.h ../bfd/bfdver.h \ config.h $(INCDIR)/fopen-same.h ../bfd/bfd.h $(INCDIR)/ansidecl.h \ $(INCDIR)/symcat.h bucomm.h diff --git a/binutils/Makefile.in b/binutils/Makefile.in index eead9ef..e0fc8f3 100644 --- a/binutils/Makefile.in +++ b/binutils/Makefile.in @@ -532,15 +532,15 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --cygnus '; \ - cd $(srcdir) && $(AUTOMAKE) --cygnus \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ + cd $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --cygnus Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ cd $(top_srcdir) && \ - $(AUTOMAKE) --cygnus Makefile + $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -1343,7 +1343,7 @@ readelf.o: readelf.c sysdep.h $(INCDIR)/ansidecl.h \ $(INCDIR)/elf/spu.h $(INCDIR)/elf/v850.h $(INCDIR)/elf/vax.h \ $(INCDIR)/elf/x86-64.h $(INCDIR)/elf/xstormy16.h $(INCDIR)/elf/xtensa.h \ $(INCDIR)/aout/ar.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h \ - unwind-ia64.h + unwind-ia64.h $(INCDIR)/safe-ctype.h rename.o: rename.c sysdep.h $(INCDIR)/ansidecl.h ../bfd/bfdver.h \ config.h $(INCDIR)/fopen-same.h ../bfd/bfd.h $(INCDIR)/ansidecl.h \ $(INCDIR)/symcat.h bucomm.h diff --git a/binutils/NEWS b/binutils/NEWS index 20070d7..0009c6f 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -1,4 +1,6 @@ -*- text -*- +* Added -p switch to readelf to allow string dumps of sections. + Changes in 2.18: * Resolved 37 coding problems in bfd including static array overruns, null pointer dereferences and use of a malloc buffer after it has been freed, as diff --git a/binutils/doc/Makefile.in b/binutils/doc/Makefile.in index d258024..8136d2a 100644 --- a/binutils/doc/Makefile.in +++ b/binutils/doc/Makefile.in @@ -282,9 +282,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --cygnus doc/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \ cd $(top_srcdir) && \ - $(AUTOMAKE) --cygnus doc/Makefile + $(AUTOMAKE) --foreign doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 52787f7..a2768bf 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -3601,6 +3601,7 @@ readelf [@option{-a}|@option{--all}] [@option{-A}|@option{--arch-specific}] [@option{-D}|@option{--use-dynamic}] [@option{-x} <number or name>|@option{--hex-dump=}<number or name>] + [@option{-p} <number or name>|@option{--string-dump=}<number or name>] [@option{-w[liaprmfFsoR]}| @option{--debug-dump}[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges]] [@option{-I}|@option{-histogram}] @@ -3726,6 +3727,12 @@ Displays the contents of the indicated section as a hexadecimal dump. A number identifies a particular section by index in the section table; any other string identifies all sections with that name in the object file. +@item -p <number or name> +@itemx --string-dump=<number or name> +Displays the contents of the indicated section as printable strings. +A number identifies a particular section by index in the section table; +any other string identifies all sections with that name in the object file. + @item -w[liaprmfFsoR] @itemx --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges] Displays the contents of the debug sections in the file, if any are diff --git a/binutils/readelf.c b/binutils/readelf.c index 9fc8e0c..e166dca 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -158,6 +158,7 @@ #include "getopt.h" #include "libiberty.h" +#include "safe-ctype.h" char *program_name = "readelf"; static long archive_file_offset; @@ -219,33 +220,37 @@ static size_t group_count; static struct group *section_groups; static struct group **section_headers_groups; -/* A linked list of the section names for which dumps were requested - by name. */ + +/* Flag bits indicating particular types of dump. */ +#define HEX_DUMP (1 << 0) /* The -x command line switch. */ +#define DISASS_DUMP (1 << 1) /* The -i command line switch. */ +#define DEBUG_DUMP (1 << 2) /* The -w command line switch. */ +#define STRING_DUMP (1 << 3) /* The -p command line switch. */ + +typedef unsigned char dump_type; + +/* A linked list of the section names for which dumps were requested. */ struct dump_list_entry { char *name; - int type; + dump_type type; struct dump_list_entry *next; }; static struct dump_list_entry *dump_sects_byname; -/* A dynamic array of flags indicating for which sections a hex dump - has been requested (via the -x switch) and/or a disassembly dump - (via the -i switch). */ -char *cmdline_dump_sects = NULL; -unsigned num_cmdline_dump_sects = 0; +/* A dynamic array of flags indicating for which sections a dump + has been requested via command line switches. */ +static dump_type * cmdline_dump_sects = NULL; +static unsigned int num_cmdline_dump_sects = 0; /* A dynamic array of flags indicating for which sections a dump of some kind has been requested. It is reset on a per-object file basis and then initialised from the cmdline_dump_sects array, the results of interpreting the -w switch, and the dump_sects_byname list. */ -char *dump_sects = NULL; -unsigned int num_dump_sects = 0; +static dump_type * dump_sects = NULL; +static unsigned int num_dump_sects = 0; -#define HEX_DUMP (1 << 0) -#define DISASS_DUMP (1 << 1) -#define DEBUG_DUMP (1 << 2) /* How to print a vma value. */ typedef enum print_mode @@ -2745,9 +2750,10 @@ static struct option options[] = {"arch-specific", no_argument, 0, 'A'}, {"version-info", no_argument, 0, 'V'}, {"use-dynamic", no_argument, 0, 'D'}, + {"unwind", no_argument, 0, 'u'}, {"hex-dump", required_argument, 0, 'x'}, {"debug-dump", optional_argument, 0, OPTION_DEBUG_DUMP}, - {"unwind", no_argument, 0, 'u'}, + {"string-dump", required_argument, 0, 'p'}, #ifdef SUPPORT_DISASSEMBLY {"instruction-dump", required_argument, 0, 'i'}, #endif @@ -2782,14 +2788,17 @@ usage (FILE *stream) -V --version-info Display the version sections (if present)\n\ -A --arch-specific Display architecture specific information (if any).\n\ -D --use-dynamic Use the dynamic section info when displaying symbols\n\ - -x --hex-dump=<number> Dump the contents of section <number>\n\ + -x --hex-dump=<number|name>\n\ + Dump the contents of section <number|name> as bytes\n\ + -p --string-dump=<number|name>\n\ + Dump the contents of section <number|name> as strings\n\ -w[liaprmfFsoR] or\n\ --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\ Display the contents of DWARF2 debug sections\n")); #ifdef SUPPORT_DISASSEMBLY fprintf (stream, _("\ - -i --instruction-dump=<number>\n\ - Disassemble the contents of section <number>\n")); + -i --instruction-dump=<number|name>\n\ + Disassemble the contents of section <number|name>\n")); #endif fprintf (stream, _("\ -I --histogram Display histogram of bucket list lengths\n\ @@ -2810,20 +2819,20 @@ usage (FILE *stream) the first time. */ static void -request_dump (unsigned int section, int type) +request_dump_bynumber (unsigned int section, dump_type type) { if (section >= num_dump_sects) { - char *new_dump_sects; + dump_type *new_dump_sects; - new_dump_sects = calloc (section + 1, 1); + new_dump_sects = calloc (section + 1, sizeof (* dump_sects)); if (new_dump_sects == NULL) error (_("Out of memory allocating dump request table.\n")); else { /* Copy current flag settings. */ - memcpy (new_dump_sects, dump_sects, num_dump_sects); + memcpy (new_dump_sects, dump_sects, num_dump_sects * sizeof (* dump_sects)); free (dump_sects); @@ -2841,7 +2850,7 @@ request_dump (unsigned int section, int type) /* Request a dump by section name. */ static void -request_dump_byname (const char *section, int type) +request_dump_byname (const char *section, dump_type type) { struct dump_list_entry *new_request; @@ -2868,7 +2877,7 @@ parse_args (int argc, char **argv) usage (stderr); while ((c = getopt_long - (argc, argv, "ersuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF) + (argc, argv, "ersuahnldSDAINtgw::x:i:vVWHp:", options, NULL)) != EOF) { char *cp; int section; @@ -2946,10 +2955,18 @@ parse_args (int argc, char **argv) do_dump++; section = strtoul (optarg, & cp, 0); if (! *cp && section >= 0) - request_dump (section, HEX_DUMP); + request_dump_bynumber (section, HEX_DUMP); else request_dump_byname (optarg, HEX_DUMP); break; + case 'p': + do_dump++; + section = strtoul (optarg, & cp, 0); + if (! *cp && section >= 0) + request_dump_bynumber (section, STRING_DUMP); + else + request_dump_byname (optarg, STRING_DUMP); + break; case 'w': do_dump++; if (optarg == 0) @@ -3097,11 +3114,9 @@ parse_args (int argc, char **argv) do_dump++; section = strtoul (optarg, & cp, 0); if (! *cp && section >= 0) - { - request_dump (section, DISASS_DUMP); - break; - } - goto oops; + request_dump_bynumber (section, DISASS_DUMP); + else + request_dump_byname (optarg, DISASS_DUMP); #endif case 'v': print_version (program_name); @@ -3113,9 +3128,6 @@ parse_args (int argc, char **argv) do_wide++; break; default: -#ifdef SUPPORT_DISASSEMBLY - oops: -#endif /* xgettext:c-format */ error (_("Invalid option '-%c'\n"), c); /* Drop through. */ @@ -4182,14 +4194,14 @@ process_section_headers (FILE *file) || (do_debug_str && streq (name, "str")) || (do_debug_loc && streq (name, "loc")) ) - request_dump (i, DEBUG_DUMP); + request_dump_bynumber (i, DEBUG_DUMP); } /* linkonce section to be combined with .debug_info at link time. */ else if ((do_debugging || do_debug_info) && const_strneq (name, ".gnu.linkonce.wi.")) - request_dump (i, DEBUG_DUMP); + request_dump_bynumber (i, DEBUG_DUMP); else if (do_debug_frames && streq (name, ".eh_frame")) - request_dump (i, DEBUG_DUMP); + request_dump_bynumber (i, DEBUG_DUMP); } if (! do_sections) @@ -7670,7 +7682,84 @@ disassemble_section (Elf_Internal_Shdr *section, FILE *file) #endif static int -dump_section (Elf_Internal_Shdr *section, FILE *file) +dump_section_as_strings (Elf_Internal_Shdr *section, FILE *file) +{ + Elf_Internal_Shdr *relsec; + bfd_size_type num_bytes; + bfd_vma addr; + char *data; + char *end; + char *start; + char *name = SECTION_NAME (section); + bfd_boolean some_strings_shown; + + num_bytes = section->sh_size; + + if (num_bytes == 0 || section->sh_type == SHT_NOBITS) + { + printf (_("\nSection '%s' has no data to dump.\n"), name); + return 0; + } + + addr = section->sh_addr; + + start = get_data (NULL, file, section->sh_offset, 1, num_bytes, + _("section data")); + if (!start) + return 0; + + printf (_("\nString dump of section '%s':\n"), name); + + /* If the section being dumped has relocations against it the user might + be expecting these relocations to have been applied. Check for this + case and issue a warning message in order to avoid confusion. + FIXME: Maybe we ought to have an option that dumps a section with + relocs applied ? */ + for (relsec = section_headers; + relsec < section_headers + elf_header.e_shnum; + ++relsec) + { + if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL) + || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum + || SECTION_HEADER (relsec->sh_info) != section + || relsec->sh_size == 0 + || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum) + continue; + + printf (_(" Note: This section has relocations against it, but these have NOT been applied to this dump.\n")); + break; + } + + data = start; + end = start + num_bytes; + some_strings_shown = FALSE; + + while (data < end) + { + while (!ISPRINT (* data)) + if (++ data >= end) + break; + + if (data < end) + { + printf (" [%6zx] %s\n", data - start, data); + data += strlen (data); + some_strings_shown = TRUE; + } + } + + if (! some_strings_shown) + printf (_(" No strings found in this section.")); + + free (start); + + putchar ('\n'); + return 1; +} + + +static int +dump_section_as_bytes (Elf_Internal_Shdr *section, FILE *file) { Elf_Internal_Shdr *relsec; bfd_size_type bytes; @@ -8023,7 +8112,7 @@ initialise_dumps_byname (void) for (i = 0, any = 0; i < elf_header.e_shnum; i++) if (streq (SECTION_NAME (section_headers + i), cur->name)) { - request_dump (i, cur->type); + request_dump_bynumber (i, cur->type); any = 1; } @@ -8053,10 +8142,13 @@ process_section_contents (FILE *file) disassemble_section (section, file); #endif if (dump_sects[i] & HEX_DUMP) - dump_section (section, file); + dump_section_as_bytes (section, file); if (dump_sects[i] & DEBUG_DUMP) display_debug_section (section, file); + + if (dump_sects[i] & STRING_DUMP) + dump_section_as_strings (section, file); } /* Check to see if the user requested a @@ -9554,16 +9646,17 @@ process_object (char *file_name, FILE *file) must make sure that the dump_sets array is zeroed out before each object file is processed. */ if (num_dump_sects > num_cmdline_dump_sects) - memset (dump_sects, 0, num_dump_sects); + memset (dump_sects, 0, num_dump_sects * sizeof (* dump_sects)); if (num_cmdline_dump_sects > 0) { if (num_dump_sects == 0) /* A sneaky way of allocating the dump_sects array. */ - request_dump (num_cmdline_dump_sects, 0); + request_dump_bynumber (num_cmdline_dump_sects, 0); assert (num_dump_sects >= num_cmdline_dump_sects); - memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects); + memcpy (dump_sects, cmdline_dump_sects, + num_cmdline_dump_sects * sizeof (* dump_sects)); } if (! process_file_header ()) @@ -9938,12 +10031,13 @@ main (int argc, char **argv) if (num_dump_sects > 0) { /* Make a copy of the dump_sects array. */ - cmdline_dump_sects = malloc (num_dump_sects); + cmdline_dump_sects = malloc (num_dump_sects * sizeof (* dump_sects)); if (cmdline_dump_sects == NULL) error (_("Out of memory allocating dump request table.\n")); else { - memcpy (cmdline_dump_sects, dump_sects, num_dump_sects); + memcpy (cmdline_dump_sects, dump_sects, + num_dump_sects * sizeof (* dump_sects)); num_cmdline_dump_sects = num_dump_sects; } } diff --git a/binutils/testsuite/ChangeLog b/binutils/testsuite/ChangeLog index c1fcd3c..82292aa 100644 --- a/binutils/testsuite/ChangeLog +++ b/binutils/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-08-30 Nick Clifton <nickc@redhat.com> + + * binutils-all/dumptest.s: New test file. + * binutils-all/readelf.exp: Add test of readelf's -p switch. + 2007-08-28 Mark Shinwell <shinwell@codesourcery.com> Joseph Myers <joseph@codesourcery.com> diff --git a/binutils/testsuite/binutils-all/dumptest.s b/binutils/testsuite/binutils-all/dumptest.s new file mode 100644 index 0000000..6335d22 --- /dev/null +++ b/binutils/testsuite/binutils-all/dumptest.s @@ -0,0 +1,2 @@ + .data + .ascii "test_string" diff --git a/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp index d8ba1c0..52be1ee 100644 --- a/binutils/testsuite/binutils-all/readelf.exp +++ b/binutils/testsuite/binutils-all/readelf.exp @@ -21,6 +21,12 @@ # Based on scripts written by Ian Lance Taylor <ian@cygnus.com> # and Ken Raeburn <raeburn@cygnus.com>. +# Exclude non-ELF targets. +if ![is_elf_format] { + verbose "$READELF is only intended for ELF targets" 2 + return +} + # First some helpful procedures, then the tests themselves # Return the contents of the filename given @@ -203,10 +209,58 @@ proc readelf_wi_test {} { } -# Exclude non-ELF targets. -if ![is_elf_format] { - verbose "$READELF is only intended for ELF targets" 2 - return +# Test readelf's dumping abilities. + +proc readelf_dump_test {} { + global READELF + global READELFFLAGS + global srcdir + global subdir + + # Assemble the dump test file. + if {![binutils_assemble $srcdir/$subdir/dumptest.s tmpdir/dumptest.o]} then { + unresolved "readelf -p: failed to assemble dump test file" + return + } + # Download it. + set tempfile [remote_download host tmpdir/dumptest.o] + + # Run "readelf -p.data" on it. + set got [remote_exec host "$READELF $READELFFLAGS -p.data $tempfile" "" "/dev/null" "readelf.out"] + set got [lindex $got 1] + + # Upload the results. + set output [remote_upload host readelf.out] + + # Check for something going wrong. + if ![string match "" $got] then { + fail "readelf -p: unexpected output" + send_log $got + send_log "\n" + return + } + + # Search for strings that should be in the output. + set sought { + ".*test_string.*" + } + + foreach looked_for $sought { + set lines [grep $output $looked_for] + if ![llength $lines] then { + fail "readelf -p: missing: $looked_for" + send_log readelf.out + return + } + } + + file_on_host delete $tempfile + file_on_host delete $output + + # All done. + pass "readelf -p" + + # XXX FIXME: Add test of readelf -x here } if ![is_remote host] { @@ -220,7 +274,7 @@ send_user "Version [binutil_version $READELF]" # Assemble the test file. if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then { - perror "unresolved 1" + perror "could not assemble test file" unresolved "readelf - failed to assemble" return } @@ -241,3 +295,5 @@ readelf_test -s $tempfile readelf.ss {} readelf_test -r $tempfile readelf.r {} readelf_wi_test + +readelf_dump_test |