From: Tom Tromey Date: Thu, 2 Mar 2023 20:51:17 +0000 (-0700) Subject: Add readMemory and writeMemory requests to DAP X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d466f7492eccccb0f3c0936c12b5b140e139e353;p=binutils-gdb.git Add readMemory and writeMemory requests to DAP 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. --- 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