Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
To: gdb-patches@sourceware.org, Markus Metzger <markus.t.metzger@intel.com>
Subject: [PATCH v3 09/44] gdb, gdbserver, ze: in-memory libraries
Date: Fri,  1 Aug 2025 11:37:11 +0200	[thread overview]
Message-ID: <20250801-upstream-intelgt-mvp-v3-9-59ce0f87075b@intel.com> (raw)
In-Reply-To: <20250801-upstream-intelgt-mvp-v3-0-59ce0f87075b@intel.com>

From: Markus Metzger <markus.t.metzger@intel.com>

For Intel GPU devices, device libraries live in the host memory and are
loaded onto the device from there.

Add support for reporting such in-memory shared libraries via

    qXfer:libraries:read

and have GDB read them from target memory.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
 gdb/NEWS                      |   6 ++
 gdb/doc/gdb.texinfo           |  43 +++++++++----
 gdb/features/library-list.dtd |   8 ++-
 gdb/remote.c                  |   3 +
 gdb/solib-target.c            |  88 +++++++++++++++++++++++++--
 gdb/solib-target.h            |   2 +
 gdb/solib.c                   |  31 +++++++++-
 gdb/solib.h                   |  12 +++-
 gdbserver/dll.cc              |  95 +++++++++++++++++++++++------
 gdbserver/dll.h               |  34 ++++++++++-
 gdbserver/server.cc           | 137 ++++++++++++++++++++++++++++++++++++++++--
 gdbserver/server.h            |   3 +
 12 files changed, 415 insertions(+), 47 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 5736565d4758a31ad7902905d280c2f68f7a8b08..36944e1a0a408aab3200bcd32c8ee462bb06428e 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -196,6 +196,12 @@ vFile:lstat
   vFile:stat but if the filename is a symbolic link, return
   information about the link itself, the file the link refers to.
 
+qXfer:libraries:read's response
+
+  The qXfer:libraries:read query supports reporting in-memory libraries.  GDB
+  indicates support by supplying qXfer:libraries:read:in-memory-library+ in the
+  qSupported packet.
+
 * Changed remote packets
 
 qXfer:threads:read
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a4c98d18e20182765f8cf0546447c6777cdd5e2d..628ee49b703c23888f518af584128111c9473ef9 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24882,6 +24882,9 @@ future connections is shown.  The available settings are:
 @tab @code{no resumed thread left stop reply}
 @tab Tracking thread lifetime.
 
+@item @code{qXfer:libraries:read:in-memory-library}
+@tab @code{in-memory-library library elements}
+@tab Support for in-memory libraries.
 @end multitable
 
 @cindex packet size, remote, configuring
@@ -48295,9 +48298,10 @@ queries the target's operating system and reports which libraries
 are loaded.
 
 The @samp{qXfer:libraries:read} packet returns an XML document which
-lists loaded libraries and their offsets.  Each library has an
-associated name and one or more segment or section base addresses,
-which report where the library was loaded in memory.
+lists loaded libraries and their offsets.  Each library has either an
+associated name or begin and end addresses and one or more segment or
+section base addresses, which report where the library was loaded in
+memory.
 
 For the common case of libraries that are fully linked binaries, the
 library should have a list of segments.  If the target supports
@@ -48309,6 +48313,10 @@ depend on the library's link-time base addresses.
 @value{GDBN} must be linked with the Expat library to support XML
 library lists.  @xref{Expat}.
 
+@value{GDBN} indicates support for in-memory library elements by
+supplying the @code{qXfer:libraries:read:in-memory-library+}
+@samp{qSupported} feature (@pxref{qSupported}).
+
 A simple memory map, with one loaded library relocated by a single
 offset, looks like this:
 
@@ -48320,6 +48328,16 @@ offset, looks like this:
 </library-list>
 @end smallexample
 
+A corresponding memory map for an in-memory library looks like this:
+
+@smallexample
+<library-list>
+  <in-memory-library begin="0xa000000" end="0xa001000">
+    <segment address="0x10000000"/>
+  </in-memory-library>
+</library-list>
+@end smallexample
+
 Another simple memory map, with one loaded library with three
 allocated sections (.text, .data, .bss), looks like this:
 
@@ -48337,14 +48355,17 @@ The format of a library list is described by this DTD:
 
 @smallexample
 <!-- library-list: Root element with versioning -->
-<!ELEMENT library-list  (library)*>
-<!ATTLIST library-list  version CDATA   #FIXED  "1.0">
-<!ELEMENT library       (segment*, section*)>
-<!ATTLIST library       name    CDATA   #REQUIRED>
-<!ELEMENT segment       EMPTY>
-<!ATTLIST segment       address CDATA   #REQUIRED>
-<!ELEMENT section       EMPTY>
-<!ATTLIST section       address CDATA   #REQUIRED>
+<!ELEMENT library-list            (library | in-memory-library)*>
+<!ATTLIST library-list            version CDATA   #FIXED  "1.1">
+<!ELEMENT library                 (segment*, section*)>
+<!ATTLIST library                 name    CDATA   #REQUIRED>
+<!ELEMENT in-memory-library       (segment*, section*)>
+<!ATTLIST in-memory-library       begin    CDATA   #REQUIRED
+                                  end      CDATA   #REQUIRED>
+<!ELEMENT segment                 EMPTY>
+<!ATTLIST segment                 address CDATA   #REQUIRED>
+<!ELEMENT section                 EMPTY>
+<!ATTLIST section                 address CDATA   #REQUIRED>
 @end smallexample
 
 In addition, segments and section descriptors cannot be mixed within a
diff --git a/gdb/features/library-list.dtd b/gdb/features/library-list.dtd
index 66945cbe97c13cfac5a4d00e9a752ccd8419252f..baa01485af950c58e9e242229365501c043e2fe1 100644
--- a/gdb/features/library-list.dtd
+++ b/gdb/features/library-list.dtd
@@ -5,12 +5,16 @@
      notice and this notice are preserved.  -->
 
 <!-- library-list: Root element with versioning -->
-<!ELEMENT library-list  (library)*>
-<!ATTLIST library-list  version CDATA   #FIXED  "1.0">
+<!ELEMENT library-list  (library | in-memory-library)*>
+<!ATTLIST library-list  version CDATA   #FIXED  "1.1">
 
 <!ELEMENT library       (segment*, section*)>
 <!ATTLIST library       name    CDATA   #REQUIRED>
 
+<!ELEMENT in-memory-library       (segment*, section*)>
+<!ATTLIST in-memory-library       begin    CDATA   #REQUIRED
+                                  end      CDATA   #REQUIRED>
+
 <!ELEMENT segment       EMPTY>
 <!ATTLIST segment       address CDATA   #REQUIRED>
 
diff --git a/gdb/remote.c b/gdb/remote.c
index 6208a90f94a70bf25b0e16cfc4dcce1e01f28828..3d3acd19a53c3665055f8e27cc8669916083f562 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5975,6 +5975,9 @@ remote_target::remote_query_supported ()
 	  != AUTO_BOOLEAN_FALSE)
 	remote_query_supported_append (&q, "memory-tagging+");
 
+      remote_query_supported_append
+	(&q, "qXfer:libraries:read:in-memory-library+");
+
       /* Keep this one last to work around a gdbserver <= 7.10 bug in
 	 the qSupported:xmlRegisters=i386 handling.  */
       if (remote_support_xml != NULL
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index 770028d9903953cb761c2901aae5a1f247aaa34b..5d9bc8f53204eb7e629f3807bcb170c6ace357aa 100644
--- a/gdb/solib-target.c
+++ b/gdb/solib-target.c
@@ -23,16 +23,36 @@
 #include "symfile.h"
 #include "target.h"
 #include "solib-target.h"
+#include "gdbsupport/filestuff.h"
+#include "gdb_bfd.h"
 #include <vector>
 #include "inferior.h"
 
+/* The location of a loaded library.  */
+
+enum lm_location_t
+{
+  lm_on_disk,
+  lm_in_memory
+};
+
 /* Private data for each loaded library.  */
 struct lm_info_target final : public lm_info
 {
+  /* The library's location.  */
+  lm_location_t location;
+
   /* The library's name.  The name is normally kept in the struct
-     solib; it is only here during XML parsing.  */
+     solib; it is only here during XML parsing.
+
+     This is only valid if location == lm_on_disk.  */
   std::string name;
 
+  /* The library's begin and end memory addresses.
+
+     This is only valid if location == lm_in_memory.  */
+  CORE_ADDR begin = 0ull, end = 0ull;
+
   /* The target can either specify segment bases or section bases, not
      both.  */
 
@@ -122,12 +142,32 @@ library_list_start_library (struct gdb_xml_parser *parser,
 {
   auto *list = (std::vector<lm_info_target_up> *) user_data;
   lm_info_target *item = new lm_info_target;
+  item->location = lm_on_disk;
   item->name
     = (const char *) xml_find_attribute (attributes, "name")->value.get ();
 
   list->emplace_back (item);
 }
 
+/* Handle the start of a <in-memory-library> element.  */
+
+static void
+in_memory_library_list_start_library (struct gdb_xml_parser *parser,
+				      const struct gdb_xml_element *element,
+				      void *user_data,
+				      std::vector<gdb_xml_value> &attributes)
+{
+  auto *list = (std::vector<lm_info_target_up> *) user_data;
+  lm_info_target *item = new lm_info_target;
+  item->location = lm_in_memory;
+  item->begin = (CORE_ADDR) *(ULONGEST *)
+    xml_find_attribute (attributes, "begin")->value.get ();
+  item->end = (CORE_ADDR) *(ULONGEST *)
+    xml_find_attribute (attributes, "end")->value.get ();
+
+  list->emplace_back (item);
+}
+
 static void
 library_list_end_library (struct gdb_xml_parser *parser,
 			  const struct gdb_xml_element *element,
@@ -156,7 +196,7 @@ library_list_start_list (struct gdb_xml_parser *parser,
     {
       const char *string = (const char *) version->value.get ();
 
-      if (strcmp (string, "1.0") != 0)
+      if ((strcmp (string, "1.0") != 0) && (strcmp (string, "1.1") != 0))
 	gdb_xml_error (parser,
 		       _("Library list has unsupported version \"%s\""),
 		       string);
@@ -191,10 +231,19 @@ static const struct gdb_xml_attribute library_attributes[] = {
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
+static const struct gdb_xml_attribute in_memory_library_attributes[] = {
+  { "begin", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_element library_list_children[] = {
   { "library", library_attributes, library_children,
     GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
     library_list_start_library, library_list_end_library },
+  { "in-memory-library", in_memory_library_attributes, library_children,
+    GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
+    in_memory_library_list_start_library, library_list_end_library },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
@@ -246,10 +295,31 @@ target_solib_ops::current_sos () const
   for (lm_info_target_up &info : library_list)
     {
       auto &new_solib = sos.emplace_back (*this);
+      switch (info->location)
+	{
+	case lm_on_disk:
+	  /* We don't need a copy of the name in INFO anymore.  */
+	  new_solib.name = std::move (info->name);
+	  new_solib.original_name = new_solib.name;
+	  break;
+
+	case lm_in_memory:
+	  if (info->end <= info->begin)
+	    warning (_("bad in-memory-library location: begin=%s, end=%s"),
+		     core_addr_to_string_nz (info->begin),
+		     core_addr_to_string_nz (info->end));
+	  else
+	    {
+	      new_solib.original_name = std::string ("in-memory-")
+		+ core_addr_to_string_nz (info->begin)
+		+ "-"
+		+ core_addr_to_string_nz (info->end);
 
-      /* We don't need a copy of the name in INFO anymore.  */
-      new_solib.name = std::move (info->name);
-      new_solib.original_name = new_solib.name;
+	      new_solib.begin = info->begin;
+	      new_solib.end = info->end;
+	    }
+	  break;
+	}
       new_solib.lm_info = std::move (info);
     }
 
@@ -386,6 +456,14 @@ target_solib_ops::in_dynsym_resolve_code (CORE_ADDR pc) const
   return in_plt_section (pc);
 }
 
+gdb_bfd_ref_ptr
+target_solib_ops::bfd_open_from_target_memory (CORE_ADDR addr,
+					       CORE_ADDR size,
+					       const char *target) const
+{
+  return gdb_bfd_open_from_target_memory (addr, size, target);
+}
+
 /* See solib-target.h.  */
 
 solib_ops_up
diff --git a/gdb/solib-target.h b/gdb/solib-target.h
index 89ae2bc9b9e155b9cc31b7410a814e2340ab867a..ecd67658c71cb854f012c4311ba79bb40a2ca1b1 100644
--- a/gdb/solib-target.h
+++ b/gdb/solib-target.h
@@ -29,6 +29,8 @@ struct target_solib_ops : solib_ops
   void relocate_section_addresses (solib &so, target_section *) const override;
   owning_intrusive_list<solib> current_sos () const override;
   bool in_dynsym_resolve_code (CORE_ADDR pc) const override;
+  gdb_bfd_ref_ptr bfd_open_from_target_memory
+    (CORE_ADDR addr, CORE_ADDR size, const char *target) const override;
 };
 
 /* Return a new solib_ops for systems fetching solibs from the target.  */
diff --git a/gdb/solib.c b/gdb/solib.c
index 3ec2032f01289011ba1bc3a651b076364f9438f1..f2b26d4e9f9b56b0d174e5223669bd392c3114de 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -473,6 +473,14 @@ solib_ops::bfd_open (const char *pathname) const
   return solib_bfd_open (pathname);
 }
 
+gdb_bfd_ref_ptr
+solib_ops::bfd_open_from_target_memory (CORE_ADDR addr,
+					CORE_ADDR size,
+					const char *target) const
+{
+  error (_("Target does not support in-memory shared libraries."));
+}
+
 /* Given a pointer to one of the shared objects in our list of mapped
    objects, use the recorded name to open a bfd descriptor for the
    object, build a section table, relocate all the section addresses
@@ -488,8 +496,25 @@ solib_ops::bfd_open (const char *pathname) const
 static int
 solib_map_sections (solib &so)
 {
-  gdb::unique_xmalloc_ptr<char> filename (tilde_expand (so.name.c_str ()));
-  gdb_bfd_ref_ptr abfd (so.ops ().bfd_open (filename.get ()));
+  gdb_bfd_ref_ptr abfd;
+  if (!so.name.empty ())
+    {
+      gdb::unique_xmalloc_ptr<char> filename (tilde_expand (so.name.c_str ()));
+      abfd = so.ops ().bfd_open (filename.get ());
+    }
+  else if (so.begin != 0 && so.end != 0)
+    {
+      if (so.end <= so.begin)
+	error (_("Bad address range [%s; %s) for in-memory shared library."),
+	       core_addr_to_string_nz (so.begin),
+	       core_addr_to_string_nz (so.end));
+
+      abfd = so.ops ().bfd_open_from_target_memory (so.begin,
+						    so.end - so.begin,
+						    gnutarget);
+    }
+  else
+    internal_error (_("bad so_list"));
 
   /* If we have a core target then the core target might have some helpful
      information (i.e. build-ids) about the shared libraries we are trying
@@ -536,7 +561,7 @@ solib_map_sections (solib &so)
 	    {
 	      warning (_("Build-id of %ps does not match core file."),
 		       styled_string (file_name_style.style (),
-				      filename.get ()));
+				      so.name.c_str ()));
 	      abfd = nullptr;
 	    }
 	}
diff --git a/gdb/solib.h b/gdb/solib.h
index b9465e103bdd89c83ba575d7551ce84e5e1c7a36..32101d27cc5acae22939eb6a9f72239aaf4812a4 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -94,9 +94,14 @@ struct solib : intrusive_list_node<solib>
      map we've already loaded.  */
   std::string original_name;
 
-  /* Shared object file name, expanded to something GDB can open.  */
+  /* Shared object file name, expanded to something GDB can open.
+     This is an empty string for in-memory shared objects.  */
   std::string name;
 
+  /* The address range of an in-memory shared object.  Both BEGIN and END
+     are zero for on-disk shared objects.  */
+  CORE_ADDR begin = 0, end = 0;
+
   /* The following fields of the structure are built from
      information gathered from the shared object file itself, and
      are set when we actually add it to our symbol tables.
@@ -259,6 +264,11 @@ struct solib_ops
      The supports_namespaces method must return true for this to be called.  */
   virtual std::vector<const solib *> get_solibs_in_ns (int ns) const
   { gdb_assert_not_reached ("namespaces not supported"); }
+
+  /* Open an in-memory shared library at ADDR of at most SIZE bytes.
+     The TARGET string is used to identify the target.  */
+  virtual gdb_bfd_ref_ptr bfd_open_from_target_memory
+    (CORE_ADDR addr, CORE_ADDR size, const char *target) const;
 };
 
 /* A unique pointer to an solib_ops.  */
diff --git a/gdbserver/dll.cc b/gdbserver/dll.cc
index 5ce8b2b45d508bab69dd6c57cce6d4f60911d065..c8e7c03012a6fd1650a7f7a4827f79b3735d624b 100644
--- a/gdbserver/dll.cc
+++ b/gdbserver/dll.cc
@@ -40,34 +40,44 @@ loaded_dll (process_info *proc, const char *name, CORE_ADDR base_addr)
   proc->dlls_changed = true;
 }
 
-/* Record that the DLL with NAME and BASE_ADDR has been unloaded
-   from the current process.  */
+/* Record a newly loaded in-memory DLL at BASE_ADDR for PROC.  */
 
 void
-unloaded_dll (const char *name, CORE_ADDR base_addr)
+loaded_dll (process_info *proc, CORE_ADDR begin, CORE_ADDR end,
+	    CORE_ADDR base_addr)
 {
-  unloaded_dll (current_process (), name, base_addr);
+  gdb_assert (proc != nullptr);
+
+  /* We do not support duplicate in-memory libraries.  */
+  std::list<dll_info> &dlls = proc->all_dlls;
+  std::list<dll_info>::iterator it
+    = std::find_if (dlls.begin (), dlls.end (),
+		    [begin, end] (const dll_info &dll)
+	{
+	  return ((dll.begin == begin) && (dll.end == end));
+	});
+
+  if (it != dlls.end ())
+    error (_("Duplicate in-memory library; begin: %s, end: %s, base: %s."),
+	   paddress (begin), paddress (end), paddress (base_addr));
+
+  proc->all_dlls.emplace_back (begin, end, base_addr);
+  proc->dlls_changed = true;
 }
 
 /* Record that the DLL with NAME and BASE_ADDR has been unloaded
-   from PROC.  */
+   from the current process.  */
 
 void
-unloaded_dll (process_info *proc, const char *name, CORE_ADDR base_addr)
+unloaded_dll (const char *name, CORE_ADDR base_addr)
 {
-  gdb_assert (proc != nullptr);
-  auto pred = [&] (const dll_info &dll)
-    {
-      if (base_addr != UNSPECIFIED_CORE_ADDR
-	  && base_addr == dll.base_addr)
-	return true;
-
-      if (name != NULL && dll.name == name)
-	return true;
-
-      return false;
-    };
+  unloaded_dll (current_process (), name, base_addr);
+}
 
+static void
+unload_dll_if (process_info *proc,
+	       std::function<bool (const dll_info &)> pred)
+{
   auto iter = std::find_if (proc->all_dlls.begin (), proc->all_dlls.end (),
 			    pred);
 
@@ -89,3 +99,52 @@ unloaded_dll (process_info *proc, const char *name, CORE_ADDR base_addr)
       proc->dlls_changed = true;
     }
 }
+
+/* Record that the DLL with NAME and BASE_ADDR has been unloaded
+   from PROC.  */
+
+void
+unloaded_dll (process_info *proc, const char *name, CORE_ADDR base_addr)
+{
+  unload_dll_if (proc, [&] (const dll_info &dll)
+    {
+      if (dll.location != dll_info::on_disk)
+	return false;
+
+      if (base_addr != UNSPECIFIED_CORE_ADDR
+	  && base_addr == dll.base_addr)
+	return true;
+
+      if (name != NULL && dll.name == name)
+	return true;
+
+      return false;
+    });
+}
+
+/* Record that the in-memory DLL from BEGIN to END loaded at BASE_ADDR has been
+   unloaded.  */
+
+void
+unloaded_dll (process_info *proc, CORE_ADDR begin, CORE_ADDR end,
+	      CORE_ADDR base_addr)
+{
+  unload_dll_if (proc, [&] (const dll_info &dll)
+    {
+      if (dll.location != dll_info::in_memory)
+	return false;
+
+      if (base_addr != UNSPECIFIED_CORE_ADDR
+	  && base_addr == dll.base_addr)
+	return true;
+
+      /* We do not require the end address to be specified - we don't
+	 support partially unloaded libraries, anyway.  */
+      if ((begin == dll.begin)
+	  && (end == UNSPECIFIED_CORE_ADDR
+	      || end == dll.end))
+	return true;
+
+      return false;
+    });
+}
diff --git a/gdbserver/dll.h b/gdbserver/dll.h
index b5d9c3957f0ab6851083aee342f90b74b4dd10d9..a3af86dd6122ff8b8c47a335890f54a906f6d5be 100644
--- a/gdbserver/dll.h
+++ b/gdbserver/dll.h
@@ -18,25 +18,57 @@
 #ifndef GDBSERVER_DLL_H
 #define GDBSERVER_DLL_H
 
+#include "gdbsupport/gdb_unlinker.h"
 #include <list>
 
 struct process_info;
 
 struct dll_info
 {
+  enum location_t
+  {
+    on_disk,
+    in_memory
+  };
+
   dll_info (const std::string &name_, CORE_ADDR base_addr_)
-  : name (name_), base_addr (base_addr_)
+    : location (on_disk), name (name_), base_addr (base_addr_)
+  {}
+
+  dll_info (CORE_ADDR begin_, CORE_ADDR end_, CORE_ADDR base_addr_)
+    : location (in_memory), begin (begin_), end (end_), base_addr (base_addr_)
   {}
 
+  /* Where the library bits are stored.  */
+  location_t location;
+
+  /* The name of a file on disk containing the library.
+
+     This is only valid if LOCATION == ON_DISK.  */
   std::string name;
+
+  /* An optional unlinker in case this is a temporary file.  */
+  std::optional<gdb::unlinker> unlinker;
+
+  /* The address range in memory containing the library.
+
+     This is only valid if LOCATION == IN_MEMORY.  */
+  CORE_ADDR begin;
+  CORE_ADDR end;
+
+  /* The base address at which the library is loaded.  */
   CORE_ADDR base_addr;
 };
 
 extern void loaded_dll (const char *name, CORE_ADDR base_addr);
 extern void loaded_dll (process_info *proc, const char *name,
 			CORE_ADDR base_addr);
+extern void loaded_dll (process_info *proc, CORE_ADDR begin, CORE_ADDR end,
+			CORE_ADDR base_addr);
 extern void unloaded_dll (const char *name, CORE_ADDR base_addr);
 extern void unloaded_dll (process_info *proc, const char *name,
 			  CORE_ADDR base_addr);
+extern void unloaded_dll (process_info *proc, CORE_ADDR begin, CORE_ADDR end,
+			  CORE_ADDR base_addr);
 
 #endif /* GDBSERVER_DLL_H */
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index ce84c7f75d98999117752465fd129226b0f443e9..aa695f2f2f80686ea6dc2ae3ae1bfd7c081067bf 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -1885,6 +1885,128 @@ handle_qxfer_features (const char *annex,
   return len;
 }
 
+/* Turn an in-memory library DLL into an on-disk library using a temporary
+   file.  */
+
+static void
+dll_to_tmpfile (dll_info &dll)
+{
+  gdb_assert (dll.location == dll_info::in_memory);
+
+  if (dll.end <= dll.begin)
+    error (_("bad in-memory-library location: begin=%s, end=%s"),
+	   core_addr_to_string_nz (dll.begin),
+	   core_addr_to_string_nz (dll.end));
+
+  std::vector<unsigned char> buffer (dll.end - dll.begin);
+  int errcode = gdb_read_memory (dll.begin, buffer.data (), buffer.size ());
+  if (errcode != buffer.size ())
+    error (_("failed to read in-memory library at %s..%s"),
+	   core_addr_to_string_nz (dll.begin),
+	   core_addr_to_string_nz (dll.end));
+
+  std::string name = get_standard_temp_dir ()
+    + "/gdb-in-memory-"
+    + core_addr_to_string_nz (dll.begin)
+    + "-"
+    + core_addr_to_string_nz (dll.end);
+
+  gdb::char_vector tmpname = make_temp_filename (name);
+
+  scoped_fd fd { gdb_mkostemp_cloexec (tmpname.data (), O_BINARY) };
+  if (fd.get () == -1)
+    error (_("failed to create temporary file %s: %s"), tmpname.data (),
+	   safe_strerror (errno));
+
+  gdb::unlinker unlinker (tmpname.data ());
+  size_t size = buffer.size ();
+  unsigned char *head = buffer.data ();
+  do
+    {
+      ssize_t written = write (fd.get (), head, size);
+      if (written <= 0)
+	error (_("failed to write into %s"), name.c_str ());
+
+      head += written;
+      size -= written;
+    }
+  while (size > 0);
+
+  dll.location = dll_info::on_disk;
+  dll.name = tmpname.data ();
+  dll.unlinker.emplace (dll.name.c_str ());
+
+  unlinker.keep ();
+}
+
+/* Print a qXfer:libraries:read entry for DLL.  */
+
+static std::string
+print_qxfer_libraries_entry (dll_info &dll)
+{
+  switch (dll.location)
+    {
+    case dll_info::in_memory:
+      if (get_client_state ().in_memory_library_supported)
+	return string_printf
+	  ("  <in-memory-library begin=\"0x%s\" end=\"0x%s\">"
+	   "<segment address=\"0x%s\"/></in-memory-library>\n",
+	   paddress (dll.begin), paddress (dll.end),
+	   paddress (dll.base_addr));
+
+      /* GDB does not support in-memory-library.  Fall back to storing it in a
+	 temporary file and report that file to GDB.  */
+      try
+	{
+	  dll_to_tmpfile (dll);
+	}
+      catch (const gdb_exception &ex)
+	{
+	  warning ("%s", ex.what ());
+	  return std::string ();
+	}
+
+      [[fallthrough]];
+    case dll_info::on_disk:
+      return string_printf
+	("  <library name=\"%s\"><segment address=\"0x%s\"/></library>\n",
+	 dll.name.c_str (), paddress (dll.base_addr));
+    }
+
+  gdb_assert_not_reached ("unknown dll location: %x", dll.location);
+}
+
+/* Determine the library-list version required for communicating the shared
+   libraries.  */
+
+static std::string
+library_list_version_needed (const std::list<dll_info> &dlls)
+{
+  const client_state &cs = get_client_state ();
+  int major = 1, minor = 0;
+
+  for (const dll_info &dll : dlls)
+    {
+      switch (dll.location)
+	{
+	case dll_info::on_disk:
+	  major = std::max (major, 1);
+	  minor = std::max (minor, 0);
+	  break;
+
+	case dll_info::in_memory:
+	  if (cs.in_memory_library_supported)
+	    {
+	      major = std::max (major, 1);
+	      minor = std::max (minor, 1);
+	    }
+	  break;
+	}
+    }
+
+  return std::to_string (major) + std::string (".") + std::to_string (minor);
+}
+
 /* Handle qXfer:libraries:read.  */
 
 static int
@@ -1898,13 +2020,13 @@ handle_qxfer_libraries (const char *annex,
   if (annex[0] != '\0' || current_thread == NULL)
     return -1;
 
-  std::string document = "<library-list version=\"1.0\">\n";
-
   process_info *proc = current_process ();
-  for (const dll_info &dll : proc->all_dlls)
-    document += string_printf
-      ("  <library name=\"%s\"><segment address=\"0x%s\"/></library>\n",
-       dll.name.c_str (), paddress (dll.base_addr));
+  std::string document = "<library-list version=\""
+    + library_list_version_needed (proc->all_dlls)
+    + "\">\n";
+
+  for (dll_info &dll : proc->all_dlls)
+    document += print_qxfer_libraries_entry (dll);
 
   document += "</library-list>\n";
 
@@ -2742,6 +2864,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 		}
 	      else if (feature == "error-message+")
 		cs.error_message_supported = true;
+	      else if (feature == "qXfer:libraries:read:in-memory-library+")
+		cs.in_memory_library_supported = true;
 	      else
 		{
 		  /* Move the unknown features all together.  */
@@ -2772,6 +2896,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 	  /* We do not have any hook to indicate whether the non-SVR4 target
 	     backend supports qXfer:libraries:read, so always report it.  */
 	  strcat (own_buf, ";qXfer:libraries:read+");
+	  strcat (own_buf, ";qXfer:libraries:read:in-memory-library+");
 	}
 
       if (the_target->supports_read_auxv ())
diff --git a/gdbserver/server.h b/gdbserver/server.h
index 5609584f716488fca599a8d30dfa0f11b50042c8..ebb5980f70dd778abfaade1086b4b89a529b4298 100644
--- a/gdbserver/server.h
+++ b/gdbserver/server.h
@@ -196,6 +196,9 @@ struct client_state
      are not supported with qRcmd and m packets, but are still supported
      everywhere else.  This is for backward compatibility reasons.  */
   bool error_message_supported = false;
+
+  /* True if qXfer:libraries:read supports in-memory-library.  */
+  bool in_memory_library_supported = false;
 };
 
 client_state &get_client_state ();

-- 
2.34.1

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

  parent reply	other threads:[~2025-08-01  9:48 UTC|newest]

Thread overview: 92+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-01  9:37 [PATCH v3 00/44] A new target to debug Intel GPUs Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 01/44] gdb, intelgt: add intelgt as a basic machine Tankut Baris Aktemur
2025-12-09 20:44   ` Simon Marchi
2025-12-19 11:13     ` Aktemur, Tankut Baris
2025-08-01  9:37 ` [PATCH v3 02/44] bfd: add intelgt target to BFD Tankut Baris Aktemur
2025-08-01 12:20   ` Jan Beulich
2025-08-08  5:03     ` Metzger, Markus T
2025-12-09 21:05   ` Simon Marchi
2025-12-19 12:46     ` Aktemur, Tankut Baris
2025-08-01  9:37 ` [PATCH v3 03/44] ld: add intelgt as a target configuration Tankut Baris Aktemur
2025-08-01 12:06   ` Jan Beulich
2025-08-08  5:03     ` Metzger, Markus T
2025-08-01  9:37 ` [PATCH v3 04/44] opcodes: add intelgt as a configuration Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 05/44] gdb, gdbserver, gdbsupport: add 'device' tag to XML target description Tankut Baris Aktemur
2025-12-09 21:27   ` Simon Marchi
2025-12-15 21:03     ` Simon Marchi
2025-12-18 15:04       ` Aktemur, Tankut Baris
2026-01-09 19:12         ` Aktemur, Tankut Baris
2026-01-09 19:34           ` Simon Marchi
2025-08-01  9:37 ` [PATCH v3 06/44] gdb, arch, intelgt: add intelgt arch definitions Tankut Baris Aktemur
2025-12-09 21:48   ` Simon Marchi
2025-12-16 15:47     ` Metzger, Markus T
2025-08-01  9:37 ` [PATCH v3 07/44] gdb, intelgt: add the target-dependent definitions for the Intel GT architecture Tankut Baris Aktemur
2025-12-11 18:53   ` Simon Marchi
2025-12-19 16:01     ` Aktemur, Tankut Baris
2025-08-01  9:37 ` [PATCH v3 08/44] gdb, intelgt: add disassemble feature " Tankut Baris Aktemur
2025-12-11 19:37   ` Simon Marchi
2025-12-23 11:03     ` Aktemur, Tankut Baris
2025-08-01  9:37 ` Tankut Baris Aktemur [this message]
2025-12-12  4:13   ` [PATCH v3 09/44] gdb, gdbserver, ze: in-memory libraries Simon Marchi
2025-12-12 11:20     ` Metzger, Markus T
2025-12-12 19:34       ` Simon Marchi
2025-12-15 13:07         ` Metzger, Markus T
2025-12-15 21:25           ` Simon Marchi
2025-08-01  9:37 ` [PATCH v3 10/44] gdb, gdbserver, rsp, ze: acknowledge libraries Tankut Baris Aktemur
2025-12-12  4:41   ` Simon Marchi
2025-12-12 14:28     ` Metzger, Markus T
2025-08-01  9:37 ` [PATCH v3 11/44] gdb, solib, ze: update target_solib_ops::bfd_open_from_target_memory Tankut Baris Aktemur
2025-12-12  4:43   ` Simon Marchi
2025-12-12 14:33     ` Metzger, Markus T
2025-08-01  9:37 ` [PATCH v3 12/44] gdb, infrun, ze: allow saving process events Tankut Baris Aktemur
2025-12-12  4:57   ` Simon Marchi
2025-12-15 13:13     ` Metzger, Markus T
2025-12-16 21:10       ` Simon Marchi
2025-12-17  9:30         ` Metzger, Markus T
2025-12-17 20:44           ` Simon Marchi
2025-12-18  7:20             ` Metzger, Markus T
2025-08-01  9:37 ` [PATCH v3 13/44] gdb, ze: add TARGET_WAITKIND_UNAVAILABLE Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 14/44] gdb, infrun, ze: handle stopping unavailable threads Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 15/44] gdb, infrun, ze: allow resuming " Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 16/44] gdb, gdbserver, ze: add U stop reply Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 17/44] gdb, gdbserver, ze: add library notification to " Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 18/44] gdbserver, ze: report TARGET_WAITKIND_UNAVAILABLE events Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 19/44] gdb, ze: handle TARGET_WAITKIND_UNAVAILABLE in stop_all_threads Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 20/44] gdb, remote: handle thread unavailability in print_one_stopped_thread Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 21/44] gdb, remote: do 'remote_add_inferior' in 'remote_notice_new_inferior' earlier Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 22/44] gdb, remote: handle a generic process PID in remote_notice_new_inferior Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 23/44] gdb, remote: handle a generic process PID in process_stop_reply Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 24/44] gdb: use the pid from inferior in setup_inferior Tankut Baris Aktemur
2025-12-12 19:51   ` Simon Marchi
2025-12-13 12:40     ` Aktemur, Tankut Baris
2025-08-01  9:37 ` [PATCH v3 25/44] gdb: revise the pid_to_exec_file target op Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 26/44] gdb: load solibs if the target does not have the notion of an exec file Tankut Baris Aktemur
2025-12-12 20:30   ` Simon Marchi
2026-01-09 19:10     ` Aktemur, Tankut Baris
2025-08-01  9:37 ` [PATCH v3 27/44] gdbserver: import AC_LIB_HAVE_LINKFLAGS macro into the autoconf script Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 28/44] gdbserver: add a pointer to the owner thread in regcache Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 29/44] gdbserver: wait for stopped threads in queue_stop_reply_callback Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 30/44] gdbserver: adjust pid after the target attaches Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 31/44] gdb: do not create a thread after a process event Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 32/44] gdb, ze: on a whole process stop, mark all threads as not_resumed Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 33/44] gdb, dwarf, ze: add DW_OP_INTEL_regval_bits Tankut Baris Aktemur
2025-08-01 12:02   ` Jan Beulich
2025-08-01 12:31     ` Metzger, Markus T
2025-08-01 12:50       ` Jan Beulich
2025-08-08  5:25         ` Metzger, Markus T
2025-08-01  9:37 ` [PATCH v3 34/44] gdbserver: allow configuring for a heterogeneous target Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 35/44] gdbserver, ze, intelgt: introduce ze-low and intel-ze-low targets Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 36/44] testsuite, sycl: add SYCL support Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 37/44] testsuite, sycl: add test for backtracing inside a kernel Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 38/44] testsuite, sycl: add test for 'info locals' and 'info args' Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 39/44] testsuite, sycl: add tests for stepping and accessing data elements Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 40/44] testsuite, sycl: add test for 1-D and 2-D parallel_for kernels Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 41/44] testsuite, sycl: add test for scheduler-locking Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 42/44] testsuite, arch, intelgt: add a disassembly test Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 43/44] testsuite, arch, intelgt: add intelgt-program-bp.exp Tankut Baris Aktemur
2025-08-01  9:37 ` [PATCH v3 44/44] testsuite, sycl: test canceling a stepping flow Tankut Baris Aktemur
2025-09-17 12:43 ` [PATCH v3 00/44] A new target to debug Intel GPUs Aktemur, Tankut Baris
2025-10-14  6:34   ` Aktemur, Tankut Baris
2025-12-08 11:32 ` Aktemur, Tankut Baris
2025-12-09 21:30 ` Simon Marchi
2025-12-19 12:52   ` Aktemur, Tankut Baris

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250801-upstream-intelgt-mvp-v3-9-59ce0f87075b@intel.com \
    --to=tankut.baris.aktemur@intel.com \
    --cc=gdb-patches@sourceware.org \
    --cc=markus.t.metzger@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox