aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.server/fetch-exec-and-args.c
AgeCommit message (Collapse)AuthorFilesLines
2025-10-03gdb/gdbserver: add new qExecAndArgs packetAndrew Burgess1-0/+34
This commit adds a new remote protocol packet qExecAndArgs, and updates GDB to use it. When gdbserver is started a user can provide an executable and arguments, these are used (by the remote target) to start an initial inferior, this is the inferior to which GDB first connects. When GDB is connected in extended-remote mode, if the user does a 'run' without specifying a new 'remote exec-file' then the executable given on the gdbserver command line is reused to start the new inferior. Interestingly, the arguments given on the gdbserver command line are only used when starting the first inferior, subsequent inferiors will be passed an empty argument string by GDB. This might catch out a user, causing the rerun to behave differently than the first run. In this commit I will add a new qExecAndArgs packet, which I think will improve the experience in this area. The new qExecAndArgs packet is sent from GDB, and gdbserver replies with a packet that includes the executable filename and the arguments string that were used for starting the initial inferior. On the GDB side this information can be used to update GDB's state, the 'show remote exec-file' will reflect how gdbserver was started, and 'show args' will reflect the arguments used for starting the inferior. As a result of updating the args, if the user restarts the inferior, then this same argument string will be passed back to the remote target, and used for the new inferior. Thus, rerunning the inferior will behave just like the initial inferior, which I think is a good improvement. Finally, GDB will warn if the user has 'set remote exec-file' and then connects to a gdbserver that was started with some alternative filename, like this: (gdb) set remote exec-file /tmp/foo (gdb) target remote | gdbserver --once - /tmp/bar ... snip ... warning: updating 'remote exec-file' to '/tmp/bar' to match remote target ... snip ... I made the choice to have GDB update the remote exec-file setting to match the remote, as, after the 'target remote', we are connected to an inferior that is running /tmp/bar (in this case), so trying to hang onto the non-matching user supplied setting doesn't seem helpful. There is one case where I can see this choice being a problem, if a user does: (gdb) set remote exec-file /tmp/foo (gdb) target extended-remote | gdbserver --multi --once - /tmp/bar ... snip ... warning: updating 'remote exec-file' to '/tmp/bar' to match remote target ... snip ... (gdb) run In this case, prior to this patch, they would 'run' /tmp/foo, while after this patch, they will run /tmp/bar. I think it is unfortunate that I'm breaking this use case, but, I'm not _that_ sorry -- just start gdbserver with the correct executable, or even no executable, and the problem goes away. This last point is important, in extended-remote mode, it is possible to start gdbserver without specifying an executable, like this: $ gdbserver --multi --once :54321 In this case gdbserver doesn't start an initial inferior. When GDB connects the qExecAndArgs reply from gdbserver indicates that no information (executable or arguments) were set, and any existing information is retained, as in this session: (gdb) set sysroot (gdb) set remote exec-file /tmp/foo (gdb) set args a b c (gdb) target extended-remote | ./gdbserver/gdbserver --multi --once - Remote debugging using | ./gdbserver/gdbserver --multi --once - Remote debugging using stdio (gdb) show remote exec-file The remote exec-file is "/tmp/foo". (gdb) show args Argument list to give program being debugged when it is started is "a b c". (gdb) This is the second time proposing this new packet. The first attempt can be found here: https://inbox.sourceware.org/gdb-patches/80d8b37d757033976b1a8ddd370c294c7aae8f8c.1692200989.git.aburgess@redhat.com The review feedback on this patch was that the inferior arguments should be passed back as a vector of individual strings. This makes sense, at the time that feedback was given, GDB would pass arguments to gdbserver as a vector of individual arguments, so it would seem sensible that gdbserver should adopt the same approach for passing arguments back to GDB. However, since then I have been working on how GDB passes the inferior arguments to gdbserver, fixing a lot of broken corner cases, which culminated in this patch: commit 8e28eef6cdcbd86ad61325ce1e6bd563b0fad1e1 Date: Thu Nov 23 18:46:54 2023 +0000 gdb/gdbserver: pass inferior arguments as a single string Though we do retain the vector of individual arguments behaviour for backward compatibility with old remote targets, the preferred approach now is for GDB to pass arguments to gdbserver as a single string. This removes the need for GDB/gdbserver to try and figure out what is the correct escaping to apply to the arguments, and fixes some argument passing corner cases. And so, now, I think it makes sense that gdbserver should also pass the arguments back to GDB as a single string. I've updated the documentation a little to (I hope) explain how gdbserver should escape things before passing them back to GDB (TLDR: no additional escaping should be added just for sending to GDB. The argument string should be sent to GDB as if it were being sent to the 'set args' GDB command). The main test for this new functionality is gdb.server/fetch-exec-and-args.exp, but I've also added a test gdb.replay/fetch-exec-and-args.exp, which allows me to test a corner case that isn't currently exercised by gdbserver, this is the case for sending pack inferior arguments, but no executable. The qExecAndArgs reply format is 'S;exec;args;' where 'exec' and 'args' are hex encoded strings. If 'args' is empty then this is perfectly valid, this just means there were no command line arguments. But what if 'exec' is empty? I needed to decide what to do in this case. The easiest choice is to treat empty 'exec' as the executable is not set. But currently, due to how gdbserver works, it is not possible to hit this case, so I used the gdbreplay testing framework to exercise this instead. There were a few supporting changes needed to write this test though. Reviewed-By: Eli Zaretskii <eliz@gnu.org> Approved-By: Tom Tromey <tom@tromey.com>