https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104317
>From 88b48a5df0153a44276f14872c48e10639dcb673 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Wed, 14 Aug 2024 11:52:40 +0000 Subject: [PATCH 01/10] [lldb-dap] Support inspecting memory Adds support for the `readMemory` request which allows VS-Code to inspect memory. Also, add `memoryReference` to variablesa and `evaluate` responses, such that the binary view can be opened from the variables view and from the "watch" pane. --- .../test/tools/lldb-dap/dap_server.py | 13 ++ lldb/test/API/tools/lldb-dap/memory/Makefile | 3 + .../tools/lldb-dap/memory/TestDAP_memory.py | 135 +++++++++++++ lldb/test/API/tools/lldb-dap/memory/main.cpp | 10 + lldb/tools/lldb-dap/JSONUtils.cpp | 29 ++- lldb/tools/lldb-dap/JSONUtils.h | 6 + lldb/tools/lldb-dap/lldb-dap.cpp | 177 +++++++++++++++++- 7 files changed, 367 insertions(+), 6 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/memory/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py create mode 100644 lldb/test/API/tools/lldb-dap/memory/main.cpp diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index c6417760f17a2b..78c0f6233413b6 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -691,6 +691,19 @@ def request_disassemble( for inst in instructions: self.disassembled_instructions[inst["address"]] = inst + def request_read_memory(self, memoryReference, offset, count): + args_dict = { + "memoryReference": memoryReference, + "offset": offset, + "count": count, + } + command_dict = { + "command": "readMemory", + "type": "request", + "arguments": args_dict, + } + return self.send_recv(command_dict) + def request_evaluate(self, expression, frameIndex=0, threadId=None, context=None): stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) if stackFrame is None: diff --git a/lldb/test/API/tools/lldb-dap/memory/Makefile b/lldb/test/API/tools/lldb-dap/memory/Makefile new file mode 100644 index 00000000000000..99998b20bcb050 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/memory/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py new file mode 100644 index 00000000000000..f950d5eecda671 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py @@ -0,0 +1,135 @@ +""" +Test lldb-dap memory support +""" + +from base64 import b64decode +import dap_server +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbdap_testcase +import os + + +class TestDAP_memory(lldbdap_testcase.DAPTestCaseBase): + def test_read_memory(self): + """ + Tests the 'read_memory' request + """ + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + source = "main.cpp" + self.source_path = os.path.join(os.getcwd(), source) + self.set_source_breakpoints( + source, + [line_number(source, "// Breakpoint")], + ) + self.continue_to_next_stop() + + locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + rawptr_ref = locals["rawptr"]["memoryReference"] + + # We can read the complete string + mem = self.dap_server.request_read_memory(rawptr_ref, 0, 5)["body"] + self.assertEqual(mem["unreadableBytes"], 0) + self.assertEqual(b64decode(mem["data"]), b"dead\0") + + # Use an offset + mem = self.dap_server.request_read_memory(rawptr_ref, 2, 3)["body"] + self.assertEqual(b64decode(mem["data"]), b"ad\0") + + # Use a negative offset + mem = self.dap_server.request_read_memory(rawptr_ref, -1, 6)["body"] + self.assertEqual(b64decode(mem["data"])[1:], b"dead\0") + + # Reads of size 0 are successful + # VS-Code sends those in order to check if a `memoryReference` can actually be dereferenced. + mem = self.dap_server.request_read_memory(rawptr_ref, 0, 0) + self.assertEqual(mem["success"], True) + self.assertEqual(mem["body"]["data"], "") + + # Reads at offset 0x0 fail + mem = self.dap_server.request_read_memory("0x0", 0, 6) + self.assertEqual(mem["success"], False) + self.assertTrue(mem["message"].startswith("Unable to read memory: ")) + + def test_memory_refs_variables(self): + """ + Tests memory references for evaluate + """ + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + source = "main.cpp" + self.source_path = os.path.join(os.getcwd(), source) + self.set_source_breakpoints( + source, + [line_number(source, "// Breakpoint")], + ) + self.continue_to_next_stop() + + locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + + # Pointers should have memory-references + self.assertIn("memoryReference", locals["rawptr"].keys()) + # Smart pointers also have memory-references + self.assertIn( + "memoryReference", + self.dap_server.get_local_variable_child("smartptr", "pointer").keys(), + ) + # Non-pointers should not have memory-references + self.assertNotIn("memoryReference", locals["not_a_ptr"].keys()) + + def test_memory_refs_evaluate(self): + """ + Tests memory references for evaluate + """ + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + source = "main.cpp" + self.source_path = os.path.join(os.getcwd(), source) + self.set_source_breakpoints( + source, + [line_number(source, "// Breakpoint")], + ) + self.continue_to_next_stop() + + # Pointers contain memory references + self.assertIn( + "memoryReference", + self.dap_server.request_evaluate("rawptr + 1")["body"].keys(), + ) + + # Non-pointer expressions don't include a memory reference + self.assertNotIn( + "memoryReference", + self.dap_server.request_evaluate("1 + 3")["body"].keys(), + ) + + def test_memory_refs_set_variable(self): + """ + Tests memory references for `setVariable` + """ + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + source = "main.cpp" + self.source_path = os.path.join(os.getcwd(), source) + self.set_source_breakpoints( + source, + [line_number(source, "// Breakpoint")], + ) + self.continue_to_next_stop() + + # Pointers contain memory references + ptr_value = self.get_local_as_int("rawptr") + self.assertIn( + "memoryReference", + self.dap_server.request_setVariable(1, "rawptr", ptr_value + 2)[ + "body" + ].keys(), + ) + + # Non-pointer expressions don't include a memory reference + self.assertNotIn( + "memoryReference", + self.dap_server.request_setVariable(1, "not_a_ptr", 42)["body"].keys(), + ) diff --git a/lldb/test/API/tools/lldb-dap/memory/main.cpp b/lldb/test/API/tools/lldb-dap/memory/main.cpp new file mode 100644 index 00000000000000..807b010d2434d6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/memory/main.cpp @@ -0,0 +1,10 @@ +#include <iostream> +#include <memory> + +int main() { + int not_a_ptr = 666; + const char *rawptr = "dead"; + std::unique_ptr<int> smartptr(new int(42)); + // Breakpoint + return 0; +} diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index f175079c6f1fb5..5641cee43605d5 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -1180,6 +1180,19 @@ std::string VariableDescription::GetResult(llvm::StringRef context) { return description.trim().str(); } +lldb::addr_t GetMemoryReference(lldb::SBValue v) { + if (!v.GetType().IsPointerType() && !v.GetType().IsArrayType()) { + return LLDB_INVALID_ADDRESS; + } + + lldb::SBValue deref = v.Dereference(); + if (!deref.IsValid()) { + return LLDB_INVALID_ADDRESS; + } + + return deref.GetLoadAddress(); +} + // "Variable": { // "type": "object", // "description": "A Variable is a name/value pair. Optionally a variable @@ -1239,8 +1252,16 @@ std::string VariableDescription::GetResult(llvm::StringRef context) { // can use this optional information to present the // children in a paged UI and fetch them in chunks." // } -// -// +// "memoryReference": { +// "type": "string", +// "description": "A memory reference associated with this variable. +// For pointer type variables, this is generally a +// reference to the memory address contained in the +// pointer. For executable data, this reference may later +// be used in a `disassemble` request. This attribute may +// be returned by a debug adapter if corresponding +// capability `supportsMemoryReferences` is true." +// }, // "$__lldb_extensions": { // "description": "Unofficial extensions to the protocol", // "properties": { @@ -1348,6 +1369,10 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, else object.try_emplace("variablesReference", (int64_t)0); + if (lldb::addr_t addr = GetMemoryReference(v); addr != LLDB_INVALID_ADDRESS) { + object.try_emplace("memoryReference", "0x" + llvm::utohexstr(addr)); + } + object.try_emplace("$__lldb_extensions", desc.GetVariableExtensionsJSON()); return llvm::json::Value(std::move(object)); } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index f8fec22d7aa0ea..68c338423ad7e7 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -441,6 +441,12 @@ struct VariableDescription { std::string GetResult(llvm::StringRef context); }; +/// Get the corresponding `memoryReference` for a value. +/// +/// According to the DAP documentation, the `memoryReference` should +/// refer to the pointee, not to the address of the pointer itself. +lldb::addr_t GetMemoryReference(lldb::SBValue v); + /// Create a "Variable" object for a LLDB thread object. /// /// This function will fill in the following keys in the returned diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index c2ebc9a96a9a29..55d5cb7b73e906 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -9,6 +9,7 @@ #include "DAP.h" #include "Watchpoint.h" #include "lldb/API/SBMemoryRegionInfo.h" +#include "llvm/Support/Base64.h" #include <cassert> #include <climits> @@ -1541,6 +1542,16 @@ void request_completions(const llvm::json::Object &request) { // present the variables in a paged UI and fetch // them in chunks." // } +// "memoryReference": { +// "type": "string", +// "description": "A memory reference to a location appropriate +// for this result. For pointer type eval +// results, this is generally a reference to the +// memory address contained in the pointer. This +// attribute may be returned by a debug adapter +// if corresponding capability +// `supportsMemoryReferences` is true." +// }, // }, // "required": [ "result", "variablesReference" ] // } @@ -1606,6 +1617,10 @@ void request_evaluate(const llvm::json::Object &request) { } else { body.try_emplace("variablesReference", (int64_t)0); } + if (lldb::addr_t addr = GetMemoryReference(value); + addr != LLDB_INVALID_ADDRESS) { + body.try_emplace("memoryReference", "0x" + llvm::utohexstr(addr)); + } } } response.try_emplace("body", std::move(body)); @@ -1875,6 +1890,8 @@ void request_initialize(const llvm::json::Object &request) { // The debug adapter supports stepping granularities (argument `granularity`) // for the stepping requests. body.try_emplace("supportsSteppingGranularity", true); + // The debug adapter support for instruction breakpoint. + body.try_emplace("supportsInstructionBreakpoints", true); llvm::json::Array completion_characters; completion_characters.emplace_back("."); @@ -1916,8 +1933,8 @@ void request_initialize(const llvm::json::Object &request) { body.try_emplace("supportsLogPoints", true); // The debug adapter supports data watchpoints. body.try_emplace("supportsDataBreakpoints", true); - // The debug adapter support for instruction breakpoint. - body.try_emplace("supportsInstructionBreakpoints", true); + // The debug adapter supports the `readMemory` request. + body.try_emplace("supportsReadMemoryRequest", true); // Put in non-DAP specification lldb specific information. llvm::json::Object lldb_json; @@ -3775,8 +3792,12 @@ void request_setVariable(const llvm::json::Object &request) { if (variable.MightHaveChildren()) newVariablesReference = g_dap.variables.InsertExpandableVariable( variable, /*is_permanent=*/false); - body.try_emplace("variablesReference", newVariablesReference); + + if (lldb::addr_t addr = GetMemoryReference(variable); + addr != LLDB_INVALID_ADDRESS) { + body.try_emplace("memoryReference", "0x" + llvm::utohexstr(addr)); + } } else { EmplaceSafeString(body, "message", std::string(error.GetCString())); } @@ -4201,6 +4222,154 @@ void request_disassemble(const llvm::json::Object &request) { response.try_emplace("body", std::move(body)); g_dap.SendJSON(llvm::json::Value(std::move(response))); } + +// "ReadMemoryRequest": { +// "allOf": [ { "$ref": "#/definitions/Request" }, { +// "type": "object", +// "description": "Reads bytes from memory at the provided location. Clients +// should only call this request if the corresponding +// capability `supportsReadMemoryRequest` is true.", +// "properties": { +// "command": { +// "type": "string", +// "enum": [ "readMemory" ] +// }, +// "arguments": { +// "$ref": "#/definitions/ReadMemoryArguments" +// } +// }, +// "required": [ "command", "arguments" ] +// }] +// }, +// "ReadMemoryArguments": { +// "type": "object", +// "description": "Arguments for `readMemory` request.", +// "properties": { +// "memoryReference": { +// "type": "string", +// "description": "Memory reference to the base location from which data +// should be read." +// }, +// "offset": { +// "type": "integer", +// "description": "Offset (in bytes) to be applied to the reference +// location before reading data. Can be negative." +// }, +// "count": { +// "type": "integer", +// "description": "Number of bytes to read at the specified location and +// offset." +// } +// }, +// "required": [ "memoryReference", "count" ] +// }, +// "ReadMemoryResponse": { +// "allOf": [ { "$ref": "#/definitions/Response" }, { +// "type": "object", +// "description": "Response to `readMemory` request.", +// "properties": { +// "body": { +// "type": "object", +// "properties": { +// "address": { +// "type": "string", +// "description": "The address of the first byte of data returned. +// Treated as a hex value if prefixed with `0x`, or +// as a decimal value otherwise." +// }, +// "unreadableBytes": { +// "type": "integer", +// "description": "The number of unreadable bytes encountered after +// the last successfully read byte.\nThis can be +// used to determine the number of bytes that should +// be skipped before a subsequent +// `readMemory` request succeeds." +// }, +// "data": { +// "type": "string", +// "description": "The bytes read from memory, encoded using base64. +// If the decoded length of `data` is less than the +// requested `count` in the original `readMemory` +// request, and `unreadableBytes` is zero or +// omitted, then the client should assume it's +// reached the end of readable memory." +// } +// }, +// "required": [ "address" ] +// } +// } +// }] +// }, +void request_readMemory(const llvm::json::Object &request) { + llvm::json::Object response; + FillResponse(request, response); + auto arguments = request.getObject("arguments"); + + lldb::SBProcess process = g_dap.target.GetProcess(); + if (!process.IsValid()) { + response["success"] = false; + response["message"] = "No process running"; + g_dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } + + auto memoryReference = GetString(arguments, "memoryReference"); + lldb::addr_t addr; + if (memoryReference.consumeInteger(0, addr)) { + response["success"] = false; + response["message"] = + "Malformed memory reference: " + memoryReference.str(); + g_dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } + + addr += GetSigned(arguments, "offset", 0); + const auto requested_count = GetUnsigned(arguments, "count", 0); + lldb::SBMemoryRegionInfo region_info; + lldb::SBError memRegError = process.GetMemoryRegionInfo(addr, region_info); + if (memRegError.Fail()) { + response["success"] = false; + EmplaceSafeString(response, "message", + "Unable to find memory region: " + + std::string(memRegError.GetCString())); + g_dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } + const auto available_count = + std::min(requested_count, region_info.GetRegionEnd() - addr); + const auto unavailable_count = requested_count - available_count; + + std::vector<uint8_t> buf; + buf.resize(available_count); + if (available_count > 0) { + lldb::SBError memReadError; + auto bytes_read = + process.ReadMemory(addr, buf.data(), available_count, memReadError); + if (memReadError.Fail()) { + response["success"] = false; + EmplaceSafeString(response, "message", + "Unable to read memory: " + + std::string(memReadError.GetCString())); + g_dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } + if (bytes_read != available_count) { + response["success"] = false; + EmplaceSafeString(response, "message", "Unexpected, short read"); + g_dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } + } + + llvm::json::Object body; + std::string formatted_addr = "0x" + llvm::utohexstr(addr); + body.try_emplace("address", formatted_addr); + body.try_emplace("data", llvm::encodeBase64(buf)); + body.try_emplace("unreadableBytes", unavailable_count); + response.try_emplace("body", std::move(body)); + g_dap.SendJSON(llvm::json::Value(std::move(response))); +} + // A request used in testing to get the details on all breakpoints that are // currently set in the target. This helps us to test "setBreakpoints" and // "setFunctionBreakpoints" requests to verify we have the correct set of @@ -4499,7 +4668,7 @@ void RegisterRequestCallbacks() { g_dap.RegisterRequestCallback("threads", request_threads); g_dap.RegisterRequestCallback("variables", request_variables); g_dap.RegisterRequestCallback("disassemble", request_disassemble); - // Instruction breakpoint request + g_dap.RegisterRequestCallback("readMemory", request_readMemory); g_dap.RegisterRequestCallback("setInstructionBreakpoints", request_setInstructionBreakpoints); // Custom requests >From ea52649e84867b55eb04cca9566e631c16b81abd Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Thu, 15 Aug 2024 10:19:39 +0000 Subject: [PATCH 02/10] Address code style comments --- lldb/tools/lldb-dap/JSONUtils.cpp | 24 ++++++++++-------------- lldb/tools/lldb-dap/JSONUtils.h | 2 +- lldb/tools/lldb-dap/lldb-dap.cpp | 20 ++++++++------------ 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 5641cee43605d5..4e6502ac33317f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -690,8 +690,7 @@ std::optional<llvm::json::Value> CreateSource(lldb::SBFrame &frame) { // "instructionPointerReference": { // "type": "string", // "description": "A memory reference for the current instruction -// pointer -// in this frame." +// pointer in this frame." // }, // "moduleId": { // "type": ["integer", "string"], @@ -1180,17 +1179,15 @@ std::string VariableDescription::GetResult(llvm::StringRef context) { return description.trim().str(); } -lldb::addr_t GetMemoryReference(lldb::SBValue v) { - if (!v.GetType().IsPointerType() && !v.GetType().IsArrayType()) { - return LLDB_INVALID_ADDRESS; - } +std::optional<lldb::addr_t> GetMemoryReference(lldb::SBValue v) { + if (!v.GetType().IsPointerType() && !v.GetType().IsArrayType()) + return std::nullopt; lldb::SBValue deref = v.Dereference(); - if (!deref.IsValid()) { - return LLDB_INVALID_ADDRESS; - } - - return deref.GetLoadAddress(); + lldb::addr_t load_addr = deref.GetLoadAddress(); + if (load_addr != LLDB_INVALID_ADDRESS) + return load_addr; + return std::nullopt; } // "Variable": { @@ -1369,9 +1366,8 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, else object.try_emplace("variablesReference", (int64_t)0); - if (lldb::addr_t addr = GetMemoryReference(v); addr != LLDB_INVALID_ADDRESS) { - object.try_emplace("memoryReference", "0x" + llvm::utohexstr(addr)); - } + if (std::optional<lldb::addr_t> addr = GetMemoryReference(v)) + object.try_emplace("memoryReference", "0x" + llvm::utohexstr(*addr)); object.try_emplace("$__lldb_extensions", desc.GetVariableExtensionsJSON()); return llvm::json::Value(std::move(object)); diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 68c338423ad7e7..43fb0c5d95300d 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -445,7 +445,7 @@ struct VariableDescription { /// /// According to the DAP documentation, the `memoryReference` should /// refer to the pointee, not to the address of the pointer itself. -lldb::addr_t GetMemoryReference(lldb::SBValue v); +std::optional<lldb::addr_t> GetMemoryReference(lldb::SBValue v); /// Create a "Variable" object for a LLDB thread object. /// diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index 55d5cb7b73e906..ffe03d54e8cde0 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -1617,10 +1617,8 @@ void request_evaluate(const llvm::json::Object &request) { } else { body.try_emplace("variablesReference", (int64_t)0); } - if (lldb::addr_t addr = GetMemoryReference(value); - addr != LLDB_INVALID_ADDRESS) { - body.try_emplace("memoryReference", "0x" + llvm::utohexstr(addr)); - } + if (std::optional<lldb::addr_t> addr = GetMemoryReference(value)) + body.try_emplace("memoryReference", "0x" + llvm::utohexstr(*addr)); } } response.try_emplace("body", std::move(body)); @@ -3794,10 +3792,8 @@ void request_setVariable(const llvm::json::Object &request) { variable, /*is_permanent=*/false); body.try_emplace("variablesReference", newVariablesReference); - if (lldb::addr_t addr = GetMemoryReference(variable); - addr != LLDB_INVALID_ADDRESS) { - body.try_emplace("memoryReference", "0x" + llvm::utohexstr(addr)); - } + if (std::optional<lldb::addr_t> addr = GetMemoryReference(variable)) + body.try_emplace("memoryReference", "0x" + llvm::utohexstr(*addr)); } else { EmplaceSafeString(body, "message", std::string(error.GetCString())); } @@ -4324,7 +4320,7 @@ void request_readMemory(const llvm::json::Object &request) { } addr += GetSigned(arguments, "offset", 0); - const auto requested_count = GetUnsigned(arguments, "count", 0); + const uint64_t requested_count = GetUnsigned(arguments, "count", 0); lldb::SBMemoryRegionInfo region_info; lldb::SBError memRegError = process.GetMemoryRegionInfo(addr, region_info); if (memRegError.Fail()) { @@ -4335,15 +4331,15 @@ void request_readMemory(const llvm::json::Object &request) { g_dap.SendJSON(llvm::json::Value(std::move(response))); return; } - const auto available_count = + const uint64_t available_count = std::min(requested_count, region_info.GetRegionEnd() - addr); - const auto unavailable_count = requested_count - available_count; + const uint64_t unavailable_count = requested_count - available_count; std::vector<uint8_t> buf; buf.resize(available_count); if (available_count > 0) { lldb::SBError memReadError; - auto bytes_read = + uint64_t bytes_read = process.ReadMemory(addr, buf.data(), available_count, memReadError); if (memReadError.Fail()) { response["success"] = false; >From 8822955cdb3315ab4a932322ea659cda12192c43 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Thu, 15 Aug 2024 10:39:38 +0000 Subject: [PATCH 03/10] Check memory region readability --- lldb/tools/lldb-dap/lldb-dap.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index ffe03d54e8cde0..ded0027520f98f 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -4331,6 +4331,12 @@ void request_readMemory(const llvm::json::Object &request) { g_dap.SendJSON(llvm::json::Value(std::move(response))); return; } + if (!region_info.IsReadable()) { + response["success"] = false; + response.try_emplace("message", "Memory region is not readable"); + g_dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } const uint64_t available_count = std::min(requested_count, region_info.GetRegionEnd() - addr); const uint64_t unavailable_count = requested_count - available_count; >From 201cacb1ec9b54bfa1b0a6b2c96514342c552b5c Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Thu, 15 Aug 2024 10:41:09 +0000 Subject: [PATCH 04/10] Fix variable naming --- lldb/tools/lldb-dap/lldb-dap.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index ded0027520f98f..40de2a1e4aebc2 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -4322,12 +4322,12 @@ void request_readMemory(const llvm::json::Object &request) { addr += GetSigned(arguments, "offset", 0); const uint64_t requested_count = GetUnsigned(arguments, "count", 0); lldb::SBMemoryRegionInfo region_info; - lldb::SBError memRegError = process.GetMemoryRegionInfo(addr, region_info); - if (memRegError.Fail()) { + lldb::SBError memreg_error = process.GetMemoryRegionInfo(addr, region_info); + if (memreg_error.Fail()) { response["success"] = false; EmplaceSafeString(response, "message", "Unable to find memory region: " + - std::string(memRegError.GetCString())); + std::string(memreg_error.GetCString())); g_dap.SendJSON(llvm::json::Value(std::move(response))); return; } @@ -4344,14 +4344,14 @@ void request_readMemory(const llvm::json::Object &request) { std::vector<uint8_t> buf; buf.resize(available_count); if (available_count > 0) { - lldb::SBError memReadError; + lldb::SBError memread_error; uint64_t bytes_read = - process.ReadMemory(addr, buf.data(), available_count, memReadError); - if (memReadError.Fail()) { + process.ReadMemory(addr, buf.data(), available_count, memread_error); + if (memread_error.Fail()) { response["success"] = false; EmplaceSafeString(response, "message", "Unable to read memory: " + - std::string(memReadError.GetCString())); + std::string(memread_error.GetCString())); g_dap.SendJSON(llvm::json::Value(std::move(response))); return; } >From 05f4a3b0a3e3d5c8aacde3058ac1db71046f68c2 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Thu, 15 Aug 2024 10:53:28 +0000 Subject: [PATCH 05/10] Adjust test case --- lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py index f950d5eecda671..536b4afb8e0719 100644 --- a/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py +++ b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py @@ -51,7 +51,7 @@ def test_read_memory(self): # Reads at offset 0x0 fail mem = self.dap_server.request_read_memory("0x0", 0, 6) self.assertEqual(mem["success"], False) - self.assertTrue(mem["message"].startswith("Unable to read memory: ")) + self.assertEqual(mem["message"], "Memory region is not readable") def test_memory_refs_variables(self): """ >From cd708b96a5aa0f2b0948d6f9045a9d2dc24f7e6f Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Fri, 16 Aug 2024 11:49:30 +0000 Subject: [PATCH 06/10] Introduce `EncodeMemoryReference` & `DecodeMemoryReference` --- lldb/tools/lldb-dap/JSONUtils.cpp | 18 +++++++++++++++++- lldb/tools/lldb-dap/JSONUtils.h | 7 +++++++ lldb/tools/lldb-dap/lldb-dap.cpp | 22 ++++++++++++---------- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 4e6502ac33317f..376fafdab7c1ac 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -112,6 +112,22 @@ bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key) { return obj.find(key) != obj.end(); } +std::string EncodeMemoryReference(lldb::addr_t addr) { + return "0x" + llvm::utohexstr(addr); +} + +std::optional<lldb::addr_t> +DecodeMemoryReference(llvm::StringRef memoryReference) { + if (!memoryReference.starts_with("0x")) + return std::nullopt; + + lldb::addr_t addr; + if (memoryReference.consumeInteger(0, addr)) + return std::nullopt; + + return addr; +} + std::vector<std::string> GetStrings(const llvm::json::Object *obj, llvm::StringRef key) { std::vector<std::string> strs; @@ -1367,7 +1383,7 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, object.try_emplace("variablesReference", (int64_t)0); if (std::optional<lldb::addr_t> addr = GetMemoryReference(v)) - object.try_emplace("memoryReference", "0x" + llvm::utohexstr(*addr)); + object.try_emplace("memoryReference", EncodeMemoryReference(*addr)); object.try_emplace("$__lldb_extensions", desc.GetVariableExtensionsJSON()); return llvm::json::Value(std::move(object)); diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 43fb0c5d95300d..6102ac53e6c989 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -131,6 +131,13 @@ int64_t GetSigned(const llvm::json::Object *obj, llvm::StringRef key, /// \b True if the key exists in the \a obj, \b False otherwise. bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key); +/// Encodes a memory reference +std::string EncodeMemoryReference(lldb::addr_t addr); + +/// Decodes a memory reference +std::optional<lldb::addr_t> +DecodeMemoryReference(llvm::StringRef memoryReference); + /// Extract an array of strings for the specified key from an object. /// /// String values in the array will be extracted without any quotes diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index 40de2a1e4aebc2..fd25f2a3a9f50d 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -1618,7 +1618,7 @@ void request_evaluate(const llvm::json::Object &request) { body.try_emplace("variablesReference", (int64_t)0); } if (std::optional<lldb::addr_t> addr = GetMemoryReference(value)) - body.try_emplace("memoryReference", "0x" + llvm::utohexstr(*addr)); + body.try_emplace("memoryReference", EncodeMemoryReference(*addr)); } } response.try_emplace("body", std::move(body)); @@ -3793,7 +3793,7 @@ void request_setVariable(const llvm::json::Object &request) { body.try_emplace("variablesReference", newVariablesReference); if (std::optional<lldb::addr_t> addr = GetMemoryReference(variable)) - body.try_emplace("memoryReference", "0x" + llvm::utohexstr(*addr)); + body.try_emplace("memoryReference", EncodeMemoryReference(*addr)); } else { EmplaceSafeString(body, "message", std::string(error.GetCString())); } @@ -4090,17 +4090,18 @@ void request_variables(const llvm::json::Object &request) { void request_disassemble(const llvm::json::Object &request) { llvm::json::Object response; FillResponse(request, response); - auto arguments = request.getObject("arguments"); + auto *arguments = request.getObject("arguments"); - auto memoryReference = GetString(arguments, "memoryReference"); - lldb::addr_t addr_ptr; - if (memoryReference.consumeInteger(0, addr_ptr)) { + llvm::StringRef memoryReference = GetString(arguments, "memoryReference"); + auto addr_opt = DecodeMemoryReference(memoryReference); + if (!addr_opt.has_value()) { response["success"] = false; response["message"] = "Malformed memory reference: " + memoryReference.str(); g_dap.SendJSON(llvm::json::Value(std::move(response))); return; } + lldb::addr_t addr_ptr = *addr_opt; addr_ptr += GetSigned(arguments, "instructionOffset", 0); lldb::SBAddress addr(addr_ptr, g_dap.target); @@ -4299,7 +4300,7 @@ void request_disassemble(const llvm::json::Object &request) { void request_readMemory(const llvm::json::Object &request) { llvm::json::Object response; FillResponse(request, response); - auto arguments = request.getObject("arguments"); + auto* arguments = request.getObject("arguments"); lldb::SBProcess process = g_dap.target.GetProcess(); if (!process.IsValid()) { @@ -4309,15 +4310,16 @@ void request_readMemory(const llvm::json::Object &request) { return; } - auto memoryReference = GetString(arguments, "memoryReference"); - lldb::addr_t addr; - if (memoryReference.consumeInteger(0, addr)) { + llvm::StringRef memoryReference = GetString(arguments, "memoryReference"); + auto addr_opt = DecodeMemoryReference(memoryReference); + if (!addr_opt.has_value()) { response["success"] = false; response["message"] = "Malformed memory reference: " + memoryReference.str(); g_dap.SendJSON(llvm::json::Value(std::move(response))); return; } + lldb::addr_t addr = *addr_opt; addr += GetSigned(arguments, "offset", 0); const uint64_t requested_count = GetUnsigned(arguments, "count", 0); >From 3b7e326d1fec1e8f3354c55e23c4e633a79833cb Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Fri, 16 Aug 2024 12:01:53 +0000 Subject: [PATCH 07/10] Do not provide memory references for arrays. `Dereference` did not work anyway --- lldb/tools/lldb-dap/JSONUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 376fafdab7c1ac..942bf228aec663 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -1196,7 +1196,7 @@ std::string VariableDescription::GetResult(llvm::StringRef context) { } std::optional<lldb::addr_t> GetMemoryReference(lldb::SBValue v) { - if (!v.GetType().IsPointerType() && !v.GetType().IsArrayType()) + if (!v.GetType().IsPointerType()) return std::nullopt; lldb::SBValue deref = v.Dereference(); >From 12f37b6a57c06b2bddb0f3397913d21f05552518 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Mon, 19 Aug 2024 22:32:31 +0000 Subject: [PATCH 08/10] request_read_memory -> request_readMemory --- .../lldbsuite/test/tools/lldb-dap/dap_server.py | 2 +- .../API/tools/lldb-dap/memory/TestDAP_memory.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 78c0f6233413b6..d6a386975c8fb9 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -691,7 +691,7 @@ def request_disassemble( for inst in instructions: self.disassembled_instructions[inst["address"]] = inst - def request_read_memory(self, memoryReference, offset, count): + def request_readMemory(self, memoryReference, offset, count): args_dict = { "memoryReference": memoryReference, "offset": offset, diff --git a/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py index 536b4afb8e0719..f865c423a3da31 100644 --- a/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py +++ b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py @@ -12,9 +12,9 @@ class TestDAP_memory(lldbdap_testcase.DAPTestCaseBase): - def test_read_memory(self): + def test_readMemory(self): """ - Tests the 'read_memory' request + Tests the 'readMemory' request """ program = self.getBuildArtifact("a.out") self.build_and_launch(program) @@ -30,26 +30,26 @@ def test_read_memory(self): rawptr_ref = locals["rawptr"]["memoryReference"] # We can read the complete string - mem = self.dap_server.request_read_memory(rawptr_ref, 0, 5)["body"] + mem = self.dap_server.request_readMemory(rawptr_ref, 0, 5)["body"] self.assertEqual(mem["unreadableBytes"], 0) self.assertEqual(b64decode(mem["data"]), b"dead\0") # Use an offset - mem = self.dap_server.request_read_memory(rawptr_ref, 2, 3)["body"] + mem = self.dap_server.request_readMemory(rawptr_ref, 2, 3)["body"] self.assertEqual(b64decode(mem["data"]), b"ad\0") # Use a negative offset - mem = self.dap_server.request_read_memory(rawptr_ref, -1, 6)["body"] + mem = self.dap_server.request_readMemory(rawptr_ref, -1, 6)["body"] self.assertEqual(b64decode(mem["data"])[1:], b"dead\0") # Reads of size 0 are successful # VS-Code sends those in order to check if a `memoryReference` can actually be dereferenced. - mem = self.dap_server.request_read_memory(rawptr_ref, 0, 0) + mem = self.dap_server.request_readMemory(rawptr_ref, 0, 0) self.assertEqual(mem["success"], True) self.assertEqual(mem["body"]["data"], "") # Reads at offset 0x0 fail - mem = self.dap_server.request_read_memory("0x0", 0, 6) + mem = self.dap_server.request_readMemory("0x0", 0, 6) self.assertEqual(mem["success"], False) self.assertEqual(mem["message"], "Memory region is not readable") >From 6b23fbff90717e54563eaac0f18a6b28ae345cee Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Mon, 16 Sep 2024 08:09:10 +0000 Subject: [PATCH 09/10] Provide non-dereferenced memory references --- .../tools/lldb-dap/memory/TestDAP_memory.py | 101 +++++++----------- lldb/test/API/tools/lldb-dap/memory/main.cpp | 1 - lldb/tools/lldb-dap/JSONUtils.cpp | 15 +-- lldb/tools/lldb-dap/JSONUtils.h | 6 -- lldb/tools/lldb-dap/lldb-dap.cpp | 8 +- 5 files changed, 47 insertions(+), 84 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py index f865c423a3da31..8bee70e50dcad9 100644 --- a/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py +++ b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py @@ -12,9 +12,9 @@ class TestDAP_memory(lldbdap_testcase.DAPTestCaseBase): - def test_readMemory(self): + def test_memory_refs_variables(self): """ - Tests the 'readMemory' request + Tests memory references for evaluate """ program = self.getBuildArtifact("a.out") self.build_and_launch(program) @@ -27,33 +27,13 @@ def test_readMemory(self): self.continue_to_next_stop() locals = {l["name"]: l for l in self.dap_server.get_local_variables()} - rawptr_ref = locals["rawptr"]["memoryReference"] - - # We can read the complete string - mem = self.dap_server.request_readMemory(rawptr_ref, 0, 5)["body"] - self.assertEqual(mem["unreadableBytes"], 0) - self.assertEqual(b64decode(mem["data"]), b"dead\0") - - # Use an offset - mem = self.dap_server.request_readMemory(rawptr_ref, 2, 3)["body"] - self.assertEqual(b64decode(mem["data"]), b"ad\0") - - # Use a negative offset - mem = self.dap_server.request_readMemory(rawptr_ref, -1, 6)["body"] - self.assertEqual(b64decode(mem["data"])[1:], b"dead\0") - - # Reads of size 0 are successful - # VS-Code sends those in order to check if a `memoryReference` can actually be dereferenced. - mem = self.dap_server.request_readMemory(rawptr_ref, 0, 0) - self.assertEqual(mem["success"], True) - self.assertEqual(mem["body"]["data"], "") - # Reads at offset 0x0 fail - mem = self.dap_server.request_readMemory("0x0", 0, 6) - self.assertEqual(mem["success"], False) - self.assertEqual(mem["message"], "Memory region is not readable") + # Pointers should have memory-references + self.assertIn("memoryReference", locals["rawptr"].keys()) + # Non-pointers should also have memory-references + self.assertIn("memoryReference", locals["not_a_ptr"].keys()) - def test_memory_refs_variables(self): + def test_memory_refs_evaluate(self): """ Tests memory references for evaluate """ @@ -67,21 +47,14 @@ def test_memory_refs_variables(self): ) self.continue_to_next_stop() - locals = {l["name"]: l for l in self.dap_server.get_local_variables()} - - # Pointers should have memory-references - self.assertIn("memoryReference", locals["rawptr"].keys()) - # Smart pointers also have memory-references self.assertIn( "memoryReference", - self.dap_server.get_local_variable_child("smartptr", "pointer").keys(), + self.dap_server.request_evaluate("rawptr")["body"].keys(), ) - # Non-pointers should not have memory-references - self.assertNotIn("memoryReference", locals["not_a_ptr"].keys()) - def test_memory_refs_evaluate(self): + def test_memory_refs_set_variable(self): """ - Tests memory references for evaluate + Tests memory references for `setVariable` """ program = self.getBuildArtifact("a.out") self.build_and_launch(program) @@ -93,21 +66,17 @@ def test_memory_refs_evaluate(self): ) self.continue_to_next_stop() - # Pointers contain memory references + ptr_value = self.get_local_as_int("rawptr") self.assertIn( "memoryReference", - self.dap_server.request_evaluate("rawptr + 1")["body"].keys(), - ) - - # Non-pointer expressions don't include a memory reference - self.assertNotIn( - "memoryReference", - self.dap_server.request_evaluate("1 + 3")["body"].keys(), + self.dap_server.request_setVariable(1, "rawptr", ptr_value + 2)[ + "body" + ].keys(), ) - def test_memory_refs_set_variable(self): + def test_readMemory(self): """ - Tests memory references for `setVariable` + Tests the 'readMemory' request """ program = self.getBuildArtifact("a.out") self.build_and_launch(program) @@ -119,17 +88,29 @@ def test_memory_refs_set_variable(self): ) self.continue_to_next_stop() - # Pointers contain memory references - ptr_value = self.get_local_as_int("rawptr") - self.assertIn( - "memoryReference", - self.dap_server.request_setVariable(1, "rawptr", ptr_value + 2)[ - "body" - ].keys(), - ) + ptr_deref = self.dap_server.request_evaluate("*rawptr")["body"] + memref = ptr_deref["memoryReference"] - # Non-pointer expressions don't include a memory reference - self.assertNotIn( - "memoryReference", - self.dap_server.request_setVariable(1, "not_a_ptr", 42)["body"].keys(), - ) + # We can read the complete string + mem = self.dap_server.request_readMemory(memref, 0, 5)["body"] + self.assertEqual(mem["unreadableBytes"], 0) + self.assertEqual(b64decode(mem["data"]), b"dead\0") + + # Use an offset + mem = self.dap_server.request_readMemory(memref, 2, 3)["body"] + self.assertEqual(b64decode(mem["data"]), b"ad\0") + + # Use a negative offset + mem = self.dap_server.request_readMemory(memref, -1, 6)["body"] + self.assertEqual(b64decode(mem["data"])[1:], b"dead\0") + + # Reads of size 0 are successful + # VS-Code sends those in order to check if a `memoryReference` can actually be dereferenced. + mem = self.dap_server.request_readMemory(memref, 0, 0) + self.assertEqual(mem["success"], True) + self.assertEqual(mem["body"]["data"], "") + + # Reads at offset 0x0 fail + mem = self.dap_server.request_readMemory("0x0", 0, 6) + self.assertEqual(mem["success"], False) + self.assertEqual(mem["message"], "Memory region is not readable") diff --git a/lldb/test/API/tools/lldb-dap/memory/main.cpp b/lldb/test/API/tools/lldb-dap/memory/main.cpp index 807b010d2434d6..14ac1ad95e330f 100644 --- a/lldb/test/API/tools/lldb-dap/memory/main.cpp +++ b/lldb/test/API/tools/lldb-dap/memory/main.cpp @@ -4,7 +4,6 @@ int main() { int not_a_ptr = 666; const char *rawptr = "dead"; - std::unique_ptr<int> smartptr(new int(42)); // Breakpoint return 0; } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 942bf228aec663..4c07a8f4770179 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -1195,17 +1195,6 @@ std::string VariableDescription::GetResult(llvm::StringRef context) { return description.trim().str(); } -std::optional<lldb::addr_t> GetMemoryReference(lldb::SBValue v) { - if (!v.GetType().IsPointerType()) - return std::nullopt; - - lldb::SBValue deref = v.Dereference(); - lldb::addr_t load_addr = deref.GetLoadAddress(); - if (load_addr != LLDB_INVALID_ADDRESS) - return load_addr; - return std::nullopt; -} - // "Variable": { // "type": "object", // "description": "A Variable is a name/value pair. Optionally a variable @@ -1382,8 +1371,8 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, else object.try_emplace("variablesReference", (int64_t)0); - if (std::optional<lldb::addr_t> addr = GetMemoryReference(v)) - object.try_emplace("memoryReference", EncodeMemoryReference(*addr)); + if (lldb::addr_t addr = v.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS) + object.try_emplace("memoryReference", EncodeMemoryReference(addr)); object.try_emplace("$__lldb_extensions", desc.GetVariableExtensionsJSON()); return llvm::json::Value(std::move(object)); diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 6102ac53e6c989..e44101f98103d6 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -448,12 +448,6 @@ struct VariableDescription { std::string GetResult(llvm::StringRef context); }; -/// Get the corresponding `memoryReference` for a value. -/// -/// According to the DAP documentation, the `memoryReference` should -/// refer to the pointee, not to the address of the pointer itself. -std::optional<lldb::addr_t> GetMemoryReference(lldb::SBValue v); - /// Create a "Variable" object for a LLDB thread object. /// /// This function will fill in the following keys in the returned diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index fd25f2a3a9f50d..f4c77f2b0eabe0 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -1617,8 +1617,8 @@ void request_evaluate(const llvm::json::Object &request) { } else { body.try_emplace("variablesReference", (int64_t)0); } - if (std::optional<lldb::addr_t> addr = GetMemoryReference(value)) - body.try_emplace("memoryReference", EncodeMemoryReference(*addr)); + if (lldb::addr_t addr = value.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS) + body.try_emplace("memoryReference", EncodeMemoryReference(addr)); } } response.try_emplace("body", std::move(body)); @@ -3792,8 +3792,8 @@ void request_setVariable(const llvm::json::Object &request) { variable, /*is_permanent=*/false); body.try_emplace("variablesReference", newVariablesReference); - if (std::optional<lldb::addr_t> addr = GetMemoryReference(variable)) - body.try_emplace("memoryReference", EncodeMemoryReference(*addr)); + if (lldb::addr_t addr = variable.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS) + body.try_emplace("memoryReference", EncodeMemoryReference(addr)); } else { EmplaceSafeString(body, "message", std::string(error.GetCString())); } >From 95961c478ae827e790ebb4d4f48bc28e136d7b85 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Mon, 16 Sep 2024 12:55:06 +0000 Subject: [PATCH 10/10] Fix formatting --- lldb/tools/lldb-dap/JSONUtils.cpp | 4 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 4c07a8f4770179..c068111c63ac49 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -119,11 +119,11 @@ std::string EncodeMemoryReference(lldb::addr_t addr) { std::optional<lldb::addr_t> DecodeMemoryReference(llvm::StringRef memoryReference) { if (!memoryReference.starts_with("0x")) - return std::nullopt; + return std::nullopt; lldb::addr_t addr; if (memoryReference.consumeInteger(0, addr)) - return std::nullopt; + return std::nullopt; return addr; } diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index f4c77f2b0eabe0..7e17aeef1e53c6 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -1617,7 +1617,8 @@ void request_evaluate(const llvm::json::Object &request) { } else { body.try_emplace("variablesReference", (int64_t)0); } - if (lldb::addr_t addr = value.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS) + if (lldb::addr_t addr = value.GetLoadAddress(); + addr != LLDB_INVALID_ADDRESS) body.try_emplace("memoryReference", EncodeMemoryReference(addr)); } } @@ -3792,7 +3793,8 @@ void request_setVariable(const llvm::json::Object &request) { variable, /*is_permanent=*/false); body.try_emplace("variablesReference", newVariablesReference); - if (lldb::addr_t addr = variable.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS) + if (lldb::addr_t addr = variable.GetLoadAddress(); + addr != LLDB_INVALID_ADDRESS) body.try_emplace("memoryReference", EncodeMemoryReference(addr)); } else { EmplaceSafeString(body, "message", std::string(error.GetCString())); @@ -4300,7 +4302,7 @@ void request_disassemble(const llvm::json::Object &request) { void request_readMemory(const llvm::json::Object &request) { llvm::json::Object response; FillResponse(request, response); - auto* arguments = request.getObject("arguments"); + auto *arguments = request.getObject("arguments"); lldb::SBProcess process = g_dap.target.GetProcess(); if (!process.IsValid()) { _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits