)]}'
{
  "commit": "8e28eef6cdcbd86ad61325ce1e6bd563b0fad1e1",
  "tree": "690457ca7f08bbf6ad1b969b5fbcfb307b3ea0a0",
  "parents": [
    "e5e76451fa82e0bc00599af96382b361c3d6ac32"
  ],
  "author": {
    "name": "Andrew Burgess",
    "email": "aburgess@redhat.com",
    "time": "Thu Nov 23 18:46:54 2023 +0000"
  },
  "committer": {
    "name": "Andrew Burgess",
    "email": "aburgess@redhat.com",
    "time": "Fri Sep 12 11:06:00 2025 +0100"
  },
  "message": "gdb/gdbserver: pass inferior arguments as a single string\n\nGDB holds the inferior arguments as a single string.  Currently when\nGDB needs to pass the inferior arguments to a remote target as part of\na vRun packet, this is done by splitting the single argument string\ninto its component arguments by calling gdb::remote_args::split, which\nuses the gdb_argv class to split the arguments for us.\n\nThe same gdb_argv class is used when the user has asked GDB/gdbserver\nto start the inferior without first invoking a shell; the gdb_argv\nclass is used to split the argument string into it component\narguments, and each is passed as a separate argument to the execve\ncall which spawns the inferior.\n\nThere is however, a problem with using gdb_argv to split the arguments\nbefore passing them to a remote target.  To understand this problem we\nmust first understand how gdb_argv is used when invoking an inferior\nwithout a shell.\n\nAnd to understand how gdb_argv is used to start an inferior without a\nshell, I feel we need to first look at an example of starting an\ninferior with a shell.\n\nConsider these two cases:\n\n  (a)  (gdb) set args \\$VAR\n  (b)  (gdb) set args $VAR\n\nWhen starting with a shell, in case (a) the user expects the inferior\nto receive a literal \u0027$VAR\u0027 string as an argument, while in case (b)\nthe user expects to see the shell expanded value of the variable $VAR.\n\nIf the user does \u0027set startup-with-shell off\u0027, then in (a) GDB will\nstrip the \u0027\\\u0027 while splitting the arguments, and the inferior will be\npassed a literal \u0027$VAR\u0027.  In (b) there is no \u0027\\\u0027 to strip, so also in\nthis case the inferior will receive a literal \u0027$VAR\u0027, remember\nstartup-with-shell is off, so there is no shell that can ever expand\n$VAR.\n\nNotice, that when startup-with-shell is off, we end up with a many to\none mapping, both (a) and (b) result in the literal string $VAR being\npassed to the inferior.  I think this is the correct behaviour in this\ncase.\n\nHowever, as we use gdb_argv to split the remote arguments we have the\nsame many to one mapping within the vRun packet.  But the vRun packet\nwill be used when startup-with-shell is both on and off.  What this\nmeans is that when gdbserver receives a vRun packet containing \u0027$VAR\u0027\nit doesn\u0027t know if GDB actually had \u0027$VAR\u0027, or if GDB had \u0027\\$VAR\u0027.\nAnd this is a huge problem.\n\nWe can address this by making the argument splitting for remote\ntargets smarter, and I do have patches that try to do this in this\nseries:\n\n  https://inbox.sourceware.org/gdb-patches/cover.1730731085.git.aburgess@redhat.com\n\nThat series was pretty long, and wasn\u0027t getting reviewed, so I\u0027m\npulling the individual patches out and posting them separately.\n\nThis patch doesn\u0027t try to improve remote argument splitting.  I think\nthat splitting and then joining the arguments is a mistake which can\nonly introduce problems.  The patch in the above series which tries to\nmake the splitting and joining \"smarter\" handles unquoted, single\nquoted, and double quoted strings.  But that doesn\u0027t really address\nparameter substitution, command substitution, or arithmetic expansion.\nAnd even if we did try to address these cases, what rules exactly\nwould we implement?  Probably POSIX shell rules, but what if the\nremote target doesn\u0027t have a POSIX shell?  The only reason we\u0027re\ntalking about which shell rules to follow is because the splitting and\njoining logic needs to mirror those rules.  If we stop splitting and\njoining then we no longer need to care about the target\u0027s shell.\n\nClearly, for backward compatibility we need to maintain some degree of\nargument splitting and joining as we currently have; and that\u0027s why I\nhave a later patch (see the series above) that tries to improve that\nsplitting and joining a little.  But I think, what we should really\ndo, is add a new feature flag (as used by the qSupported packet) and,\nif GDB and the remote target agree, we should pass the inferior\narguments as a single string.\n\nThis solves all our problems.  In the startup with shell case, we no\nlonger need to worry about splitting at all.  The arguments are passed\nunmodified to the remote target, that can then pass the arguments to\nthe shell directly.\n\nIn the \u0027startup-with-shell off\u0027 case it is now up to the remote target\nto split the arguments, though in gdbserver we already did this, so\nnothing really changes in this case.  And if the remote target doesn\u0027t\nhave a POSIX shell, well GDB just doesn\u0027t need to worry about it!\n\nSomething similar to this was originally suggested in this series:\n\n  https://inbox.sourceware.org/gdb-patches/20211022071933.3478427-1-m.weghorn@posteo.de/\n\nthough this series didn\u0027t try to maintain backward compatibility,\nwhich I think is an issue that my patch solves.  Additionally, this\nseries only passed the arguments as a single string in some cases,\nI\u0027ve simplified this so that, when GDB and the remote agree, the\narguments are always passed as a single string.  I think this is a\nlittle cleaner.\n\nI\u0027ve also added documentation and some tests with this commit,\nincluding ensuring that we test both the new single string approach,\nand the fallback split/join approach.\n\nI\u0027ve credited the author of the referenced series as co-author as they\ndid come to a similar conclusion, though I think my implementation is\ndifferent enough that I\u0027m happy to list myself as primary author.\n\nBug: https://sourceware.org/bugzilla/show_bug.cgi?id\u003d28392\n\nCo-Authored-By: Michael Weghorn \u003cm.weghorn@posteo.de\u003e\nReviewed-By: Eli Zaretskii \u003celiz@gnu.org\u003e\nTested-By: Guinevere Larsen \u003cguinevere@redhat.com\u003e\nApproved-by: Kevin Buettner \u003ckevinb@redhat.com\u003e\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "1daddd059eb80f37d5c159dad60f752c3fb25168",
      "old_mode": 33188,
      "old_path": "gdb/NEWS",
      "new_id": "01bd1524c7ae38e9a3c75394005a6154313598ea",
      "new_mode": 33188,
      "new_path": "gdb/NEWS"
    },
    {
      "type": "modify",
      "old_id": "f8154212fa438553ceb50f7021f3c88398cff397",
      "old_mode": 33188,
      "old_path": "gdb/doc/gdb.texinfo",
      "new_id": "676143be416684dc8ca076b7bb46be1afc0741f6",
      "new_mode": 33188,
      "new_path": "gdb/doc/gdb.texinfo"
    },
    {
      "type": "modify",
      "old_id": "1eb4f7279cfe4948ec0a8c6e1c691cb51c0cae3c",
      "old_mode": 33188,
      "old_path": "gdb/remote.c",
      "new_id": "984b7166b7bec405be6c4621e13e3c5803666312",
      "new_mode": 33188,
      "new_path": "gdb/remote.c"
    },
    {
      "type": "modify",
      "old_id": "b8596608439ff2d072f9f39707afcf4bcafe2e0d",
      "old_mode": 33188,
      "old_path": "gdb/testsuite/gdb.base/args.exp",
      "new_id": "573543cc1f8623e76607ab73ee501d6a99516896",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.base/args.exp"
    },
    {
      "type": "modify",
      "old_id": "3887239ef3654e790af6406d2f2d33d64fd9d47d",
      "old_mode": 33188,
      "old_path": "gdb/testsuite/gdb.base/inferior-args.exp",
      "new_id": "b2916701ba9a93e9d6729e02464340ac964fd414",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.base/inferior-args.exp"
    },
    {
      "type": "modify",
      "old_id": "25b161ad4f15f8f4fb8f3ea2857b954891ea8fef",
      "old_mode": 33188,
      "old_path": "gdb/testsuite/gdb.base/startup-with-shell.exp",
      "new_id": "a6ebb57c00e72996944939e82d2a26c1b368a398",
      "new_mode": 33188,
      "new_path": "gdb/testsuite/gdb.base/startup-with-shell.exp"
    },
    {
      "type": "modify",
      "old_id": "1f910a415b6ea5e3748bb2a05cde89f8083f6c46",
      "old_mode": 33188,
      "old_path": "gdbserver/server.cc",
      "new_id": "5907e86847ad84762d9d56ee58ef60f75c2093a8",
      "new_mode": 33188,
      "new_path": "gdbserver/server.cc"
    },
    {
      "type": "modify",
      "old_id": "b9dacb823bcb217a0bcbb08ced513ffa2e41737a",
      "old_mode": 33188,
      "old_path": "gdbserver/server.h",
      "new_id": "1bf3e7757a65163bd0f0453fba43c4fbe21e6c94",
      "new_mode": 33188,
      "new_path": "gdbserver/server.h"
    }
  ]
}
