From patchwork Thu May 16 18:01:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 90304 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 23AB8384646C for ; Thu, 16 May 2024 18:01:51 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-io1-xd34.google.com (mail-io1-xd34.google.com [IPv6:2607:f8b0:4864:20::d34]) by sourceware.org (Postfix) with ESMTPS id B3C2D384AB42 for ; Thu, 16 May 2024 18:01:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B3C2D384AB42 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 B3C2D384AB42 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::d34 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1715882479; cv=none; b=GDEEFDFbOwltUFEvbUNS0CWRTbEPvHFbqdEkI2m2jziuriTiDHn2yk4jogPNYrp1rbH90RU4hUci2emWLc7C/MYGc+abr4d6tKSZ47tSaiFWekTG3qsScbUckEOeK1hsp3vVAKx4WSYqfnJcZiFdpC+qdcazds/BjXX+kk8ZoEg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1715882479; c=relaxed/simple; bh=FB/piAzB0Fh5BvW7S82uDTd8ruV4k7k3m9H/Q2J1tH8=; h=DKIM-Signature:From:Date:Subject:MIME-Version:Message-Id:To; b=lhRfJuwZlDiTChBdJWmrCy4PDTT6iAxPyG6ipu7/3TOxA3ZffZwkEHprm7/SENqZ7TI3RiySdmnIohBaGYBt8nSRV9bLweCTtq+4P8RNw/HZtDrKuFbQdKMjB8bZEcm353xO59i+qA41fv5pNYLz5GHR7vaAw1/oqCRTBLH4LVk= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-io1-xd34.google.com with SMTP id ca18e2360f4ac-7e21742025aso58283039f.2 for ; Thu, 16 May 2024 11:01:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1715882476; x=1716487276; 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=K3syEcd2+4zRGNoMO1gf+rxqspKrvh4Uvkhdh/aXivY=; b=T5LioF173MPlzekyVcRVUHZtET7Yelo5VRcSErCefWV1GxsdASEi4dO68JKrWdKfZi 99JVkIgtNNiXXtnhoFcZuzVvsmH70U+Mtmuh0v5fLrmFZGLdKo/NR0j9oPYFNUAgtQ6o u/M3lzNdI3IqfG/HKf8YUB11GV3f0d0FG+mszTkK8M5EK2NrPojcf1xtuzP9u6pLV2Qb YEwsMwAdhOaRtJFvuUSuRVEz2JmWhGG+xSP768MgFHWBD5aSpqwx7LLO9eJjFrlXLLGK gUGxsH64R5EW0sli2iTPOT7dUL33WKXrPGHFo2Y6dINIYzucNXAVKXHYs94yVxLPz0VP HGTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1715882476; x=1716487276; 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=K3syEcd2+4zRGNoMO1gf+rxqspKrvh4Uvkhdh/aXivY=; b=LbXfUsqj1O42yTB0/xUjuAvAKClANwUbBJzIN2YwYWjkgA50qSDLxW8OReR0ijLSbA VOBfaFYBR+iWOgkS4ex36m8M/KKv7gnKVZnLTSieGxFqXS6prOtHKmixT46lVZeU4EMh JeFJqG1A8Ks7h4YDU+JXTbav427v38Prm7zS4clqrft0yOCAQjZM39sRFDbdlOyzjKfy nxjvf6ogUOAc/UQ2WwPhVTeyRL57YsAwii1LE/qLphglCYzHxKP+3XpATNObXkWlCzmO XBBPVRSpvGdDKqaHejF3aDvtlee9orfYvPhbODQmlBYzS6JQ7c8uS+KeeLgaQaTNHzZl CN1Q== X-Gm-Message-State: AOJu0YweC59wiQ8dkQj3wEI78XwgqTxdBkyznRTo/uo9j0D4FVr/avNg LL9x/vC6yv0kgn+ui9HNqNO2pzU7Owy+vAxa3z8s2NkxymlddnZcSrZHckUTuN8a0FxUGQF8B2E = X-Google-Smtp-Source: AGHT+IH4jgQfRyiu/7f77h3n73fQbEOMcSqct29uCbGfjjHUPf9QVZxBE5MkAjVByEd+Gkkr8FI68g== X-Received: by 2002:a05:6e02:1565:b0:36d:b604:7930 with SMTP id e9e14a558f8ab-36db6047c1fmr68056615ab.14.1715882472939; Thu, 16 May 2024 11:01:12 -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.12 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 May 2024 11:01:12 -0700 (PDT) From: Tom Tromey Date: Thu, 16 May 2024 12:01:11 -0600 Subject: [PATCH 1/3] Memoize gdb.Block and make them hashable MIME-Version: 1.0 Message-Id: <20240516-dap-global-scope-v1-1-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=-11.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 In subsequent patches, it's handy if gdb.Block is hashable, so it can be stored in a set or a dictionary. However, doing this in a straightforward way is not really possible, because a block isn't truly immutable -- it can be invalidated. And, while this isn't a real problem for my use case (in DAP the maps are only used during a single stop), it seemed error-prone. This patch instead takes the approach of using the gdb.Block's own object identity to allow hashing. This seems fine because the contents don't affect the hashing. In order for this to work, though, the blocks have to be memoized -- two requests for the same block must return the same object. This also allows (actually, requires) the simplification of the rich-compare method for blocks. Reviewed-By: Alexandra Petlanova Hajkova --- gdb/python/py-block.c | 143 +++++++++++++++++++--------------- gdb/testsuite/gdb.python/py-block.exp | 4 + 2 files changed, 83 insertions(+), 64 deletions(-) diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c index 3de6200e7c2..62e93d55072 100644 --- a/gdb/python/py-block.c +++ b/gdb/python/py-block.c @@ -31,10 +31,6 @@ struct block_object { between a block and an object file. When a block is created also store a pointer to the object file for later use. */ struct objfile *objfile; - /* Keep track of all blocks with a doubly-linked list. Needed for - block invalidation if the source object file has been freed. */ - block_object *prev; - block_object *next; }; struct block_syms_iterator_object { @@ -76,32 +72,9 @@ struct block_syms_iterator_object { } \ } while (0) -/* This is called when an objfile is about to be freed. - Invalidate the block as further actions on the block would result - in bad data. All access to obj->symbol should be gated by - BLPY_REQUIRE_VALID which will raise an exception on invalid - blocks. */ -struct blpy_deleter -{ - void operator() (block_object *obj) - { - while (obj) - { - block_object *next = obj->next; - - obj->block = NULL; - obj->objfile = NULL; - obj->next = NULL; - obj->prev = NULL; - - obj = next; - } - } -}; - extern PyTypeObject block_syms_iterator_object_type CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object"); -static const registry::key +static const registry::key blpy_objfile_data_key; static PyObject * @@ -278,42 +251,54 @@ blpy_getitem (PyObject *self, PyObject *key) return nullptr; } +/* Deleter function for the hash table. */ + static void -blpy_dealloc (PyObject *obj) +block_object_del (void *obj) { block_object *block = (block_object *) obj; + block->block = nullptr; + block->objfile = nullptr; +} - if (block->prev) - block->prev->next = block->next; - else if (block->objfile) - blpy_objfile_data_key.set (block->objfile, block->next); - if (block->next) - block->next->prev = block->prev; - block->block = NULL; - Py_TYPE (obj)->tp_free (obj); +/* Hash function for the hash table. */ + +static hashval_t +block_object_hash (const void *obj) +{ + const block_object *block = (const block_object *) obj; + return htab_hash_pointer (block->block); +} + +/* Equality function for the hash table. Note that searches must be + done with a plain block. */ + +static int +block_object_eq (const void *a, const void *b) +{ + const block_object *blocka = (const block_object *) a; + const block *blockb = (const block *) b; + return blocka->block == blockb; } -/* Given a block, and a block_object that has previously been - allocated and initialized, populate the block_object with the - struct block data. Also, register the block_object life-cycle - with the life-cycle of the object file associated with this - block, if needed. */ +/* Called when a gdb.Block is destroyed. This removes it from the + hash. */ + static void -set_block (block_object *obj, const struct block *block, - struct objfile *objfile) +blpy_dealloc (PyObject *obj) { - obj->block = block; - obj->prev = NULL; - if (objfile) + block_object *block = (block_object *) obj; + + if (block->objfile != nullptr) { - obj->objfile = objfile; - obj->next = blpy_objfile_data_key.get (objfile); - if (obj->next) - obj->next->prev = obj; - blpy_objfile_data_key.set (objfile, obj); + htab_t table = blpy_objfile_data_key.get (block->objfile); + hashval_t hash = block_object_hash (block); + /* This will clear the contents of the block as a side + effect. */ + htab_remove_elt_with_hash (table, block->block, hash); } - else - obj->next = NULL; + + Py_TYPE (obj)->tp_free (obj); } /* Create a new block object (gdb.Block) that encapsulates the struct @@ -321,13 +306,32 @@ set_block (block_object *obj, const struct block *block, PyObject * block_to_block_object (const struct block *block, struct objfile *objfile) { - block_object *block_obj; + htab_t table = blpy_objfile_data_key.get (objfile); + if (table == nullptr) + { + table = htab_create_alloc (10, block_object_hash, block_object_eq, + block_object_del, xcalloc, xfree); + blpy_objfile_data_key.set (objfile, table); + } + + hashval_t hash = htab_hash_pointer (block); + block_object *result = (block_object *) htab_find_with_hash (table, block, + hash); + if (result != nullptr) + { + PyObject *py_result = (PyObject *) result; + Py_INCREF (py_result); + return py_result; + } + + result = PyObject_New (block_object, &block_object_type); + result->block = block; + result->objfile = objfile; - block_obj = PyObject_New (block_object, &block_object_type); - if (block_obj) - set_block (block_obj, block, objfile); + void **slot = htab_find_slot_with_hash (table, block, hash, INSERT); + *slot = result; - return (PyObject *) block_obj; + return (PyObject *) result; } /* Return struct block reference that is wrapped by this object. */ @@ -452,6 +456,20 @@ blpy_repr (PyObject *self) name, str.c_str ()); } +/* Hash function for block objects. */ + +static Py_hash_t +blpy_hash (PyObject *self) +{ + /* Python doesn't really expose its pointer hash function, so we use + our own. */ + Py_hash_t result = (Py_hash_t) htab_hash_pointer (self); + /* -1 has a special meaning for Python. */ + if (result == -1) + result = -2; + return result; +} + /* Implements the equality comparison for Block objects. All other comparison operators will throw NotImplemented, as they aren't valid for blocks. */ @@ -466,10 +484,7 @@ blpy_richcompare (PyObject *self, PyObject *other, int op) return Py_NotImplemented; } - block_object *self_block = (block_object *) self; - block_object *other_block = (block_object *) other; - - bool expected = self_block->block == other_block->block; + bool expected = self == other; bool equal = op == Py_EQ; return PyBool_FromLong (equal == expected); } @@ -542,7 +557,7 @@ PyTypeObject block_object_type = { 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ &block_object_as_mapping, /*tp_as_mapping*/ - 0, /*tp_hash */ + blpy_hash, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ diff --git a/gdb/testsuite/gdb.python/py-block.exp b/gdb/testsuite/gdb.python/py-block.exp index 99642a546a7..0e6851ddf8b 100644 --- a/gdb/testsuite/gdb.python/py-block.exp +++ b/gdb/testsuite/gdb.python/py-block.exp @@ -119,8 +119,12 @@ gdb_test "python print (block.is_valid())" "True" \ "Check block validity" gdb_test "python print (block_iter.is_valid())" "True" \ "Check block_iter validity" +gdb_test_no_output "python x = hash(block)" "block is hashable" +gdb_test "python print (type (x))" "" "block hash is integer" gdb_unload gdb_test "python print (block.is_valid())" "False" \ "Check block validity after unload" gdb_test "python print (block_iter.is_valid())" "False" \ "Check block_iter validity after unload" +gdb_test "python print (hash (block) == x)" "True" \ + "block hash did not change" From patchwork Thu May 16 18:01:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 90303 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 BD5903849AD0 for ; Thu, 16 May 2024 18:01:50 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-io1-xd32.google.com (mail-io1-xd32.google.com [IPv6:2607:f8b0:4864:20::d32]) by sourceware.org (Postfix) with ESMTPS id 3D10E384CB97 for ; Thu, 16 May 2024 18:01:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3D10E384CB97 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 3D10E384CB97 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::d32 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1715882479; cv=none; b=nJ1eF1cBwfFLaLv5kckUFqsXN5eSL5nFN9mlzhZ+z9TBe+jdoa1C8fdEEjbqQL9STC4lqwfumFoJRJ0FzmP80oPlgCvhBZYSsVQflsywFugHcbFQ8kjsVB8NCjZhYQlPeN80jj9eEZB4T0TLQZqQYkhhL32JLYoGBSLQHJ2jVr0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1715882479; c=relaxed/simple; bh=RcKdVA0307Y+RdaOhLldRIPc+TFHG9k+dDVi2CUcQpI=; h=DKIM-Signature:From:Date:Subject:MIME-Version:Message-Id:To; b=dha+figwGjRN39avbohu1YAHtPwQHS8SLI2eLzdAMMKQ+ImHgK9ShJYVPRiOla5iVsVRPjjRofDmTTbVtTDwy6SV94h3qSmk3Ms3J+tP3asjO+tb6d2TXIRR+aLJNkVEcVSJR8hWxCj34F7rS2c2nJqOii4RSqqiHDMnyZawuqs= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-io1-xd32.google.com with SMTP id ca18e2360f4ac-7e18adf7268so69374939f.0 for ; Thu, 16 May 2024 11:01:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1715882475; x=1716487275; 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=JV34CI0v1hHG96iJYxKOFUUmjIpgOId+AWJpQJbVs60=; b=PXiEE/1mx+chrzndB1f/Tvpyb0CMpmjcDvZhvTAirkh0487n69DvLTmETRzllqzRl/ O2sdWUVpdyvOiND0ttJjS6wMPh9rB78LIO7TtWzs8mOoo+Y3Qdxx6sgyw3zM24Fkr9rG WhKaXEvjvj6SJMZKNTnAVXt2aGAtv6KkpJs3KV9STafLlMvY9zdUT+kWZTr2pyF3TgtS HBTM5OJvdPB4kdKK6HS6iaa54bmWx7HiznoW4+HZO0qaJbf8ps6a9mZamrLIzKT7tRbo PhelDVae93kZwiD2S9FF/DU/hqdPyEPvXNSaDh+T1tFez45bR7GgWm7NhcKhijFNWJ9g VUTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1715882475; x=1716487275; 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=JV34CI0v1hHG96iJYxKOFUUmjIpgOId+AWJpQJbVs60=; b=BgbZXVuHiavv1ae7Kr76v9yEVsVaU+Lm2DeZocwk3Ag2KxprX5MlYfwjRuq7SvJUai rsKucy8dRNixzBcwymBa9B0Dnaodv+JtpstOnAy9j1oQIENDUvWOqG5NYRW6RemPu97q YgCdYT7+HjhG8cQ2DRFS3Ty/k0TWpIXHKNDLMt28RM72Lo9KfQc/b20A0DS7gXchUXjL wGgB+3Oxvei9KKKgZi/zx4cqrDoQiAFBSWY9eHswRqjamRvwG36U/rZsPIaRiCtEtAHT 2nH5QG97H9ZnWGrWrgFJx39nQaDeobgGrnL+1uI1D6V9Z8gdxi0lmfVPFjewNM7KHy+1 Y1sA== X-Gm-Message-State: AOJu0YyWylHP0XGHIiNQn4Y/SF0u8o84a8HTZB/vCCVLyAMznZCg0n7b nJzqZoM2F5dUfgt9syWUJJOL05MZ3nJdxQihA5IsssCa2SbHDfhndcDgrtFGs+GIS86d/0DXt1c = X-Google-Smtp-Source: AGHT+IEn0UK6uGdF5Q5xroGKDeWDc05xrTYMh0PDwcpgdkIhxm3ZXq7LnG5LEbCVLBydnJ60D3Um4w== X-Received: by 2002:a6b:7f42:0:b0:7e1:7b55:ad24 with SMTP id ca18e2360f4ac-7e1b51ab391mr2194431239f.2.1715882473891; Thu, 16 May 2024 11:01:13 -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:13 -0700 (PDT) From: Tom Tromey Date: Thu, 16 May 2024 12:01:12 -0600 Subject: [PATCH 2/3] Convert DAP disassemble code to use Block hashing MIME-Version: 1.0 Message-Id: <20240516-dap-global-scope-v1-2-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=-11.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 This changes the DAP disassemble code to use the new Block hashing, storing the already-visited blocks in a set rather than a list. --- gdb/python/lib/gdb/dap/disassemble.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gdb/python/lib/gdb/dap/disassemble.py b/gdb/python/lib/gdb/dap/disassemble.py index d65790a40b0..a2e27e54a64 100644 --- a/gdb/python/lib/gdb/dap/disassemble.py +++ b/gdb/python/lib/gdb/dap/disassemble.py @@ -27,9 +27,8 @@ class _BlockTracker: # just one label -- DAP wouldn't let us return multiple labels # anyway. self.labels = {} - # List of blocks that have already been handled. Note that - # blocks aren't hashable so a set is not used. - self.blocks = [] + # Blocks that have already been handled. + self.blocks = set() # Add a gdb.Block and its superblocks, ignoring the static and # global block. BLOCK can also be None, which is ignored. @@ -37,7 +36,7 @@ class _BlockTracker: while block is not None: if block.is_static or block.is_global or block in self.blocks: return - self.blocks.append(block) + self.blocks.add(block) if block.function is not None: self.labels[block.start] = block.function.name for sym in block: 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"