]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdbserver: better handling for missing argument values
authorAndrew Burgess <aburgess@redhat.com>
Fri, 1 Aug 2025 11:26:41 +0000 (12:26 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Tue, 23 Sep 2025 17:40:00 +0000 (18:40 +0100)
By passing ':' within the optstring to getopt_long, the getopt_long
call will now return ':' for missing value errors and '?' for unknown
argument errors, rather than returning '?' for all error types.

We can now print a different error message for missing argument
values.  For example:

  $ gdbserver --debug-file :54321 /tmp/hello
  Missing argument value for: --debug-file

Compared to:

  $ gdbserver --unknown :54321 ~/tmp/hello.x
  Unknown argument: --unknown

Current HEAD gdbserver treats every error as the 'Unknown argument'
error.

While I was messing with the code that prints these error messages,
I've wrapped then with _(...) to allow for internationalisation.

Approved-By: Tom Tromey <tom@tromey.com>
gdb/testsuite/gdb.server/argument-errors.exp [new file with mode: 0644]
gdbserver/server.cc

diff --git a/gdb/testsuite/gdb.server/argument-errors.exp b/gdb/testsuite/gdb.server/argument-errors.exp
new file mode 100644 (file)
index 0000000..45037bf
--- /dev/null
@@ -0,0 +1,81 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2025 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test gdbserver prints a suitable message when argument values are
+# missing.
+
+load_lib gdbserver-support.exp
+
+standard_testfile
+
+require allow_gdbserver_tests
+
+set gdbserver [find_gdbserver]
+if { $gdbserver == "" } {
+    unsupported "could not find gdbserver"
+    return
+}
+
+# Start gdbserver using CMD_ARGS and a non-existent program name.  We
+# expect to see an error message matching ERROR_RE from gdbserver.
+proc test_argument_error { cmd_args error_re } {
+    # Fire off gdbserver.  gdbserver should give an error because
+    # --debug-file is missing its argument.
+    set spawn_id [remote_spawn target "$::gdbserver $cmd_args non-existing-program"]
+
+    set saw_expected_error false
+    set test "check gdbserver error: $cmd_args"
+    expect {
+       -i $spawn_id
+       -re $error_re {
+           set saw_expected_error true
+           exp_continue
+       }
+       eof {
+           gdb_assert $saw_expected_error $test
+           wait
+       }
+       timeout {
+           fail "$test (timeout)"
+       }
+    }
+
+    # expect defaults to spawn_id in many places.  Avoid confusing any
+    # following code.
+    unset spawn_id
+}
+
+# Check that an argument that expects a value will not use a port, or
+# another argument, as its value.
+foreach arg { --debug-format --debug-file } {
+    test_argument_error "$arg stdio" \
+       "Missing argument value for: $arg"
+    test_argument_error "$arg :54321" \
+       "Missing argument value for: $arg"
+    test_argument_error "$arg -" \
+       "Missing argument value for: $arg"
+    test_argument_error "$arg --once -" \
+       "Missing argument value for: $arg"
+}
+
+# Test unknown argument handling.
+test_argument_error "--unknown -" \
+    "Unknown argument: --unknown"
+test_argument_error "-unknown -" \
+    "Unknown argument: -unknown"
+test_argument_error "--unknown=blah -" \
+    "Unknown argument: --unknown"
index 1e0be1cc69b7cef6a361afbfaf2690b08138ad7f..8dc1f498d4f0a4d7f000f6392b6d423d3cc0e70e 100644 (file)
@@ -4202,7 +4202,7 @@ captured_main (int argc, char *argv[])
      If getopt_long is free to reorder ARGV then it will try to steal those
      arguments for itself.  */
   while ((longindex = -1,
-         optc = getopt_long (argc, argv, "+", longopts, &longindex)) != -1)
+         optc = getopt_long (argc, argv, "+:", longopts, &longindex)) != -1)
     {
       /* As a GNU extension, getopt_long supports '--arg value' form,
         without an '=' symbol between the 'arg' and the 'value'.  This
@@ -4254,7 +4254,7 @@ captured_main (int argc, char *argv[])
              /* For required arguments, if we don't have an argument, then
                 this is an errror, set OPTC to reflect this.  */
              if (longopts[longindex].has_arg == required_argument)
-               optc = '?';
+               optc = ':';
            }
        }
 
@@ -4427,6 +4427,7 @@ captured_main (int argc, char *argv[])
          escape_args = false;
          break;
 
+       case ':':
        case '?':
          /* Figuring out which element of ARGV contained the invalid
             argument is not simple.  There are a couple of cases we need
@@ -4453,7 +4454,11 @@ captured_main (int argc, char *argv[])
          else
            bad_arg = argv[optind];
 
-         fprintf (stderr, "Unknown argument: %s\n", bad_arg.c_str ());
+         if (optc == '?')
+           fprintf (stderr, _("Unknown argument: %s\n"), bad_arg.c_str ());
+         else
+           fprintf (stderr, _("Missing argument value for: %s\n"),
+                    bad_arg.c_str ());
          exit (1);
        }
     }