[3/3] binutils: read from stdin if input file is -

Message ID 20180225012308.47820-4-ahmad@a3f.at
State New
Headers show
Series
  • binutils: read from stdin if input file is -
Related show

Commit Message

Ahmad Fatoum Feb. 25, 2018, 1:23 a.m.
This changes the behavior of:
dlltool, nlmconv, nm, objcopy, objdump and size

Opening files named - now requires prefixing ./ or similar.
---
 binutils/NEWS                               |  3 ++
 binutils/dlltool.c                          |  9 ++++-
 binutils/doc/binutils.texi                  | 36 +++++++++++-------
 binutils/nlmconv.c                          |  5 ++-
 binutils/nm.c                               | 14 +++++--
 binutils/objcopy.c                          | 38 +++++++++++++++----
 binutils/objdump.c                          | 10 ++++-
 binutils/size.c                             | 10 ++++-
 binutils/testsuite/binutils-all/nm.exp      | 57 +++++++++++++++++------------
 binutils/testsuite/binutils-all/objcopy.exp | 13 ++++++-
 binutils/testsuite/binutils-all/objdump.exp |  8 +++-
 binutils/testsuite/binutils-all/size.exp    | 45 ++++++++++++++---------
 binutils/testsuite/config/default.exp       |  4 +-
 binutils/testsuite/lib/utils-lib.exp        |  5 ++-
 14 files changed, 176 insertions(+), 81 deletions(-)

-- 
2.16.1

Patch

diff --git a/binutils/NEWS b/binutils/NEWS
index c0fa05f25e..eb9abc18f1 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,8 @@ 
 -*- text -*-
 
+* Add ability to read from standard input if input file is `-' in dlltool,
+  nlmconv, nm, objcopy, objdump and size.
+
 Changes in 2.30:
 
 * Add --debug-dump=links option to readelf and --dwarf=links option to objdump
diff --git a/binutils/dlltool.c b/binutils/dlltool.c
index 189907a0b0..37d244e0e7 100644
--- a/binutils/dlltool.c
+++ b/binutils/dlltool.c
@@ -1679,7 +1679,14 @@  scan_open_obj_file (bfd *abfd)
 static void
 scan_obj_file (const char *filename)
 {
-  bfd * f = bfd_openr (filename, 0);
+  bfd *f;
+  const char *filename_bfd = filename;
+  if (strcmp (filename_bfd, "-") == 0)
+    {
+      filename_bfd = NULL;
+      filename = "<stdin>";
+    }
+  f = bfd_openr (filename_bfd, 0);
 
   if (!f)
     /* xgettext:c-format */
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index caf7f9d37d..dc4b72bdc3 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -776,8 +776,9 @@  nm [@option{-A}|@option{-o}|@option{--print-file-name}] [@option{-a}|@option{--d
 
 @c man begin DESCRIPTION nm
 @sc{gnu} @command{nm} lists the symbols from object files @var{objfile}@dots{}.
-If no object files are listed as arguments, @command{nm} assumes the file
-@file{a.out}.
+If an @var{objfile} is a single dash (`-'), @command{nm} reads from the
+standard input.  If no object files are listed as arguments, @command{nm}
+assumes the file @file{a.out}.
 
 For each symbol, @command{nm} shows:
 
@@ -1248,9 +1249,11 @@  same endianness or which have no endianness (e.g., @samp{srec}).
 @item @var{infile}
 @itemx @var{outfile}
 The input and output files, respectively.
+If @var{infile} is a single dash (`-'), @command{objcopy} reads from the
+standard input.
 If you do not specify @var{outfile}, @command{objcopy} creates a
 temporary file and destructively renames the result with
-the name of @var{infile}.
+the name of @var{infile}, unless @var{infile} is `-'.
 
 @item -I @var{bfdname}
 @itemx --input-target=@var{bfdname}
@@ -2107,9 +2110,10 @@  information is mostly useful to programmers who are working on the
 compilation tools, as opposed to programmers who just want their
 program to compile and work.
 
-@var{objfile}@dots{} are the object files to be examined.  When you
-specify archives, @command{objdump} shows information on each of the member
-object files.
+@var{objfile}@dots{} are the object files to be examined.  If an @var{objfile}
+is a single dash (`-'), @command{objdump} reads from the standard input.
+When you specify archives, @command{objdump} shows information on each of the
+member object files.
 
 @c man end
 
@@ -2836,8 +2840,9 @@  size [@option{-A}|@option{-B}|@option{--format=}@var{compatibility}]
 
 The @sc{gnu} @command{size} utility lists the section sizes---and the total
 size---for each of the object or archive files @var{objfile} in its
-argument list.  By default, one line of output is generated for each
-object file or each module in an archive.
+argument list.  If an @var{objfile} is a single dash (`-'), @command{size}
+reads from the standard input.  By default, one line of output is generated
+for each object file or each module in an archive.
 
 @var{objfile}@dots{} are the object files to be examined.
 If none are specified, the file @code{a.out} will be used.
@@ -3734,11 +3739,12 @@  nlmconv [@option{-I} @var{bfdname}|@option{--input-target=}@var{bfdname}]
 
 @command{nlmconv} converts the relocatable @samp{i386} object file
 @var{infile} into the NetWare Loadable Module @var{outfile}, optionally
-reading @var{headerfile} for NLM header information.  For instructions
-on writing the NLM command file language used in header files, see the
-@samp{linkers} section, @samp{NLMLINK} in particular, of the @cite{NLM
-Development and Tools Overview}, which is part of the NLM Software
-Developer's Kit (``NLM SDK''), available from Novell, Inc.
+reading @var{headerfile} for NLM header information.  If @var{infile} is
+a single dash (`-'), @command{nlmconv} reads from the standard input.
+For instructions on writing the NLM command file language used in header
+files, see the @samp{linkers} section, @samp{NLMLINK} in particular,
+of the @cite{NLM Development and Tools Overview}, which is part of the
+NLM Software Developer's Kit (``NLM SDK''), available from Novell, Inc.
 @command{nlmconv} uses the @sc{gnu} Binary File Descriptor library to read
 @var{infile};
 @ifclear man
@@ -4214,7 +4220,9 @@  dlltool [@option{-d}|@option{--input-def} @var{def-file-name}]
 
 @command{dlltool} reads its inputs, which can come from the @option{-d} and
 @option{-b} options as well as object files specified on the command
-line.  It then processes these inputs and if the @option{-e} option has
+line.  If the @var{object-file} is a single dash (`-'), @command{dlltool}
+reads from the standard input.
+It then processes these inputs and if the @option{-e} option has
 been specified it creates a exports file.  If the @option{-l} option
 has been specified it creates a library file and if the @option{-z} option
 has been specified it creates a def file.  Any or all of the @option{-e},
diff --git a/binutils/nlmconv.c b/binutils/nlmconv.c
index 68941f80d0..ad9f04d1dd 100644
--- a/binutils/nlmconv.c
+++ b/binutils/nlmconv.c
@@ -199,6 +199,7 @@  main (int argc, char **argv)
   int len;
   char *modname;
   char **matching;
+  bfd_boolean read_stdin = FALSE;
 
 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
   setlocale (LC_MESSAGES, "");
@@ -261,6 +262,8 @@  main (int argc, char **argv)
     {
       input_file = argv[optind];
       ++optind;
+      if (strcmp (input_file, "-") == 0)
+        read_stdin = TRUE;
       if (optind < argc)
 	{
 	  output_file = argv[optind];
@@ -329,7 +332,7 @@  main (int argc, char **argv)
       show_usage (stderr, 1);
     }
 
-  inbfd = bfd_openr (input_file, input_format);
+  inbfd = bfd_openr (read_stdin ? NULL : input_file, input_format);
   if (inbfd == NULL)
     bfd_fatal (input_file);
 
diff --git a/binutils/nm.c b/binutils/nm.c
index 696eb7817e..77739a42f7 100644
--- a/binutils/nm.c
+++ b/binutils/nm.c
@@ -1299,11 +1299,19 @@  display_file (char *filename)
   bfd_boolean retval = TRUE;
   bfd *file;
   char **matching;
+  const char *filename_bfd = filename;
 
-  if (get_file_size (filename) < 1)
-    return FALSE;
+  if (strcmp (filename_bfd, "-") == 0)
+    {
+      filename_bfd= NULL;
+      filename = "<stdin>";
+    }
+  else if (get_file_size (filename) < 1)
+    {
+      return FALSE;
+    }
 
-  file = bfd_openr (filename, target ? target : plugin_target);
+  file = bfd_openr (filename_bfd, target ? target : plugin_target);
   if (file == NULL)
     {
       bfd_nonfatal (filename);
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 8cdf27a87e..a7e5405646 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -3420,9 +3420,15 @@  copy_file (const char *input_filename, const char *output_filename,
   bfd *ibfd;
   char **obj_matching;
   char **core_matching;
-  off_t size = get_file_size (input_filename);
+  off_t size;
+  const char *filename_bfd = input_filename;
 
-  if (size < 1)
+  if (strcmp (filename_bfd, "-") == 0)
+    {
+        filename_bfd = NULL;
+        input_filename = "<stdin>";
+    }
+  else if ((size = get_file_size (input_filename)) < 1)
     {
       if (size == 0)
 	non_fatal (_("error: the input file '%s' is empty"),
@@ -3433,7 +3439,7 @@  copy_file (const char *input_filename, const char *output_filename,
 
   /* To allow us to do "strip *" without dying on the first
      non-object file, failures are nonfatal.  */
-  ibfd = bfd_openr (input_filename, input_target);
+  ibfd = bfd_openr (filename_bfd, input_target);
   if (ibfd == NULL)
     {
       bfd_nonfatal_message (input_filename, NULL, NULL, NULL);
@@ -4685,6 +4691,7 @@  copy_main (int argc, char *argv[])
   bfd_boolean show_version = FALSE;
   bfd_boolean change_warn = TRUE;
   bfd_boolean formats_info = FALSE;
+  bfd_boolean read_stdin = FALSE;
   int c;
   struct stat statbuf;
   const bfd_arch_info_type *input_arch = NULL;
@@ -5393,6 +5400,8 @@  copy_main (int argc, char *argv[])
     copy_usage (stderr, 1);
 
   input_filename = argv[optind];
+  if (strcmp (input_filename, "-") == 0)
+      read_stdin = TRUE;
   if (optind + 1 < argc)
     output_filename = argv[optind + 1];
 
@@ -5459,9 +5468,13 @@  copy_main (int argc, char *argv[])
     }
 
   if (preserve_dates)
-    if (stat (input_filename, & statbuf) < 0)
-      fatal (_("warning: could not locate '%s'.  System error message: %s"),
-	     input_filename, strerror (errno));
+    {
+      if (read_stdin)
+        fatal (_("warning: can't preserve date of input: <stdin>"));
+      if (stat (input_filename, & statbuf) < 0)
+        fatal (_("warning: could not locate '%s'.  System error message: %s"),
+               input_filename, strerror (errno));
+    }
 
   /* If there is no destination file, or the source and destination files
      are the same, then create a temp and rename the result into the input.  */
@@ -5481,8 +5494,17 @@  copy_main (int argc, char *argv[])
       if (preserve_dates)
 	set_times (tmpname, &statbuf);
       if (tmpname != output_filename)
-	status = (smart_rename (tmpname, input_filename,
-				preserve_dates) != 0);
+        {
+          if (read_stdin)
+            {
+               /* Might be nifty to dump the object to stdout if no destination file was
+                * specified. This requires ensuring nothing else writes to stdout though */
+               unlink_if_ordinary (tmpname);
+               fatal (_("error: source file <stdin> can't be reused as destination file"));
+            }
+
+          status = (smart_rename (tmpname, input_filename, preserve_dates) != 0);
+       }
     }
   else
     unlink_if_ordinary (tmpname);
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 37a9f0d2e1..f3797e420b 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -3758,14 +3758,20 @@  static void
 display_file (char *filename, char *target, bfd_boolean last_file)
 {
   bfd *file;
+  const char *filename_bfd = filename;
 
-  if (get_file_size (filename) < 1)
+  if (strcmp (filename_bfd, "-") == 0)
+    {
+      filename_bfd = NULL;
+      filename = "<stdin>";
+    }
+  else if (get_file_size (filename) < 1)
     {
       exit_status = 1;
       return;
     }
 
-  file = bfd_openr (filename, target);
+  file = bfd_openr (filename_bfd, target);
   if (file == NULL)
     {
       nonfatal (filename);
diff --git a/binutils/size.c b/binutils/size.c
index 47f14fce33..82080d8bee 100644
--- a/binutils/size.c
+++ b/binutils/size.c
@@ -385,14 +385,20 @@  static void
 display_file (char *filename)
 {
   bfd *file;
+  const char *filename_bfd = filename;
 
-  if (get_file_size (filename) < 1)
+  if (strcmp (filename_bfd, "-") == 0)
+    {
+      filename_bfd = NULL;
+      filename = "<stdin>";
+    }
+  else if (get_file_size (filename) < 1)
     {
       return_code = 1;
       return;
     }
 
-  file = bfd_openr (filename, target);
+  file = bfd_openr (filename_bfd, target);
   if (file == NULL)
     {
       bfd_nonfatal (filename);
diff --git a/binutils/testsuite/binutils-all/nm.exp b/binutils/testsuite/binutils-all/nm.exp
index f8779c18f6..9c465acbf0 100644
--- a/binutils/testsuite/binutils-all/nm.exp
+++ b/binutils/testsuite/binutils-all/nm.exp
@@ -29,6 +29,35 @@  if ![is_remote host] {
 
 send_user "Version [binutil_version $NM]"
 
+proc test_nm { testfile args } {
+    global NM
+    global NMFLAGS
+
+    set got [binutils_run $NM "$NMFLAGS $testfile" $args]
+
+    if [info exists vars] then { unset vars }
+    while {[regexp "(\[a-zA-Z\]) (\[a-z_\]*_symbol)(.*)" $got all type symbol rest]} {
+	set vars($symbol) $type
+	set got $rest
+    }
+
+    if {![info exists vars(text_symbol)] \
+	    || $vars(text_symbol) != "T" \
+	    || ![info exists vars(data_symbol)] \
+	    || $vars(data_symbol) != "D" \
+	    || ![info exists vars(common_symbol)] \
+	    || $vars(common_symbol) != "C" \
+	    || ![info exists vars(external_symbol)] \
+	    || $vars(external_symbol) != "U" \
+	    || ![info exists vars(static_text_symbol)] \
+	    || $vars(static_text_symbol) != "t" \
+	    || ![info exists vars(static_data_symbol)] \
+	    || $vars(static_data_symbol) != "d"} {
+	fail "nm (no arguments) $testfile"
+    } else {
+	pass "nm (no arguments) $testfile"
+    }
+}
 
 if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then {
     fail "nm (assembling)"
@@ -41,6 +70,10 @@  if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then {
     }
 
     # Test nm with no arguments.
+    test_nm $tempfile
+
+    # Test nm with no arguments, but reading from stdin
+    test_nm "-" $tempfile
 
     # This test does not work correctly on ECOFF targets, because ECOFF
     # stores most symbols twice, which messes up the nm output.
@@ -52,30 +85,6 @@  if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then {
     # does not enter static symbols in the symbol table.
     setup_xfail "*-*-aix*"
 
-    set got [binutils_run $NM "$NMFLAGS $tempfile"]
-
-    if [info exists vars] then { unset vars }
-    while {[regexp "(\[a-zA-Z\]) (\[a-z_\]*_symbol)(.*)" $got all type symbol rest]} {
-	set vars($symbol) $type
-	set got $rest
-    }
-
-    if {![info exists vars(text_symbol)] \
-	    || $vars(text_symbol) != "T" \
-	    || ![info exists vars(data_symbol)] \
-	    || $vars(data_symbol) != "D" \
-	    || ![info exists vars(common_symbol)] \
-	    || $vars(common_symbol) != "C" \
-	    || ![info exists vars(external_symbol)] \
-	    || $vars(external_symbol) != "U" \
-	    || ![info exists vars(static_text_symbol)] \
-	    || $vars(static_text_symbol) != "t" \
-	    || ![info exists vars(static_data_symbol)] \
-	    || $vars(static_data_symbol) != "d"} {
-	fail "nm (no arguments)"
-    } else {
-	pass "nm (no arguments)"
-    }
 
     # Test nm -g
 
diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp
index f4a7692cdf..27dbf96e3e 100644
--- a/binutils/testsuite/binutils-all/objcopy.exp
+++ b/binutils/testsuite/binutils-all/objcopy.exp
@@ -38,7 +38,7 @@  if ![is_remote host] {
 
 # Test that objcopy does not modify a file when copying it.
 
-proc objcopy_test {testname srcfile} {
+proc objcopy_test {testname srcfile args} {
     global OBJCOPY
     global OBJCOPYFLAGS
     global srcdir
@@ -46,13 +46,21 @@  proc objcopy_test {testname srcfile} {
     global tempfile
     global copyfile
 
+    if { [llength $args] == 0 } {
+	set objcopyfile "$tempfile"
+	set stdin ""
+    } else {
+	set objcopyfile "-"
+	set stdin "$tempfile"
+    }
+
     if {![binutils_assemble $srcdir/$subdir/${srcfile} $tempfile]} then {
 	unresolved "objcopy ($testname)"
 	remote_file host delete $tempfile
 	return
     }
 
-    set got [binutils_run $OBJCOPY "$OBJCOPYFLAGS $tempfile ${copyfile}.o"]
+    set got [binutils_run $OBJCOPY "$OBJCOPYFLAGS $objcopyfile ${copyfile}.o" $stdin]
 
     if ![string equal "" $got] then {
 	fail "objcopy ($testname)"
@@ -106,6 +114,7 @@  proc objcopy_test {testname srcfile} {
 }
 
 objcopy_test "simple copy" bintest.s
+objcopy_test "simple copy from stdin" bintest.s "use stdin"
 
 if { [file exists $tempfile] } {
     # Test reversing bytes in a section.
diff --git a/binutils/testsuite/binutils-all/objdump.exp b/binutils/testsuite/binutils-all/objdump.exp
index f006d64f10..bf1b0d3391 100644
--- a/binutils/testsuite/binutils-all/objdump.exp
+++ b/binutils/testsuite/binutils-all/objdump.exp
@@ -93,12 +93,12 @@  if { ![istarget "alpha-*-*"] || [is_elf_format] } then {
 
 # Test objdump -f
 
-proc test_objdump_f { testfile dumpfile } {
+proc test_objdump_f { testfile dumpfile args} {
     global OBJDUMP
     global OBJDUMPFLAGS
     global cpus_regex
 
-    set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -f $testfile"]
+    set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -f $testfile" $args]
 
     set want "$dumpfile:\[ 	\]*file format.*architecture:\[ 	\]*${cpus_regex}.*HAS_RELOC.*HAS_SYMS"
 
@@ -114,6 +114,10 @@  if { [ remote_file host exists $testarchive ] } then {
     test_objdump_f $testarchive bintest2.o
 }
 
+# Test objdump -f -
+
+test_objdump_f "-" "<stdin>" $testfile
+
 # Test objdump -h
 
 proc test_objdump_h { testfile dumpfile } {
diff --git a/binutils/testsuite/binutils-all/size.exp b/binutils/testsuite/binutils-all/size.exp
index 185872d341..00d1646601 100644
--- a/binutils/testsuite/binutils-all/size.exp
+++ b/binutils/testsuite/binutils-all/size.exp
@@ -29,25 +29,18 @@  if ![is_remote host] {
 
 send_user "Version [binutil_version $SIZE]"
 
+set dec "\[0-9\]+"
+set hex "\[0-9a-fA-F\]+"
 
-if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then {
-    fail "size (assembling)"
-} else {
+proc test_size { testfile displayfile args} {
+    global SIZE
+    global SIZEFLAGS
+    global dec
+    global hex
 
-    if [is_remote host] {
-	set testfile [remote_download host tmpdir/bintest.o]
-    } else {
-	set testfile tmpdir/bintest.o
-    }
-
-    set dec "\[0-9\]+"
-    set hex "\[0-9a-fA-F\]+"
-
-    # Test size with no arguments
-
-    set got [binutils_run $SIZE "$SIZEFLAGS $testfile"]
+    set got [binutils_run $SIZE "$SIZEFLAGS $testfile" $args]
 
-    set want "($dec)\[ 	\]+($dec)\[ 	\]+($dec)\[ 	\]+($dec)\[ 	\]+($hex)\[ 	\]+${testfile}"
+    set want "($dec)\[ 	\]+($dec)\[ 	\]+($dec)\[ 	\]+($dec)\[ 	\]+($hex)\[ 	\]+${displayfile}"
 
     if ![regexp $want $got all text data bss dtot hextot] then {
 	fail "size (no arguments)"
@@ -56,11 +49,27 @@  if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then {
 	    # The z80-coff port defaults to a "binary" like output
 	    # file format which does not include a data section.
 	    setup_xfail "z80-*-coff"
-	    fail "size (no arguments)"
+	    fail "size (no arguments) $displayfile"
 	} else {
-	    pass "size (no arguments)"
+	    pass "size (no arguments) $displayfile"
 	}
     }
+}
+
+if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then {
+    fail "size (assembling)"
+} else {
+    if [is_remote host] {
+	set testfile [remote_download host tmpdir/bintest.o]
+    } else {
+	set testfile tmpdir/bintest.o
+    }
+
+    # Test size with no arguments
+    test_size $testfile $testfile
+
+    # Test size with no arguments, but reading from stdin
+    test_size "-" "<stdin>" $testfile
 
     # Test size -A
 
diff --git a/binutils/testsuite/config/default.exp b/binutils/testsuite/config/default.exp
index c5acd46e8f..fbde02fafd 100644
--- a/binutils/testsuite/config/default.exp
+++ b/binutils/testsuite/config/default.exp
@@ -114,8 +114,8 @@  if {[file isfile tmpdir/gas/as[exe_ext]]} then {
 #	sets binutils_run_failed if the program does not exist
 #	sets binutils_run_status to the exit status of the program
 #
-proc binutils_run { prog progargs } {
-    default_binutils_run $prog $progargs
+proc binutils_run { prog progargs args } {
+    default_binutils_run $prog $progargs {*}$args
 }
 
 #
diff --git a/binutils/testsuite/lib/utils-lib.exp b/binutils/testsuite/lib/utils-lib.exp
index cb1211204e..63ba9b5e70 100644
--- a/binutils/testsuite/lib/utils-lib.exp
+++ b/binutils/testsuite/lib/utils-lib.exp
@@ -53,7 +53,7 @@  proc binutil_version { prog } {
 #	sets binutils_run_failed if the program does not exist
 #	sets binutils_run_status to the exit status of the program
 #
-proc default_binutils_run { prog progargs } {
+proc default_binutils_run { prog progargs args } {
     global binutils_run_failed
     global binutils_run_status
     global host_triplet
@@ -87,7 +87,8 @@  proc default_binutils_run { prog progargs } {
     # shell otherwise.
     regsub -all "\\$" "$progargs" "\\$" progargs
 
-    set state [remote_exec host $prog $progargs]
+    set state [remote_exec host $prog $progargs {*}$args]
+
     set binutils_run_status [lindex $state 0]
     set exec_output [prune_warnings [lindex $state 1]]
     if {![string match "" $exec_output]} then {