[1/2] gdb: move remote arg splitting and joining into gdbsupport/

Message ID 5d5d38644491a26cee8cd3618253c4b1cbcad0c3.1742317144.git.aburgess@redhat.com
State New
Headers
Series Add some unit tests for remote argument passing |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Andrew Burgess March 18, 2025, 5 p.m. UTC
  This is a refactoring commit.  When passing inferior arguments to
gdbserver we have two actions that need to be performed, splitting and
joining.

On the GDB side, we take the inferior arguments, a single string, and
split the string into a list of individual arguments.  These are then
sent to gdbserver over the remote protocol.

On the gdbserver side we receive the list of individual arguments and
join these back together into a single inferior argument string.

In the next commit I plan to add some unit testing for this remote
argument passing process.  Ideally, for unit testing, we need the code
being tested to be located in some easily callable function, rather
than being inline at the site of use.

So in this commit I propose to move the splitting and joining logic
out into a separate file, we can then use this within GDB and
gdbserver when passing arguments between GDB and gdbserver, but we can
also call the same functions for some unit testing.

In this commit I'm not adding the unit tests, they will be added next,
so for now there should be no user visible changes after this commit.

Tested-By: Guinevere Larsen <guinevere@redhat.com>
---
 gdb/remote.c              | 12 ++++-----
 gdbserver/server.cc       |  3 ++-
 gdbsupport/Makefile.am    |  1 +
 gdbsupport/Makefile.in    | 14 +++++-----
 gdbsupport/remote-args.cc | 43 ++++++++++++++++++++++++++++++
 gdbsupport/remote-args.h  | 55 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 115 insertions(+), 13 deletions(-)
 create mode 100644 gdbsupport/remote-args.cc
 create mode 100644 gdbsupport/remote-args.h
  

Comments

Simon Marchi April 24, 2025, 4:09 p.m. UTC | #1
On 2025-03-18 13:00, Andrew Burgess wrote:
> diff --git a/gdbsupport/remote-args.h b/gdbsupport/remote-args.h
> new file mode 100644
> index 00000000000..93dbdc6bc96
> --- /dev/null
> +++ b/gdbsupport/remote-args.h
> ...
> +
> +} /* namespace remote_args */
> +
> +} /* namespac gdb */

pre-commit indicates that this file is missing an include guard.  Also,
just above, "namespac".

Simon
  
Simon Marchi April 24, 2025, 7:38 p.m. UTC | #2
On 2025-04-24 12:09, Simon Marchi wrote:
> 
> 
> On 2025-03-18 13:00, Andrew Burgess wrote:
>> diff --git a/gdbsupport/remote-args.h b/gdbsupport/remote-args.h
>> new file mode 100644
>> index 00000000000..93dbdc6bc96
>> --- /dev/null
>> +++ b/gdbsupport/remote-args.h
>> ...
>> +
>> +} /* namespace remote_args */
>> +
>> +} /* namespac gdb */
> 
> pre-commit indicates that this file is missing an include guard.  Also,
> just above, "namespac".
> 
> Simon
> 

I went ahead and pushed the patch below, since it's a trivial fix.

From 876c853cb99cd9c097fa915c8d00bf6b9d7c5904 Mon Sep 17 00:00:00 2001
From: Simon Marchi <simon.marchi@polymtl.ca>
Date: Thu, 24 Apr 2025 15:36:23 -0400
Subject: [PATCH] gdbsupport: add missing include guard to remote-args.h

Also, fix a type in "namespace".

Change-Id: I3e5d1d49c765a035217437c0635b12dc28e41bf6
---
 gdbsupport/remote-args.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/gdbsupport/remote-args.h b/gdbsupport/remote-args.h
index 93dbdc6bc96c..0533da6e6798 100644
--- a/gdbsupport/remote-args.h
+++ b/gdbsupport/remote-args.h
@@ -17,6 +17,9 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+#ifndef GDBSUPPORT_REMOTE_ARGS_H
+#define GDBSUPPORT_REMOTE_ARGS_H
+
 /* The functions declared here are used when passing inferior arguments
    from GDB to gdbserver.
 
@@ -52,4 +55,6 @@ extern std::string join (const std::vector<char *> &args);
 
 } /* namespace remote_args */
 
-} /* namespac gdb */
+} /* namespace gdb */
+
+#endif /* GDBSUPPORT_REMOTE_ARGS_H */

base-commit: 745cf6b7862d1bbf256a3d8b68d4942a13118c38
  
Andrew Burgess April 28, 2025, 4:16 p.m. UTC | #3
Simon Marchi <simark@simark.ca> writes:

> On 2025-04-24 12:09, Simon Marchi wrote:
>> 
>> 
>> On 2025-03-18 13:00, Andrew Burgess wrote:
>>> diff --git a/gdbsupport/remote-args.h b/gdbsupport/remote-args.h
>>> new file mode 100644
>>> index 00000000000..93dbdc6bc96
>>> --- /dev/null
>>> +++ b/gdbsupport/remote-args.h
>>> ...
>>> +
>>> +} /* namespace remote_args */
>>> +
>>> +} /* namespac gdb */
>> 
>> pre-commit indicates that this file is missing an include guard.  Also,
>> just above, "namespac".
>> 
>> Simon
>> 
>
> I went ahead and pushed the patch below, since it's a trivial fix.

Thanks for fixing these.  Sorry for letting these slip though.

Thanks,
Andrew
  

Patch

diff --git a/gdb/remote.c b/gdb/remote.c
index 66c58c884d3..64d11e19ff2 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -80,6 +80,7 @@ 
 #include "async-event.h"
 #include "gdbsupport/selftest.h"
 #include "cli/cli-style.h"
+#include "gdbsupport/remote-args.h"
 
 /* The remote target.  */
 
@@ -10835,16 +10836,15 @@  remote_target::extended_remote_run (const std::string &args)
 
   if (!args.empty ())
     {
-      int i;
+      std::vector<std::string> split_args = gdb::remote_args::split (args);
 
-      gdb_argv argv (args.c_str ());
-      for (i = 0; argv[i] != NULL; i++)
+      for (const auto &a : split_args)
 	{
-	  if (strlen (argv[i]) * 2 + 1 + len >= get_remote_packet_size ())
+	  if (a.size () * 2 + 1 + len >= get_remote_packet_size ())
 	    error (_("Argument list too long for run packet"));
 	  rs->buf[len++] = ';';
-	  len += 2 * bin2hex ((gdb_byte *) argv[i], rs->buf.data () + len,
-			      strlen (argv[i]));
+	  len += 2 * bin2hex ((gdb_byte *) a.c_str (), rs->buf.data () + len,
+			      a.size ());
 	}
     }
 
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index def01c1ee80..f4feb5906c4 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -51,6 +51,7 @@ 
 #include "gdbsupport/scoped_restore.h"
 #include "gdbsupport/search.h"
 #include "gdbsupport/gdb_argv_vec.h"
+#include "gdbsupport/remote-args.h"
 
 /* PBUFSIZ must also be at least as big as IPA_CMD_BUF_SIZE, because
    the client state data is passed directly to some agent
@@ -3465,7 +3466,7 @@  handle_v_run (char *own_buf)
   else
     program_path.set (new_program_name.get ());
 
-  program_args = construct_inferior_arguments (new_argv.get (), true);
+  program_args = gdb::remote_args::join (new_argv.get ());
 
   try
     {
diff --git a/gdbsupport/Makefile.am b/gdbsupport/Makefile.am
index e77298751cd..9e7def7b830 100644
--- a/gdbsupport/Makefile.am
+++ b/gdbsupport/Makefile.am
@@ -80,6 +80,7 @@  libgdbsupport_a_SOURCES = \
     pathstuff.cc \
     print-utils.cc \
     ptid.cc \
+    remote-args.cc \
     rsp-low.cc \
     run-time-clock.cc \
     safe-strerror.cc \
diff --git a/gdbsupport/Makefile.in b/gdbsupport/Makefile.in
index db3d6f6b4dd..190b16f767e 100644
--- a/gdbsupport/Makefile.in
+++ b/gdbsupport/Makefile.in
@@ -163,12 +163,12 @@  am_libgdbsupport_a_OBJECTS = agent.$(OBJEXT) btrace-common.$(OBJEXT) \
 	gdb_tilde_expand.$(OBJEXT) gdb_wait.$(OBJEXT) \
 	gdb_vecs.$(OBJEXT) job-control.$(OBJEXT) netstuff.$(OBJEXT) \
 	new-op.$(OBJEXT) osabi.$(OBJEXT) pathstuff.$(OBJEXT) \
-	print-utils.$(OBJEXT) ptid.$(OBJEXT) rsp-low.$(OBJEXT) \
-	run-time-clock.$(OBJEXT) safe-strerror.$(OBJEXT) \
-	scoped_mmap.$(OBJEXT) search.$(OBJEXT) signals.$(OBJEXT) \
-	signals-state-save-restore.$(OBJEXT) task-group.$(OBJEXT) \
-	tdesc.$(OBJEXT) thread-pool.$(OBJEXT) xml-utils.$(OBJEXT) \
-	$(am__objects_1) $(am__objects_2)
+	print-utils.$(OBJEXT) ptid.$(OBJEXT) remote-args.$(OBJEXT) \
+	rsp-low.$(OBJEXT) run-time-clock.$(OBJEXT) \
+	safe-strerror.$(OBJEXT) scoped_mmap.$(OBJEXT) search.$(OBJEXT) \
+	signals.$(OBJEXT) signals-state-save-restore.$(OBJEXT) \
+	task-group.$(OBJEXT) tdesc.$(OBJEXT) thread-pool.$(OBJEXT) \
+	xml-utils.$(OBJEXT) $(am__objects_1) $(am__objects_2)
 libgdbsupport_a_OBJECTS = $(am_libgdbsupport_a_OBJECTS)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -438,6 +438,7 @@  libgdbsupport_a_SOURCES = \
     pathstuff.cc \
     print-utils.cc \
     ptid.cc \
+    remote-args.cc \
     rsp-low.cc \
     run-time-clock.cc \
     safe-strerror.cc \
@@ -548,6 +549,7 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pathstuff.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print-utils.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote-args.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsp-low.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run-time-clock.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/safe-strerror.Po@am__quote@
diff --git a/gdbsupport/remote-args.cc b/gdbsupport/remote-args.cc
new file mode 100644
index 00000000000..2493433cc62
--- /dev/null
+++ b/gdbsupport/remote-args.cc
@@ -0,0 +1,43 @@ 
+/* Copyright (C) 2023-2025 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "gdbsupport/common-defs.h"
+#include "gdbsupport/remote-args.h"
+#include "gdbsupport/common-inferior.h"
+#include "gdbsupport/buildargv.h"
+
+/* See remote-args.h.  */
+
+std::vector<std::string>
+gdb::remote_args::split (const std::string &args)
+{
+  std::vector<std::string> results;
+
+  gdb_argv argv (args.c_str ());
+  for (int i = 0; argv[i] != nullptr; i++)
+    results.emplace_back (argv[i]);
+
+  return results;
+}
+
+/* See remote-args.h.  */
+
+std::string
+gdb::remote_args::join (const std::vector<char *> &args)
+{
+  return construct_inferior_arguments (args, true);
+}
diff --git a/gdbsupport/remote-args.h b/gdbsupport/remote-args.h
new file mode 100644
index 00000000000..93dbdc6bc96
--- /dev/null
+++ b/gdbsupport/remote-args.h
@@ -0,0 +1,55 @@ 
+/* Functions to help when passing arguments between GDB and gdbserver.
+
+   Copyright (C) 2023-2025 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+/* The functions declared here are used when passing inferior arguments
+   from GDB to gdbserver.
+
+   The remote protocol requires that arguments are passed as a vector of
+   separate argument while GDB stores the arguments as a single string, and
+   gdbserver also requires the arguments be a single string.
+
+   These functions then provide a mechanism to split up an argument string
+   and recombine it within gdbserver while preserving escaping of special
+   characters within the argument string.  */
+
+namespace gdb
+{
+
+namespace remote_args
+{
+
+/* ARGS is an inferior argument string.  This function splits ARGS into
+   individual arguments and returns a vector containing each argument.  */
+
+extern std::vector<std::string> split (const std::string &args);
+
+/* Join together the separate arguments in ARGS and build a single
+   inferior argument string.  The string returned by this function will be
+   equivalent, but not necessarily identical to the string passed to
+   ::split, for example passing the string '"a b"' (without the single
+   quotes, but including the double quotes) to ::split, will return an
+   argument of 'a b' (without the single quotes).  When this argument is
+   passed through ::join we will get back the string 'a\ b' (without the
+   single quotes), that is, we choose to escape the white space, rather
+   than wrap the argument in quotes.  */
+extern std::string join (const std::vector<char *> &args);
+
+} /* namespace remote_args */
+
+} /* namespac gdb */