From patchwork Wed May 24 16:37:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 69977 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 2740138845A6 for ; Wed, 24 May 2023 16:40:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2740138845A6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1684946405; bh=rtcu6P7FB9NOrFAl6weu9ph5nDpj/CWHcFTPf+UAPUE=; h=Date:Subject:References:In-Reply-To:To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=x2kijyafO9XIWPc6RO3bVYqsv3GEPRdjLiIUK964sqpQdjXGvTZ411goy1l3rDoI/ 7FM9yz9TxQTYIjHocxpVNnVPesvzggw2PmlP+2NzO4xHXLk9EUs2XmfRFSdLwObAD0 HHxLnQ11MMmM9xWRgYsXq+lwsjLxuu1KMCCmSnu4= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-io1-xd2c.google.com (mail-io1-xd2c.google.com [IPv6:2607:f8b0:4864:20::d2c]) by sourceware.org (Postfix) with ESMTPS id BD9F33857722 for ; Wed, 24 May 2023 16:37:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BD9F33857722 Received: by mail-io1-xd2c.google.com with SMTP id ca18e2360f4ac-7665e607d1bso30451839f.3 for ; Wed, 24 May 2023 09:37:29 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684946249; x=1687538249; 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=rtcu6P7FB9NOrFAl6weu9ph5nDpj/CWHcFTPf+UAPUE=; b=YHnuM3RBH37q5Kgc761nmSU0GoNIuFx5JorMbe3dr2K7hXJBOqK/odijdI9QKYmQMq uNkwvlTXWN9s/9laYh/qJiIvgBmauLWSSAOcgXIux6e6ZaB7UvBRisvU7DcneyXG3WvP u/lKz5xvIDAjCer3HkXUHDcKyHfHvKKRiPhgrS8XF/F0+6WuYUStHO3gnZYmrXgiPD1F IO1AgvEgAYC6/CHq+2AucoJQ6c799DrOWE613pjwE6n/rRa1KtqCYXLRWXQCRwjcIMi/ YgnPoiaa/fz3hw6rdkoo+UOG+SgTK2bjo7NL++/FGBDPsG+c/9iPB7+c2IvcD8yTpgPe NapA== X-Gm-Message-State: AC+VfDyGdgYnheG3Kq42aTedYCnNw1AO3TpLfhiIP4lUqp5VQ4/pgvAf R5vMoMf4jztvnCIY6Mf8nzApe1QB2z7zTmMZvGnLdw== X-Google-Smtp-Source: ACHHUZ4HVqTZ/VCPfJ2bJ1+ZPA3J08DIINiFeP3+diG4IwiyeBTM7r7Uk8zhvXCjiKLoKAGRKIexEA== X-Received: by 2002:a05:6602:2211:b0:760:ea10:757 with SMTP id n17-20020a056602221100b00760ea100757mr10875879ion.20.1684946249351; Wed, 24 May 2023 09:37:29 -0700 (PDT) Received: from localhost.localdomain (71-211-130-244.hlrn.qwest.net. [71.211.130.244]) by smtp.gmail.com with ESMTPSA id o22-20020a6bcf16000000b0076c81bf2731sm3397266ioa.20.2023.05.24.09.37.28 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 May 2023 09:37:29 -0700 (PDT) Date: Wed, 24 May 2023 10:37:00 -0600 Subject: [PATCH 09/25] Implement DAP setExceptionBreakpoints request MIME-Version: 1.0 Message-Id: <20230427-ada-catch-exception-v1-9-947caa9905e3@adacore.com> References: <20230427-ada-catch-exception-v1-0-947caa9905e3@adacore.com> In-Reply-To: <20230427-ada-catch-exception-v1-0-947caa9905e3@adacore.com> To: gdb-patches@sourceware.org X-Mailer: b4 0.12.2 X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Tom Tromey via Gdb-patches From: Tom Tromey Reply-To: Tom Tromey Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" This implements the DAP setExceptionBreakpoints request for Ada. This is a somewhat minimal implementation, in that "exceptionOptions" are not implemented (or advertised) -- I wasn't completely sure how this feature is supposed to work. I haven't added C++ exception handling here, but it's easy to do if needed. This patch relies on the new MI command execution support to do its work. --- gdb/python/lib/gdb/dap/breakpoint.py | 65 ++++++++++++++++++++++++-- gdb/python/lib/gdb/dap/server.py | 4 +- gdb/testsuite/gdb.dap/catch-exception.exp | 65 ++++++++++++++++++++++++++ gdb/testsuite/gdb.dap/catch-exception/pck.ads | 18 +++++++ gdb/testsuite/gdb.dap/catch-exception/prog.adb | 44 +++++++++++++++++ 5 files changed, 189 insertions(+), 7 deletions(-) diff --git a/gdb/python/lib/gdb/dap/breakpoint.py b/gdb/python/lib/gdb/dap/breakpoint.py index f0e1f103d1b..877069f79a5 100644 --- a/gdb/python/lib/gdb/dap/breakpoint.py +++ b/gdb/python/lib/gdb/dap/breakpoint.py @@ -37,12 +37,11 @@ def breakpoint_descriptor(bp): # https://github.com/microsoft/debug-adapter-protocol/issues/13 loc = bp.locations[0] (basename, line) = loc.source - return { + result = { "id": bp.number, "verified": True, "source": { "name": os.path.basename(basename), - "path": loc.fullname, # We probably don't need this but it doesn't hurt to # be explicit. "sourceReference": 0, @@ -50,6 +49,10 @@ def breakpoint_descriptor(bp): "line": line, "instructionReference": hex(loc.address), } + path = loc.fullname + if path is not None: + result["source"]["path"] = path + return result else: return { "id": bp.number, @@ -58,9 +61,10 @@ def breakpoint_descriptor(bp): # Helper function to set some breakpoints according to a list of -# specifications. +# specifications and a callback function to do the work of creating +# the breakpoint. @in_gdb_thread -def _set_breakpoints(kind, specs): +def _set_breakpoints_callback(kind, specs, creator): global breakpoint_map # Try to reuse existing breakpoints if possible. if kind in breakpoint_map: @@ -75,7 +79,7 @@ def _set_breakpoints(kind, specs): bp = saved_map.pop(keyspec) else: # FIXME handle exceptions here - bp = gdb.Breakpoint(**spec) + bp = creator(**spec) breakpoint_map[kind][keyspec] = bp result.append(breakpoint_descriptor(bp)) # Delete any breakpoints that were not reused. @@ -84,6 +88,13 @@ def _set_breakpoints(kind, specs): return result +# Helper function to set odinary breakpoints according to a list of +# specifications. +@in_gdb_thread +def _set_breakpoints(kind, specs): + return _set_breakpoints_callback(kind, specs, gdb.Breakpoint) + + @request("setBreakpoints") def set_breakpoint(*, source, breakpoints=[], **args): if "path" not in source: @@ -141,3 +152,47 @@ def set_insn_breakpoints(*, breakpoints, offset=None, **args): return { "breakpoints": result, } + + +@in_gdb_thread +def _catch_exception(filterId, condition=None, **args): + if filterId == "assert": + args = ["-catch-assert"] + elif filterId == "exception": + args = ["-catch-exception"] + else: + raise Exception(f"Invalid exception filterID: {filterId}") + if condition is not None: + args.extend(["-c", condition]) + result = gdb.execute_mi(*args) + # A little lame that there's no more direct way. + for bp in gdb.breakpoints(): + if bp.number == result["bkptno"]: + return bp + raise Exception("Could not find catchpoint after creating") + + +@in_gdb_thread +def _set_exception_catchpoints(filter_options): + return _set_breakpoints_callback("exception", filter_options, _catch_exception) + + +@request("setExceptionBreakpoints") +@capability("supportsExceptionFilterOptions") +@capability("exceptionBreakpointFilters", ({ + "filter": "assert", + "label": "Ada assertions", + "supportsCondition": True, +}, { + "filter": "exception", + "label": "Ada exceptions", + "supportsCondition": True, +})) +def set_exception_breakpoints(*, filters, filterOptions=[], **args): + # Convert the 'filters' to the filter-options style. + options = [{"filterId": filter} for filter in filters] + options.extend(filterOptions) + result = send_gdb_with_response(lambda: _set_exception_catchpoints(options)) + return { + "breakpoints": result, + } diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py index ff88282049f..f27fa9caa4f 100644 --- a/gdb/python/lib/gdb/dap/server.py +++ b/gdb/python/lib/gdb/dap/server.py @@ -171,13 +171,13 @@ def request(name): return wrap -def capability(name): +def capability(name, value=True): """A decorator that indicates that the wrapper function implements the DAP capability NAME.""" def wrap(func): global _capabilities - _capabilities[name] = True + _capabilities[name] = value return func return wrap diff --git a/gdb/testsuite/gdb.dap/catch-exception.exp b/gdb/testsuite/gdb.dap/catch-exception.exp new file mode 100644 index 00000000000..6bfeb3ed87e --- /dev/null +++ b/gdb/testsuite/gdb.dap/catch-exception.exp @@ -0,0 +1,65 @@ +# Copyright 2023 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 . + +load_lib ada.exp +load_lib dap-support.exp + +require allow_ada_tests allow_dap_tests gnat_runtime_has_debug_info + +standard_ada_testfile prog + +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable \ + {debug additional_flags=-gnata}] != ""} { + return -1 +} + +if {[dap_launch $binfile] == ""} { + return +} + +set obj [dap_check_request_and_response "set exception catchpoints" \ + setExceptionBreakpoints \ + {o filters [a [s assert]] \ + filterOptions [a [o filterId [s exception] \ + condition [s "Global_Var = 23"]]]}] + +set bps [dict get [lindex $obj 0] body breakpoints] +gdb_assert {[llength $bps] == 2} "two breakpoints" + +# The "path" should never be "null". +set i 1 +foreach spec $bps { + # If "path" does not exist, then that is fine as well. + if {![dict exists $spec source path]} { + pass "breakpoint $i path" + } else { + gdb_assert {[dict get $spec source path] != "null"} \ + "breakpoint $i path" + } + incr i +} + +dap_check_request_and_response "start inferior" configurationDone + +dap_wait_for_event_and_check "stopped at first raise" stopped \ + "body reason" breakpoint \ + "body hitBreakpointIds" 2 + +dap_check_request_and_response "continue to assert" continue +dap_wait_for_event_and_check "stopped at assert" stopped \ + "body reason" breakpoint \ + "body hitBreakpointIds" 1 + +dap_shutdown diff --git a/gdb/testsuite/gdb.dap/catch-exception/pck.ads b/gdb/testsuite/gdb.dap/catch-exception/pck.ads new file mode 100644 index 00000000000..e82a54fa60a --- /dev/null +++ b/gdb/testsuite/gdb.dap/catch-exception/pck.ads @@ -0,0 +1,18 @@ +-- Copyright 2023 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 . + +package Pck is + Global_Var : Integer := 91; +end Pck; diff --git a/gdb/testsuite/gdb.dap/catch-exception/prog.adb b/gdb/testsuite/gdb.dap/catch-exception/prog.adb new file mode 100644 index 00000000000..287eb2492f9 --- /dev/null +++ b/gdb/testsuite/gdb.dap/catch-exception/prog.adb @@ -0,0 +1,44 @@ +-- Copyright 2023 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 . + +with Pck; use Pck; + +procedure Prog is +begin + + begin + raise Program_Error; + exception + when others => + null; + end; + + begin + Global_Var := 23; + raise Program_Error; + exception + when others => + null; + end; + + begin + pragma Assert (False); + null; + exception + when others => + null; + end; + +end Prog;