]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdbserver: allow gnu style arguments to gdbserver
authorAndrew Burgess <aburgess@redhat.com>
Fri, 1 Aug 2025 11:22:38 +0000 (12:22 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Tue, 23 Sep 2025 17:40:00 +0000 (18:40 +0100)
Now that we use getopt_long for argument processing in gdbserver, it
is relatively easy to support GNU style arguments, that is, arguments
passed without an '=' between the argument and the value.

As support for GNU style arguments is the default from getopt_long,
the first part of this commit is to remove the code which deliberately
disables the GNU argument support.

With that done, we now need to consider optional arguments.  In this
case, getopt_long doesn't automatically grab the next word from ARGV
to be the argument value, so I've added some code to do this.

I've also tried to make this code a little smart.  As the first
argument passed to gdbserver that doesn't have a '--' at the start is
the PORT number, the new code block I've added tries to spot if the
argument value might be the port number.  If it is, then we don't
allow the port number to become the argument value, and instead, we
pretend the argument value is missing.  This seems to give better
error messages.

There are going to be UI changes in how gdbserver handles incorrect
arguments after this commit.  However, the behaviour for valid
command lines should be unchanged.

Approved-By: Tom Tromey <tom@tromey.com>
gdbserver/server.cc

index 5ad60be5b4790373231e44a811b6f48a98120b67..1e0be1cc69b7cef6a361afbfaf2690b08138ad7f 100644 (file)
@@ -4204,25 +4204,58 @@ captured_main (int argc, char *argv[])
   while ((longindex = -1,
          optc = getopt_long (argc, argv, "+", longopts, &longindex)) != -1)
     {
-      /* We only support '--option=value' form, not '--option value'.  To
-        achieve this, if global OPTARG points to the start of the previous
-        ARGV entry, then we must have used the second (unsupported) form,
-        so set OPTARG to NULL and decrement OPTIND to make it appear that
-        there was no value passed.  If the option requires an argument,
-        then this means we should convert OPTC to '?' to indicate an
-        error.  */
+      /* As a GNU extension, getopt_long supports '--arg value' form,
+        without an '=' symbol between the 'arg' and the 'value'.  This
+        block aids in supporting this form.
+
+        If we found a matching entry in LONGOPTS, the entry has an
+        optional argument, and OPTARG is NULL, then this indicates that we
+        saw the '--arg value' form. Look at the next ARGV entry to see if
+        it exists, and doesn't look like a port number, or the start of
+        another argument.  If this is the case, then make the next ARGV
+        entry the argument value.  Otherwise, continue with no
+        argument.
+
+        If we found a matching entry in LONGOPTS, the entry has a required
+        argument, then OPTARG will not be NULL.  In this case, if the
+        start of OPTARG is the start of the previous ARGV entry, then this
+        indicates we saw the '--arg value' form.  If OPTARG looks like a
+        port number, or the start of another argument, then assume the
+        user didn't in fact pass a value, but forgot.  Pretend we are
+        missing the argument value.  */
       if (longindex != -1
-         && longopts[longindex].has_arg != no_argument)
+         && ((longopts[longindex].has_arg == optional_argument
+              &&optarg == nullptr)
+             || (longopts[longindex].has_arg == required_argument
+                 && optarg == argv[optind - 1])))
        {
-         if (optarg == argv[optind - 1])
+         if (longopts[longindex].has_arg == optional_argument)
            {
-             optarg = nullptr;
-             --optind;
+             /* Claim the next entry from ARGV as the argument value.  */
+             optarg = argv[optind];
+             optind++;
            }
+         else
+           gdb_assert (optarg != nullptr);
 
-         if (longopts[longindex].has_arg == required_argument
-             && optarg == nullptr)
-           optc = '?';
+         if (optarg == nullptr
+             || strcmp (optarg, "-") == 0
+             || strcmp (optarg, STDIO_CONNECTION_NAME) == 0
+             || startswith (optarg, "--")
+             || strchr (optarg, ':') != nullptr)
+           {
+             /* OPTARG is NULL, looks like a port number, or could be the
+                start of another argument.  Clear OPTARG as we don't have
+                an argument, and decrement OPTIND so the next call to
+                getopt will process this as an argument.  */
+             optarg = nullptr;
+             optind--;
+
+             /* 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 = '?';
+           }
        }
 
       switch (optc)