From patchwork Thu Jan 16 15:52:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 104919 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 8C896384F026 for ; Thu, 16 Jan 2025 15:56:16 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8C896384F026 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=adacore.com header.i=@adacore.com header.a=rsa-sha256 header.s=google header.b=Db7X9O8U X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-io1-xd30.google.com (mail-io1-xd30.google.com [IPv6:2607:f8b0:4864:20::d30]) by sourceware.org (Postfix) with ESMTPS id 7686E384F01C for ; Thu, 16 Jan 2025 15:52:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7686E384F01C 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 7686E384F01C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::d30 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1737042736; cv=none; b=byNfWcYKoS9NlvFZlTFB1Dv+/cov97llrf3H+2RoQ2PA6w1xT611DD8mTeNDey+kERKNskO2wvwH5tV3GEETIIITmuYRis8vRy1nrlZhyOgLfhqV42iz+YuMp8hYO81A6BNtHkw1j5XCHN7FbhLDzhlgfWWcUjHvZFG3k7st+XM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1737042736; c=relaxed/simple; bh=dQMPgkdCGB1eoApwFdnDypHhRZp6f+mEmRwkEP4w/jg=; h=DKIM-Signature:From:Date:Subject:MIME-Version:Message-Id:To; b=pqG7HPLhhTNgRoeX7ewheLy0w2v6ESK/2i+IRawcBuJbHY7zihpMB4Yrv5kPzDqb4XYZWJIVuELsXHtLNz4ZzS6uBs1KYLDRQXKalKDv+VFoYWv/kYtgbI9NumPsrdbl+ytEG/0gI8FeRh6w5HBlmh+PGaDfdRGTFspXTbvMSvg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7686E384F01C Received: by mail-io1-xd30.google.com with SMTP id ca18e2360f4ac-844df397754so35004339f.2 for ; Thu, 16 Jan 2025 07:52:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1737042736; x=1737647536; darn=sourceware.org; h=cc: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=tP/lv6x9bcKCCrGqxmYads8U9IWwbTh4DzpM+R6ntKU=; b=Db7X9O8UfhbCiN/coJuUYDDawcV3IkyAE3y9hVdLtC8oEAyWxwPJscQ/vHM0i7249g t0mQG6xgKUTcL/UvxS9OwyT2ia6pGd7k3liBCmOh9Uf/3KRD6uM01kjL335Al0nRyhuB uUKKiShBDLhjyWsnI4DdQF2SnSk4h0u6QWxunuhMmwcDy+poRPHVBhuUXGYabFPVs1Ul 2eaOINcvLTj1v/KxArbhmjry1DiIC6Jkp4C01BPzx0XlOFsDYFl9vKA8N4d+saFJMHSh nhsZ9/YGUualsDBjSi4V3r9556r+7kZpZOfdEoIdfMDX5e4Krhx7AJ3a8YRZPtywyWih 7vKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737042736; x=1737647536; h=cc: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=tP/lv6x9bcKCCrGqxmYads8U9IWwbTh4DzpM+R6ntKU=; b=G4mDvqWsJ62TDInJs3pA+ws8cFXyMywoku7n6dKQ8tqJ+7pcKtYwOIPTdqZin/jimc fOTZrM36FjLn2tvJSefRVJQqdQn1rOp8iWArVvn9QCOYbtxNeeDIA/SN+J175j0MuWRB 6CeKeiOcPs0tK8a8d0nhwmpLwjX2z2qDzF5GoUNYcsZjfHBuDpysYjrv+/vfut9/hBPO zkNmAO4zER+Iy9PVZeEB2vF62G88LJCb/VCK8WN1ueA571ydp+a7uQp1tu0ZV7j4CXSU HqE2xSue8kQjck5HC6c+JAPPKJ2vAkvcdiFaG5ZY1o7+uTEcwXYYDRo1L2OSM0kJC5z8 K49Q== X-Gm-Message-State: AOJu0YyqhW5otlg/FHRzHZnGla3ic6WPlXYdcHrfCmfgnEfXeVXDFTYD 7TIWXLPsYABlOswSfafKklDKjlvS2vsBWDPZ7fy9TCbNGp1uPn77zy47v3J0lRYxL10n/xSINIA = X-Gm-Gg: ASbGncsWYNnU0ufhHzqpyz0Fmcuo0EfzbV5GOjZrOKuqinSffGhF0z6VCSmMHXG0gI+ jzHJZHtOuXkCR6/gL7Eq5hKPQa2JlIl2Mfd+GhNRD2c7RKWobTzzJ6TPlrYdkZop8tViSzTi34Y xtKTBU8eu++bvF82DsBibpAoGh3dE6jgD4eZaS3yzJvguh5JLsX9vJdaOZda5uQk6jbTbNoPAQH MVQwev3Vu3pFKnNNXucweCBP7ah+u1g7z8MYMvSPltijVUCg1r9yjjoDEdYpDAYoyRtsbV5Gh1g a0pfMvg4bOmvBKfPWcMO X-Google-Smtp-Source: AGHT+IEjeAMWbxpVtIz8Ic31kuTjACDxKRTRyJZqBqxyfCNQYZhwHCkUUmt8XOuH+veih3hBRStZlg== X-Received: by 2002:a92:c248:0:b0:3a7:e732:4713 with SMTP id e9e14a558f8ab-3ce3a9c1aa9mr273861835ab.15.1737042735726; Thu, 16 Jan 2025 07:52:15 -0800 (PST) Received: from localhost.localdomain (97-118-36-154.hlrn.qwest.net. [97.118.36.154]) by smtp.gmail.com with ESMTPSA id e9e14a558f8ab-3cf71a9e5bcsm606495ab.28.2025.01.16.07.52.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jan 2025 07:52:15 -0800 (PST) From: Tom Tromey Date: Thu, 16 Jan 2025 08:52:12 -0700 Subject: [PATCH 1/3] Add missing includes of extract-store-integer.h MIME-Version: 1.0 Message-Id: <20250116-remove-a-class-v1-1-f0cfe6eb5c3a@adacore.com> References: <20250116-remove-a-class-v1-0-f0cfe6eb5c3a@adacore.com> In-Reply-To: <20250116-remove-a-class-v1-0-f0cfe6eb5c3a@adacore.com> To: gdb-patches@sourceware.org Cc: Tom Tromey X-Mailer: b4 0.14.2 X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_LOTSOFHASH, 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 I found a number of .c files that need to include extract-store-integer.h but that were only including it indirectly. This patch adds the missing includes. This change enables the next patch. --- gdb/compile/compile-loc2c.c | 1 + gdb/dwarf2/aranges.c | 1 + gdb/dwarf2/expr.c | 1 + gdb/dwarf2/frame.c | 1 + gdb/dwarf2/index-write.c | 1 + gdb/dwarf2/loc.c | 1 + gdb/dwarf2/read-debug-names.c | 1 + gdb/dwarf2/read-gdb-index.c | 1 + gdb/dwarf2/read.c | 1 + gdb/gdbtypes.c | 1 + 10 files changed, 10 insertions(+) diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c index 42370447052f10545b94d2df877e0c90a7be110b..df05c0140f0508d1ff3772916e541923a8f8842f 100644 --- a/gdb/compile/compile-loc2c.c +++ b/gdb/compile/compile-loc2c.c @@ -31,6 +31,7 @@ #include "dwarf2/frame.h" #include "value.h" #include "gdbarch.h" +#include "extract-store-integer.h" diff --git a/gdb/dwarf2/aranges.c b/gdb/dwarf2/aranges.c index e391ca6f933479dc9bfeac65061ed1b77f1f8ed7..af14f82126b1b5e596f67a62afa887afbe1fd1d8 100644 --- a/gdb/dwarf2/aranges.c +++ b/gdb/dwarf2/aranges.c @@ -19,6 +19,7 @@ #include "dwarf2/aranges.h" #include "dwarf2/read.h" +#include "extract-store-integer.h" /* See aranges.h. */ diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c index ee1522b7437818e0bca14ca0e91f727e50fb39f7..0977cfcab546fb97ba7231f2aac3c059a1debbc2 100644 --- a/gdb/dwarf2/expr.c +++ b/gdb/dwarf2/expr.c @@ -33,6 +33,7 @@ #include "gdbsupport/underlying.h" #include "gdbarch.h" #include "objfiles.h" +#include "extract-store-integer.h" /* This holds gdbarch-specific types used by the DWARF expression evaluator. See comments in execute_stack_op. */ diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c index 6d8a4fb5a9ea561ae98ec36669bfeae253b82ffa..2f9b8eab69448bb3315ffbeb73c521152096e3d5 100644 --- a/gdb/dwarf2/frame.c +++ b/gdb/dwarf2/frame.c @@ -31,6 +31,7 @@ #include "regcache.h" #include "value.h" #include "record.h" +#include "extract-store-integer.h" #include "complaints.h" #include "dwarf2/frame.h" diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c index 1008d19e1692c8774ebb9c4ef987a49fd1fda179..70688d7fddf59fa8cfc66e370c50ec2a63046c4d 100644 --- a/gdb/dwarf2/index-write.c +++ b/gdb/dwarf2/index-write.c @@ -40,6 +40,7 @@ #include "dwarf2/tag.h" #include "gdbsupport/gdb_tilde_expand.h" #include "dwarf2/read-debug-names.h" +#include "extract-store-integer.h" #include #include diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c index 989d33901e01070d05c1009cdd80db60af4f0b2f..a01161e83f7d75816aa791f51bd38d8830706b0a 100644 --- a/gdb/dwarf2/loc.c +++ b/gdb/dwarf2/loc.c @@ -46,6 +46,7 @@ #include #include "gdbsupport/underlying.h" #include "gdbsupport/byte-vector.h" +#include "extract-store-integer.h" static struct value *dwarf2_evaluate_loc_desc_full (struct type *type, const frame_info_ptr &frame, const gdb_byte *data, diff --git a/gdb/dwarf2/read-debug-names.c b/gdb/dwarf2/read-debug-names.c index e6f1fce4eb4bc7057223941cb78b3a8f84232b45..ffc4f3ad5eb028662c694e124c85de105067ff55 100644 --- a/gdb/dwarf2/read-debug-names.c +++ b/gdb/dwarf2/read-debug-names.c @@ -27,6 +27,7 @@ #include "mapped-index.h" #include "read.h" #include "stringify.h" +#include "extract-store-integer.h" /* This is just like cooked_index_functions, but overrides a single method so the test suite can distinguish the .debug_names case from diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c index 4dea55957346432bba4b3e262e10aa2ffa9d77d7..83bd2e08c5df403d28d662695f409e6428bb270c 100644 --- a/gdb/dwarf2/read-gdb-index.c +++ b/gdb/dwarf2/read-gdb-index.c @@ -28,6 +28,7 @@ #include "gdbsupport/gdb-checked-static-cast.h" #include "mapped-index.h" #include "read.h" +#include "extract-store-integer.h" /* When true, do not reject deprecated .gdb_index sections. */ static bool use_deprecated_index_sections = false; diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index e52e26f340ca3b485577f27da14c567808b4af5f..9484754447746b8a14b1bde2092407edb2aba298 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -97,6 +97,7 @@ #include "dwarf2/error.h" #include #include "gdbsupport/unordered_set.h" +#include "extract-store-integer.h" /* When == 1, print basic high level tracing messages. When > 1, be more verbose. diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 0928e24446708fd654194298b0dafa80730e213c..3f78230289f0ee58d598f8e89d26f5f251eb94c4 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -44,6 +44,7 @@ #include "gmp-utils.h" #include "rust-lang.h" #include "ada-lang.h" +#include "extract-store-integer.h" /* The value of an invalid conversion badness. */ #define INVALID_CONVERSION 100 From patchwork Thu Jan 16 15:52:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 104917 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 41BA1384F02E for ; Thu, 16 Jan 2025 15:54:25 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 41BA1384F02E Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=adacore.com header.i=@adacore.com header.a=rsa-sha256 header.s=google header.b=E+Jh11Hk X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-il1-x12c.google.com (mail-il1-x12c.google.com [IPv6:2607:f8b0:4864:20::12c]) by sourceware.org (Postfix) with ESMTPS id F3609384F027 for ; Thu, 16 Jan 2025 15:52:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F3609384F027 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 F3609384F027 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::12c ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1737042738; cv=none; b=Am6uZrb6LfZAiLDndYFrj39lHYvc60T8IhIW796u2UTYowfMuGB+4T6FP/InVBe3Mt9ZJH6DEB3ryeSDmjgwdmIcgPFlnLRKQf/8wWFR8fuN+/i1lwydF90v3DDzaJC3dIfSFYvlD0p14U/MhifoQynu3+JqPb5h9Tp4a/L0aOg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1737042738; c=relaxed/simple; bh=3H17gJsds4nFRVqdORT3OmF8SaD4jsiX7Op0DwXQT4g=; h=DKIM-Signature:From:Date:Subject:MIME-Version:Message-Id:To; b=Br+s/0WYCXf+g01WezJvL7sBhEJv9jiYqarPIp5GVNJcW03fgNT1Lvp01B/ONCuW3ux0Dy0/J8ZKdViivCPAG4IKQtASJ4G5HoXW/adjjq/yYeQl+BuKiSVBu6AAownRGiT9SZDHBaUdJ4f+49HFKIUPLXw0ei5Yew1UdlpUb40= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F3609384F027 Received: by mail-il1-x12c.google.com with SMTP id e9e14a558f8ab-3ce34c6872aso8842075ab.0 for ; Thu, 16 Jan 2025 07:52:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1737042737; x=1737647537; darn=sourceware.org; h=cc: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=VBo2m3HzBoHZE8dWg2ExJpwsUSMBPOQNSR2pLel5hAI=; b=E+Jh11HkddY/TKnRBeGoBGO9UhXdRzy+vv5E/3CYESc57gTGAJ2/0iDA5sRaJ2Zd2Q 76+XTL2e/PoZgX+BhLM5RkjoyUxLSuhD872+McRIdH1u9WrFiEF6LS2xlR4R2+40U2Zk 0ddm5Qtuzh8XXF8f71KTDxZ6R4vKSrbpX/gv5FLeeBDprK9/WkY4pkum40obwkRCr4Wb ghWlaA05xBv+w5yvJMZTiX1abVt9gRudmvcozul7wKVrRUzQkDi23LGHbRh4/QVg5E+o yZ1OlBGeqSPnlGkldXfQaTC40TSF9XsmBcR6o1c+0ahZ3sUQ9ln0uD5e0Q9YI4X+FFZJ 1I7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737042737; x=1737647537; h=cc: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=VBo2m3HzBoHZE8dWg2ExJpwsUSMBPOQNSR2pLel5hAI=; b=taL04KibLQFvGNJlFKmeKPEwRZPK7yEGrxNjvyPFKj/ZV70JMrZ7mfHQZX2hpH8e67 XUkv4IY/b6dl/QpnJV+2b+tU/1dlJX9L/j+OS/KG8pIB8Lk5LgE60sHX2bklU7oTkbKn /fQYzn/x24vbgfIywsALUVZpHhHFv5nA4IamQZcuRSIZkrFFSY30pkV0H4x3PhT3c4I6 tvPnysgq8ayFCsFK3TiX4n8X+7c7Gir7WtRw6yWvb8tmrzNVx07WveUqPuiPJLBJ8RpE ezLeelCKX9LlulS0oN1KXi3zggQ8+eDUP58/b6paH2T+7NwkfRac0vGnZqomjNY6q5Ov +OIg== X-Gm-Message-State: AOJu0YyDWxJEHyDKqLXzex0XU+BNOexRdtL8Kv1M6LOvUFYo1x1AIQoR Q51qneWI1SrLwQdKPwSWxH0RFNJre1bqohISEMMA0r6W5pw1ArvMfSMVrHwnJqdv85hLOI9h6AQ = X-Gm-Gg: ASbGncvfWHPW1HIjHKjP8geeFyb0SGbfM5Nz+Jg2lk3zYwxn4nQuLChetHcialfCq5Y P9RuCyy0jRm2TmMwnizVuolQOgJLJx86hCLKPSKKRyl35B2RjzfcaKDmvTlAhOdqiO05rdnbr7a HSAIAixRtkujBtxCtQsDq3N/X6jeqe1iV0cmRtxl9CrMBTxHrrWvg3zszTLnolE6A0XtOxBYGsJ YFFftdJtNJNcXYKFQYLzO4ZTOQ+yRqZnuFn8wH5r1yevm1iBGznr561cLNFSjvn0dlyTUkZ2+Kp 687SvfQaHK/aQo6eekHJ X-Google-Smtp-Source: AGHT+IGt6vRgHdCXE/El4hafgkfcopuuZAxUA2KRZmD7L4evF1eT4ryoVXThEIdiw+C1pPiGbwWnbg== X-Received: by 2002:a92:b710:0:b0:3ce:403a:8be6 with SMTP id e9e14a558f8ab-3ce403a8e41mr229184225ab.20.1737042737226; Thu, 16 Jan 2025 07:52:17 -0800 (PST) Received: from localhost.localdomain (97-118-36-154.hlrn.qwest.net. [97.118.36.154]) by smtp.gmail.com with ESMTPSA id e9e14a558f8ab-3cf71a9e5bcsm606495ab.28.2025.01.16.07.52.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jan 2025 07:52:16 -0800 (PST) From: Tom Tromey Date: Thu, 16 Jan 2025 08:52:13 -0700 Subject: [PATCH 2/3] Remove gdb_index_unpack MIME-Version: 1.0 Message-Id: <20250116-remove-a-class-v1-2-f0cfe6eb5c3a@adacore.com> References: <20250116-remove-a-class-v1-0-f0cfe6eb5c3a@adacore.com> In-Reply-To: <20250116-remove-a-class-v1-0-f0cfe6eb5c3a@adacore.com> To: gdb-patches@sourceware.org Cc: Tom Tromey X-Mailer: b4 0.14.2 X-Spam-Status: No, score=-10.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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 gdb_index_unpack is not used and can be removed. The include of extract-store-integer.h is also no longer needed by this file. --- gdb/dwarf2/index-common.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/gdb/dwarf2/index-common.h b/gdb/dwarf2/index-common.h index b9e0a632508dea68403c0d686ea9d6c6d8b02bbc..ca377213edc78b00442b973cd5c4df3e3f5f1790 100644 --- a/gdb/dwarf2/index-common.h +++ b/gdb/dwarf2/index-common.h @@ -20,7 +20,6 @@ #ifndef GDB_DWARF2_INDEX_COMMON_H #define GDB_DWARF2_INDEX_COMMON_H -#include "extract-store-integer.h" #include "hashtab.h" /* The suffix for an index file. */ @@ -32,15 +31,6 @@ architecture-independent. */ typedef uint32_t offset_type; -/* Unpack a 32-bit little-endian value. */ - -static inline offset_type -gdb_index_unpack (const gdb_byte *value) -{ - return (offset_type) extract_unsigned_integer (value, sizeof (offset_type), - BFD_ENDIAN_LITTLE); -} - /* The hash function for strings in the mapped index. This is the same as SYMBOL_HASH_NEXT, but we keep a separate copy to maintain control over the implementation. This is necessary because the hash function is tied to the From patchwork Thu Jan 16 15:52:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 104918 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 1714C384DEC5 for ; Thu, 16 Jan 2025 15:54:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1714C384DEC5 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, secure) header.d=adacore.com header.i=@adacore.com header.a=rsa-sha256 header.s=google header.b=kez5Y7kq X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-il1-x12d.google.com (mail-il1-x12d.google.com [IPv6:2607:f8b0:4864:20::12d]) by sourceware.org (Postfix) with ESMTPS id 0380F384F017 for ; Thu, 16 Jan 2025 15:52:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0380F384F017 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 0380F384F017 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::12d ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1737042740; cv=none; b=vepXjZjXGgQGUooAH6k+Bb5CZfSpxolRkYudpDOtE2mBZdyVMMLKgWdtRvi3oJQDwF16LvfP4X4j4Fb3kKHDMKcy1McTO4NPnZZmO8F0D9LjWl05INkRMl1MDIiRkOCL6KJQbNdcxHKi3EDX2RRHvfBRr8IfoA2wtST6tsC9iRI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1737042740; c=relaxed/simple; bh=lTm3lnEKHk5dbUHpFR9JySDnH9nR3iV+Yo+fqugRmE8=; h=DKIM-Signature:From:Date:Subject:MIME-Version:Message-Id:To; b=KKp40SL1ic8YSDBpz7KllBzr/KBmmZQqwFKZly4iObyu0A5ExjhSHTkKGgvN+1Yht6BGaZoynSG9X0JD9VP0+6WXsOUdT9zHxtaIhj+yMrsgBdL6b2uCZsM5eTE8ILVIml5r/rXTFoEVwauTl//mwNCxgNbaQW2L4tmEu7x5tkA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0380F384F017 Received: by mail-il1-x12d.google.com with SMTP id e9e14a558f8ab-3ce85545983so3912225ab.0 for ; Thu, 16 Jan 2025 07:52:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1737042739; x=1737647539; darn=sourceware.org; h=cc: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=Ri906LwjXcB4tMhaO9FxiZh8Z6ihm/gaHecNIdg4agw=; b=kez5Y7kqYSHfLK+8bU7Ayttdlmei/iiUyUISxSlzewQ4eLABTfFjztz6Zjcfmei8Il hrFAASJ4Jy3wjrUoQbI1aTXePKRwWarHipazioaN5Asr7IZj+/SHgLzR9ELhb0JV1pNc Tf2V60XvSWuaP1NG1QmHOB/8bjw0Kx29SV92R5kk5qjaI25J9DHeoTValfkCfUXSahMz /bzD1y4C99zVI8StjoEPZiL5V+GRRaND6WRq9XzDFBHqXlSFB1eeD+2QXuDKJS39wVUF XJmqaA4wV8WozC7xBX8PjfZNZynPOJLmKIWJHj0BV4wyUYDnqsagjB9OyMG2w+8c9kNL VFaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1737042739; x=1737647539; h=cc: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=Ri906LwjXcB4tMhaO9FxiZh8Z6ihm/gaHecNIdg4agw=; b=Q1FcF+CDcr5jxQlOg9jTZCNLMxvaLrw+MeWtHU7+ppB+XEWurhrrG7O/T8utCtbeCP 93oYw6y86kDXYMW+I5sCuloNipBJiR51IRDXs9ra+tFKBdn6pDE9JYle3iSz4XN89Ucu HTu1LH/ZMtPCm5zqwvq862uXUXbitZoNKac5dtmco7WyNvn/lxqRo7ax7r01hcZnuAfn g3VS4Mu73PWjPA8rxdMpp8E7bRFFug0SMYhF00XpeRDwCGIv9NGGp6n88NHKJQH//K9Q dKJrQk/Vr7v/dQ66AOaQdZLj66N/2YHIRiTQetNr3C4YQ9Hi/sHFW8b1eJUXj7aFSAUt 0O+Q== X-Gm-Message-State: AOJu0YxQ0evLlWIGtaH7FiAq+1zkwJbYuH4iXT+GWY2/gA+/HeZvyPOW NQU6GzCoSaajzNUCsSj26BIeljj7sFC6g2W2v/Yq0J93WcMf4qUNxtJ/Wwezr9XgUf1kIEPKOs4 = X-Gm-Gg: ASbGncvbeD9+4DGXJqOw7NM0xx+xnTm2Rltt241QTCHUCjkRUs/LylGdwqZxWXgZ8w/ YeIbt5RtwQyLnoom+FeG6aIy4hDksAdiW+DNzJ9kv3KEJlvYjHWlmDk2t7WSdWVcSi12tWcptYc LCyjmZtTv7AQ0MBTK8bq3MlPIvnut2s1IrH1Mqujl9ZK3Qi1mFShA+ZaJoCUpGI1w3+SqaagBGc RJhsk3s4iGhvu9LXsqwyZy6UYML6ZsYlPD6dnB2QHKYgONmsJS9Y6fP3u0Kmh6h5vMLpoudmKr2 0IV6AvfipVyyj1xiT6hg X-Google-Smtp-Source: AGHT+IFLO9Yufd7p86PHXbbVJxjgPad4fd1KqbWSjOSg1v/YRrMqdEVA9ehJyNHQGCqohW0hdRJHew== X-Received: by 2002:a05:6e02:170a:b0:3a7:e1c3:11f5 with SMTP id e9e14a558f8ab-3ce849f5cddmr69308905ab.6.1737042738633; Thu, 16 Jan 2025 07:52:18 -0800 (PST) Received: from localhost.localdomain (97-118-36-154.hlrn.qwest.net. [97.118.36.154]) by smtp.gmail.com with ESMTPSA id e9e14a558f8ab-3cf71a9e5bcsm606495ab.28.2025.01.16.07.52.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jan 2025 07:52:17 -0800 (PST) From: Tom Tromey Date: Thu, 16 Jan 2025 08:52:14 -0700 Subject: [PATCH 3/3] Remove mapped_index_base MIME-Version: 1.0 Message-Id: <20250116-remove-a-class-v1-3-f0cfe6eb5c3a@adacore.com> References: <20250116-remove-a-class-v1-0-f0cfe6eb5c3a@adacore.com> In-Reply-To: <20250116-remove-a-class-v1-0-f0cfe6eb5c3a@adacore.com> To: gdb-patches@sourceware.org Cc: Tom Tromey X-Mailer: b4 0.14.2 X-Spam-Status: No, score=-10.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_LOTSOFHASH, 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 The base class mapped_index_base is no longer needed. Previously it was used by both the .gdb_index and .debug_names readers, but the latter now uses the cooked index instead. This patch removes mapped_index_base, merging it into mapped_gdb_index. Supporting code that is specific to .gdb_index is also moved into read-gdb-index.c. This shrinks dwarf2/read.c a bit, which is nice. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32504 --- gdb/dwarf2/mapped-index.h | 71 ---- gdb/dwarf2/read-gdb-index.c | 853 +++++++++++++++++++++++++++++++++++++++++++- gdb/dwarf2/read.c | 784 ---------------------------------------- gdb/dwarf2/read.h | 15 - 4 files changed, 848 insertions(+), 875 deletions(-) diff --git a/gdb/dwarf2/mapped-index.h b/gdb/dwarf2/mapped-index.h index e7dd8e925077b925a0530e84a8ca6ccd4e9e1aa4..199ee57a88b3b699810f423fff5a9602b7841d78 100644 --- a/gdb/dwarf2/mapped-index.h +++ b/gdb/dwarf2/mapped-index.h @@ -24,31 +24,6 @@ #include "language.h" #include "quick-symbol.h" -/* An index into a (C++) symbol name component in a symbol name as - recorded in the mapped_index's symbol table. For each C++ symbol - in the symbol table, we record one entry for the start of each - component in the symbol in a table of name components, and then - sort the table, in order to be able to binary search symbol names, - ignoring leading namespaces, both completion and regular look up. - For example, for symbol "A::B::C", we'll have an entry that points - to "A::B::C", another that points to "B::C", and another for "C". - Note that function symbols in GDB index have no parameter - information, just the function/method names. You can convert a - name_component to a "const char *" using the - 'mapped_index::symbol_name_at(offset_type)' method. */ - -struct name_component -{ - /* Offset in the symbol name where the component starts. Stored as - a (32-bit) offset instead of a pointer to save memory and improve - locality on 64-bit architectures. */ - offset_type name_offset; - - /* The symbol's index in the symbol and constant pool tables of a - mapped_index. */ - offset_type idx; -}; - class cooked_index; /* Base class of all DWARF scanner types. */ @@ -91,50 +66,4 @@ struct dwarf_scanner_base { return nullptr; } }; -/* Base class containing bits shared by both .gdb_index and - .debug_name indexes. */ - -struct mapped_index_base : public dwarf_scanner_base -{ - mapped_index_base () = default; - DISABLE_COPY_AND_ASSIGN (mapped_index_base); - - /* The name_component table (a sorted vector). See name_component's - description above. */ - std::vector name_components; - - /* How NAME_COMPONENTS is sorted. */ - enum case_sensitivity name_components_casing; - - /* Return the number of names in the symbol table. */ - virtual size_t symbol_name_count () const = 0; - - /* Get the name of the symbol at IDX in the symbol table. */ - virtual const char *symbol_name_at - (offset_type idx, dwarf2_per_objfile *per_objfile) const = 0; - - /* Return whether the name at IDX in the symbol table should be - ignored. */ - virtual bool symbol_name_slot_invalid (offset_type idx) const - { - return false; - } - - /* Build the symbol name component sorted vector, if we haven't - yet. */ - void build_name_components (dwarf2_per_objfile *per_objfile); - - /* Returns the lower (inclusive) and upper (exclusive) bounds of the - possible matches for LN_NO_PARAMS in the name component - vector. */ - std::pair::const_iterator, - std::vector::const_iterator> - find_name_components_bounds (const lookup_name_info &ln_no_params, - enum language lang, - dwarf2_per_objfile *per_objfile) const; - - cooked_index *index_for_writing () override - { return nullptr; } -}; - #endif /* GDB_DWARF2_MAPPED_INDEX_H */ diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c index 83bd2e08c5df403d28d662695f409e6428bb270c..165816f23e7f970b9fd5ee49fdc6e67b92a9951e 100644 --- a/gdb/dwarf2/read-gdb-index.c +++ b/gdb/dwarf2/read-gdb-index.c @@ -29,6 +29,9 @@ #include "mapped-index.h" #include "read.h" #include "extract-store-integer.h" +#include "cp-support.h" +#include "symtab.h" +#include "gdbsupport/selftest.h" /* When true, do not reject deprecated .gdb_index sections. */ static bool use_deprecated_index_sections = false; @@ -73,11 +76,43 @@ class offset_view gdb::array_view m_bytes; }; +/* An index into a (C++) symbol name component in a symbol name as + recorded in the mapped_index's symbol table. For each C++ symbol + in the symbol table, we record one entry for the start of each + component in the symbol in a table of name components, and then + sort the table, in order to be able to binary search symbol names, + ignoring leading namespaces, both completion and regular look up. + For example, for symbol "A::B::C", we'll have an entry that points + to "A::B::C", another that points to "B::C", and another for "C". + Note that function symbols in GDB index have no parameter + information, just the function/method names. You can convert a + name_component to a "const char *" using the + 'mapped_index::symbol_name_at(offset_type)' method. */ + +struct name_component +{ + /* Offset in the symbol name where the component starts. Stored as + a (32-bit) offset instead of a pointer to save memory and improve + locality on 64-bit architectures. */ + offset_type name_offset; + + /* The symbol's index in the symbol and constant pool tables of a + mapped_index. */ + offset_type idx; +}; + /* A description of .gdb_index index. The file format is described in a comment by the code that writes the index. */ -struct mapped_gdb_index final : public mapped_index_base +struct mapped_gdb_index : public dwarf_scanner_base { + /* The name_component table (a sorted vector). See name_component's + description above. */ + std::vector name_components; + + /* How NAME_COMPONENTS is sorted. */ + enum case_sensitivity name_components_casing; + /* Index data format version. */ int version = 0; @@ -110,7 +145,7 @@ struct mapped_gdb_index final : public mapped_index_base return symbol_table[2 * idx + 1]; } - bool symbol_name_slot_invalid (offset_type idx) const override + bool symbol_name_slot_invalid (offset_type idx) const { return (symbol_name_index (idx) == 0 && symbol_vec_index (idx) == 0); @@ -118,16 +153,29 @@ struct mapped_gdb_index final : public mapped_index_base /* Convenience method to get at the name of the symbol at IDX in the symbol table. */ - const char *symbol_name_at - (offset_type idx, dwarf2_per_objfile *per_objfile) const override + virtual const char *symbol_name_at + (offset_type idx, dwarf2_per_objfile *per_objfile) const { return (const char *) (this->constant_pool.data () + symbol_name_index (idx)); } - size_t symbol_name_count () const override + virtual size_t symbol_name_count () const { return this->symbol_table.size () / 2; } + /* Build the symbol name component sorted vector, if we haven't + yet. */ + void build_name_components (dwarf2_per_objfile *per_objfile); + + /* Returns the lower (inclusive) and upper (exclusive) bounds of the + possible matches for LN_NO_PARAMS in the name component + vector. */ + std::pair::const_iterator, + std::vector::const_iterator> + find_name_components_bounds (const lookup_name_info &ln_no_params, + enum language lang, + dwarf2_per_objfile *per_objfile) const; + quick_symbol_functions_up make_quick_functions () const override; bool version_check () const override @@ -143,8 +191,798 @@ struct mapped_gdb_index final : public mapped_index_base void *obj = index_addrmap->find (static_cast (addr)); return static_cast (obj); } + + cooked_index *index_for_writing () override + { return nullptr; } }; + +/* Starting from a search name, return the string that finds the upper + bound of all strings that start with SEARCH_NAME in a sorted name + list. Returns the empty string to indicate that the upper bound is + the end of the list. */ + +static std::string +make_sort_after_prefix_name (const char *search_name) +{ + /* When looking to complete "func", we find the upper bound of all + symbols that start with "func" by looking for where we'd insert + the closest string that would follow "func" in lexicographical + order. Usually, that's "func"-with-last-character-incremented, + i.e. "fund". Mind non-ASCII characters, though. Usually those + will be UTF-8 multi-byte sequences, but we can't be certain. + Especially mind the 0xff character, which is a valid character in + non-UTF-8 source character sets (e.g. Latin1 'ÿ'), and we can't + rule out compilers allowing it in identifiers. Note that + conveniently, strcmp/strcasecmp are specified to compare + characters interpreted as unsigned char. So what we do is treat + the whole string as a base 256 number composed of a sequence of + base 256 "digits" and add 1 to it. I.e., adding 1 to 0xff wraps + to 0, and carries 1 to the following more-significant position. + If the very first character in SEARCH_NAME ends up incremented + and carries/overflows, then the upper bound is the end of the + list. The string after the empty string is also the empty + string. + + Some examples of this operation: + + SEARCH_NAME => "+1" RESULT + + "abc" => "abd" + "ab\xff" => "ac" + "\xff" "a" "\xff" => "\xff" "b" + "\xff" => "" + "\xff\xff" => "" + "" => "" + + Then, with these symbols for example: + + func + func1 + fund + + completing "func" looks for symbols between "func" and + "func"-with-last-character-incremented, i.e. "fund" (exclusive), + which finds "func" and "func1", but not "fund". + + And with: + + funcÿ (Latin1 'ÿ' [0xff]) + funcÿ1 + fund + + completing "funcÿ" looks for symbols between "funcÿ" and "fund" + (exclusive), which finds "funcÿ" and "funcÿ1", but not "fund". + + And with: + + ÿÿ (Latin1 'ÿ' [0xff]) + ÿÿ1 + + completing "ÿ" or "ÿÿ" looks for symbols between between "ÿÿ" and + the end of the list. + */ + std::string after = search_name; + while (!after.empty () && (unsigned char) after.back () == 0xff) + after.pop_back (); + if (!after.empty ()) + after.back () = (unsigned char) after.back () + 1; + return after; +} + +/* See declaration. */ + +std::pair::const_iterator, + std::vector::const_iterator> +mapped_gdb_index::find_name_components_bounds + (const lookup_name_info &lookup_name_without_params, language lang, + dwarf2_per_objfile *per_objfile) const +{ + auto *name_cmp + = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp; + + const char *lang_name + = lookup_name_without_params.language_lookup_name (lang); + + /* Comparison function object for lower_bound that matches against a + given symbol name. */ + auto lookup_compare_lower = [&] (const name_component &elem, + const char *name) + { + const char *elem_qualified = this->symbol_name_at (elem.idx, per_objfile); + const char *elem_name = elem_qualified + elem.name_offset; + return name_cmp (elem_name, name) < 0; + }; + + /* Comparison function object for upper_bound that matches against a + given symbol name. */ + auto lookup_compare_upper = [&] (const char *name, + const name_component &elem) + { + const char *elem_qualified = this->symbol_name_at (elem.idx, per_objfile); + const char *elem_name = elem_qualified + elem.name_offset; + return name_cmp (name, elem_name) < 0; + }; + + auto begin = this->name_components.begin (); + auto end = this->name_components.end (); + + /* Find the lower bound. */ + auto lower = [&] () + { + if (lookup_name_without_params.completion_mode () && lang_name[0] == '\0') + return begin; + else + return std::lower_bound (begin, end, lang_name, lookup_compare_lower); + } (); + + /* Find the upper bound. */ + auto upper = [&] () + { + if (lookup_name_without_params.completion_mode ()) + { + /* In completion mode, we want UPPER to point past all + symbols names that have the same prefix. I.e., with + these symbols, and completing "func": + + function << lower bound + function1 + other_function << upper bound + + We find the upper bound by looking for the insertion + point of "func"-with-last-character-incremented, + i.e. "fund". */ + std::string after = make_sort_after_prefix_name (lang_name); + if (after.empty ()) + return end; + return std::lower_bound (lower, end, after.c_str (), + lookup_compare_lower); + } + else + return std::upper_bound (lower, end, lang_name, lookup_compare_upper); + } (); + + return {lower, upper}; +} + +/* See declaration. */ + +void +mapped_gdb_index::build_name_components (dwarf2_per_objfile *per_objfile) +{ + if (!this->name_components.empty ()) + return; + + this->name_components_casing = case_sensitivity; + auto *name_cmp + = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp; + + /* The code below only knows how to break apart components of C++ + symbol names (and other languages that use '::' as + namespace/module separator) and Ada symbol names. */ + auto count = this->symbol_name_count (); + for (offset_type idx = 0; idx < count; idx++) + { + if (this->symbol_name_slot_invalid (idx)) + continue; + + const char *name = this->symbol_name_at (idx, per_objfile); + + /* Add each name component to the name component table. */ + unsigned int previous_len = 0; + + if (strstr (name, "::") != nullptr) + { + for (unsigned int current_len = cp_find_first_component (name); + name[current_len] != '\0'; + current_len += cp_find_first_component (name + current_len)) + { + gdb_assert (name[current_len] == ':'); + this->name_components.push_back ({previous_len, idx}); + /* Skip the '::'. */ + current_len += 2; + previous_len = current_len; + } + } + else + { + /* Handle the Ada encoded (aka mangled) form here. */ + for (const char *iter = strstr (name, "__"); + iter != nullptr; + iter = strstr (iter, "__")) + { + this->name_components.push_back ({previous_len, idx}); + iter += 2; + previous_len = iter - name; + } + } + + this->name_components.push_back ({previous_len, idx}); + } + + /* Sort name_components elements by name. */ + auto name_comp_compare = [&] (const name_component &left, + const name_component &right) + { + const char *left_qualified + = this->symbol_name_at (left.idx, per_objfile); + const char *right_qualified + = this->symbol_name_at (right.idx, per_objfile); + + const char *left_name = left_qualified + left.name_offset; + const char *right_name = right_qualified + right.name_offset; + + return name_cmp (left_name, right_name) < 0; + }; + + std::sort (this->name_components.begin (), + this->name_components.end (), + name_comp_compare); +} + +/* Helper for dw2_expand_symtabs_matching that works with a + mapped_index_base instead of the containing objfile. This is split + to a separate function in order to be able to unit test the + name_components matching using a mock mapped_index_base. For each + symbol name that matches, calls MATCH_CALLBACK, passing it the + symbol's index in the mapped_index_base symbol table. */ + +static bool +dw2_expand_symtabs_matching_symbol + (mapped_gdb_index &index, + const lookup_name_info &lookup_name_in, + gdb::function_view symbol_matcher, + gdb::function_view match_callback, + dwarf2_per_objfile *per_objfile, + gdb::function_view lang_matcher) +{ + lookup_name_info lookup_name_without_params + = lookup_name_in.make_ignore_params (); + + /* Build the symbol name component sorted vector, if we haven't + yet. */ + index.build_name_components (per_objfile); + + /* The same symbol may appear more than once in the range though. + E.g., if we're looking for symbols that complete "w", and we have + a symbol named "w1::w2", we'll find the two name components for + that same symbol in the range. To be sure we only call the + callback once per symbol, we first collect the symbol name + indexes that matched in a temporary vector and ignore + duplicates. */ + std::vector matches; + + struct name_and_matcher + { + symbol_name_matcher_ftype *matcher; + const char *name; + + bool operator== (const name_and_matcher &other) const + { + return matcher == other.matcher && strcmp (name, other.name) == 0; + } + }; + + /* A vector holding all the different symbol name matchers, for all + languages. */ + std::vector matchers; + + for (int i = 0; i < nr_languages; i++) + { + enum language lang_e = (enum language) i; + if (lang_matcher != nullptr && !lang_matcher (lang_e)) + continue; + + const language_defn *lang = language_def (lang_e); + symbol_name_matcher_ftype *name_matcher + = lang->get_symbol_name_matcher (lookup_name_without_params); + + name_and_matcher key { + name_matcher, + lookup_name_without_params.language_lookup_name (lang_e) + }; + + /* Don't insert the same comparison routine more than once. + Note that we do this linear walk. This is not a problem in + practice because the number of supported languages is + low. */ + if (std::find (matchers.begin (), matchers.end (), key) + != matchers.end ()) + continue; + matchers.push_back (std::move (key)); + + auto bounds + = index.find_name_components_bounds (lookup_name_without_params, + lang_e, per_objfile); + + /* Now for each symbol name in range, check to see if we have a name + match, and if so, call the MATCH_CALLBACK callback. */ + + for (; bounds.first != bounds.second; ++bounds.first) + { + const char *qualified + = index.symbol_name_at (bounds.first->idx, per_objfile); + + if (!name_matcher (qualified, lookup_name_without_params, NULL) + || (symbol_matcher != NULL && !symbol_matcher (qualified))) + continue; + + matches.push_back (bounds.first->idx); + } + } + + std::sort (matches.begin (), matches.end ()); + + /* Finally call the callback, once per match. */ + ULONGEST prev = -1; + bool result = true; + for (offset_type idx : matches) + { + if (prev != idx) + { + if (!match_callback (idx)) + { + result = false; + break; + } + prev = idx; + } + } + + /* Above we use a type wider than idx's for 'prev', since 0 and + (offset_type)-1 are both possible values. */ + static_assert (sizeof (prev) > sizeof (offset_type), ""); + + return result; +} + +#if GDB_SELF_TEST + +namespace selftests { namespace dw2_expand_symtabs_matching { + +/* A mock .gdb_index/.debug_names-like name index table, enough to + exercise dw2_expand_symtabs_matching_symbol, which works with the + mapped_index_base interface. Builds an index from the symbol list + passed as parameter to the constructor. */ +class mock_mapped_index : public mapped_gdb_index +{ +public: + mock_mapped_index (gdb::array_view symbols) + : m_symbol_table (symbols) + {} + + DISABLE_COPY_AND_ASSIGN (mock_mapped_index); + + /* Return the number of names in the symbol table. */ + size_t symbol_name_count () const override + { + return m_symbol_table.size (); + } + + /* Get the name of the symbol at IDX in the symbol table. */ + const char *symbol_name_at + (offset_type idx, dwarf2_per_objfile *per_objfile) const override + { + return m_symbol_table[idx]; + } + + quick_symbol_functions_up make_quick_functions () const override + { + return nullptr; + } + +private: + gdb::array_view m_symbol_table; +}; + +/* Convenience function that converts a NULL pointer to a "" + string, to pass to print routines. */ + +static const char * +string_or_null (const char *str) +{ + return str != NULL ? str : ""; +} + +/* Check if a lookup_name_info built from + NAME/MATCH_TYPE/COMPLETION_MODE matches the symbols in the mock + index. EXPECTED_LIST is the list of expected matches, in expected + matching order. If no match expected, then an empty list is + specified. Returns true on success. On failure prints a warning + indicating the file:line that failed, and returns false. */ + +static bool +check_match (const char *file, int line, + mock_mapped_index &mock_index, + const char *name, symbol_name_match_type match_type, + bool completion_mode, + std::initializer_list expected_list, + dwarf2_per_objfile *per_objfile) +{ + lookup_name_info lookup_name (name, match_type, completion_mode); + + bool matched = true; + + auto mismatch = [&] (const char *expected_str, + const char *got) + { + warning (_("%s:%d: match_type=%s, looking-for=\"%s\", " + "expected=\"%s\", got=\"%s\"\n"), + file, line, + (match_type == symbol_name_match_type::FULL + ? "FULL" : "WILD"), + name, string_or_null (expected_str), string_or_null (got)); + matched = false; + }; + + auto expected_it = expected_list.begin (); + auto expected_end = expected_list.end (); + + dw2_expand_symtabs_matching_symbol (mock_index, lookup_name, + nullptr, + [&] (offset_type idx) + { + const char *matched_name = mock_index.symbol_name_at (idx, per_objfile); + const char *expected_str + = expected_it == expected_end ? NULL : *expected_it++; + + if (expected_str == NULL || strcmp (expected_str, matched_name) != 0) + mismatch (expected_str, matched_name); + return true; + }, per_objfile, nullptr); + + const char *expected_str + = expected_it == expected_end ? NULL : *expected_it++; + if (expected_str != NULL) + mismatch (expected_str, NULL); + + return matched; +} + +/* The symbols added to the mock mapped_index for testing (in + canonical form). */ +static const char *test_symbols[] = { + "function", + "std::bar", + "std::zfunction", + "std::zfunction2", + "w1::w2", + "ns::foo", + "ns::foo", + "ns::foo", + "ns2::tmpl::foo2", + "(anonymous namespace)::A::B::C", + + /* These are used to check that the increment-last-char in the + matching algorithm for completion doesn't match "t1_fund" when + completing "t1_func". */ + "t1_func", + "t1_func1", + "t1_fund", + "t1_fund1", + + /* A UTF-8 name with multi-byte sequences to make sure that + cp-name-parser understands this as a single identifier ("função" + is "function" in PT). */ + (const char *)u8"u8função", + + /* Test a symbol name that ends with a 0xff character, which is a + valid character in non-UTF-8 source character sets (e.g. Latin1 + 'ÿ'), and we can't rule out compilers allowing it in identifiers. + We test this because the completion algorithm finds the upper + bound of symbols by looking for the insertion point of + "func"-with-last-character-incremented, i.e. "fund", and adding 1 + to 0xff should wraparound and carry to the previous character. + See comments in make_sort_after_prefix_name. */ + "yfunc\377", + + /* Some more symbols with \377 (0xff). See above. */ + "\377", + "\377\377123", + + /* A name with all sorts of complications. Starts with "z" to make + it easier for the completion tests below. */ +#define Z_SYM_NAME \ + "z::std::tuple<(anonymous namespace)::ui*, std::bar<(anonymous namespace)::ui> >" \ + "::tuple<(anonymous namespace)::ui*, " \ + "std::default_delete<(anonymous namespace)::ui>, void>" + + Z_SYM_NAME +}; + +/* Returns true if the mapped_index_base::find_name_component_bounds + method finds EXPECTED_SYMS in INDEX when looking for SEARCH_NAME, + in completion mode. */ + +static bool +check_find_bounds_finds (mapped_gdb_index &index, + const char *search_name, + gdb::array_view expected_syms, + dwarf2_per_objfile *per_objfile) +{ + lookup_name_info lookup_name (search_name, + symbol_name_match_type::FULL, true); + + auto bounds = index.find_name_components_bounds (lookup_name, + language_cplus, + per_objfile); + + size_t distance = std::distance (bounds.first, bounds.second); + if (distance != expected_syms.size ()) + return false; + + for (size_t exp_elem = 0; exp_elem < distance; exp_elem++) + { + auto nc_elem = bounds.first + exp_elem; + const char *qualified = index.symbol_name_at (nc_elem->idx, per_objfile); + if (strcmp (qualified, expected_syms[exp_elem]) != 0) + return false; + } + + return true; +} + +/* Test the lower-level mapped_index::find_name_component_bounds + method. */ + +static void +test_mapped_index_find_name_component_bounds () +{ + mock_mapped_index mock_index (test_symbols); + + mock_index.build_name_components (NULL /* per_objfile */); + + /* Test the lower-level mapped_index::find_name_component_bounds + method in completion mode. */ + { + static const char *expected_syms[] = { + "t1_func", + "t1_func1", + }; + + SELF_CHECK (check_find_bounds_finds + (mock_index, "t1_func", expected_syms, + NULL /* per_objfile */)); + } + + /* Check that the increment-last-char in the name matching algorithm + for completion doesn't get confused with Ansi1 'ÿ' / 0xff. See + make_sort_after_prefix_name. */ + { + static const char *expected_syms1[] = { + "\377", + "\377\377123", + }; + SELF_CHECK (check_find_bounds_finds + (mock_index, "\377", expected_syms1, NULL /* per_objfile */)); + + static const char *expected_syms2[] = { + "\377\377123", + }; + SELF_CHECK (check_find_bounds_finds + (mock_index, "\377\377", expected_syms2, + NULL /* per_objfile */)); + } +} + +/* Test dw2_expand_symtabs_matching_symbol. */ + +static void +test_dw2_expand_symtabs_matching_symbol () +{ + mock_mapped_index mock_index (test_symbols); + + /* We let all tests run until the end even if some fails, for debug + convenience. */ + bool any_mismatch = false; + + /* Create the expected symbols list (an initializer_list). Needed + because lists have commas, and we need to pass them to CHECK, + which is a macro. */ +#define EXPECT(...) { __VA_ARGS__ } + + /* Wrapper for check_match that passes down the current + __FILE__/__LINE__. */ +#define CHECK_MATCH(NAME, MATCH_TYPE, COMPLETION_MODE, EXPECTED_LIST) \ + any_mismatch |= !check_match (__FILE__, __LINE__, \ + mock_index, \ + NAME, MATCH_TYPE, COMPLETION_MODE, \ + EXPECTED_LIST, NULL) + + /* Identity checks. */ + for (const char *sym : test_symbols) + { + /* Should be able to match all existing symbols. */ + CHECK_MATCH (sym, symbol_name_match_type::FULL, false, + EXPECT (sym)); + + /* Should be able to match all existing symbols with + parameters. */ + std::string with_params = std::string (sym) + "(int)"; + CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, + EXPECT (sym)); + + /* Should be able to match all existing symbols with + parameters and qualifiers. */ + with_params = std::string (sym) + " ( int ) const"; + CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, + EXPECT (sym)); + + /* This should really find sym, but cp-name-parser.y doesn't + know about lvalue/rvalue qualifiers yet. */ + with_params = std::string (sym) + " ( int ) &&"; + CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, + {}); + } + + /* Check that the name matching algorithm for completion doesn't get + confused with Latin1 'ÿ' / 0xff. See + make_sort_after_prefix_name. */ + { + static const char str[] = "\377"; + CHECK_MATCH (str, symbol_name_match_type::FULL, true, + EXPECT ("\377", "\377\377123")); + } + + /* Check that the increment-last-char in the matching algorithm for + completion doesn't match "t1_fund" when completing "t1_func". */ + { + static const char str[] = "t1_func"; + CHECK_MATCH (str, symbol_name_match_type::FULL, true, + EXPECT ("t1_func", "t1_func1")); + } + + /* Check that completion mode works at each prefix of the expected + symbol name. */ + { + static const char str[] = "function(int)"; + size_t len = strlen (str); + std::string lookup; + + for (size_t i = 1; i < len; i++) + { + lookup.assign (str, i); + CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true, + EXPECT ("function")); + } + } + + /* While "w" is a prefix of both components, the match function + should still only be called once. */ + { + CHECK_MATCH ("w", symbol_name_match_type::FULL, true, + EXPECT ("w1::w2")); + CHECK_MATCH ("w", symbol_name_match_type::WILD, true, + EXPECT ("w1::w2")); + } + + /* Same, with a "complicated" symbol. */ + { + static const char str[] = Z_SYM_NAME; + size_t len = strlen (str); + std::string lookup; + + for (size_t i = 1; i < len; i++) + { + lookup.assign (str, i); + CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true, + EXPECT (Z_SYM_NAME)); + } + } + + /* In FULL mode, an incomplete symbol doesn't match. */ + { + CHECK_MATCH ("std::zfunction(int", symbol_name_match_type::FULL, false, + {}); + } + + /* A complete symbol with parameters matches any overload, since the + index has no overload info. */ + { + CHECK_MATCH ("std::zfunction(int)", symbol_name_match_type::FULL, true, + EXPECT ("std::zfunction", "std::zfunction2")); + CHECK_MATCH ("zfunction(int)", symbol_name_match_type::WILD, true, + EXPECT ("std::zfunction", "std::zfunction2")); + CHECK_MATCH ("zfunc", symbol_name_match_type::WILD, true, + EXPECT ("std::zfunction", "std::zfunction2")); + } + + /* Check that whitespace is ignored appropriately. A symbol with a + template argument list. */ + { + static const char expected[] = "ns::foo"; + CHECK_MATCH ("ns :: foo < int > ", symbol_name_match_type::FULL, false, + EXPECT (expected)); + CHECK_MATCH ("foo < int > ", symbol_name_match_type::WILD, false, + EXPECT (expected)); + } + + /* Check that whitespace is ignored appropriately. A symbol with a + template argument list that includes a pointer. */ + { + static const char expected[] = "ns::foo"; + /* Try both completion and non-completion modes. */ + static const bool completion_mode[2] = {false, true}; + for (size_t i = 0; i < 2; i++) + { + CHECK_MATCH ("ns :: foo < char * >", symbol_name_match_type::FULL, + completion_mode[i], EXPECT (expected)); + CHECK_MATCH ("foo < char * >", symbol_name_match_type::WILD, + completion_mode[i], EXPECT (expected)); + + CHECK_MATCH ("ns :: foo < char * > (int)", symbol_name_match_type::FULL, + completion_mode[i], EXPECT (expected)); + CHECK_MATCH ("foo < char * > (int)", symbol_name_match_type::WILD, + completion_mode[i], EXPECT (expected)); + } + } + + { + /* Check method qualifiers are ignored. */ + static const char expected[] = "ns::foo"; + CHECK_MATCH ("ns :: foo < char * > ( int ) const", + symbol_name_match_type::FULL, true, EXPECT (expected)); + CHECK_MATCH ("ns :: foo < char * > ( int ) &&", + symbol_name_match_type::FULL, true, EXPECT (expected)); + CHECK_MATCH ("foo < char * > ( int ) const", + symbol_name_match_type::WILD, true, EXPECT (expected)); + CHECK_MATCH ("foo < char * > ( int ) &&", + symbol_name_match_type::WILD, true, EXPECT (expected)); + } + + /* Test lookup names that don't match anything. */ + { + CHECK_MATCH ("bar2", symbol_name_match_type::WILD, false, + {}); + + CHECK_MATCH ("doesntexist", symbol_name_match_type::FULL, false, + {}); + } + + /* Some wild matching tests, exercising "(anonymous namespace)", + which should not be confused with a parameter list. */ + { + static const char *syms[] = { + "A::B::C", + "B::C", + "C", + "A :: B :: C ( int )", + "B :: C ( int )", + "C ( int )", + }; + + for (const char *s : syms) + { + CHECK_MATCH (s, symbol_name_match_type::WILD, false, + EXPECT ("(anonymous namespace)::A::B::C")); + } + } + + { + static const char expected[] = "ns2::tmpl::foo2"; + CHECK_MATCH ("tmp", symbol_name_match_type::WILD, true, + EXPECT (expected)); + CHECK_MATCH ("tmpl<", symbol_name_match_type::WILD, true, + EXPECT (expected)); + } + + SELF_CHECK (!any_mismatch); + +#undef EXPECT +#undef CHECK_MATCH +} + +static void +run_test () +{ + test_mapped_index_find_name_component_bounds (); + test_dw2_expand_symtabs_matching_symbol (); +} + +}} // namespace selftests::dw2_expand_symtabs_matching + +#endif /* GDB_SELF_TEST */ + struct dwarf2_gdb_index : public dwarf2_base_index_functions { /* This dumps minimal information about the index. @@ -743,4 +1581,9 @@ Warning: This option must be enabled before gdb reads the file."), NULL, NULL, &setlist, &showlist); + +#if GDB_SELF_TEST + selftests::register_test ("dw2_expand_symtabs_matching", + selftests::dw2_expand_symtabs_matching::run_test); +#endif } diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 9484754447746b8a14b1bde2092407edb2aba298..4503977d62b8c277c4f379973fe0a67d54f3a23b 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -2078,788 +2078,6 @@ dwarf2_base_index_functions::expand_all_symtabs (struct objfile *objfile) } } - -/* Starting from a search name, return the string that finds the upper - bound of all strings that start with SEARCH_NAME in a sorted name - list. Returns the empty string to indicate that the upper bound is - the end of the list. */ - -static std::string -make_sort_after_prefix_name (const char *search_name) -{ - /* When looking to complete "func", we find the upper bound of all - symbols that start with "func" by looking for where we'd insert - the closest string that would follow "func" in lexicographical - order. Usually, that's "func"-with-last-character-incremented, - i.e. "fund". Mind non-ASCII characters, though. Usually those - will be UTF-8 multi-byte sequences, but we can't be certain. - Especially mind the 0xff character, which is a valid character in - non-UTF-8 source character sets (e.g. Latin1 'ÿ'), and we can't - rule out compilers allowing it in identifiers. Note that - conveniently, strcmp/strcasecmp are specified to compare - characters interpreted as unsigned char. So what we do is treat - the whole string as a base 256 number composed of a sequence of - base 256 "digits" and add 1 to it. I.e., adding 1 to 0xff wraps - to 0, and carries 1 to the following more-significant position. - If the very first character in SEARCH_NAME ends up incremented - and carries/overflows, then the upper bound is the end of the - list. The string after the empty string is also the empty - string. - - Some examples of this operation: - - SEARCH_NAME => "+1" RESULT - - "abc" => "abd" - "ab\xff" => "ac" - "\xff" "a" "\xff" => "\xff" "b" - "\xff" => "" - "\xff\xff" => "" - "" => "" - - Then, with these symbols for example: - - func - func1 - fund - - completing "func" looks for symbols between "func" and - "func"-with-last-character-incremented, i.e. "fund" (exclusive), - which finds "func" and "func1", but not "fund". - - And with: - - funcÿ (Latin1 'ÿ' [0xff]) - funcÿ1 - fund - - completing "funcÿ" looks for symbols between "funcÿ" and "fund" - (exclusive), which finds "funcÿ" and "funcÿ1", but not "fund". - - And with: - - ÿÿ (Latin1 'ÿ' [0xff]) - ÿÿ1 - - completing "ÿ" or "ÿÿ" looks for symbols between between "ÿÿ" and - the end of the list. - */ - std::string after = search_name; - while (!after.empty () && (unsigned char) after.back () == 0xff) - after.pop_back (); - if (!after.empty ()) - after.back () = (unsigned char) after.back () + 1; - return after; -} - -/* See declaration. */ - -std::pair::const_iterator, - std::vector::const_iterator> -mapped_index_base::find_name_components_bounds - (const lookup_name_info &lookup_name_without_params, language lang, - dwarf2_per_objfile *per_objfile) const -{ - auto *name_cmp - = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp; - - const char *lang_name - = lookup_name_without_params.language_lookup_name (lang); - - /* Comparison function object for lower_bound that matches against a - given symbol name. */ - auto lookup_compare_lower = [&] (const name_component &elem, - const char *name) - { - const char *elem_qualified = this->symbol_name_at (elem.idx, per_objfile); - const char *elem_name = elem_qualified + elem.name_offset; - return name_cmp (elem_name, name) < 0; - }; - - /* Comparison function object for upper_bound that matches against a - given symbol name. */ - auto lookup_compare_upper = [&] (const char *name, - const name_component &elem) - { - const char *elem_qualified = this->symbol_name_at (elem.idx, per_objfile); - const char *elem_name = elem_qualified + elem.name_offset; - return name_cmp (name, elem_name) < 0; - }; - - auto begin = this->name_components.begin (); - auto end = this->name_components.end (); - - /* Find the lower bound. */ - auto lower = [&] () - { - if (lookup_name_without_params.completion_mode () && lang_name[0] == '\0') - return begin; - else - return std::lower_bound (begin, end, lang_name, lookup_compare_lower); - } (); - - /* Find the upper bound. */ - auto upper = [&] () - { - if (lookup_name_without_params.completion_mode ()) - { - /* In completion mode, we want UPPER to point past all - symbols names that have the same prefix. I.e., with - these symbols, and completing "func": - - function << lower bound - function1 - other_function << upper bound - - We find the upper bound by looking for the insertion - point of "func"-with-last-character-incremented, - i.e. "fund". */ - std::string after = make_sort_after_prefix_name (lang_name); - if (after.empty ()) - return end; - return std::lower_bound (lower, end, after.c_str (), - lookup_compare_lower); - } - else - return std::upper_bound (lower, end, lang_name, lookup_compare_upper); - } (); - - return {lower, upper}; -} - -/* See declaration. */ - -void -mapped_index_base::build_name_components (dwarf2_per_objfile *per_objfile) -{ - if (!this->name_components.empty ()) - return; - - this->name_components_casing = case_sensitivity; - auto *name_cmp - = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp; - - /* The code below only knows how to break apart components of C++ - symbol names (and other languages that use '::' as - namespace/module separator) and Ada symbol names. */ - auto count = this->symbol_name_count (); - for (offset_type idx = 0; idx < count; idx++) - { - if (this->symbol_name_slot_invalid (idx)) - continue; - - const char *name = this->symbol_name_at (idx, per_objfile); - - /* Add each name component to the name component table. */ - unsigned int previous_len = 0; - - if (strstr (name, "::") != nullptr) - { - for (unsigned int current_len = cp_find_first_component (name); - name[current_len] != '\0'; - current_len += cp_find_first_component (name + current_len)) - { - gdb_assert (name[current_len] == ':'); - this->name_components.push_back ({previous_len, idx}); - /* Skip the '::'. */ - current_len += 2; - previous_len = current_len; - } - } - else - { - /* Handle the Ada encoded (aka mangled) form here. */ - for (const char *iter = strstr (name, "__"); - iter != nullptr; - iter = strstr (iter, "__")) - { - this->name_components.push_back ({previous_len, idx}); - iter += 2; - previous_len = iter - name; - } - } - - this->name_components.push_back ({previous_len, idx}); - } - - /* Sort name_components elements by name. */ - auto name_comp_compare = [&] (const name_component &left, - const name_component &right) - { - const char *left_qualified - = this->symbol_name_at (left.idx, per_objfile); - const char *right_qualified - = this->symbol_name_at (right.idx, per_objfile); - - const char *left_name = left_qualified + left.name_offset; - const char *right_name = right_qualified + right.name_offset; - - return name_cmp (left_name, right_name) < 0; - }; - - std::sort (this->name_components.begin (), - this->name_components.end (), - name_comp_compare); -} - -/* See read.h. */ - -bool -dw2_expand_symtabs_matching_symbol - (mapped_index_base &index, - const lookup_name_info &lookup_name_in, - gdb::function_view symbol_matcher, - gdb::function_view match_callback, - dwarf2_per_objfile *per_objfile, - gdb::function_view lang_matcher) -{ - lookup_name_info lookup_name_without_params - = lookup_name_in.make_ignore_params (); - - /* Build the symbol name component sorted vector, if we haven't - yet. */ - index.build_name_components (per_objfile); - - /* The same symbol may appear more than once in the range though. - E.g., if we're looking for symbols that complete "w", and we have - a symbol named "w1::w2", we'll find the two name components for - that same symbol in the range. To be sure we only call the - callback once per symbol, we first collect the symbol name - indexes that matched in a temporary vector and ignore - duplicates. */ - std::vector matches; - - struct name_and_matcher - { - symbol_name_matcher_ftype *matcher; - const char *name; - - bool operator== (const name_and_matcher &other) const - { - return matcher == other.matcher && strcmp (name, other.name) == 0; - } - }; - - /* A vector holding all the different symbol name matchers, for all - languages. */ - std::vector matchers; - - for (int i = 0; i < nr_languages; i++) - { - enum language lang_e = (enum language) i; - if (lang_matcher != nullptr && !lang_matcher (lang_e)) - continue; - - const language_defn *lang = language_def (lang_e); - symbol_name_matcher_ftype *name_matcher - = lang->get_symbol_name_matcher (lookup_name_without_params); - - name_and_matcher key { - name_matcher, - lookup_name_without_params.language_lookup_name (lang_e) - }; - - /* Don't insert the same comparison routine more than once. - Note that we do this linear walk. This is not a problem in - practice because the number of supported languages is - low. */ - if (std::find (matchers.begin (), matchers.end (), key) - != matchers.end ()) - continue; - matchers.push_back (std::move (key)); - - auto bounds - = index.find_name_components_bounds (lookup_name_without_params, - lang_e, per_objfile); - - /* Now for each symbol name in range, check to see if we have a name - match, and if so, call the MATCH_CALLBACK callback. */ - - for (; bounds.first != bounds.second; ++bounds.first) - { - const char *qualified - = index.symbol_name_at (bounds.first->idx, per_objfile); - - if (!name_matcher (qualified, lookup_name_without_params, NULL) - || (symbol_matcher != NULL && !symbol_matcher (qualified))) - continue; - - matches.push_back (bounds.first->idx); - } - } - - std::sort (matches.begin (), matches.end ()); - - /* Finally call the callback, once per match. */ - ULONGEST prev = -1; - bool result = true; - for (offset_type idx : matches) - { - if (prev != idx) - { - if (!match_callback (idx)) - { - result = false; - break; - } - prev = idx; - } - } - - /* Above we use a type wider than idx's for 'prev', since 0 and - (offset_type)-1 are both possible values. */ - static_assert (sizeof (prev) > sizeof (offset_type), ""); - - return result; -} - -#if GDB_SELF_TEST - -namespace selftests { namespace dw2_expand_symtabs_matching { - -/* A mock .gdb_index/.debug_names-like name index table, enough to - exercise dw2_expand_symtabs_matching_symbol, which works with the - mapped_index_base interface. Builds an index from the symbol list - passed as parameter to the constructor. */ -class mock_mapped_index : public mapped_index_base -{ -public: - mock_mapped_index (gdb::array_view symbols) - : m_symbol_table (symbols) - {} - - DISABLE_COPY_AND_ASSIGN (mock_mapped_index); - - /* Return the number of names in the symbol table. */ - size_t symbol_name_count () const override - { - return m_symbol_table.size (); - } - - /* Get the name of the symbol at IDX in the symbol table. */ - const char *symbol_name_at - (offset_type idx, dwarf2_per_objfile *per_objfile) const override - { - return m_symbol_table[idx]; - } - - quick_symbol_functions_up make_quick_functions () const override - { - return nullptr; - } - -private: - gdb::array_view m_symbol_table; -}; - -/* Convenience function that converts a NULL pointer to a "" - string, to pass to print routines. */ - -static const char * -string_or_null (const char *str) -{ - return str != NULL ? str : ""; -} - -/* Check if a lookup_name_info built from - NAME/MATCH_TYPE/COMPLETION_MODE matches the symbols in the mock - index. EXPECTED_LIST is the list of expected matches, in expected - matching order. If no match expected, then an empty list is - specified. Returns true on success. On failure prints a warning - indicating the file:line that failed, and returns false. */ - -static bool -check_match (const char *file, int line, - mock_mapped_index &mock_index, - const char *name, symbol_name_match_type match_type, - bool completion_mode, - std::initializer_list expected_list, - dwarf2_per_objfile *per_objfile) -{ - lookup_name_info lookup_name (name, match_type, completion_mode); - - bool matched = true; - - auto mismatch = [&] (const char *expected_str, - const char *got) - { - warning (_("%s:%d: match_type=%s, looking-for=\"%s\", " - "expected=\"%s\", got=\"%s\"\n"), - file, line, - (match_type == symbol_name_match_type::FULL - ? "FULL" : "WILD"), - name, string_or_null (expected_str), string_or_null (got)); - matched = false; - }; - - auto expected_it = expected_list.begin (); - auto expected_end = expected_list.end (); - - dw2_expand_symtabs_matching_symbol (mock_index, lookup_name, - nullptr, - [&] (offset_type idx) - { - const char *matched_name = mock_index.symbol_name_at (idx, per_objfile); - const char *expected_str - = expected_it == expected_end ? NULL : *expected_it++; - - if (expected_str == NULL || strcmp (expected_str, matched_name) != 0) - mismatch (expected_str, matched_name); - return true; - }, per_objfile, nullptr); - - const char *expected_str - = expected_it == expected_end ? NULL : *expected_it++; - if (expected_str != NULL) - mismatch (expected_str, NULL); - - return matched; -} - -/* The symbols added to the mock mapped_index for testing (in - canonical form). */ -static const char *test_symbols[] = { - "function", - "std::bar", - "std::zfunction", - "std::zfunction2", - "w1::w2", - "ns::foo", - "ns::foo", - "ns::foo", - "ns2::tmpl::foo2", - "(anonymous namespace)::A::B::C", - - /* These are used to check that the increment-last-char in the - matching algorithm for completion doesn't match "t1_fund" when - completing "t1_func". */ - "t1_func", - "t1_func1", - "t1_fund", - "t1_fund1", - - /* A UTF-8 name with multi-byte sequences to make sure that - cp-name-parser understands this as a single identifier ("função" - is "function" in PT). */ - (const char *)u8"u8função", - - /* Test a symbol name that ends with a 0xff character, which is a - valid character in non-UTF-8 source character sets (e.g. Latin1 - 'ÿ'), and we can't rule out compilers allowing it in identifiers. - We test this because the completion algorithm finds the upper - bound of symbols by looking for the insertion point of - "func"-with-last-character-incremented, i.e. "fund", and adding 1 - to 0xff should wraparound and carry to the previous character. - See comments in make_sort_after_prefix_name. */ - "yfunc\377", - - /* Some more symbols with \377 (0xff). See above. */ - "\377", - "\377\377123", - - /* A name with all sorts of complications. Starts with "z" to make - it easier for the completion tests below. */ -#define Z_SYM_NAME \ - "z::std::tuple<(anonymous namespace)::ui*, std::bar<(anonymous namespace)::ui> >" \ - "::tuple<(anonymous namespace)::ui*, " \ - "std::default_delete<(anonymous namespace)::ui>, void>" - - Z_SYM_NAME -}; - -/* Returns true if the mapped_index_base::find_name_component_bounds - method finds EXPECTED_SYMS in INDEX when looking for SEARCH_NAME, - in completion mode. */ - -static bool -check_find_bounds_finds (mapped_index_base &index, - const char *search_name, - gdb::array_view expected_syms, - dwarf2_per_objfile *per_objfile) -{ - lookup_name_info lookup_name (search_name, - symbol_name_match_type::FULL, true); - - auto bounds = index.find_name_components_bounds (lookup_name, - language_cplus, - per_objfile); - - size_t distance = std::distance (bounds.first, bounds.second); - if (distance != expected_syms.size ()) - return false; - - for (size_t exp_elem = 0; exp_elem < distance; exp_elem++) - { - auto nc_elem = bounds.first + exp_elem; - const char *qualified = index.symbol_name_at (nc_elem->idx, per_objfile); - if (strcmp (qualified, expected_syms[exp_elem]) != 0) - return false; - } - - return true; -} - -/* Test the lower-level mapped_index::find_name_component_bounds - method. */ - -static void -test_mapped_index_find_name_component_bounds () -{ - mock_mapped_index mock_index (test_symbols); - - mock_index.build_name_components (NULL /* per_objfile */); - - /* Test the lower-level mapped_index::find_name_component_bounds - method in completion mode. */ - { - static const char *expected_syms[] = { - "t1_func", - "t1_func1", - }; - - SELF_CHECK (check_find_bounds_finds - (mock_index, "t1_func", expected_syms, - NULL /* per_objfile */)); - } - - /* Check that the increment-last-char in the name matching algorithm - for completion doesn't get confused with Ansi1 'ÿ' / 0xff. See - make_sort_after_prefix_name. */ - { - static const char *expected_syms1[] = { - "\377", - "\377\377123", - }; - SELF_CHECK (check_find_bounds_finds - (mock_index, "\377", expected_syms1, NULL /* per_objfile */)); - - static const char *expected_syms2[] = { - "\377\377123", - }; - SELF_CHECK (check_find_bounds_finds - (mock_index, "\377\377", expected_syms2, - NULL /* per_objfile */)); - } -} - -/* Test dw2_expand_symtabs_matching_symbol. */ - -static void -test_dw2_expand_symtabs_matching_symbol () -{ - mock_mapped_index mock_index (test_symbols); - - /* We let all tests run until the end even if some fails, for debug - convenience. */ - bool any_mismatch = false; - - /* Create the expected symbols list (an initializer_list). Needed - because lists have commas, and we need to pass them to CHECK, - which is a macro. */ -#define EXPECT(...) { __VA_ARGS__ } - - /* Wrapper for check_match that passes down the current - __FILE__/__LINE__. */ -#define CHECK_MATCH(NAME, MATCH_TYPE, COMPLETION_MODE, EXPECTED_LIST) \ - any_mismatch |= !check_match (__FILE__, __LINE__, \ - mock_index, \ - NAME, MATCH_TYPE, COMPLETION_MODE, \ - EXPECTED_LIST, NULL) - - /* Identity checks. */ - for (const char *sym : test_symbols) - { - /* Should be able to match all existing symbols. */ - CHECK_MATCH (sym, symbol_name_match_type::FULL, false, - EXPECT (sym)); - - /* Should be able to match all existing symbols with - parameters. */ - std::string with_params = std::string (sym) + "(int)"; - CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, - EXPECT (sym)); - - /* Should be able to match all existing symbols with - parameters and qualifiers. */ - with_params = std::string (sym) + " ( int ) const"; - CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, - EXPECT (sym)); - - /* This should really find sym, but cp-name-parser.y doesn't - know about lvalue/rvalue qualifiers yet. */ - with_params = std::string (sym) + " ( int ) &&"; - CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, - {}); - } - - /* Check that the name matching algorithm for completion doesn't get - confused with Latin1 'ÿ' / 0xff. See - make_sort_after_prefix_name. */ - { - static const char str[] = "\377"; - CHECK_MATCH (str, symbol_name_match_type::FULL, true, - EXPECT ("\377", "\377\377123")); - } - - /* Check that the increment-last-char in the matching algorithm for - completion doesn't match "t1_fund" when completing "t1_func". */ - { - static const char str[] = "t1_func"; - CHECK_MATCH (str, symbol_name_match_type::FULL, true, - EXPECT ("t1_func", "t1_func1")); - } - - /* Check that completion mode works at each prefix of the expected - symbol name. */ - { - static const char str[] = "function(int)"; - size_t len = strlen (str); - std::string lookup; - - for (size_t i = 1; i < len; i++) - { - lookup.assign (str, i); - CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true, - EXPECT ("function")); - } - } - - /* While "w" is a prefix of both components, the match function - should still only be called once. */ - { - CHECK_MATCH ("w", symbol_name_match_type::FULL, true, - EXPECT ("w1::w2")); - CHECK_MATCH ("w", symbol_name_match_type::WILD, true, - EXPECT ("w1::w2")); - } - - /* Same, with a "complicated" symbol. */ - { - static const char str[] = Z_SYM_NAME; - size_t len = strlen (str); - std::string lookup; - - for (size_t i = 1; i < len; i++) - { - lookup.assign (str, i); - CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true, - EXPECT (Z_SYM_NAME)); - } - } - - /* In FULL mode, an incomplete symbol doesn't match. */ - { - CHECK_MATCH ("std::zfunction(int", symbol_name_match_type::FULL, false, - {}); - } - - /* A complete symbol with parameters matches any overload, since the - index has no overload info. */ - { - CHECK_MATCH ("std::zfunction(int)", symbol_name_match_type::FULL, true, - EXPECT ("std::zfunction", "std::zfunction2")); - CHECK_MATCH ("zfunction(int)", symbol_name_match_type::WILD, true, - EXPECT ("std::zfunction", "std::zfunction2")); - CHECK_MATCH ("zfunc", symbol_name_match_type::WILD, true, - EXPECT ("std::zfunction", "std::zfunction2")); - } - - /* Check that whitespace is ignored appropriately. A symbol with a - template argument list. */ - { - static const char expected[] = "ns::foo"; - CHECK_MATCH ("ns :: foo < int > ", symbol_name_match_type::FULL, false, - EXPECT (expected)); - CHECK_MATCH ("foo < int > ", symbol_name_match_type::WILD, false, - EXPECT (expected)); - } - - /* Check that whitespace is ignored appropriately. A symbol with a - template argument list that includes a pointer. */ - { - static const char expected[] = "ns::foo"; - /* Try both completion and non-completion modes. */ - static const bool completion_mode[2] = {false, true}; - for (size_t i = 0; i < 2; i++) - { - CHECK_MATCH ("ns :: foo < char * >", symbol_name_match_type::FULL, - completion_mode[i], EXPECT (expected)); - CHECK_MATCH ("foo < char * >", symbol_name_match_type::WILD, - completion_mode[i], EXPECT (expected)); - - CHECK_MATCH ("ns :: foo < char * > (int)", symbol_name_match_type::FULL, - completion_mode[i], EXPECT (expected)); - CHECK_MATCH ("foo < char * > (int)", symbol_name_match_type::WILD, - completion_mode[i], EXPECT (expected)); - } - } - - { - /* Check method qualifiers are ignored. */ - static const char expected[] = "ns::foo"; - CHECK_MATCH ("ns :: foo < char * > ( int ) const", - symbol_name_match_type::FULL, true, EXPECT (expected)); - CHECK_MATCH ("ns :: foo < char * > ( int ) &&", - symbol_name_match_type::FULL, true, EXPECT (expected)); - CHECK_MATCH ("foo < char * > ( int ) const", - symbol_name_match_type::WILD, true, EXPECT (expected)); - CHECK_MATCH ("foo < char * > ( int ) &&", - symbol_name_match_type::WILD, true, EXPECT (expected)); - } - - /* Test lookup names that don't match anything. */ - { - CHECK_MATCH ("bar2", symbol_name_match_type::WILD, false, - {}); - - CHECK_MATCH ("doesntexist", symbol_name_match_type::FULL, false, - {}); - } - - /* Some wild matching tests, exercising "(anonymous namespace)", - which should not be confused with a parameter list. */ - { - static const char *syms[] = { - "A::B::C", - "B::C", - "C", - "A :: B :: C ( int )", - "B :: C ( int )", - "C ( int )", - }; - - for (const char *s : syms) - { - CHECK_MATCH (s, symbol_name_match_type::WILD, false, - EXPECT ("(anonymous namespace)::A::B::C")); - } - } - - { - static const char expected[] = "ns2::tmpl::foo2"; - CHECK_MATCH ("tmp", symbol_name_match_type::WILD, true, - EXPECT (expected)); - CHECK_MATCH ("tmpl<", symbol_name_match_type::WILD, true, - EXPECT (expected)); - } - - SELF_CHECK (!any_mismatch); - -#undef EXPECT -#undef CHECK_MATCH -} - -static void -run_test () -{ - test_mapped_index_find_name_component_bounds (); - test_dw2_expand_symtabs_matching_symbol (); -} - -}} // namespace selftests::dw2_expand_symtabs_matching - -#endif /* GDB_SELF_TEST */ - /* See read.h. */ bool @@ -22342,8 +21560,6 @@ the demangler."), &ada_function_alias_funcs); #if GDB_SELF_TEST - selftests::register_test ("dw2_expand_symtabs_matching", - selftests::dw2_expand_symtabs_matching::run_test); selftests::register_test ("dwarf2_find_containing_comp_unit", selftests::find_containing_comp_unit::run_test); #endif diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index e8735ddef6faa5eeb8c8077c73d2b5a61ef450b3..12d5f066e87e1c657da569ae8ef99f333146beae 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -931,21 +931,6 @@ extern bool dw2_expand_symtabs_matching_one gdb::function_view expansion_notify, gdb::function_view lang_matcher); -/* Helper for dw2_expand_symtabs_matching that works with a - mapped_index_base instead of the containing objfile. This is split - to a separate function in order to be able to unit test the - name_components matching using a mock mapped_index_base. For each - symbol name that matches, calls MATCH_CALLBACK, passing it the - symbol's index in the mapped_index_base symbol table. */ - -extern bool dw2_expand_symtabs_matching_symbol - (mapped_index_base &index, - const lookup_name_info &lookup_name_in, - gdb::function_view symbol_matcher, - gdb::function_view match_callback, - dwarf2_per_objfile *per_objfile, - gdb::function_view lang_matcher); - /* If FILE_MATCHER is non-NULL, set all the dwarf2_per_cu_quick_data::MARK of the current DWARF2_PER_OBJFILE that match FILE_MATCHER. */