From patchwork Sun May 7 09:41:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Farre X-Patchwork-Id: 68887 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 7DAA23858C52 for ; Sun, 7 May 2023 09:42:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7DAA23858C52 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1683452535; bh=0U047DXrXMbvhnUH1poz+9Q7EP0wEMLXU6HqP/0iQSM=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=U3sQfXhITFbVXD00htAn7XVysiY+VixGBkpSJBXV6e4QjC4b4N5ZrMwH1kIIb789K ci5IDpAbnVU4CxIargxVNuQiZNgpBmcE7lOK0jLis1tjgNbNQlM0XflKv7H3nOkggV 6MXbQ3lZH/ubIfOpuv7jknIbX9kBpmyLvcs7Sj0U= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-lf1-x132.google.com (mail-lf1-x132.google.com [IPv6:2a00:1450:4864:20::132]) by sourceware.org (Postfix) with ESMTPS id 67D563858D28 for ; Sun, 7 May 2023 09:41:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 67D563858D28 Received: by mail-lf1-x132.google.com with SMTP id 2adb3069b0e04-4f24cfb8539so348275e87.3 for ; Sun, 07 May 2023 02:41:51 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683452509; x=1686044509; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=0U047DXrXMbvhnUH1poz+9Q7EP0wEMLXU6HqP/0iQSM=; b=RGrC5xDyPz0iAPVI6C6JaiRa6KqrwVyr+WSgwgSPUSZ5/5l40U4oo/D7NMeIcLqGqL cjnN0zbScVSIWRmyaVF+yxqMt3COhfSgyjg2pqpF6eGl0qAeO3TlS2WDzxA71Tpm1gLQ 0a1Sy7C5QPHKK35JOTmq4UGkR4IvGSJr85PnPxCh1uiTvlcHsNx7fBj9kcDgoCr5pVoQ 9n+igoebgRUwXlGt8tXfj85Qfo99bB8d8geHdHqYLrHK5eJOYANkPOEyHSLPoPKEdV3m DzveIatUqgcTki2jXAfGDOmO74RgQLLD3JAnEYlV0eB6r9pQjTu8waHsyLDyxcwuStCb c6mw== X-Gm-Message-State: AC+VfDxjiiToZsPxmFh1KhhvcGSqBK3VKRlLXuk8qZrplAOPoyAkx5Hd k1MsiYt1+ccOXFc7O+WKNk1ZOolhyMi8kA== X-Google-Smtp-Source: ACHHUZ4LpJgbTmfyoLg9ghsrszfB73TMLEgrHpYl224FSvrH3coUHETP8jnTLhdKtRLjYwWGYhacFQ== X-Received: by 2002:a05:6512:49b:b0:4ec:8524:65a4 with SMTP id v27-20020a056512049b00b004ec852465a4mr1810159lfq.55.1683452509078; Sun, 07 May 2023 02:41:49 -0700 (PDT) Received: from fedora.. (78-73-77-63-no2450.tbcn.telia.com. [78.73.77.63]) by smtp.gmail.com with ESMTPSA id s11-20020ac25feb000000b004cca1658a41sm927827lfg.300.2023.05.07.02.41.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 07 May 2023 02:41:48 -0700 (PDT) To: gdb-patches@sourceware.org Cc: Simon Farre Subject: [PATCH] gdb/DAP: Add customRequest Date: Sun, 7 May 2023 11:41:44 +0200 Message-Id: <20230507094144.894866-1-simon.farre.cx@gmail.com> X-Mailer: git-send-email 2.40.1 MIME-Version: 1.0 X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, 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: Simon Farre via Gdb-patches From: Simon Farre Reply-To: Simon Farre Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" First, some preface; as a maintainer on one of the few implementations of a pure GDB-only debug adapter extension for VSCode (technically, it's designed for GDB+RR) called "Midas", there is one thing that is crucial for making the DAP interpreter useful, or rather, to make it be able to fully utilize all the different super powers that GDB has and that is custom requests. Midas implements the DA by making GDB feign the DAP in python, but using CLI and MI, by parsing MI and turning it into JSON. Not great, but it was the only solution that existed at the time. The Python interpreter, when in CLI-mode, currently provides something similar to custom requests, with custom commands from the command line via the base class `gdb.Command`. But with the current implementation of the DAP-interpreter, no class hierarchies are needed. This patch introduces the customRequest, which allows for DA's (debug adapters) that want to use the full extent of GDB's functionality by working a bit like the extension of `gdb.Command`, But instead of deriving from a base class and instantiating a command object the DA would source python code that will be added to the custom requests handler of the DAP-interpreter, for example like: `-iex "source foo.py"` or `-iex "source debug-adapter-std-lib.py"` or whatever she/he wants to call it. Here's an example of what `foo.py` might look like: > import gdb > import gdb.dap > from gdb.dap import server # import logic, possibly should look different > > @server.custom_request("foo") > def fooRequestHandler(argumentBaz): > # full Python interpreter access, full access to all of GDB, like we're @ the CLI > # say goodbye to MI! Yay! :P > return { "bar": gdb.execute("print foo", to_string=True), "someParam": argumentBaz } Now, the DA would be able to send a request that looks like > header omitted > {"seq":6,"type":"request","command":"customRequest","arguments":{"command":"foo","args":["baz"]}} And in this particular case the response to that request would be: > { > "request_seq":6, > "type":"response", > "command":"customRequest", > "body": { > "bar": "resultFromPrintCommand", > "someParam": "baz" > }, > "success":true,"seq":19 > } If the command is unrecognized it will respond with a "success" : false, and an error message. As a debug adapter maintainer for VSCode, a customRequest like this would be not only useful, but crucial. VSCode itself in it's debug adapter interface specification, i.e. not the protocol spec, but the Typescript interface, defines customRequest-functionality, which can be found here; https://github.com/microsoft/vscode-debugadapter-node/blob/main/adapter/src/debugSession.ts#L638 Unfortunately, there's nothing about such a request in the DAP-spec, but I'd argue that's really irrelevant; the largest code editor for debug adapter protocol implementers, has a notion of it, though it's up to DA-implementers to make sure they understand their own requests. There are other, (in my opinion) bonuses of the customRequest functionality. The major one being it can be a driving factor for further development of Python in GDB, by providing an access point to GDB that returns "real python objects" (instead of the above example of returning a string from the CLI-command) from commands and make it more possible for future debug adapters to migrate away from MI (if they so choose), which is difficult to work with, hard to read and even harder to test. JSON is superior since there's so much open source code that supports JSON and in a lot of languages it's even got built in support. "Driving GDB" via the DAP-interpreter from any modern language is trivial because of this. Beyond this patch, documentation would be needed also, to document how to create customRequests, like the one above. I'm hoping Eli can provide me with some direction here. --- gdb/python/lib/gdb/dap/server.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py index ff88282049f..7cd60873319 100644 --- a/gdb/python/lib/gdb/dap/server.py +++ b/gdb/python/lib/gdb/dap/server.py @@ -33,6 +33,8 @@ _capabilities = {} # Map command names to callables. _commands = {} +_custom_requests = {} + # The global server. _server = None @@ -171,6 +173,27 @@ def request(name): return wrap +def custom_request(name): + """A decorator that indicates that the wrapper function should be + handled by a custom request""" + + def wrap(func): + global _custom_requests + _custom_requests[name] = func + return in_dap_thread(func) + + return wrap + +@request("customRequest") +def custom_request_handler(**args): + global _custom_requests + cmd = args["command"] + if _custom_requests.get(cmd) is not None: + return _custom_requests[cmd](args["args"]) + else: + raise Exception(f"Unrecognized customRequest {cmd}") + + def capability(name): """A decorator that indicates that the wrapper function implements the DAP capability NAME."""