From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id yDceKOTc9mdaai0AWB0awg (envelope-from ) for ; Wed, 09 Apr 2025 16:47:32 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=CCaNaGsy; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id A02CC1E0C3; Wed, 9 Apr 2025 16:47:32 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED 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 B091E1E0C0 for ; Wed, 9 Apr 2025 16:47:31 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 55D32384188F for ; Wed, 9 Apr 2025 20:47:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 55D32384188F Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=CCaNaGsy Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 5778D3845879 for ; Wed, 9 Apr 2025 20:44:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5778D3845879 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5778D3845879 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1744231495; cv=none; b=NkWE4hD/V78hgGBo05PIJXaRVP3HrH2zimqdzp6pkRxLn+BIwE8mvYp8lKU6XnDaSWPhukyUBm9vFIufio3vGBXZ6tyvryvbVia08H+StnABECZhNkgMMIASo84oz6ibPHOT1dmSGJOS92lnxj/AMfAui9Yc+ccn/yF1aDkwkX0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1744231495; c=relaxed/simple; bh=cj2xzc5sBM1ijz3pK5AIG568YhXT9j+rxoGwIDqFTW0=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=MdquyqyvYTlQhoVNSy1DGqVhjomQGklhyF6eWXYY1FWShGVeLlS3cZP1VlIutWEgvcMqxHTLCUJ8klMKtkb8JtTFXZQsNyUtT8agEtocbKeqjJD5qyEvpd3xJz9Q+FTneq2vbQAMHZWfAQgmcMPtgNHGz5UtEybkzBJ0IRKDdJA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5778D3845879 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744231495; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mz46G/gbDCRZBMT3boaOihY10iQjb0/4Ru5ntpQrpI0=; b=CCaNaGsyrNcOS9rRtNjSRLA1mcF1ql4bjt9UCI990YYMZAQCDoB5oNj1rLNNmk1fCb6HhD Fj/IV9W5xlkswEXcO5jy15LDv5eXggt8n/pkvSW+XL4mUoNjQqcWvtaVMsvxhTH+LWzi/2 PZtfNTiH5azbCHePrtO7U8rTHtwszjU= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-288-feJqSGVBMkq80GNlKzUmZQ-1; Wed, 09 Apr 2025 16:44:53 -0400 X-MC-Unique: feJqSGVBMkq80GNlKzUmZQ-1 X-Mimecast-MFC-AGG-ID: feJqSGVBMkq80GNlKzUmZQ_1744231492 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A499019560B8; Wed, 9 Apr 2025 20:44:52 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.159]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0D2881955BC0; Wed, 9 Apr 2025 20:44:50 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen , Eli Zaretskii Subject: [PATCH v2 3/3] GDB: Introduce "info namespaces" command Date: Wed, 9 Apr 2025 17:44:27 -0300 Message-ID: <20250409204427.1680979-4-guinevere@redhat.com> In-Reply-To: <20250409204427.1680979-1-guinevere@redhat.com> References: <20250409204427.1680979-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: T6Dx76oFt6PEZFOO9g-SeDQxEQzdOrf_V2gG-okNwRs_1744231492 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true 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 Continuing to improve GDB's ability to debug linker namespaces, this commit adds the command "info linker- namespaces". The command is similar to "info sharedlibrary" but focused on improved readability when the inferior has multiple linker namespaces active. This command can be used in 2 different ways, with or without an argument. When called without argument, the command will print the number of namespaces, and for each active namespace, it's identifier, how many libraries are loaded in it, and all the libraries (in a similar table to what "info sharedlibrary" shows). As an example, this is what GDB's output could look like: (gdb) info linker-namespaces There are 2 linker namespaces loaded There are 3 libraries loaded in linker namespace [[0]] Displaying libraries for linker namespace [[0]]: From To Syms Read Shared Object Library 0x00007ffff7fc6000 0x00007ffff7fff000 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7ebc000 0x00007ffff7fa2000 Yes (*) /lib64/libm.so.6 0x00007ffff7cc9000 0x00007ffff7ebc000 Yes (*) /lib64/libc.so.6 (*): Shared library is missing debugging information. There are 4 libraries loaded in linker namespace [[1]] Displaying libraries for linker namespace [[1]]: From To Syms Read Shared Object Library 0x00007ffff7fc6000 0x00007ffff7fff000 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7fb9000 0x00007ffff7fbe000 Yes gdb.base/dlmopen-ns-ids/dlmopen-lib.so 0x00007ffff7bc4000 0x00007ffff7caa000 Yes (*) /lib64/libm.so.6 0x00007ffff79d1000 0x00007ffff7bc4000 Yes (*) /lib64/libc.so.6 (*): Shared library is missing debugging information. When called with an argument, the argument must be a namespace identifier (either with or without the square brackets decorators). In this situation, the command will truncate the output to only show the relevant information for the requested namespace. For example: (gdb) info linker-namespaces 0 There are 3 libraries loaded in linker namespace [[0]] Displaying libraries for linker namespace [[0]]: From To Syms Read Shared Object Library 0x00007ffff7fc6000 0x00007ffff7fff000 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7ebc000 0x00007ffff7fa2000 Yes (*) /lib64/libm.so.6 0x00007ffff7cc9000 0x00007ffff7ebc000 Yes (*) /lib64/libc.so.6 (*): Shared library is missing debugging information. The test gdb.base/dlmopen-ns-id.exp has been extended to test this new command. Reviewed-By: Eli Zaretskii --- gdb/NEWS | 5 ++ gdb/doc/gdb.texinfo | 16 ++++ gdb/solib-svr4.c | 49 ++++++++++++ gdb/solib.c | 93 +++++++++++++++++++++++ gdb/solist.h | 4 + gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 93 +++++++++++++++++++++++ 6 files changed, 260 insertions(+) diff --git a/gdb/NEWS b/gdb/NEWS index 053541683f1..17a16db2341 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -60,6 +60,11 @@ show riscv numeric-register-names (e.g 'x1') or their abi names (e.g. 'ra'). Defaults to 'off', matching the old behaviour (abi names). +info linker-namespaces +info linker-namespaces [[N]] + Print information about the given linker namespace (identified as N), + or about all the namespaces if no argument is given. + * Changed commands info sharedlibrary diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 2dda8abd407..b1c13d6dbd0 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -22223,6 +22223,22 @@ command for this. This command exists for historical reasons. It is less useful than setting a catchpoint, because it does not allow for conditions or commands as a catchpoint does. +@table @code +@kindex info linker-namespaces +@item info linker-namespaces +@item info linker-namespaces @code{[[@var{n}]]} + +With no argument, print the number of linker namespaces which are +currently active --- that is, namespaces that have libraries loaded +into them. Then, it prints the number of libraries loaded into each +namespace, and all the libraries loaded into them, in the same way +as @code{info sharedlibrary}. + +If an argument @code{[[@var{n}]]} is provided, only prints the +library count and the libraried for the provided namespace @var{n}. +The surrounding square brackets are optional. +@end table + @table @code @item set stop-on-solib-events @kindex set stop-on-solib-events diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 148359a0227..2a2745dc271 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -3558,6 +3558,54 @@ svr4_num_active_namespaces () return info->active_namespaces.size (); } +/* See solib_ops::get_solibs_in_ns in solist.h. */ +static std::vector +svr4_get_solibs_in_ns (int nsid) +{ + std::vector ns_solibs; + svr4_info *info = get_svr4_info (current_program_space); + + /* If the namespace ID is inactive, there will be no active + libraries, so we can have an early exit, as a treat. */ + if (info->active_namespaces.count (nsid) != 1) + return ns_solibs; + + /* Since we only have the names of solibs in a given namespace, + we'll need to walk through the solib list of the inferior and + find which solib objects correspond to which svr4_so. We create + an unordered map with the names and lm_info to check things + faster, and to be able to remove SOs from the map, to avoid + returning the dynamic linker multiple times. */ + CORE_ADDR debug_base = info->namespace_id[nsid]; + std::unordered_map namespace_solibs; + for (svr4_so &so : info->solib_lists[debug_base]) + { + namespace_solibs[so.name] + = gdb::checked_static_cast + (so.lm_info.get ()); + } + for (const solib &so: current_program_space->solibs ()) + { + auto *lm_inferior + = gdb::checked_static_cast (so.lm_info.get ()); + + /* This is inspired by the svr4_same, by finding the svr4_so object + in the map, and then double checking if the lm_info is considered + the same. */ + if (namespace_solibs.count (so.so_original_name) > 0 + && namespace_solibs[so.so_original_name]->l_addr_inferior + == lm_inferior->l_addr_inferior) + { + ns_solibs.push_back (&so); + /* Remove the SO from the map, so that we don't end up + printing the dynamic linker multiple times. */ + namespace_solibs.erase (so.so_original_name); + } + } + + return ns_solibs; +} + const struct solib_ops svr4_so_ops = { svr4_relocate_section_addresses, @@ -3575,6 +3623,7 @@ const struct solib_ops svr4_so_ops = svr4_find_solib_addr, svr4_find_solib_ns, svr4_num_active_namespaces, + svr4_get_solibs_in_ns, }; void _initialize_svr4_solib (); diff --git a/gdb/solib.c b/gdb/solib.c index d641a24dc86..4c0a79cc14e 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1149,6 +1149,96 @@ info_sharedlibrary_command (const char *pattern, int from_tty) } } +/* Implement the "info linker-namespaces" command. If the current + gdbarch's solib_ops object does not support multiple namespaces, + this command would just look like "info sharedlibrary", so point + the user to that command instead. + If solib_ops does support multiple namespaces, this command + will group the libraries by linker namespace, or only print the + libraries in the supplied namespace. */ +static void +info_linker_namespace_command (const char *pattern, int from_tty) +{ + const solib_ops *ops = gdbarch_so_ops (current_inferior ()->arch ()); + /* This command only really makes sense for inferiors that support + linker namespaces, so we can leave early. */ + if (ops->num_active_namespaces == nullptr) + error (_("Current inferior does not support linker namespaces." \ + "Use \"info sharedlibrary\" instead")); + + struct ui_out *uiout = current_uiout; + std::vector>> all_solibs_to_print; + + if (pattern != nullptr) + while (*pattern == ' ') + pattern++; + + if (pattern == nullptr || pattern[0] == '\0') + { + uiout->message (_ ("There are %d linker namespaces loaded\n"), + ops->num_active_namespaces ()); + + int printed = 0; + for (int i = 0; printed < ops->num_active_namespaces (); i++) + { + std::vector solibs_to_print + = ops->get_solibs_in_ns (i); + if (solibs_to_print.size () > 0) + { + all_solibs_to_print.push_back (std::make_pair + (i, solibs_to_print)); + printed++; + } + } + } + else + { + int ns; + /* Check if the pattern includes the optional [[ and ]] decorators. + To match multiple occurrences, '+' needs to be escaped, and every + escape sequence must be doubled to survive the compiler pass. */ + re_comp ("^\\[\\[[0-9]\\+\\]\\]$"); + if (re_exec (pattern)) + ns = strtol (pattern+2, nullptr, 10); + else + { + char * end = nullptr; + ns = strtol (pattern, &end, 10); + if (end[0] != '\0') + error (_ ("Invalid linker namespace identifier: %s"), pattern); + } + + all_solibs_to_print.push_back + (std::make_pair (ns, ops->get_solibs_in_ns (ns))); + } + + bool ns_separator = false; + + for (auto &solibs_pair : all_solibs_to_print) + { + if (ns_separator) + uiout->message ("\n\n"); + else + ns_separator = true; + int ns = solibs_pair.first; + std::vector solibs_to_print = solibs_pair.second; + if (solibs_to_print.size () == 0) + { + uiout->message (_("Linker namespace [[%d]] is not active.\n"), ns); + /* If we got here, a specific namespace was requested, so there + will only be one vector. We can leave early. */ + break; + } + uiout->message + (_ ("There are %ld libraries loaded in linker namespace [[%d]]\n"), + solibs_to_print.size (), ns); + uiout->message + (_ ("Displaying libraries for linker namespace [[%d]]:\n"), ns); + + print_solib_list_table (solibs_to_print, false); + } +} + /* See solib.h. */ bool @@ -1791,6 +1881,9 @@ _initialize_solib () add_com ("nosharedlibrary", class_files, no_shared_libraries_command, _ ("Unload all shared object library symbols.")); + add_info ("linker-namespaces", info_linker_namespace_command, + _ ("Get information about linker namespaces in the inferior.")); + add_setshow_boolean_cmd ("auto-solib-add", class_support, &auto_solib_add, _ ("\ Set autoloading of shared library symbols."), diff --git a/gdb/solist.h b/gdb/solist.h index 0b7bbf9bd18..6ab5a06ccc9 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -194,6 +194,10 @@ struct solib_ops /* Returns the number of active namespaces in the inferior. */ int (*num_active_namespaces) (); + + /* Returns all solibs for a given namespace. If the namespace is not + active, returns an empty vector. */ + std::vector (*get_solibs_in_ns) (int ns); }; /* A unique pointer to a so_list. */ diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp index 8f5376fa3de..a4cd9aa6fbe 100644 --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp @@ -157,5 +157,98 @@ proc_with_prefix test_conv_vars {} { gdb_continue_to_end "" continue 1 } +# Run several tests relating to the command "info namespaces". +proc test_info_linker_namespaces {} { + clean_restart $::binfile + + if { ![runto_main] } { + return + } + + with_test_prefix "info linker-namespaces" { + gdb_breakpoint [gdb_get_line_number "TAG: first dlclose"] + gdb_continue_to_breakpoint "TAG: first dlclose" + } + + # First, test printing a single namespace, and ensure all of + # them are correct, using both syntaxes. + set found_libm false + set found_libc false + set found_all_libs false + gdb_test_multiple "info linker-namespaces \[\[0\]\]" "print namespace 0" -lbl { + -re "^\r\nThere are ($::decimal) libraries loaded in linker namespace \\\[\\\[0\\\]\\\]" { + set libs $expect_out(1,string) + set found_all_libs [expr $libs == 3] + exp_continue + } + -re "^\r\n\[^\r\n\]+libm\.so\[^\r\n\]*(?=\r\n)" { + set found_libm true + exp_continue + } + -re "^\r\n\[^\r\n\]+libc\.so\[^\r\n\]*(?=\r\n)" { + set found_libc true + exp_continue + } + -re "^\r\n$::gdb_prompt $" { + gdb_assert $found_libm "libm was reported" + gdb_assert $found_libc "libc was reported" + gdb_assert $found_all_libs "the correct number of libraries was reported" + } + -re "(^\r\n)?\[^\r\n\]+(?=\r\n)" { + exp_continue + } + } + foreach_with_prefix ns {1 2 3} { + set found_libm false + set found_libc false + set found_test_so false + set found_all_libs false + gdb_test_multiple "info linker-namespaces $ns" "print namespace $ns" -lbl { + -re "^\r\nThere are ($::decimal) libraries loaded in linker namespace \\\[\\\[$ns\\\]\\\]" { + set libs $expect_out(1,string) + set found_all_libs [expr $libs == 4] + exp_continue + } + -re "^\r\n\[^\r\n\]+libm\.so\[^\r\n\]*(?=\r\n)" { + set found_libm true + exp_continue + } + -re "^\r\n\[^\r\n\]+libc\.so\[^\r\n\]*(?=\r\n)" { + set found_libc true + exp_continue + } + -re "^\r\n\[^\r\n\]+${::binfile_lib}\[^\r\n\]*(?=\r\n)" { + set found_test_so true + exp_continue + } + -re "^\r\n$::gdb_prompt $" { + gdb_assert $found_libm "libm was reported" + gdb_assert $found_libc "libc was reported" + gdb_assert $found_test_so "this testfle's SO was reported" + gdb_assert $found_all_libs "the correct number of libraries was reported" + } + -re "(^\r\n)?\[^\r\n\]+(?=\r\n)" { + exp_continue + } + } + } + + # These patterns are simpler, and purposefully glob multiple lines. + # The point is to ensure that we find and display all the namespaces, + # without worrying about the libraries printed, since that was tested + # above. + gdb_test "info linker-namespaces" \ + [multi_line "There are 4 linker namespaces loaded" \ + "There are 3 libraries loaded in linker namespace ..0.." \ + ".*" \ + "There are 4 libraries loaded in linker namespace ..1.." \ + ".*" \ + "There are 4 libraries loaded in linker namespace ..2.." \ + ".*" \ + "There are 4 libraries loaded in linker namespace ..3.." \ + ".*" ] "print namespaces with no argument" +} + test_info_shared test_conv_vars +test_info_linker_namespaces -- 2.49.0