]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
server.c: handle qExecAndArgs remote protocol packet
authorAlexandra Hájková <ahajkova@redhat.com>
Wed, 15 Oct 2025 10:27:25 +0000 (06:27 -0400)
committerMark Wielaard <mark@klomp.org>
Fri, 24 Oct 2025 14:42:00 +0000 (16:42 +0200)
New qExecAndArgs packet has been added recently to GDB's remote
protocol.

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.

When running valgrind together with GDB like this:

./vg-in-place --tool=memcheck --vgdb-error=0 /bin/ls -lh

~/build/gdb/gdb/gdb
target remote | coregrind/vgdb
We can now ask GDB to show the executable's arguments:

(gdb) show args

Argument list to give program being debugged when it is started is "-lh".

or the executable's name:

(gdb) show remote exec-file
The remote exec-file is "/bin/ls".

coregrind/m_gdbserver/server.c

index 21e21da737f50d666149d710849494f05586bfee..6a131e1babb4b2487cf3568b33b65b4b062e415b 100644 (file)
@@ -873,6 +873,65 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p)
       return;
    }
 
+   /* Without argument, traditional remote protocol.  */
+   if (strcmp ("qExecAndArgs", arg_own_buf) == 0) {
+     const HChar *exename = VG_(resolved_exename);
+
+     /* If we don't have an executable, return "U".  */
+     if (exename == NULL) {
+        arg_own_buf[0] = 'U';
+        arg_own_buf[1] = '\0';
+        return;
+     }
+
+     /* Build the response: "S;<hex-prog>;<hex-args>;"
+        Need to hex-encode both the program name and arguments.  */
+
+     /* First, encode the executable name.  */
+     char hex_exename[2 * VG_(strlen)(exename) + 1];
+     hexify(hex_exename, exename, VG_(strlen)(exename));
+
+     /* Build the arguments string from VG_(args_for_client).  */
+     int num_args = VG_(sizeXA)(VG_(args_for_client));
+     char *args_str = NULL;
+
+     if (num_args > 0) {
+       int count = 0;
+       for (int i = 0; i < num_args; i++) {
+         HChar* arg = * (HChar**) VG_(indexXA)(VG_(args_for_client), i);
+         count += VG_(strlen)(arg);
+       }
+
+       /* Allocate space for args + spaces between them + null terminator.  */
+       int args_str_size = count + num_args;
+       args_str = VG_(malloc)("handle_query.qExecAndArgs", args_str_size);
+       char *p = args_str;
+
+       for (int i = 0; i < num_args; i++) {
+         HChar* arg = * (HChar**) VG_(indexXA)(VG_(args_for_client), i);
+         int num = VG_(strlen)(arg);
+         VG_(memcpy)(p, arg, num);
+         p += num;
+         if (i < num_args - 1) {
+           *p++ = ' ';  /* Add space separator between arguments.  */
+         }
+       }
+       *p = '\0';  /* Null terminate the string.  */
+
+       char hex_args_buf[2 * VG_(strlen)(args_str) + 1];
+       hexify(hex_args_buf, args_str, VG_(strlen)(args_str));
+       VG_(free)(args_str);
+
+       /* Build the full response.  */
+       VG_(sprintf)(arg_own_buf, "S;%s;%s;", hex_exename, hex_args_buf);
+     } else {
+       /* No arguments, just send program name with empty args.  */
+       VG_(sprintf)(arg_own_buf, "S;%s;;", hex_exename);
+     }
+
+      return;
+   }
+
    if (strcmp ("qSymbol::", arg_own_buf) == 0) {
       /* We have no symbol to read. */
       write_ok (arg_own_buf);