From patchwork Thu May 16 18:01:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 90305 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B4623384A880 for ; Thu, 16 May 2024 18:02:22 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-io1-xd2d.google.com (mail-io1-xd2d.google.com [IPv6:2607:f8b0:4864:20::d2d]) by sourceware.org (Postfix) with ESMTPS id 9E3B2384AB6F for ; Thu, 16 May 2024 18:01:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9E3B2384AB6F Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=adacore.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 9E3B2384AB6F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::d2d ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1715882480; cv=none; b=sGyGtBAJtkI635P63TbZGUV3IJzdBM1X+NYUTmdwvfQIw7mcWoo/dzL0uEuHKgsVzlc8G6ORDfwgfOWStJRONsjCYUTIN049IS7rsjRs+x7lytsepCKUyFPo3cS0EAfo105Ratq9Ed6Zkun+6HRIvclSuPQaM+/eLa4knKW8GXk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1715882480; c=relaxed/simple; bh=jNoBIB1BNvNdHZdkxjnLAmYNi+Hd8kQvnTjYFK8THS4=; h=DKIM-Signature:From:Date:Subject:MIME-Version:Message-Id:To; b=tG/ZTTV6rdlaNaK1wYDNDX7djeOPbbcCjOYN/b4jfF2WXSFDtw3AfEPSBhaYVTQiSR5fDpzKDqGdxcTjISspOlCzvZBRDPFKpkbEQ5JEtw05McSq1Iy/YyevaHka1vwDWo/X7dgZQNsXbLkN3/Se4/MAjeKQ7PSl/j1fN+OtI5A= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-io1-xd2d.google.com with SMTP id ca18e2360f4ac-7e1cd52db2eso62285039f.0 for ; Thu, 16 May 2024 11:01:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1715882477; x=1716487277; darn=sourceware.org; h=to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=Oq7Ia2YFKE2jKuCmOh9sooJh1Ruz2O0trwzIZrO1gtM=; b=VIkG3cZ3L/rSC90oJJ6KGWiQMO7nFNK/f8bgd9/OT/oq3tc3bIYLRAHYsw4v4OtFJk t8rsEzcSpvHneKofa0xJQbn4MFjguHEbfRu+CT/oUjvD2C87yYT72qVsym0IRtX8ZZhw x1S3OgcAJgqOD2KyTx7VnPzqpkMDYfx83lwy77cnPkgOblvVe+NcmDybCyaH8/l6fY3C pF8SBH9NIP1kLEr44ADqGnxZwi30DxPw4HrOQrvFQr1xO2lse+X6YfVQcOANO2fQ71w2 JnORi5LXUWRhVmAQP28xB3nX16SBhNJtjWKilP5Gc8cfAiB2TYKWvfNkQkg987NxFOsb 5F8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1715882477; x=1716487277; h=to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Oq7Ia2YFKE2jKuCmOh9sooJh1Ruz2O0trwzIZrO1gtM=; b=cOJ2y0HDS8Ez/MLvy9WpV2KAdrRPrVC2zJS0ec752TiFhTZo6TQoDCea1SDJvuKOBX Vf3hsreM3nQUkOn/+9j+EdjtmJwPanOdPkAnggG2WCa9KJBmbXJLzmuFU2wiON+rLrzh GqrcDk0uz8JlDQM4wm2zyPXBdPI4h6zEnE3hSXOGWR2fO9AkNrbbQsfNGmER6f1qB1th bfkJkUW7VWrB+/d8kiIvXIwg57QUB8RD5Cl3XssVonl6htQjaEYioW5XhrijN7xvn49J VVHJTKfpclksKCaJX6cbtsQQEOsfIQRXOy9hzCVaULkLtDJM+dE89dMmyXaP7lZQsC+h HA1w== X-Gm-Message-State: AOJu0YxTjfwjmZdVSyPYesQB8lKzBk1yul/3AS+dJD3Ww8AAL2Qkls9l wyKsrGq1uE1zBjDka1MeMMXVRtkz6ylMkmDmzBHLJA69DGgtI5GXw2fvEj0Y0BYdfsq+7A+pSjI = X-Google-Smtp-Source: AGHT+IGeMCePkGBucRMW3HD9nP4YxbPQZ0mt9GOJFmZgb8iuMdzmanRNdjWczuuNb8mDocDC6yKbMQ== X-Received: by 2002:a05:6e02:12c7:b0:36a:fe09:4ddb with SMTP id e9e14a558f8ab-36cc145607fmr246672945ab.2.1715882475237; Thu, 16 May 2024 11:01:15 -0700 (PDT) Received: from localhost.localdomain (75-166-134-4.hlrn.qwest.net. [75.166.134.4]) by smtp.gmail.com with ESMTPSA id 8926c6da1cb9f-489376dc936sm4287426173.142.2024.05.16.11.01.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 May 2024 11:01:14 -0700 (PDT) From: Tom Tromey Date: Thu, 16 May 2024 12:01:13 -0600 Subject: [PATCH 3/3] Return global scope from DAP scopes request MIME-Version: 1.0 Message-Id: <20240516-dap-global-scope-v1-3-07c493009505@adacore.com> References: <20240516-dap-global-scope-v1-0-07c493009505@adacore.com> In-Reply-To: <20240516-dap-global-scope-v1-0-07c493009505@adacore.com> To: gdb-patches@sourceware.org X-Mailer: b4 0.13.0 X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org 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+patchwork=sourceware.org@sourceware.org A co-worker requested that the DAP code emit a scope for global variables. It's not really practical to do this for all globals, but it seemed reasonable to do this for globals coming from the frame's compilation unit. For Ada in particular, this is convenient as it exposes package-scoped variables. Reviewed-By: Eli Zaretskii --- gdb/NEWS | 3 ++ gdb/data-directory/Makefile.in | 1 + gdb/python/lib/gdb/dap/globalvars.py | 97 +++++++++++++++++++++++++++++++++++ gdb/python/lib/gdb/dap/scopes.py | 4 ++ gdb/testsuite/gdb.dap/ptrref.exp | 8 +-- gdb/testsuite/gdb.dap/rust-slices.exp | 4 +- 6 files changed, 113 insertions(+), 4 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 691abff420b..ab252c81ab6 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -179,6 +179,9 @@ show unwind-on-signal ** The "set debug dap-log-file" command is now documented. This command was available in GDB 14 but not documented. + ** The "scopes" request will now return a scope holding global + variables from the stack frame's compilation unit. + * Guile API ** New constants SYMBOL_TYPE_DOMAIN, SYMBOL_FUNCTION_DOMAIN, and diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in index 98a43529b07..f529656ca05 100644 --- a/gdb/data-directory/Makefile.in +++ b/gdb/data-directory/Makefile.in @@ -98,6 +98,7 @@ PYTHON_FILE_LIST = \ gdb/dap/evaluate.py \ gdb/dap/events.py \ gdb/dap/frames.py \ + gdb/dap/globalvars.py \ gdb/dap/__init__.py \ gdb/dap/io.py \ gdb/dap/launch.py \ diff --git a/gdb/python/lib/gdb/dap/globalvars.py b/gdb/python/lib/gdb/dap/globalvars.py new file mode 100644 index 00000000000..149c9a8f22f --- /dev/null +++ b/gdb/python/lib/gdb/dap/globalvars.py @@ -0,0 +1,97 @@ +# Copyright 2024 Free Software Foundation, Inc. + +# 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 . + +import gdb + +from .sources import make_source +from .startup import in_gdb_thread +from .varref import BaseReference + +# Map a block identifier to a scope object. +_id_to_scope = {} + + +# Arrange to clear the scope references when the inferior runs. +@in_gdb_thread +def clear(event): + global _id_to_scope + _id_to_scope = {} + + +gdb.events.cont.connect(clear) + + +# A scope that holds static and/or global variables. +class _Globals(BaseReference): + def __init__(self, filename, var_list): + super().__init__("Globals") + self.filename = filename + self.var_list = var_list + + def to_object(self): + result = super().to_object() + result["presentationHint"] = "globals" + # How would we know? + result["expensive"] = False + result["namedVariables"] = self.child_count() + if self.filename is not None: + result["source"] = make_source(self.filename) + return result + + def has_children(self): + # This object won't even be created if there are no variables + # to return. + return True + + def child_count(self): + return len(self.var_list) + + @in_gdb_thread + def fetch_one_child(self, idx): + return self.var_list[idx].value() + + +@in_gdb_thread +def get_global_scope(frame): + """Given a frame decorator, return the corresponding global scope + object. + + If the frame does not have a block, or if the CU does not have + globals (that is, empty static and global blocks), return None.""" + inf_frame = frame.inferior_frame() + # It's unfortunate that this API throws instead of returning None. + try: + block = inf_frame.block() + except RuntimeError: + return None + + global _id_to_scope + block = block.static_block + if block in _id_to_scope: + return _id_to_scope[block] + + syms = [] + block_iter = block + while block_iter is not None: + syms += [sym for sym in block_iter if sym.is_variable] + block_iter = block_iter.superblock + + if len(syms) == 0: + return None + + result = _Globals(frame.filename(), syms) + _id_to_scope[block] = result + + return result diff --git a/gdb/python/lib/gdb/dap/scopes.py b/gdb/python/lib/gdb/dap/scopes.py index 8cd860141d6..ad2f10f4057 100644 --- a/gdb/python/lib/gdb/dap/scopes.py +++ b/gdb/python/lib/gdb/dap/scopes.py @@ -16,6 +16,7 @@ import gdb from .frames import frame_for_id +from .globalvars import get_global_scope from .server import request from .startup import in_gdb_thread from .varref import BaseReference @@ -161,4 +162,7 @@ def scopes(*, frameId: int, **extra): scopes.append(_ScopeReference("Locals", "locals", frame, locs)) scopes.append(_RegisterReference("Registers", frame)) frame_to_scope[frameId] = scopes + global_scope = get_global_scope(frame) + if global_scope is not None: + scopes.append(global_scope) return {"scopes": [x.to_object() for x in scopes]} diff --git a/gdb/testsuite/gdb.dap/ptrref.exp b/gdb/testsuite/gdb.dap/ptrref.exp index 0552c3b9815..236ffae12d5 100644 --- a/gdb/testsuite/gdb.dap/ptrref.exp +++ b/gdb/testsuite/gdb.dap/ptrref.exp @@ -54,12 +54,14 @@ set scopes [dap_check_request_and_response "get scopes" scopes \ [format {o frameId [i %d]} $frame_id]] set scopes [dict get [lindex $scopes 0] body scopes] -gdb_assert {[llength $scopes] == 2} "two scopes" +gdb_assert {[llength $scopes] == 3} "three scopes" -lassign $scopes scope reg_scope +lassign $scopes scope reg_scope global_scope gdb_assert {[dict get $scope name] == "Locals"} "scope is locals" +gdb_assert {[dict get $global_scope name] == "Globals"} "scope is globals" -gdb_assert {[dict get $scope namedVariables] == 4} "three vars in scope" +gdb_assert {[dict get $scope namedVariables] == 4} "four vars in locals" +gdb_assert {[dict get $global_scope namedVariables] == 1} "one var in globals" set num [dict get $scope variablesReference] set refs [lindex [dap_check_request_and_response "fetch variables" \ diff --git a/gdb/testsuite/gdb.dap/rust-slices.exp b/gdb/testsuite/gdb.dap/rust-slices.exp index c85568d69ea..d3bd3050c16 100644 --- a/gdb/testsuite/gdb.dap/rust-slices.exp +++ b/gdb/testsuite/gdb.dap/rust-slices.exp @@ -59,7 +59,9 @@ set scopes [dap_check_request_and_response "get scopes" scopes \ [format {o frameId [i %d]} $frame_id]] set scopes [dict get [lindex $scopes 0] body scopes] -gdb_assert {[llength $scopes] == 2} "two scopes" +# There are three scopes because an artificial symbol ends up in the +# DWARF. See https://github.com/rust-lang/rust/issues/125126. +gdb_assert {[llength $scopes] == 3} "three scopes" lassign $scopes scope ignore gdb_assert {[dict get $scope name] == "Locals"} "scope is locals"