From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id /wDLBDptdGghNzQAWB0awg (envelope-from ) for ; Sun, 13 Jul 2025 22:36:42 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=lvf4c1Gp; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 006851E11C; Sun, 13 Jul 2025 22:36:41 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.8 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_SBL_CSS,RCVD_IN_VALIDITY_CERTIFIED, RCVD_IN_VALIDITY_RPBL,RCVD_IN_VALIDITY_SAFE autolearn=ham autolearn_force=no version=4.0.1 Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 28B221E0C2 for ; Sun, 13 Jul 2025 22:36:34 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A59ED3858410 for ; Mon, 14 Jul 2025 02:36:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A59ED3858410 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=lvf4c1Gp Received: from mail-pf1-x430.google.com (mail-pf1-x430.google.com [IPv6:2607:f8b0:4864:20::430]) by sourceware.org (Postfix) with ESMTPS id 4E7223858D37 for ; Mon, 14 Jul 2025 02:35:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4E7223858D37 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linaro.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4E7223858D37 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::430 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1752460555; cv=none; b=k+tJXFn7E1OKutk1Z1hEZQkTLnCjMC1K7AwsoLfgZaw7raFPYpmcFGccqWW1UV+rmDvEnyI81y8RWNKDG4gWkjm7Aj5Nt8Zm1gAjldzMEP7icpO3B+z/Ol7sD1zntzpcXapnbXcIA2bmN0LelLd6hvqrZZqMLNouk8W7XPCEEDQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1752460555; c=relaxed/simple; bh=qwP9znRfEzmYrcnkUCjhXkDuB2runt2pQDjuYKaKDnA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=h4BIRrXbpaJT6nUIoOJxQHw77FEzDBWgs2RhoTQS/ziGMvl2/qXWmsuGz+bojTVY2mLpmmUA73/EG7TSqQrKzZVKLx5+ghrzaih87PE493CfWriqPzfn70AefhFq6DTSMfvJYKsyqO+Fbzh7+Mb/o+0+B05QSFTeCPjM9c0Wuj0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4E7223858D37 Received: by mail-pf1-x430.google.com with SMTP id d2e1a72fcca58-74af4af04fdso3667311b3a.1 for ; Sun, 13 Jul 2025 19:35:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1752460554; x=1753065354; darn=sourceware.org; h=content-transfer-encoding:mime-version:message-id:date:user-agent :references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+1zZv4yiirbnIsjBa99IhKZE1jc37RmUsE16qcNfsxE=; b=lvf4c1GpgpDEn5+hCS7APSbL/NMiMQf/oq7RQvLi503ehVxGJI0i/fsPhJMUCoL9co 7Lc+leRaRWlj0py7PkaoByr3vrdsUguslujJyTUFDz4OpifwNIGBQeqTTZVyAIgr1MvN qaS3FDKQI2VTZQUPIbsjN3HPUH/jUQIjTo5RfYoWC1lRxaFmegMeHY8R1KQ9yDThOzKb GXlldTIgYPpCEVKC+Tpwvs/2IK8KIdFnKT2HGaKKsmZG/yJj37cKUtVDwAMZbppSrwPU nfvHFad9uSZeWYTbyNI/0kychoDgVDskqqJuWAlu/dlXOgjIIFZSQy/5O2CKUR4T2G7S WZIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752460554; x=1753065354; h=content-transfer-encoding:mime-version:message-id:date:user-agent :references:in-reply-to:subject:cc:to:from:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=+1zZv4yiirbnIsjBa99IhKZE1jc37RmUsE16qcNfsxE=; b=fjJVWI9aH4q9ByD432OJQQRqQ0Geb2Z5CPQS623TCRbgMcidmWUbnwsFOowSUyNHEB GeIobkFW3gU74oG5lqSNeqeLRJqFMX7TKUCgFlADn003j8rSJAVVmiBP4Jv8Drj4qpb9 izJ1OmpdQP3KKjIpfYK/dDLzDY4bnk/+b2lQxKkt6o9LACc0+PSPKjDSyakW1idLzGwj 3NO9Mqpm8wDnfIZfUy6DA6p5PeQGF6dg1Ld+h+VK9YfKua6z/oA9fW/ZWmWX4i8S+csr 8k7Mj8ZS+DGfnL+/fEoXwd0KjlZulfTaG3YV3nFlpoX2bFnAbwdK/auuPZnJ8zlY6mnm HJrg== X-Gm-Message-State: AOJu0Yzeoym4o5d/PXbRaglSUafiwT79Slsl5azJxJ1H3XoTCzPe0ulS ZWQdmenFE1hR4c9UyfT72ewiPE/eE0Ai38OUAWNXzKkY2J0SpY/3Vh7ukbKYj1HLkqg= X-Gm-Gg: ASbGncuUnFmUaKyjk3pcf3LArwM+bQESsLmVHrjXA9vYVTOghuMrRsGWu+K+Qb42iBy xSNJh1DHOaVpps6lujoPl+WDrStnYjkII3nadSvGxc7sAnmiJGeMg+qdqXQMIh6B91MNq7DNVlc K5i1O+RpzcktW1WTBVKe4sg6+bqAxDh8kjgU+YGZvYrs8T+aC4FZfn0Yc3nWJpKiAgn/5M9v2hP m2Ayh8YmnV4VJo1FEC8qWnWESEuGMNNgtXxAgnNnKZCjVqD/TJpqF3md1MvCWnIyXgdbjJz/zfA dl2ExI5XNPokhBXi8qETyLZHBEKtEAzogL5U1ZmwUCjEmVTkM4NfjXnef+QJgMXJIJ60EW6EK5F OCFG5JDEko5OmnRa2LnjD1n/gFXNXh6FB X-Google-Smtp-Source: AGHT+IGzRPhjh30SYg/mfW3IRCDDx/5bg0DL1OOLuLBtTUsH5cycqYmdMk9IwkwzFoSH4L4VHBFNCA== X-Received: by 2002:a05:6a21:339a:b0:234:1e08:4a81 with SMTP id adf61e73a8af0-2341e084b64mr6413871637.14.1752460554056; Sun, 13 Jul 2025 19:35:54 -0700 (PDT) Received: from localhost ([2804:14d:7e39:88d6:f4b6:c7e5:e537:b9ae]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-b3bbe719d07sm9068176a12.63.2025.07.13.19.35.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 13 Jul 2025 19:35:53 -0700 (PDT) From: Thiago Jung Bauermann To: Tankut Baris Aktemur Cc: gdb-patches@sourceware.org, Markus Metzger Subject: Re: [PATCH v2 10/47] gdb, gdbserver, ze: in-memory libraries In-Reply-To: <20241213-upstream-intelgt-mvp-v2-10-5c4caeb7b33d@intel.com> (Tankut Baris Aktemur's message of "Fri, 13 Dec 2024 16:59:27 +0100") References: <20241213-upstream-intelgt-mvp-v2-0-5c4caeb7b33d@intel.com> <20241213-upstream-intelgt-mvp-v2-10-5c4caeb7b33d@intel.com> User-Agent: mu4e 1.12.11; emacs 30.1 Date: Sun, 13 Jul 2025 23:35:51 -0300 Message-ID: <878qkr1ou0.fsf@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Tankut Baris Aktemur writes: > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index ddd414659fcc554813fc2a12a79e581ad7a188b9..c84a8372c223e724e3042322a= 8bee07b12423050 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -48026,9 +48026,10 @@ queries the target's operating system and report= s which libraries > are loaded. >=20=20 > 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. >=20=20 > For the common case of libraries that are fully linked binaries, the > library should have a list of segments. If the target supports > @@ -48040,6 +48041,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}. >=20=20 > +@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: >=20=20 > @@ -48051,6 +48056,16 @@ offset, looks like this: > > @end smallexample >=20=20 > +A corresponding memory map for an in-memory library looks like this: > + > +@smallexample > + > + > + > + Typo: the end tag doesn't match the start tag. > + > +@end smallexample > + > Another simple memory map, with one loaded library with three > allocated sections (.text, .data, .bss), looks like this: >=20=20 > @@ -48068,14 +48083,17 @@ The format of a library list is described by th= is DTD: >=20=20 > @smallexample > > - > - > - > - > - > - > - > - > + > + > + > + > + > + + end CDATA #REQUIRED> > + > + > + > + > @end smallexample >=20=20 > 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 98ed7bc28dcc4562ef4259fdd78138fe69d69d29..f55071c8e906f091752e8ca78= ec29bcd76028433 100644 > --- a/gdb/features/library-list.dtd > +++ b/gdb/features/library-list.dtd > @@ -5,12 +5,16 @@ > notice and this notice are preserved. --> >=20=20 > > - > - > + > + Theoretically, this would cause the parser to reject an XML unless it has version=3D"1.1", despite the fact that GDB is still able to parse 1.0 documents. Therefore, this should just be changed to CDATA #REQUIRED, and we can rely on library_list_start_list to check if the version is acceptable. I said "theoretically" and "would" above because I experimented with it (actually, with which is what I can test on Linux) and GDB didn't reject an XML reply with a tag that's not present in the DTD, and also it didn't care about the value of the version attribute. The DTD is simply ignored. Looking around a bit, I found a comment=C2=B9 by an Expat maintainer saying: > The thing is: Expat is a non-validating XML parser. So I'm not sure what purpose the DTDs have in GDB. Perhaps they're just part of the documentation? If the DTD was enforced, it would be ok to keep version at 1.0 since an old GDB would reject a library-list document with in-memory-library elements because it wouldn't conform to the expected DTD. As it is though, it looks like the version bump is indeed necessary. There's another version bump elsewhere in this series though, which I think isn't really needed in practice =E2=80=94 will there ever be a versio= n of GDB in the field which supports version 1.1 but not 1.2? > > >=20=20 > + > + + end CDATA #REQUIRED> > + > > > > @@ -246,10 +295,35 @@ solib_target_current_sos (void) > for (lm_info_target_up &info : library_list) > { > auto &new_solib =3D sos.emplace_back (); > + switch (info->location) > + { > + case lm_on_disk: > + /* We don't need a copy of the name in INFO anymore. */ > + new_solib.so_name =3D std::move (info->name); > + new_solib.so_original_name =3D new_solib.so_name; > + break; > + > + case lm_in_memory: > + { > + if (info->end <=3D info->begin) > + error (_("bad in-memory-library location: begin=3D%s, end=3D%s"), > + core_addr_to_string_nz (info->begin), > + core_addr_to_string_nz (info->end)); Is erroring out better than printing a warning and skipping the bad library entry? > + /* Give it a name although this isn't really needed. */ > + std::string orig_name > + =3D std::string ("in-memory-") > + + core_addr_to_string_nz (info->begin) > + + "-" > + + core_addr_to_string_nz (info->end); > + > + new_solib.so_original_name =3D orig_name; I know less about C++ than I would like: would it be better to use std::move (orig_name) here, or can we rely on the compiler being smart enough to notice that it doesn't need orig_name after this line and avoid a copy? If you don't know either, I'd add an std::move just to be sure. > + new_solib.begin =3D info->begin; > + new_solib.end =3D info->end; > + } > + break; > + } >=20=20 > - /* We don't need a copy of the name in INFO anymore. */ > - new_solib.so_name =3D std::move (info->name); > - new_solib.so_original_name =3D new_solib.so_name; > new_solib.lm_info =3D std::move (info); > } > diff --git a/gdb/solist.h b/gdb/solist.h > index 8ad0aefd9e32b264b08a853eb3577829a8e74767..c4d053a5c6c0261f1176121b2= bc1f904ac2424a4 100644 > --- a/gdb/solist.h > +++ b/gdb/solist.h > @@ -67,9 +67,14 @@ struct solib : intrusive_list_node > map we've already loaded. */ > std::string so_original_name; >=20=20 > - /* 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 so_name; >=20=20 > + /* The address range of an in-memory shared object. Both BEGIN and END > + are zero for on-disk shared objects. */ > + CORE_ADDR begin, end; It's better to initialize these to 0 here. > /* 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. > @@ -180,6 +185,12 @@ struct solib_ops > name). */ >=20=20 > std::optional (*find_solib_addr) (solib &so); > + > + /* Open an in-memory shared library at ADDR of at most SIZE bytes. The > + TARGET string is used to identify the target. */ > + gdb_bfd_ref_ptr (*bfd_open_from_target_memory) (CORE_ADDR addr, > + CORE_ADDR size, > + const char *target); > }; >=20=20 > /* A unique pointer to a so_list. */ > diff --git a/gdbserver/dll.cc b/gdbserver/dll.cc > index f49aa560aec57e246948d944ec377b0beb8d1dc5..c2c63e9a69a54ddede77e40ea= 33b4e19cbdc71af 100644 > --- a/gdbserver/dll.cc > +++ b/gdbserver/dll.cc > @@ -40,6 +40,17 @@ loaded_dll (process_info *proc, const char *name, CORE= _ADDR base_addr) > proc->dlls_changed =3D true; > } >=20=20 > +/* Record a newly loaded in-memory DLL at BASE_ADDR for PROC. */ You should also document the BEGIN and END arguments. In particular, I'm interested in learning the difference between BEGIN and BASE_ADDR. > + > +void > +loaded_dll (process_info *proc, CORE_ADDR begin, CORE_ADDR end, > + CORE_ADDR base_addr) > +{ > + gdb_assert (proc !=3D nullptr); > + proc->all_dlls.emplace_back (begin, end, base_addr); > + proc->dlls_changed =3D true; > +} Even though both versions of loaded_dll are small, it's a bit unfortunate that they're almost identical. This is because of the choice to have two constructors for dll_info and the location member being initialized depending on which one is called. I understand that design choice, but given that it leads to this duplication of code I think it's better to have location explicit in the constructor (or a new constructor with location explicitly passed in it) and then one version of loaded_dll can simply call the other one (or both can call a third, internal loaded_dll version) with an explicit location argument. > /* Record that the DLL with NAME and BASE_ADDR has been unloaded > from the current process. */ >=20=20 > @@ -58,6 +69,9 @@ unloaded_dll (process_info *proc, const char *name, COR= E_ADDR base_addr) > gdb_assert (proc !=3D nullptr); > auto pred =3D [&] (const dll_info &dll) > { > + if (dll.location !=3D dll_info::on_disk) > + return false; > + > if (base_addr !=3D UNSPECIFIED_CORE_ADDR > && base_addr =3D=3D dll.base_addr) > return true; > @@ -89,3 +103,48 @@ unloaded_dll (process_info *proc, const char *name, C= ORE_ADDR base_addr) > proc->dlls_changed =3D true; > } > } > + > +/* Record that the in-memory DLL from BEGIN to END loaded at BASE_ADDR h= as been > + unloaded. */ > + > +void > +unloaded_dll (process_info *proc, CORE_ADDR begin, CORE_ADDR end, > + CORE_ADDR base_addr) > +{ > + gdb_assert (proc !=3D nullptr); > + auto pred =3D [&] (const dll_info &dll) > + { > + if (dll.location !=3D dll_info::in_memory) > + return false; > + > + if (base_addr !=3D UNSPECIFIED_CORE_ADDR > + && base_addr =3D=3D 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 !=3D UNSPECIFIED_CORE_ADDR > + && begin =3D=3D dll.begin > + && (end =3D=3D UNSPECIFIED_CORE_ADDR > + || end =3D=3D dll.end)) > + return true; > + > + return false; > + }; > + > + auto iter =3D std::find_if (proc->all_dlls.begin (), proc->all_dlls.en= d (), > + pred); > + > + if (iter =3D=3D proc->all_dlls.end ()) > + /* For some inferiors we might get unloaded_dll events without having > + a corresponding loaded_dll. In that case, the dll cannot be found > + in ALL_DLL, and there is nothing further for us to do. */ > + return; > + else > + { > + /* DLL has been found so remove the entry and free associated > + resources. */ > + proc->all_dlls.erase (iter); > + proc->dlls_changed =3D 1; > + } > +} Here the duplication problem between the two versions of unloaded_dll is worse. It's possible do define an unloaded_dll_1 internal function with the code above and getting an dll_info::location_t as argument that is called by both versions of unloaded_dll. > diff --git a/gdbserver/dll.h b/gdbserver/dll.h > index e603df4be2b26017fa5b795f861d8d4111779d85..9bce28e70cf3939b5b062e4b9= c0f0d2d10a1d1d7 100644 > --- a/gdbserver/dll.h > +++ b/gdbserver/dll.h > @@ -24,19 +24,36 @@ struct process_info; >=20=20 > 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_) > {} >=20=20 > + location_t location; > std::string name; > + CORE_ADDR begin; Here too it would be nice to have a comment explaining the difference between begin and base_addr. > + CORE_ADDR end; > CORE_ADDR base_addr; > }; >=20=20 > 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 e= nd, > + 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); >=20=20 > #endif /* GDBSERVER_DLL_H */ > diff --git a/gdbserver/server.cc b/gdbserver/server.cc > index 264fac44b74db69746fdecb1cdd1fd748139cc4f..90902099a1b5a84fe86cb8391= bf983a5943e78c5 100644 > --- a/gdbserver/server.cc > +++ b/gdbserver/server.cc > @@ -1884,6 +1884,97 @@ handle_qxfer_features (const char *annex, > return len; > } >=20=20 > +static std::string > +dll_to_tmpfile (dll_info &dll) There should be a documentation comment for this function. > +{ > + if (dll.end <=3D dll.begin) > + error (_("bad in-memory-library location: begin=3D%s, end=3D%s"), > + core_addr_to_string_nz (dll.begin), > + core_addr_to_string_nz (dll.end)); > + > + gdb::byte_vector buffer (dll.end - dll.begin); > + int errcode =3D gdb_read_memory (dll.begin, buffer.data (), buffer.siz= e ()); > + if (errcode !=3D 0) > + 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 > + =3D std::string ("gdb-in-memory-solib-") > + + core_addr_to_string_nz (dll.begin) > + + "-" > + + core_addr_to_string_nz (dll.end); > + > + gdb_file_up file =3D gdb_create_tmpfile (name); This is the only use of gdb_create_tmpfile. I think that instead of having files that will be deleted when gdbserver exits, it would be better if the files were deleted when they aren't necessary anymore. gdb_create_tmpfile could return not only a gdb_file_up, but also a gdb::unlinker (in an std::pair, I suppose). Then dll_to_tmpfile could add it to new member of dll_info with type std::optional. Thus, when the dll_info object is destroyed, the tmp file will be deleted. WDYT? Also, this could be a dll_info::to_tmpfile method instead of a separate function. > + size_t written =3D fwrite (buffer.data (), buffer.size (), 1, file.get= ()); > + if (written !=3D 1) > + error (_("failed to write into %s"), name.c_str ()); > + > + return name; > +} > + > +/* 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 > + (" " > + "\n", > + paddress (dll.begin), paddress (dll.end), > + paddress (dll.base_addr)); > + > + /* GDB does not support in-memory-library. Fall back to storing i= t in a > + temporary file and report that file to GDB. */ > + dll.name =3D dll_to_tmpfile (dll); > + [[fallthrough]]; > + > + case dll_info::on_disk: > + return string_printf > + (" \n", > + dll.name.c_str (), paddress (dll.base_addr)); > + } > + > + warning (_("unknown dll location: %x"), dll.location); This can only happen via some internal error in gdbserver, right? Isn't it better to use gdb_assert_not_reached? > + return std::string (); > +} > + > +/* Determine the library-list version required for communicating the sha= red > + libraries. */ > + > +static std::string > +library_list_version_needed (const std::list &dlls) > +{ > + const client_state &cs =3D get_client_state (); > + int major =3D 1, minor =3D 0; > + > + for (const dll_info &dll : dlls) > + { > + switch (dll.location) > + { > + case dll_info::on_disk: > + major =3D std::max (major, 1); > + minor =3D std::max (minor, 0); > + break; > + > + case dll_info::in_memory: > + if (cs.in_memory_library_supported) > + { > + major =3D std::max (major, 1); > + minor =3D std::max (minor, 1); > + } > + break; > + } > + } > + > + return std::to_string (major) + std::string (".") + std::to_string (mi= nor); > +} This makes the version depend on what the currnet list of dll_infos needs, not just on the features supported by GDB or gdbserver. If there's no in-memory library loaded, then the XML will be version 1.0. If later an in-memory library is loaded, then the next XML will be version 1.1 I expected the version to depend just on the features advertised by GDB and gdbserver, so I was a bit surprised. I don't think this is a problem, but I just mention here in case someone has an opinion about it. > diff --git a/gdbserver/server.h b/gdbserver/server.h > index e1297d41f8406dab670397f5600e4e08558f23b7..3bacd1062f8bf47720189d2d0= 2b36ddb6089e6bc 100644 > --- a/gdbserver/server.h > +++ b/gdbserver/server.h > @@ -168,6 +168,9 @@ struct client_state > space randomization feature before starting an inferior. */ > int disable_randomization =3D 1; >=20=20 > + /* True if qXfer:libraries:read supports in-memory-library. */ > + bool in_memory_library_supported =3D false; > + Nit: I would add this to the end of the struct, together with the other bools about protocol features. > int pass_signals[GDB_SIGNAL_LAST]; > int program_signals[GDB_SIGNAL_LAST]; > int program_signals_p =3D 0; --=20 Thiago =C2=B9 https://github.com/libexpat/libexpat/issues/968#issuecomment-2692251= 715