From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-il1-x12e.google.com (mail-il1-x12e.google.com [IPv6:2607:f8b0:4864:20::12e]) by sourceware.org (Postfix) with ESMTPS id 97A203858039 for ; Tue, 14 Mar 2023 15:20:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 97A203858039 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=adacore.com Received: by mail-il1-x12e.google.com with SMTP id 4so8811733ilz.6 for ; Tue, 14 Mar 2023 08:20:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1678807255; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=f2evHVWZcYeDV8WQHv1nzGM3UGtqbgeAJhiADWChdyU=; b=hEwOU2wjwIIsSEtMIDlMEbro4eKBFB6AN6sQzeJXIkr3mE+LhMoXLEfMilp5ybN05f qjivORXJ/J8el2WGl1/+2mQ77mkTeSV8oBTP53J40dqAYQiO2XhUB2QQyqU8tpcO173E S46CY6j01W/5zaFvwYfZ0uKvAh+8YTd0nZVYx1tc+kAjZUoFGE40BCwhekG8Z6BeRRpI MghoORmlqdt/bmhsxt8ffL309IVISFPrO/SzbMub/rNdBCrF02USn+J02MgOvoXnY962 iMvRLGJAZ2A7B+k5ZoIaWuiAagGegz0thD2IGYS0XZm6LIN5rc6xlTs0ooFR3uETo0ga Z6Yg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678807255; 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=f2evHVWZcYeDV8WQHv1nzGM3UGtqbgeAJhiADWChdyU=; b=WOHZUn2GujAqpmV7VuedPYKaux2v1NLYw4qQ/Nq8Y1jb5uu2tGJeS/mQmGTumC7W/B ealL2PAm59wdmG93wRVFxwKXeh9m8oKSUIVJw6P9NdetHncudFwx8XEu1UTqqsSAzXKh saJYxaKy3KBCKq0HtohyEz2sfhoECAu0bpKnmBz/N8ry+euCZIaIYlFUoOsHIHxmvVBD W426Nvq2UKeYwI/hhKq31krHI9oU2P6nzAQ4JUZ0Qa6SP5geXNG8gLf51B4MKUnEJyj6 gc28DogFrAcQtmDDOnrSItBJ5rwehzliOckN59KKm5SzSJ4/tiHra2lYz+H42k6ojEJE C7YQ== X-Gm-Message-State: AO0yUKWmH1jXIFoCVDIzvOE3xEH002MrUD7xtk+xfJUVGi38LzddauAA k+6+BjTJy97PeqJ92QNDTrt7hwLt+Q4+CoAhknY= X-Google-Smtp-Source: AK7set85JRsHRrhzVM3h/r9oCYTtw7VwOMF05mSPRTWXIv9CacIU6qq/G9e2Cy5owKWjFpsstFknxQ== X-Received: by 2002:a92:d941:0:b0:315:7fd1:687e with SMTP id l1-20020a92d941000000b003157fd1687emr2733667ilq.7.1678807254827; Tue, 14 Mar 2023 08:20:54 -0700 (PDT) Received: from localhost.localdomain (71-211-185-113.hlrn.qwest.net. [71.211.185.113]) by smtp.gmail.com with ESMTPSA id y17-20020a056e02119100b0031798b87a14sm886864ili.19.2023.03.14.08.20.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Mar 2023 08:20:54 -0700 (PDT) From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [PATCH] Add readMemory and writeMemory requests to DAP Date: Tue, 14 Mar 2023 09:20:45 -0600 Message-Id: <20230314152045.1147144-1-tromey@adacore.com> X-Mailer: git-send-email 2.39.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.5 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 autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: This adds the DAP readMemory and writeMemory requests. A small change to the evaluation code is needed in order to test this -- this is one of the few ways for a client to actually acquire a memory reference. --- gdb/data-directory/Makefile.in | 1 + gdb/python/lib/gdb/dap/__init__.py | 1 + gdb/python/lib/gdb/dap/memory.py | 51 ++++++++++++++++++ gdb/python/lib/gdb/dap/varref.py | 5 ++ gdb/testsuite/gdb.dap/memory.c | 25 +++++++++ gdb/testsuite/gdb.dap/memory.exp | 85 ++++++++++++++++++++++++++++++ 6 files changed, 168 insertions(+) create mode 100644 gdb/python/lib/gdb/dap/memory.py create mode 100644 gdb/testsuite/gdb.dap/memory.c create mode 100644 gdb/testsuite/gdb.dap/memory.exp diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in index ff1340c44c0..39979037245 100644 --- a/gdb/data-directory/Makefile.in +++ b/gdb/data-directory/Makefile.in @@ -96,6 +96,7 @@ PYTHON_FILE_LIST = \ gdb/dap/__init__.py \ gdb/dap/io.py \ gdb/dap/launch.py \ + gdb/dap/memory.py \ gdb/dap/next.py \ gdb/dap/pause.py \ gdb/dap/scopes.py \ diff --git a/gdb/python/lib/gdb/dap/__init__.py b/gdb/python/lib/gdb/dap/__init__.py index 9038e108f40..014fd086f4b 100644 --- a/gdb/python/lib/gdb/dap/__init__.py +++ b/gdb/python/lib/gdb/dap/__init__.py @@ -25,6 +25,7 @@ from . import bt from . import disassemble from . import evaluate from . import launch +from . import memory from . import next from . import pause from . import scopes diff --git a/gdb/python/lib/gdb/dap/memory.py b/gdb/python/lib/gdb/dap/memory.py new file mode 100644 index 00000000000..7eb8a27ce47 --- /dev/null +++ b/gdb/python/lib/gdb/dap/memory.py @@ -0,0 +1,51 @@ +# 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 . + +import base64 +import gdb + +from .server import request, capability +from .startup import send_gdb_with_response, in_gdb_thread + + +@in_gdb_thread +def _read_memory(addr, count): + buf = gdb.selected_inferior().read_memory(addr, count) + return base64.b64encode(buf).decode("ASCII") + + +@request("readMemory") +@capability("supportsReadMemoryRequest") +def read_memory(*, memoryReference, offset=0, count, **extra): + addr = int(memoryReference, 0) + offset + buf = send_gdb_with_response(lambda: _read_memory(addr, count)) + return { + "address": hex(addr), + "data": buf, + } + + +@in_gdb_thread +def _write_memory(addr, contents): + buf = base64.b64decode(contents) + gdb.selected_inferior().write_memory(addr, buf) + + +@request("writeMemory") +@capability("supportsWriteMemoryRequest") +def write_memory(*, memoryReference, offset=0, data, **extra): + addr = int(memoryReference, 0) + offset + send_gdb_with_response(lambda: _write_memory(addr, data)) + return {} diff --git a/gdb/python/lib/gdb/dap/varref.py b/gdb/python/lib/gdb/dap/varref.py index 888415a322d..88c34c20468 100644 --- a/gdb/python/lib/gdb/dap/varref.py +++ b/gdb/python/lib/gdb/dap/varref.py @@ -116,6 +116,7 @@ class VariableReference(BaseReference): RESULT_NAME can be used to change how the simple string result is emitted in the result dictionary.""" super().__init__(name) + self.value = value self.printer = gdb.printing.make_visualizer(value) self.result_name = result_name # We cache all the children we create. @@ -160,6 +161,10 @@ class VariableReference(BaseReference): result["indexedVariables"] = num_children else: result["namedVariables"] = num_children + if self.value.type.code == gdb.TYPE_CODE_PTR: + result["memoryReference"] = hex(int(self.value)) + elif self.value.address is not None: + result["memoryReference"] = hex(int(self.value.address)) return result @in_gdb_thread diff --git a/gdb/testsuite/gdb.dap/memory.c b/gdb/testsuite/gdb.dap/memory.c new file mode 100644 index 00000000000..3b9f6138abe --- /dev/null +++ b/gdb/testsuite/gdb.dap/memory.c @@ -0,0 +1,25 @@ +/* Copyright 2023 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +#include + +uint32_t thirty_two = 7; + +int main () +{ + return 0; /* BREAK */ +} diff --git a/gdb/testsuite/gdb.dap/memory.exp b/gdb/testsuite/gdb.dap/memory.exp new file mode 100644 index 00000000000..fec552c4124 --- /dev/null +++ b/gdb/testsuite/gdb.dap/memory.exp @@ -0,0 +1,85 @@ +# 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 . + +# Test DAP read/write memory. + +load_lib dap-support.exp + +standard_testfile + +if {[build_executable ${testfile}.exp $testfile] == -1} { + return +} + +if {[dap_launch $testfile] == ""} { + return +} + +set line [gdb_get_line_number "BREAK"] +set obj [dap_check_request_and_response "set breakpoint by line number" \ + setBreakpoints \ + [format {o source [o path [%s]] breakpoints [a [o line [i %d]]]} \ + [list s $srcfile] $line]] +set line_bpno [dap_get_breakpoint_number $obj] + +dap_check_request_and_response "start inferior" configurationDone +dap_wait_for_event_and_check "inferior started" thread "body reason" started + +dap_wait_for_event_and_check "stopped at line breakpoint" stopped \ + "body reason" breakpoint \ + "body hitBreakpointIds" $line_bpno + +set obj [dap_check_request_and_response "evaluate global" \ + evaluate {o expression [s thirty_two]}] +dap_match_values "global value" [lindex $obj 0] "body result" 7 + +set addr [dict get [lindex $obj 0] body memoryReference] + +set obj [dap_check_request_and_response "read memory" \ + readMemory [format {o memoryReference [s %s] count [i 4]} $addr]] + +set bytes [binary decode base64 [dict get [lindex $obj 0] body data]] +gdb_assert {[string length $bytes] == 4} + +set newbytes "" +set zeros 0 +set sevens 0 +set others 0 +foreach byte [split $bytes ""] { + if {$byte == "\0"} { + incr zeros + append newbytes $byte + } elseif {$byte == "\x7"} { + incr sevens + append newbytes "\x8" + } else { + incr others + } +} +gdb_assert {$zeros == 3} +gdb_assert {$sevens == 1} +gdb_assert {$others == 0} + +set encoded [binary encode base64 $newbytes] + +set obj [dap_check_request_and_response "write memory" \ + writeMemory [format {o memoryReference [s %s] count [i 4] data [s %s]} \ + $addr $encoded]] + +set obj [dap_check_request_and_response "re-evaluate global" \ + evaluate {o expression [s thirty_two]}] +dap_match_values "updated global value" [lindex $obj 0] "body result" 8 + +dap_shutdown -- 2.39.1