[Lldb-commits] [lldb] [lldb-dap] Emit declarations along with variables (PR #74865)
vogelsgesang wrote: FYI @walter-erquinigo: There is a proposal under discussion to add first-class support for `declarationLocation` (and also `valueLocation`) to the debug adapter protocol. See https://github.com/microsoft/debug-adapter-protocol/issues/343 https://github.com/llvm/llvm-project/pull/74865 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang created https://github.com/llvm/llvm-project/pull/102928 `declarationLocation` is about to become part of the upstream debug adapter protocol (see microsoft/debug-adapter-protocol#343). This is a draft implementation, to be finalized and merged after the corresponding changes were merged into DAP. TODO: * Adjust comment on `CreateVariable` function with updated jsonschema as soon as the upstream changes were merged to DAP. * Update based on final protocol merged to DAP >From 5c3b3458eb3426e58ead2d66f0cc9530eb368dd3 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH] [lldb-dap] Provide `declarationLocation` for variables TODO: * Adjust comment on `CreateVariable` function with updated jsonschema as soon as the upstream changes were merged to DAP. `declarationLocation` is about to become part of the upstream debug-adapter-protocol. This is a draft implementation, to be finalized and merged after the corresponding changes were merged into DAP. --- .../lldb-dap/variables/TestDAP_variables.py| 4 lldb/tools/lldb-dap/JSONUtils.cpp | 18 -- lldb/tools/lldb-dap/JSONUtils.h| 14 -- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py index 3c6901b2fd99a5..7d982e801f741e 100644 --- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py +++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py @@ -168,6 +168,10 @@ def do_test_scopes_variables_setVariable_evaluate( "type": "int", "value": "1", }, +"declarationLocation": { +"equals": {"line": 12, "column": 14}, +"contains": {"path": ["lldb-dap", "variables", "main.cpp"]}, +}, "$__lldb_extensions": { "equals": { "value": "1", diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index a8b85f55939e17..3e0c1076643260 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -614,9 +614,8 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { // } // } // } -llvm::json::Value CreateSource(lldb::SBLineEntry &line_entry) { +llvm::json::Value CreateSource(const lldb::SBFileSpec &file) { llvm::json::Object object; - lldb::SBFileSpec file = line_entry.GetFileSpec(); if (file.IsValid()) { const char *name = file.GetFilename(); if (name) @@ -630,6 +629,10 @@ llvm::json::Value CreateSource(lldb::SBLineEntry &line_entry) { return llvm::json::Value(std::move(object)); } +llvm::json::Value CreateSource(const lldb::SBLineEntry &line_entry) { + return CreateSource(line_entry.GetFileSpec()); +} + llvm::json::Value CreateSource(llvm::StringRef source_path) { llvm::json::Object source; llvm::StringRef name = llvm::sys::path::filename(source_path); @@ -1253,6 +1256,17 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, else object.try_emplace("variablesReference", (int64_t)0); + if (lldb::SBDeclaration decl = v.GetDeclaration(); decl.IsValid()) { +llvm::json::Object decl_obj; +decl_obj.try_emplace("source", CreateSource(decl.GetFileSpec())); +if (int line = decl.GetLine()) + decl_obj.try_emplace("line", line); +if (int column = decl.GetColumn()) + decl_obj.try_emplace("column", column); + +object.try_emplace("declarationLocation", std::move(decl_obj)); + } + 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 1515f5ba2e5f4d..610f920952e77c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -282,6 +282,16 @@ llvm::json::Value CreateScope(const llvm::StringRef name, int64_t variablesReference, int64_t namedVariables, bool expensive); +/// Create a "Source" JSON object as described in the debug adaptor definition. +/// +/// \param[in] file +/// The SBFileSpec to use when populating out the "Source" object +/// +/// \return +/// A "Source" JSON object that follows the formal JSON +/// definition outlined by Microsoft. +llvm::json::Value CreateSource(const lldb::SBFileSpec &file); + /// Create a "Source" JSON object as described in the debug adaptor definition. /// /// \param[in] line_entry @@ -289,9 +299,9 @@ llvm::json::Value CreateScope(const llvm::StringRef name, /// object /// /// \return -/// A "Source" JSON object with that follows the formal JSON +/// A "Source" JSON object that follows the formal JSON ///
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
vogelsgesang wrote: @walter-erquinigo I took a first stab at implementing the DAP proposal. Seemed rather straightforward. I would love to hear if I missed anything. Also, I am not sure how to implement `valueLocation`, i.e., a the source location referecend by the value. E.g., for a function pointer, this location should point to the source location where the corresponding function was implemented. If you have any idea on how to do so, I would be interested in hearing about it 🙂 https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Expose log path in extension settings (PR #103482)
https://github.com/vogelsgesang created https://github.com/llvm/llvm-project/pull/103482 lldb-dap already supports a log file which can be enabled by setting the `LLDBDAP_LOG` environment variable. With this commit, the log location can be set directly through the VS-Code extension settings. Also, this commit bumps the version number, such that the new VS Code extension gets published to the Marketplace. >From 6c9da388efecf0e33acd6678081bfb04aca4939f Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Tue, 13 Aug 2024 00:34:42 + Subject: [PATCH] [lldb-dap] Expose log path in extension settings lldb-dap already supports a log file which can be enabled by setting the `LLDBDAP_LOG` environment variable. With this commit, the log location can be set directly through the VS-Code extension settings. Also, this commit bumps the version number, such that the new VS Code extension gets published to the Marketplace. --- lldb/tools/lldb-dap/package-lock.json | 4 ++-- lldb/tools/lldb-dap/package.json| 7 ++- lldb/tools/lldb-dap/src-ts/extension.ts | 26 - 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json index 8c70cc2d30e144..96570e42dbfdc4 100644 --- a/lldb/tools/lldb-dap/package-lock.json +++ b/lldb/tools/lldb-dap/package-lock.json @@ -1,12 +1,12 @@ { "name": "lldb-dap", - "version": "0.2.0", + "version": "0.2.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lldb-dap", - "version": "0.2.0", + "version": "0.2.4", "license": "Apache 2.0 License with LLVM exceptions", "devDependencies": { "@types/node": "^18.11.18", diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 97e4efe7bac19d..4f4261d1718c01 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -1,7 +1,7 @@ { "name": "lldb-dap", "displayName": "LLDB DAP", - "version": "0.2.3", + "version": "0.2.4", "publisher": "llvm-vs-code-extensions", "homepage": "https://lldb.llvm.org";, "description": "LLDB debugging from VSCode", @@ -73,6 +73,11 @@ "scope": "resource", "type": "string", "description": "The path to the lldb-dap binary." +}, +"lldb-dap.log-path": { + "scope": "resource", + "type": "string", + "description": "The log path for lldb-dap (if any)" } } }, diff --git a/lldb/tools/lldb-dap/src-ts/extension.ts b/lldb/tools/lldb-dap/src-ts/extension.ts index 791175f7b46224..7df09f7a29dad7 100644 --- a/lldb/tools/lldb-dap/src-ts/extension.ts +++ b/lldb/tools/lldb-dap/src-ts/extension.ts @@ -14,13 +14,29 @@ function createDefaultLLDBDapOptions(): LLDBDapOptions { session: vscode.DebugSession, packageJSONExecutable: vscode.DebugAdapterExecutable | undefined, ): Promise { - const path = vscode.workspace -.getConfiguration("lldb-dap", session.workspaceFolder) -.get("executable-path"); + const config = vscode.workspace +.getConfiguration("lldb-dap", session.workspaceFolder); + const path = config.get("executable-path"); + const log_path = config.get("log-path"); + + let env : { [key: string]: string } = {}; + if (log_path) { +env["LLDBDAP_LOG"] = log_path; + } + if (path) { -return new vscode.DebugAdapterExecutable(path, []); +return new vscode.DebugAdapterExecutable(path, [], {env}); + } else if (packageJSONExecutable) { +return new vscode.DebugAdapterExecutable(packageJSONExecutable.command, packageJSONExecutable.args, { + ...packageJSONExecutable.options, + env: { +...packageJSONExecutable.options?.env, +...env + } +}); + } else { +return undefined; } - return packageJSONExecutable; }, }; } ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
vogelsgesang wrote: No worries. I will have to rework this commit anyway. In the meantime, a proposal was merged upstream and also already implemented in VS-Code. However, there were still larger changes which will require a complete rewrite of this commit https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang created https://github.com/llvm/llvm-project/pull/104317 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. >From e01ea18961bbae0fb747b312670946bd768c5d73 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 14 Aug 2024 11:52:40 + Subject: [PATCH] [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 | 15 ++ lldb/test/API/tools/lldb-dap/memory/Makefile | 3 + .../tools/lldb-dap/memory/TestDAP_memory.py | 121 lldb/test/API/tools/lldb-dap/memory/main.cpp | 10 + lldb/tools/lldb-dap/JSONUtils.cpp | 30 ++- lldb/tools/lldb-dap/JSONUtils.h | 6 + lldb/tools/lldb-dap/lldb-dap.cpp | 172 +- 7 files changed, 354 insertions(+), 3 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 a324af57b61df3..35d792351e6bfc 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,21 @@ 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 00..8b20bcb050 --- /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 00..9ff4dbd3138428 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/memory/TestDAP_memory.py @@ -0,0 +1,121 @@ +""" +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.da
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104317 >From a5b4f6e7e105d36b82f9de588d2705ad3d622953 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 14 Aug 2024 11:52:40 + Subject: [PATCH] [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 | 172 +- 7 files changed, 365 insertions(+), 3 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 a324af57b61df3..da10e8ab5c57c2 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 00..8b20bcb050 --- /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 00..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 +""" +
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
vogelsgesang wrote: https://github.com/user-attachments/assets/f1ec37fe-414e-41ee-ad10-a213570d3e5f https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104317 >From a5b4f6e7e105d36b82f9de588d2705ad3d622953 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 14 Aug 2024 11:52:40 + Subject: [PATCH 1/2] [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 | 172 +- 7 files changed, 365 insertions(+), 3 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 a324af57b61df3..da10e8ab5c57c2 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 00..8b20bcb050 --- /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 00..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 +""" +
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
@@ -4028,6 +4049,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)) { vogelsgesang wrote: To my understanding, `GetUnsigned` works for JSON request similar to `{"memoryReference": 1234 }`. However, memory references are string-typed and not integer-typed. The request we are receiving has the form `{"memoryReference": "0x1234"}` https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
@@ -4028,6 +4049,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)) { vogelsgesang wrote: FWIW, I copied used `request_disassemble` as inspiration here https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104317 >From a5b4f6e7e105d36b82f9de588d2705ad3d622953 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 14 Aug 2024 11:52:40 + Subject: [PATCH 1/4] [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 | 172 +- 7 files changed, 365 insertions(+), 3 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 a324af57b61df3..da10e8ab5c57c2 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 00..8b20bcb050 --- /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 00..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 +""" +
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
@@ -4028,6 +4049,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 buf; + buf.resize(available_count); + if (available_count > 0) { +lldb::SBError memReadError; +auto bytes_read = +process.ReadMemory(addr, buf.data(), available_count, memReadError); +if (memReadEr
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104317 >From a5b4f6e7e105d36b82f9de588d2705ad3d622953 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 14 Aug 2024 11:52:40 + Subject: [PATCH 1/5] [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 | 172 +- 7 files changed, 365 insertions(+), 3 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 a324af57b61df3..da10e8ab5c57c2 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 00..8b20bcb050 --- /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 00..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 +""" +
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104317 >From a5b4f6e7e105d36b82f9de588d2705ad3d622953 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 14 Aug 2024 11:52:40 + Subject: [PATCH 1/5] [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 | 172 +- 7 files changed, 365 insertions(+), 3 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 a324af57b61df3..da10e8ab5c57c2 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 00..8b20bcb050 --- /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 00..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 +""" +
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
@@ -1085,6 +1085,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(); vogelsgesang wrote: I addressed the stylistic parts of this comment (`std::optional`, don't check if `Derefence()` succeeded, ...). I am not 100% sure regarding the proposed semantic changes, though, in particular about ``` if (v_type.IsPointerType() || v_type.IsReferenceType()) v = v.Dereference(); ``` This change would lead to a test case failure in the newly added memory tests. The `int not_a_ptr` would now have a memory reference associated. To my understanding of the intended debugging semantics of the DAP, it should not have an associated memory reference, though, since it is not a pointer or pointer-like type https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
vogelsgesang wrote: Thanks for the super-fast review, @clayborg! I addressed all the straightforward issues and replied to the non-straightforward ones https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Expose log path in extension settings (PR #103482)
https://github.com/vogelsgesang closed https://github.com/llvm/llvm-project/pull/103482 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/102928 >From a740c6918fd4c0e47b6d266fbb2b217112405a4f Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence tried to publish the declaration locations as value locations. However, it seems that VS-Code still has issues with correctly resolving file paths, as reported in https://github.com/microsoft/vscode/pull/225546#issuecomment-2292428591 --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 38 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 18 +-- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 285 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 a324af57b61df3..9879a34ed2020c 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 @@ -1079,6 +1079,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..26feb789db39d6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,38 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows +def test_locations(self): +""" +Tests the 'locations' request. +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.c" +self.source_path = os.path.join(os.getcwd(), source) +self.set_source_breakpoints( +source, +[line_number(source, "// BREAK HERE")], +) +self.continue_to_next_stop() + +locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + +# var1 has a declarationLocation but no valueLocation +self.assertIn("declarationLocationReference", locals["var1"].keys()) +self.assertNotIn("valueLocationReference", locals["var1"].keys()) +loc_var1 = self.dap_server.request_locations(locals["var1"]["declarationLocationReference"]) +self.assertTrue(loc_var1["su
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang ready_for_review https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
vogelsgesang wrote: Ok, this is ready for review now. The upstream protocol changes were merged in the meantime. I did leave in the `$__lldb_extensions.declaration` although it is superseded by the `declarationLocationReference`. Let me know in case you prefer me to remove it https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/102928 >From a740c6918fd4c0e47b6d266fbb2b217112405a4f Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH 1/2] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence tried to publish the declaration locations as value locations. However, it seems that VS-Code still has issues with correctly resolving file paths, as reported in https://github.com/microsoft/vscode/pull/225546#issuecomment-2292428591 --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 38 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 18 +-- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 285 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 a324af57b61df3..9879a34ed2020c 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 @@ -1079,6 +1079,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..26feb789db39d6 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,38 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows +def test_locations(self): +""" +Tests the 'locations' request. +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.c" +self.source_path = os.path.join(os.getcwd(), source) +self.set_source_breakpoints( +source, +[line_number(source, "// BREAK HERE")], +) +self.continue_to_next_stop() + +locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + +# var1 has a declarationLocation but no valueLocation +self.assertIn("declarationLocationReference", locals["var1"].keys()) +self.assertNotIn("valueLocationReference", locals["var1"].keys()) +loc_var1 = self.dap_server.request_locations(locals["var1"]["declarationLocationReference"]) +self.assertTrue(loc_var1
[Lldb-commits] [lldb] [lldb-dap] Expose log path in extension settings (PR #103482)
vogelsgesang wrote: @JDevlieghere it seems that the automation for publishing a new VS-Code extension to the MarketPlace did not kick off automatically. Could you dispatch the "Publish to VSCode Marketplace" flow manually? https://github.com/llvm/llvm-project/pull/103482 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
@@ -4028,6 +4049,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)) { vogelsgesang wrote: > Gotcha, that is interesting. I guess they let you encode and decode a > memoryReference how ever you want then right? Correct. The memory reference is actually also displayed to the user, highlighted in red in the following screenshot.  Also for single-address-space architectures, I could imagine that it would be useful to have memory references like `.rodata + 0x1234` based on the section names or `my_function + 0x1234` based on symbol names. Those memory references would convey more information to the user, and would also be stable across restarts where ASLR might shuffle the sections around. But that's an idea for another day / another commit https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104317 >From a5b4f6e7e105d36b82f9de588d2705ad3d622953 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 14 Aug 2024 11:52:40 + Subject: [PATCH 1/6] [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 | 172 +- 7 files changed, 365 insertions(+), 3 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 a324af57b61df3..da10e8ab5c57c2 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 00..8b20bcb050 --- /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 00..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 +""" +
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
@@ -4028,6 +4049,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)) { vogelsgesang wrote: > we probably want two functions to encode and decode memoryReferences to/fromt > strings in JSONUtils done https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
@@ -1085,6 +1085,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(); vogelsgesang wrote: Continued in https://github.com/llvm/llvm-project/pull/104317#discussion_r1719180273 https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
@@ -1085,6 +1084,17 @@ std::string VariableDescription::GetResult(llvm::StringRef context) { return description.trim().str(); } +std::optional GetMemoryReference(lldb::SBValue v) { + if (!v.GetType().IsPointerType() && !v.GetType().IsArrayType()) +return std::nullopt; + vogelsgesang wrote: The proposed code would led to `my_value` and `my_ptr` having the same `memoryReference` in the following code snippet: ``` int my_value; int* my_ptr = &my_value; ``` Also, when entering `my_value` and `&my_value` into the debug console, I would get the same memory references back. As a user, I would find this very confusing. As such, I do prefer the current semantics, where `my_value` does not have a memory reference. If users want to get to that memory location, they can use `&my_value` (Also, I noticed that the current code did not work for arrays. Hence, I removed the `IsArrayType`) https://github.com/llvm/llvm-project/pull/104317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Support inspecting memory (PR #104317)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104317 >From a5b4f6e7e105d36b82f9de588d2705ad3d622953 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 14 Aug 2024 11:52:40 + Subject: [PATCH 1/7] [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 | 172 +- 7 files changed, 365 insertions(+), 3 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 a324af57b61df3..da10e8ab5c57c2 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 00..8b20bcb050 --- /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 00..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 +""" +
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/102928 >From fcc6b56e27eb1bb564ccf04a328fecc5c02cf78e Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence tried to publish the declaration locations as value locations. However, it seems that VS-Code still has issues with correctly resolving file paths, as reported in https://github.com/microsoft/vscode/pull/225546#issuecomment-2292428591 --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 40 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 17 +- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 286 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 a324af57b61df3..9879a34ed2020c 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 @@ -1079,6 +1079,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..76d938d3908492 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows +def test_locations(self): +""" +Tests the 'locations' request. +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.c" +self.source_path = os.path.join(os.getcwd(), source) +self.set_source_breakpoints( +source, +[line_number(source, "// BREAK HERE")], +) +self.continue_to_next_stop() + +locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + +# var1 has a declarationLocation but no valueLocation +self.assertIn("declarationLocationReference", locals["var1"].keys()) +self.assertNotIn("valueLocationReference", locals["var1"].keys()) +loc_var1 = self.dap_server.request_locations( +locals["var1"]["declarationLocationReference"] +) +self.a
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/102928 >From 079def868f0216f31b78469f63034db5b350e250 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence tried to publish the declaration locations as value locations. However, it seems that VS-Code still has issues with correctly resolving file paths, as reported in https://github.com/microsoft/vscode/pull/225546#issuecomment-2292428591 --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 40 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 17 +- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 286 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 a324af57b61df3..9879a34ed2020c 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 @@ -1079,6 +1079,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..76d938d3908492 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows +def test_locations(self): +""" +Tests the 'locations' request. +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.c" +self.source_path = os.path.join(os.getcwd(), source) +self.set_source_breakpoints( +source, +[line_number(source, "// BREAK HERE")], +) +self.continue_to_next_stop() + +locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + +# var1 has a declarationLocation but no valueLocation +self.assertIn("declarationLocationReference", locals["var1"].keys()) +self.assertNotIn("valueLocationReference", locals["var1"].keys()) +loc_var1 = self.dap_server.request_locations( +locals["var1"]["declarationLocationReference"] +) +self.a
[Lldb-commits] [lldb] [lldb-dap] Implement value locations for function pointers (PR #104589)
https://github.com/vogelsgesang created https://github.com/llvm/llvm-project/pull/104589 Note to reviewers: This commit builds on top of the not-yet-merged PR #102928. When reviewing, ignore the first commit, it is part of the over PR. I will rebase and turn this into a non-draft PR after #102928 landed. This commit adds `valueLocationReference` to function pointers and function references. Thereby, users can navigate directly to the pointed-to function from within the "variables" pane. In general, it would be useful to also a add similar location references also to member function pointers, `std::source_location`, `std::function`, and many more. Doing so would require extending the formatters to provide such a source code location. There were two RFCs about this a while ago: https://discourse.llvm.org/t/rfc-extending-formatters-with-a-source-code-reference/68375 https://discourse.llvm.org/t/rfc-sbvalue-metadata-provider/68377/26 However, both RFCs ended without a conclusion. As such, this commit now solve the lowest-hanging fruit, i.e. function pointers. If people find it useful, I will revive the RFC afterwards. >From 079def868f0216f31b78469f63034db5b350e250 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH 1/2] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence tried to publish the declaration locations as value locations. However, it seems that VS-Code still has issues with correctly resolving file paths, as reported in https://github.com/microsoft/vscode/pull/225546#issuecomment-2292428591 --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 40 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 17 +- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 286 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 a324af57b61df3..9879a34ed2020c 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 @@ -1079,6 +1079,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..76d938d3908492 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +import dap_server +from lldbsuite.test.decorators import * +from
[Lldb-commits] [lldb] [lldb-dap] Implement value locations for function pointers (PR #104589)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104589 >From 079def868f0216f31b78469f63034db5b350e250 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH 1/2] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence tried to publish the declaration locations as value locations. However, it seems that VS-Code still has issues with correctly resolving file paths, as reported in https://github.com/microsoft/vscode/pull/225546#issuecomment-2292428591 --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 40 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 17 +- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 286 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 a324af57b61df3..9879a34ed2020c 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 @@ -1079,6 +1079,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..76d938d3908492 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows +def test_locations(self): +""" +Tests the 'locations' request. +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.c" +self.source_path = os.path.join(os.getcwd(), source) +self.set_source_breakpoints( +source, +[line_number(source, "// BREAK HERE")], +) +self.continue_to_next_stop() + +locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + +# var1 has a declarationLocation but no valueLocation +self.assertIn("declarationLocationReference", locals["var1"].keys()) +self.assertNotIn("valueLocationReference", locals["var1"].keys()) +loc_var1 = self.dap_server.request_locations( +locals["var1"]["declarationLocationReference"] +) +se
[Lldb-commits] [lldb] [lldb] Extend frame recognizers to hide frames from backtraces (PR #104523)
vogelsgesang wrote: Should hidden frames also be skipped by `StepOut`? https://github.com/llvm/llvm-project/pull/104523 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Implement value locations for function pointers (PR #104589)
vogelsgesang wrote: In the below screen recording, you can see: * The function pointers are shown in the variables view as usual * The corresponding values are linked, as indicated by the underline when hovering the value * When Cmd+Clicking on the value, the link is followed * Currently, this still leads to an error message. Afaict, this is due to a bug in VS-Code Insiders. I suspect that it does not correctly resolve the file path provided by the debug adapter. Probably this fails because I am using a remote, SSH-based editing session here. * However, from the DAP logs (visible towards the bottom of the screen), we can see that the debug adapter returns the correct file name and also the correct line https://github.com/user-attachments/assets/6d7ff263-16e9-4194-b732-a79952ebed89 https://github.com/llvm/llvm-project/pull/104589 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Implement value locations for function pointers (PR #104589)
vogelsgesang wrote: Here the screen recording of a fully functional, non-remote session: https://github.com/user-attachments/assets/64b36078-a57b-440a-85f8-0e73f88c5a56 https://github.com/llvm/llvm-project/pull/104589 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
https://github.com/vogelsgesang commented: Thanks for looking into this! The patch already looks very good! https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
vogelsgesang wrote: please rebase onto `main`. This unfortunately has a merge conflict with another change which I recently merged https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
@@ -17,14 +17,46 @@ function createDefaultLLDBDapOptions(): LLDBDapOptions { const path = vscode.workspace .getConfiguration("lldb-dap", session.workspaceFolder) .get("executable-path"); - if (path) { -return new vscode.DebugAdapterExecutable(path, []); + + if (!path) { vogelsgesang wrote: even if the path is not set, we should check if the `packageJSONExecutable` actually exists By default, the `path` is not set. As such, new users would not get this error message, although those are the ones which are most likely to run into issues https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
@@ -17,14 +17,46 @@ function createDefaultLLDBDapOptions(): LLDBDapOptions { const path = vscode.workspace .getConfiguration("lldb-dap", session.workspaceFolder) .get("executable-path"); - if (path) { -return new vscode.DebugAdapterExecutable(path, []); + + if (!path) { +return packageJSONExecutable; } - return packageJSONExecutable; + + vscode.workspace.fs.stat(vscode.Uri.file(path)).then( +(fileStats) => { vogelsgesang wrote: in addition to checking the presence of the file on launch, we could also check for it in the `onDidChangeConfiguration` event if the `executable-path` gets changed. (100% optional; feel free to just ignore this comment 🙂) https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Implement basic support for reverse-continue (PR #99736)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/99736 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Fix disassembled ranges for `disassemble` request (PR #105446)
https://github.com/vogelsgesang created https://github.com/llvm/llvm-project/pull/105446 This is a first draft PR which fixes #103021 The main issue was that the `instructionOffset` was handled as a byte offset and not as an instruction offset. This commit also incorporates previous feedback from https://reviews.llvm.org/D140358: With this change, we are using symbols and DWARF debug information to find function boundaries and correctly start disassembling at this address. TODO: * Update test case * Check if we can also support disassembling across functions >From b809f570dd8055e5b899c337ec9ff5110ab94c6e Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Mon, 19 Aug 2024 15:15:22 + Subject: [PATCH] [lldb-dap] Fix disassembled ranges for `disassemble` request TODO: * Update test case * Check if we can also support disassembling across functions Incorporated feedback from https://reviews.llvm.org/D140358 --- .../test/tools/lldb-dap/dap_server.py | 4 +- .../disassemble/TestDAP_disassemble.py| 8 +++ lldb/tools/lldb-dap/lldb-dap.cpp | 68 +-- 3 files changed, 71 insertions(+), 9 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 a324af57b61df3..75731ebfde6723 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 @@ -674,11 +674,11 @@ def request_disconnect(self, terminateDebuggee=None): return self.send_recv(command_dict) def request_disassemble( -self, memoryReference, offset=-50, instructionCount=200, resolveSymbols=True +self, memoryReference, instructionOffset=0, instructionCount=10, resolveSymbols=True ): args_dict = { "memoryReference": memoryReference, -"offset": offset, +"instructionOffset": instructionOffset, "instructionCount": instructionCount, "resolveSymbols": resolveSymbols, } diff --git a/lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py b/lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py index 9e8ef5b289f2e8..ab72eb2d13d729 100644 --- a/lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py +++ b/lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py @@ -29,6 +29,14 @@ def test_disassemble(self): ) self.continue_to_next_stop() +stackFrames = self.get_stackFrames( +threadId=threadId, startFrame=frameIndex, levels=1 +) +self.assertIsNotNone(stackFrames) + +# XXX finish updating test case +memoryReference = stackFrames[0]["instructionPointerReference"] + pc_assembly = self.disassemble(frameIndex=0) self.assertIn("location", pc_assembly, "Source location missing.") self.assertIn("instruction", pc_assembly, "Assembly instruction missing.") diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index ea84f31aec3a6c..5d9d28b59ea805 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -3910,8 +3910,8 @@ void request_disassemble(const llvm::json::Object &request) { return; } - addr_ptr += GetSigned(arguments, "instructionOffset", 0); - lldb::SBAddress addr(addr_ptr, g_dap.target); + addr_ptr += GetSigned(arguments, "offset", 0); + lldb::SBAddress addr = g_dap.target.ResolveLoadAddress(addr_ptr); if (!addr.IsValid()) { response["success"] = false; response["message"] = "Memory reference not found in the current binary."; @@ -3919,9 +3919,27 @@ void request_disassemble(const llvm::json::Object &request) { return; } - const auto inst_count = GetUnsigned(arguments, "instructionCount", 0); - lldb::SBInstructionList insts = - g_dap.target.ReadInstructions(addr, inst_count); + int64_t inst_offset = GetSigned(arguments, "instructionOffset", 0); + const int64_t inst_count = GetSigned(arguments, "instructionCount", 0); + if (inst_count < 0) { +response["success"] = false; +response["message"] = "Negative instruction count."; +g_dap.SendJSON(llvm::json::Value(std::move(response))); +return; + } + + lldb::SBInstructionList insts; + if (lldb::SBFunction func = addr.GetFunction()) { +// First try to identify the function boundaries through debug information +insts = func.GetInstructions(g_dap.target); + } else if (lldb::SBSymbol sym = addr.GetSymbol()) { +// Try to identify the function boundaries through the symbol table +insts = sym.GetInstructions(g_dap.target); + } else { +// We could not identify the function. Just disassemble starting from the +// provided address. +insts = g_dap.target.ReadInstructions(addr, inst_offset + inst_count); + } if (!insts.IsValid()) { response["success"] = false; @@ -3930,10
[Lldb-commits] [lldb] [lldb-dap] Fix disassembled ranges for `disassemble` request (PR #105446)
vogelsgesang wrote: @clayborg I would be interested in your guidance for this PR, given that you previously reviewed a similar change in https://reviews.llvm.org/D140358 I did use `SBFunction` / `SBSymbol` as suggested by you in [this comment](https://reviews.llvm.org/D140358#4027551). I did not know how to address the part ``` // then we need to repeat the search for the next function or symbol. // note there may be bytes between functions or symbols which we can disassemble // by calling _get_instructions_from_memory(...) but we must find the next // symbol or function boundary and get back on track ``` from your comment, though. Is there some API to find the next symbol? Or some API to get a list of symbols, sorted by their start address? I could of course use a brute-force approach, similar to ``` SBAddress addr; while (!addr.GetFunction() && !addr.GetSymbol()) addr = addr.OffsetAddress(1); ``` but that seems a bit wasteful https://github.com/llvm/llvm-project/pull/105446 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Mark hidden frames as "subtle" (PR #105457)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/105457 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] When sending a DAP Output Event break each message into separate lines. (PR #105456)
@@ -311,10 +309,22 @@ void DAP::SendOutput(OutputType o, const llvm::StringRef output) { category = "telemetry"; break; } - body.try_emplace("category", category); - EmplaceSafeString(body, "output", output.str()); - event.try_emplace("body", std::move(body)); - SendJSON(llvm::json::Value(std::move(event))); + + // Send each line of output as an individual event, including the newline if + // present. + ::size_t idx = 0; + do { +::size_t end = output.find('\n', idx); +if (end == llvm::StringRef::npos) + end = output.size() - 1; +llvm::json::Object event(CreateEventObject("output")); +llvm::json::Object body; +body.try_emplace("category", category); +EmplaceSafeString(body, "output", output.slice(idx, end + 1).str()); +event.try_emplace("body", std::move(body)); +SendJSON(llvm::json::Value(std::move(event))); +idx = end + 1; + } while (idx < output.size()); vogelsgesang wrote: afaict, we still send partial lines without a `\n` in the end as individual output events. Should we instead only send full lines as output events? https://github.com/llvm/llvm-project/pull/105456 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Mark hidden frames as "subtle" (PR #105457)
vogelsgesang wrote: > This looks like a nice improvement! Can we add a test for this? Added. Is this the type of test case you had in mind? Also, do I need to do anything in addition? E.g., disable the test case for libstdc++, because the stack frame recognizer only works for libc++? How would I do so? (Not sure yet, if the test case is actually correct. Still waiting for my local build to finish) https://github.com/llvm/llvm-project/pull/105457 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Mark hidden frames as "subtle" (PR #105457)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/105457 >From bdd78f79c8eb1a439472c1aa5a1bb25e83494a79 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 21 Aug 2024 00:12:39 + Subject: [PATCH] [lldb-dap] Show hidden frames as "subtle" This commit takes advantage of the recently introduced `SBFrame::IsHidden` to show those hidden frames as "subtle" frames in the UI. E.g., VS Code renders such frames grayed out in the stack trace --- .../lldb-dap/stackTrace/subtleFrames/Makefile | 3 ++ .../subtleFrames/TestDAP_subtleFrames.py | 29 +++ .../lldb-dap/stackTrace/subtleFrames/main.cpp | 13 + lldb/tools/lldb-dap/JSONUtils.cpp | 3 ++ 4 files changed, 48 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/TestDAP_subtleFrames.py create mode 100644 lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/main.cpp diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/Makefile b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/Makefile new file mode 100644 index 00..a6ae713cf424ff --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/TestDAP_subtleFrames.py b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/TestDAP_subtleFrames.py new file mode 100644 index 00..d4b28c35d08df2 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/TestDAP_subtleFrames.py @@ -0,0 +1,29 @@ +""" +Test lldb-dap stack trace response +""" + + +import dap_server +from lldbsuite.test.decorators import * +import os + +import lldbdap_testcase +from lldbsuite.test import lldbtest, lldbutil + + +class TestDAP_subtleFrames(lldbdap_testcase.DAPTestCaseBase): +def test_subtleFrames(self): +""" +Test that internal stack frames (such as the ones used by `std::function`) +are marked as "subtle". +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.cpp" +self.set_source_breakpoints(source, [line_number(source, "BREAK HERE")]) +self.continue_to_next_stop() + +backtrace = self.get_stackFrames()[0] +for f in backtrace: +if "__function" in f["name"]: +self.assertEqual(f["presentationHint"], "subtle") diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/main.cpp b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/main.cpp new file mode 100644 index 00..71944528441e38 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/main.cpp @@ -0,0 +1,13 @@ +#include +#include + +void greet() { + // BREAK HERE + std::cout << "Hello\n"; +} + +int main() { + std::function func{greet}; + func(); + return 0; +} diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index a8b85f55939e17..c080fd395b7288 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -763,6 +763,9 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) { object.try_emplace("instructionPointerReference", formatted_addr); } + if (frame.IsArtificial() || frame.IsHidden()) +object.try_emplace("presentationHint", "subtle"); + return llvm::json::Value(std::move(object)); } ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Mark hidden frames as "subtle" (PR #105457)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/105457 >From 36fd54d51e8310d4d03b40019bd96e564f8d1171 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Wed, 21 Aug 2024 00:12:39 + Subject: [PATCH] [lldb-dap] Show hidden frames as "subtle" This commit takes advantage of the recently introduced `SBFrame::IsHidden` to show those hidden frames as "subtle" frames in the UI. E.g., VS Code renders such frames grayed out in the stack trace --- .../lldb-dap/stackTrace/subtleFrames/Makefile | 3 ++ .../subtleFrames/TestDAP_subtleFrames.py | 29 +++ .../lldb-dap/stackTrace/subtleFrames/main.cpp | 13 + lldb/tools/lldb-dap/JSONUtils.cpp | 3 ++ 4 files changed, 48 insertions(+) create mode 100644 lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/TestDAP_subtleFrames.py create mode 100644 lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/main.cpp diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/Makefile b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/Makefile new file mode 100644 index 00..8b20bcb050 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/TestDAP_subtleFrames.py b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/TestDAP_subtleFrames.py new file mode 100644 index 00..1e41e841e39bc8 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/TestDAP_subtleFrames.py @@ -0,0 +1,29 @@ +""" +Test lldb-dap stack trace response +""" + + +import dap_server +from lldbsuite.test.decorators import * + +import lldbdap_testcase +from lldbsuite.test.lldbtest import * + + +class TestDAP_subtleFrames(lldbdap_testcase.DAPTestCaseBase): +@add_test_categories(["libc++"]) +def test_subtleFrames(self): +""" +Internal stack frames (such as the ones used by `std::function`) are marked as "subtle". +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.cpp" +self.set_source_breakpoints(source, [line_number(source, "BREAK HERE")]) +self.continue_to_next_stop() + +frames = self.get_stackFrames() +for f in frames: +if "__function" in f["name"]: +self.assertEqual(f["presentationHint"], "subtle") +self.assertTrue(any(f.get("presentationHint") == "subtle" for f in frames)) diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/main.cpp b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/main.cpp new file mode 100644 index 00..71944528441e38 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/stackTrace/subtleFrames/main.cpp @@ -0,0 +1,13 @@ +#include +#include + +void greet() { + // BREAK HERE + std::cout << "Hello\n"; +} + +int main() { + std::function func{greet}; + func(); + return 0; +} diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index a8b85f55939e17..c080fd395b7288 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -763,6 +763,9 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) { object.try_emplace("instructionPointerReference", formatted_addr); } + if (frame.IsArtificial() || frame.IsHidden()) +object.try_emplace("presentationHint", "subtle"); + return llvm::json::Value(std::move(object)); } ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Mark hidden frames as "subtle" (PR #105457)
vogelsgesang wrote: The included test case should be fine now, afaict https://github.com/llvm/llvm-project/pull/105457 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Implement `StepGranularity` for "next" and "step-in" (PR #105464)
@@ -3193,7 +3213,11 @@ void request_stackTrace(const llvm::json::Object &request) { // "targetId": { // "type": "integer", // "description": "Optional id of the target to step into." -// } +// }, +// "granularity": { +// "$ref": "#/definitions/SteppingGranularity", +// "description": "Stepping granularity. If no granularity is specified, a +// granularity of `statement` is assumed." // }, vogelsgesang wrote: missing closing `}` https://github.com/llvm/llvm-project/pull/105464 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] When sending a DAP Output Event break each message into separate lines. (PR #105456)
@@ -311,10 +309,22 @@ void DAP::SendOutput(OutputType o, const llvm::StringRef output) { category = "telemetry"; break; } - body.try_emplace("category", category); - EmplaceSafeString(body, "output", output.str()); - event.try_emplace("body", std::move(body)); - SendJSON(llvm::json::Value(std::move(event))); + + // Send each line of output as an individual event, including the newline if + // present. + ::size_t idx = 0; + do { +::size_t end = output.find('\n', idx); +if (end == llvm::StringRef::npos) + end = output.size() - 1; +llvm::json::Object event(CreateEventObject("output")); +llvm::json::Object body; +body.try_emplace("category", category); +EmplaceSafeString(body, "output", output.slice(idx, end + 1).str()); +event.try_emplace("body", std::move(body)); +SendJSON(llvm::json::Value(std::move(event))); +idx = end + 1; + } while (idx < output.size()); vogelsgesang wrote: Thanks for clarifying! https://github.com/llvm/llvm-project/pull/105456 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Implement `StepGranularity` for "next" and "step-in" (PR #105464)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/105464 >From c4178df5541103388e26343f62e96f8e2a65be86 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Mon, 12 Aug 2024 23:00:45 + Subject: [PATCH 1/3] [lldb-dap] Implement `StepGranularity` for "next" and "step-in" VS Code requests a `granularity` of `instruction` if the assembly view is currently focused. By implementing `StepGranularity`, we can hence properly through assembly code single-step through assembly code. --- .../test/tools/lldb-dap/dap_server.py | 8 ++--- .../test/tools/lldb-dap/lldbdap_testcase.py | 8 ++--- .../API/tools/lldb-dap/step/TestDAP_step.py | 9 ++ lldb/tools/lldb-dap/lldb-dap.cpp | 31 +-- 4 files changed, 45 insertions(+), 11 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 a324af57b61df3..87ebc674f61df6 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 @@ -816,17 +816,17 @@ def request_launch( self.wait_for_event(filter=["process", "initialized"]) return response -def request_next(self, threadId): +def request_next(self, threadId, granularity="statement"): if self.exit_status is not None: raise ValueError("request_continue called after process exited") -args_dict = {"threadId": threadId} +args_dict = {"threadId": threadId, "granularity": granularity} command_dict = {"command": "next", "type": "request", "arguments": args_dict} return self.send_recv(command_dict) -def request_stepIn(self, threadId, targetId): +def request_stepIn(self, threadId, targetId, granularity="statement"): if self.exit_status is not None: raise ValueError("request_stepIn called after process exited") -args_dict = {"threadId": threadId, "targetId": targetId} +args_dict = {"threadId": threadId, "targetId": targetId, "granularity": granularity} command_dict = {"command": "stepIn", "type": "request", "arguments": args_dict} return self.send_recv(command_dict) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index a312a88ebd7e58..3257bd14b16fed 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -222,14 +222,14 @@ def set_global(self, name, value, id=None): """Set a top level global variable only.""" return self.dap_server.request_setVariable(2, name, str(value), id=id) -def stepIn(self, threadId=None, targetId=None, waitForStop=True): -self.dap_server.request_stepIn(threadId=threadId, targetId=targetId) +def stepIn(self, threadId=None, targetId=None, waitForStop=True, granularity="statement"): +self.dap_server.request_stepIn(threadId=threadId, targetId=targetId, granularity=granularity) if waitForStop: return self.dap_server.wait_for_stopped() return None -def stepOver(self, threadId=None, waitForStop=True): -self.dap_server.request_next(threadId=threadId) +def stepOver(self, threadId=None, waitForStop=True, granularity="statement"): +self.dap_server.request_next(threadId=threadId, granularity=granularity) if waitForStop: return self.dap_server.wait_for_stopped() return None diff --git a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py index 8a1bb76340be73..9c8e226827611e 100644 --- a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py +++ b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py @@ -68,5 +68,14 @@ def test_step(self): self.assertEqual(x4, x3, "verify step over variable") self.assertGreater(line4, line3, "verify step over line") self.assertEqual(src1, src4, "verify step over source") + +# Step a single assembly instruction. +# Unfortunately, there is no portable way to verify the correct +# stepping behavior here, because the generated assembly code +# depends highly on the compiler, its version, the operating +# system, and many more factors. +self.stepOver(threadId=tid, waitForStop=True, granularity="instruction") +self.stepIn(threadId=tid, waitForStop=True, granularity="instruction") + # only step one thread that is at the breakpoint and stop break diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp inde
[Lldb-commits] [lldb] [lldb-dap] Implement `StepGranularity` for "next" and "step-in" (PR #105464)
https://github.com/vogelsgesang closed https://github.com/llvm/llvm-project/pull/105464 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/102928 >From 5bdcb821527bf67eead6c42825ea6e559ec749c3 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence published the declaration locations as value locations, and VS Code Insiders navigated to the expected places. Looking forward to proper VS Code support for `declarationLocationReference`. --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 40 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 17 +- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 286 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 874383a13e2bb6..01ff79ee430902 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 @@ -1083,6 +1083,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..76d938d3908492 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows +def test_locations(self): +""" +Tests the 'locations' request. +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.c" +self.source_path = os.path.join(os.getcwd(), source) +self.set_source_breakpoints( +source, +[line_number(source, "// BREAK HERE")], +) +self.continue_to_next_stop() + +locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + +# var1 has a declarationLocation but no valueLocation +self.assertIn("declarationLocationReference", locals["var1"].keys()) +self.assertNotIn("valueLocationReference", locals["var1"].keys()) +loc_var1 = self.dap_server.request_locations( +locals["var1"]["declarationLocationReference"] +) +self.assertTrue(loc_var1["success"]) +self.as
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Implement value locations for function pointers (PR #104589)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104589 >From 5bdcb821527bf67eead6c42825ea6e559ec749c3 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH 1/2] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence published the declaration locations as value locations, and VS Code Insiders navigated to the expected places. Looking forward to proper VS Code support for `declarationLocationReference`. --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 40 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 17 +- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 286 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 874383a13e2bb6..01ff79ee430902 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 @@ -1083,6 +1083,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..76d938d3908492 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows +def test_locations(self): +""" +Tests the 'locations' request. +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.c" +self.source_path = os.path.join(os.getcwd(), source) +self.set_source_breakpoints( +source, +[line_number(source, "// BREAK HERE")], +) +self.continue_to_next_stop() + +locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + +# var1 has a declarationLocation but no valueLocation +self.assertIn("declarationLocationReference", locals["var1"].keys()) +self.assertNotIn("valueLocationReference", locals["var1"].keys()) +loc_var1 = self.dap_server.request_locations( +locals["var1"]["declarationLocationReference"] +) +self.assertTrue(loc_var1["success"]) +sel
[Lldb-commits] [lldb] [lldb-dap] Mark hidden frames as "subtle" (PR #105457)
vogelsgesang wrote: @petrhosek this commit builds on top of #104523 and relies on the frame recognizer introduced as part of it. As soon as [your proposed solutions](https://github.com/llvm/llvm-project/pull/104523#issuecomment-2303287484) was addressed, the `subtleFrames` test case should also be passing. In case this turns out to be not the case, please ping me again https://github.com/llvm/llvm-project/pull/105457 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Implement value locations for function pointers (PR #104589)
@@ -0,0 +1,81 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows vogelsgesang wrote: this was a copy-paste mistake :/ https://github.com/llvm/llvm-project/pull/104589 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Implement value locations for function pointers (PR #104589)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/104589 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Enabling instruction breakpoint support to lldb-dap. (PR #105278)
@@ -4046,6 +4048,181 @@ void request__testGetTargetBreakpoints(const llvm::json::Object &request) { g_dap.SendJSON(llvm::json::Value(std::move(response))); } +// SetInstructionBreakpoints request; value of command field is +// 'setInstructionBreakpoints'. Replaces all existing instruction breakpoints. +// Typically, instruction breakpoints would be set from a disassembly window. To +// clear all instruction breakpoints, specify an empty array. When an +// instruction breakpoint is hit, a `stopped` event (with reason `instruction +// breakpoint`) is generated. Clients should only call this request if the +// corresponding capability `supportsInstructionBreakpoints` is true. interface +// SetInstructionBreakpointsRequest extends Request { +// command: 'setInstructionBreakpoints'; +// arguments: SetInstructionBreakpointsArguments; +// } +// interface SetInstructionBreakpointsArguments { +// The instruction references of the breakpoints +// breakpoints: InstructionBreakpoint[]; +// } +// "InstructionBreakpoint ": { +// "type": "object", +// "description": "Properties of a breakpoint passed to the +// setInstructionBreakpoints request.", "properties": { +// "instructionReference": { +// "type": "string", +// "description": "The instruction reference of the breakpoint. +// This should be a memory or instruction pointer reference from an +// EvaluateResponse, Variable, StackFrame, GotoTarget, or Breakpoint." +// }, +// "offset": { +// "type": "number", +// "description": "The offset from the instruction reference. +// This can be negative." +// }, +// "condition": { +// "type": "string", +// "description": "An expression for conditional breakpoints. +// It is only honored by a debug adapter if the corresponding capability +// supportsConditionalBreakpoints` is true." +// }, +// "hitCondition": { +// "type": "string", +// "description": "An expression that controls how many hits of the +// breakpoint are ignored. The debug adapter is expected to interpret the +// expression as needed. The attribute is only honored by a debug adapter +// if the corresponding capability `supportsHitConditionalBreakpoints` is +// true." +// }, +// } +// interface SetInstructionBreakpointsResponse extends Response { +// body: { +// Information about the breakpoints. The array elements correspond to the +// elements of the `breakpoints` array. +// breakpoints: Breakpoint[]; +// }; +// } vogelsgesang wrote: we usually copy the JSON schema documentation into the comments, not the TypeScript interface. See https://github.com/microsoft/debug-adapter-protocol/blob/main/debugAdapterProtocol.json https://github.com/llvm/llvm-project/pull/105278 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Enabling instruction breakpoint support to lldb-dap. (PR #105278)
@@ -4078,6 +4255,9 @@ void RegisterRequestCallbacks() { g_dap.RegisterRequestCallback("threads", request_threads); g_dap.RegisterRequestCallback("variables", request_variables); g_dap.RegisterRequestCallback("disassemble", request_disassemble); + // Instruction breapoint request vogelsgesang wrote: we also need to update the stopped event to use `reason: instruction breakpoint` instead of `reason: breakpoint` in case we hit one of those breakpoints https://github.com/llvm/llvm-project/pull/105278 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
@@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows vogelsgesang wrote: copy-paste error :/ https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/102928 >From 5bdcb821527bf67eead6c42825ea6e559ec749c3 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH 1/2] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence published the declaration locations as value locations, and VS Code Insiders navigated to the expected places. Looking forward to proper VS Code support for `declarationLocationReference`. --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 40 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 17 +- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 286 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 874383a13e2bb6..01ff79ee430902 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 @@ -1083,6 +1083,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..76d938d3908492 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows +def test_locations(self): +""" +Tests the 'locations' request. +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.c" +self.source_path = os.path.join(os.getcwd(), source) +self.set_source_breakpoints( +source, +[line_number(source, "// BREAK HERE")], +) +self.continue_to_next_stop() + +locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + +# var1 has a declarationLocation but no valueLocation +self.assertIn("declarationLocationReference", locals["var1"].keys()) +self.assertNotIn("valueLocationReference", locals["var1"].keys()) +loc_var1 = self.dap_server.request_locations( +locals["var1"]["declarationLocationReference"] +) +self.assertTrue(loc_var1["success"]) +sel
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
https://github.com/vogelsgesang approved this pull request. Looks good to me! Thanks for this amazing usability improvement! If this would have existed the first time I tried this extension, it would have saved me a lot of time https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
@@ -14,10 +14,52 @@ export class LLDBDapDescriptorFactory this.lldbDapOptions = lldbDapOptions; } + public static async validateDebugAdapterPath(pathUri: vscode.Uri) { +try { + const fileStats = await vscode.workspace.fs.stat(pathUri); + if (!(fileStats.type & vscode.FileType.File)) { +this.showErrorMessage(pathUri.path); + } +} catch (err) { + this.showErrorMessage(pathUri.path); +} + } + async createDebugAdapterDescriptor( session: vscode.DebugSession, executable: vscode.DebugAdapterExecutable | undefined, ): Promise { +const config = vscode.workspace.getConfiguration( + "lldb-dap", + session.workspaceFolder, +); +const customPath = config.get("executable-path"); +const path: string = customPath ? customPath : executable!!.command; + +await LLDBDapDescriptorFactory.validateDebugAdapterPath( + vscode.Uri.file(path), +); return this.lldbDapOptions.createDapExecutableCommand(session, executable); } + + /** + * Shows a message box when the debug adapter's path is not found + */ + private static showErrorMessage(path: string) { +const openSettingsAction = "Open Settings"; +vscode.window + .showErrorMessage( +`Debug adapter path: ${path} is not a valid file`, +{ modal: false }, +openSettingsAction, + ) + .then((callBackValue) => { +if (openSettingsAction === callBackValue) { + vscode.commands.executeCommand( +"workbench.action.openSettings", +"lldb-dap.executable-path", + ); +} + }); + } vogelsgesang wrote: instead of `.then()` we should be able to use an `async` function here ```suggestion private static async showErrorMessage(path: string) { const openSettingsAction = "Open Settings"; const selection = await vscode.window .showErrorMessage( `Debug adapter path: ${path} is not a valid file`, { modal: false }, openSettingsAction, ); if (openSettingsAction === callBackValue) { vscode.commands.executeCommand( "workbench.action.openSettings", "lldb-dap.executable-path", ); } } ``` https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
@@ -14,10 +14,52 @@ export class LLDBDapDescriptorFactory this.lldbDapOptions = lldbDapOptions; } + public static async validateDebugAdapterPath(pathUri: vscode.Uri) { +try { + const fileStats = await vscode.workspace.fs.stat(pathUri); + if (!(fileStats.type & vscode.FileType.File)) { +this.showErrorMessage(pathUri.path); + } +} catch (err) { + this.showErrorMessage(pathUri.path); +} + } + async createDebugAdapterDescriptor( session: vscode.DebugSession, executable: vscode.DebugAdapterExecutable | undefined, ): Promise { +const config = vscode.workspace.getConfiguration( + "lldb-dap", + session.workspaceFolder, +); +const customPath = config.get("executable-path"); +const path: string = customPath ? customPath : executable!!.command; + +await LLDBDapDescriptorFactory.validateDebugAdapterPath( + vscode.Uri.file(path), +); return this.lldbDapOptions.createDapExecutableCommand(session, executable); } + + /** + * Shows a message box when the debug adapter's path is not found + */ + private static showErrorMessage(path: string) { +const openSettingsAction = "Open Settings"; +vscode.window + .showErrorMessage( +`Debug adapter path: ${path} is not a valid file`, +{ modal: false }, vogelsgesang wrote: Afaik, non-modal is the default anyway? ```suggestion ``` https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
@@ -14,10 +14,52 @@ export class LLDBDapDescriptorFactory this.lldbDapOptions = lldbDapOptions; } + public static async validateDebugAdapterPath(pathUri: vscode.Uri) { +try { + const fileStats = await vscode.workspace.fs.stat(pathUri); + if (!(fileStats.type & vscode.FileType.File)) { +this.showErrorMessage(pathUri.path); + } +} catch (err) { + this.showErrorMessage(pathUri.path); +} + } + async createDebugAdapterDescriptor( session: vscode.DebugSession, executable: vscode.DebugAdapterExecutable | undefined, ): Promise { +const config = vscode.workspace.getConfiguration( + "lldb-dap", + session.workspaceFolder, +); +const customPath = config.get("executable-path"); +const path: string = customPath ? customPath : executable!!.command; + +await LLDBDapDescriptorFactory.validateDebugAdapterPath( + vscode.Uri.file(path), +); return this.lldbDapOptions.createDapExecutableCommand(session, executable); } + + /** + * Shows a message box when the debug adapter's path is not found + */ + private static showErrorMessage(path: string) { vogelsgesang wrote: ```suggestion private static showLLdbDapNotFoundMessage(path: string) { ``` https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
@@ -14,10 +14,52 @@ export class LLDBDapDescriptorFactory this.lldbDapOptions = lldbDapOptions; } + public static async validateDebugAdapterPath(pathUri: vscode.Uri) { +try { + const fileStats = await vscode.workspace.fs.stat(pathUri); + if (!(fileStats.type & vscode.FileType.File)) { +this.showErrorMessage(pathUri.path); + } +} catch (err) { + this.showErrorMessage(pathUri.path); +} + } + async createDebugAdapterDescriptor( session: vscode.DebugSession, executable: vscode.DebugAdapterExecutable | undefined, ): Promise { +const config = vscode.workspace.getConfiguration( + "lldb-dap", + session.workspaceFolder, +); +const customPath = config.get("executable-path"); +const path: string = customPath ? customPath : executable!!.command; + +await LLDBDapDescriptorFactory.validateDebugAdapterPath( + vscode.Uri.file(path), +); return this.lldbDapOptions.createDapExecutableCommand(session, executable); } + + /** + * Shows a message box when the debug adapter's path is not found + */ + private static showErrorMessage(path: string) { +const openSettingsAction = "Open Settings"; +vscode.window + .showErrorMessage( +`Debug adapter path: ${path} is not a valid file`, +{ modal: false }, vogelsgesang wrote: we aren't using modals in the current code. I am just proposing to be less epxlicit here. And not set "modal: false" as this is the default in the VS Code API, anyway https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
vogelsgesang wrote: > @vogelsgesang , the $__lldb_extensions.declaration is used by the Mojo > extension. Once this change gets it, I'll update the Mojo extension to use > the new declaration info and remove $__lldb_extensions.declaration. Is that extension's source code available? I wonder how you are currently using the declarationLocation in your frontend, and if your extension is based on `lldb-dap`. If so, would it make sense to upstream your UI integration to `lldb-dap`? Or maybe even to VS-Code itself? https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Implement value locations for function pointers (PR #104589)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/104589 >From 5bdcb821527bf67eead6c42825ea6e559ec749c3 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Sat, 10 Aug 2024 23:59:55 + Subject: [PATCH 1/3] [lldb-dap] Implement declaration locations This commit implements support for the "declaration location" recently added by microsoft/debug-adapter-protocol#494 to the debug adapter protocol. For the `declarationLocationReference` we need a variable ID similar to the the `variablesReference`. I decided to simply reuse the `variablesReference` here and renamed `Variables::expandable_variables` and friends accordingly. Given that almost all variables have a declaration location, we now assign those variable ids to all variables. While `declarationLocationReference` effectively supersedes `$__lldb_extensions.declaration`, I did not remove this extension, yet, since I assume that there are some closed-source extensions which rely on it. I tested this against VS-Code Insiders. However, VS-Code Insiders currently only supports `valueLoctionReference` and not `declarationLocationReference`, yet. Locally, I hence published the declaration locations as value locations, and VS Code Insiders navigated to the expected places. Looking forward to proper VS Code support for `declarationLocationReference`. --- .../test/tools/lldb-dap/dap_server.py | 11 ++ .../API/tools/lldb-dap/locations/Makefile | 3 + .../lldb-dap/locations/TestDAP_locations.py | 40 + lldb/test/API/tools/lldb-dap/locations/main.c | 5 + lldb/tools/lldb-dap/DAP.cpp | 17 +- lldb/tools/lldb-dap/DAP.h | 10 +- lldb/tools/lldb-dap/JSONUtils.cpp | 125 --- lldb/tools/lldb-dap/JSONUtils.h | 31 ++-- lldb/tools/lldb-dap/lldb-dap.cpp | 146 +++--- 9 files changed, 286 insertions(+), 102 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/locations/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py create mode 100644 lldb/test/API/tools/lldb-dap/locations/main.c 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 874383a13e2bb6..01ff79ee430902 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 @@ -1083,6 +1083,17 @@ def request_setVariable(self, containingVarRef, name, value, id=None): } return self.send_recv(command_dict) +def request_locations(self, locationReference): +args_dict = { +"locationReference": locationReference, +} +command_dict = { +"command": "locations", +"type": "request", +"arguments": args_dict, +} +return self.send_recv(command_dict) + def request_testGetTargetBreakpoints(self): """A request packet used in the LLDB test suite to get all currently set breakpoint infos for all breakpoints currently set in the diff --git a/lldb/test/API/tools/lldb-dap/locations/Makefile b/lldb/test/API/tools/lldb-dap/locations/Makefile new file mode 100644 index 00..10495940055b63 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py new file mode 100644 index 00..76d938d3908492 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/locations/TestDAP_locations.py @@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows +def test_locations(self): +""" +Tests the 'locations' request. +""" +program = self.getBuildArtifact("a.out") +self.build_and_launch(program) +source = "main.c" +self.source_path = os.path.join(os.getcwd(), source) +self.set_source_breakpoints( +source, +[line_number(source, "// BREAK HERE")], +) +self.continue_to_next_stop() + +locals = {l["name"]: l for l in self.dap_server.get_local_variables()} + +# var1 has a declarationLocation but no valueLocation +self.assertIn("declarationLocationReference", locals["var1"].keys()) +self.assertNotIn("valueLocationReference", locals["var1"].keys()) +loc_var1 = self.dap_server.request_locations( +locals["var1"]["declarationLocationReference"] +) +self.assertTrue(loc_var1["success"]) +sel
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
vogelsgesang wrote: > @vogelsgesang , can you show a screenshot of the variables pane after this > change? I want to make sure that simple types, like ints, are not displayed > as having children. **With this commit (and also with the changes from #104589)** https://github.com/user-attachments/assets/862b301c-6321-47dc-9243-bb27447b093b";> Current `main` https://github.com/user-attachments/assets/a6102469-a41a-4b0d-873a-ce8a1fee5b74";> As you can see, there are no differences re the absence / presence of the "expandable chevron" next to the variables. That being said, I do find it a bit surprising that function pointers apparently return `true` for `MightHaveChildren` https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
vogelsgesang wrote: > I'll explain what I do [...] Thanks for that context! I don't currently have a LSP in mind. Let's see which UI VS-Code will be providing for this (if any). I hope it will not conflict with your existing UI https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
vogelsgesang wrote: > This LGTM considering that the screenshot looks right and this passes all the > tests. Thanks! I assume you still want me to wait for @clayborg's review before merging? https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Provide `declarationLocation` for variables (PR #102928)
@@ -0,0 +1,40 @@ +""" +Test lldb-dap locations request +""" + + +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_locations(lldbdap_testcase.DAPTestCaseBase): +@skipIfWindows vogelsgesang wrote: @walter-erquinigo based on https://github.com/llvm/llvm-project/pull/105604, it seems that all DAP tests are in fact disabled for Windows. Should I reintroduce the `SkipIfWindows`? https://github.com/llvm/llvm-project/pull/102928 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Add frame recognizers for libc++ `std::invoke` (PR #105695)
https://github.com/vogelsgesang created https://github.com/llvm/llvm-project/pull/105695 With this commit, we also hide the implementation details of `std::invoke`. To do so, the `LibCXXFrameRecognizer` got a couple more regular expressions. The regular expression passed into the `AddRecognizer` became problematic, as it was evaluated on the demangled name. Those names also included result types for C++ symbols. For `std::__invoke` the return type is a huge `decltype(...)`, making the regular expresison really hard to write. Instead, I added support for `AddRecognizer` to match on the demangled names without result type and argument types. By hiding the implementation details of `invoke`, also the back traces for `std::function` become even nicer, because `std::function` is using `__invoke` internally. >From 18365311d0cee76bced3ba26d1ed08d9f5c6cb28 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Thu, 22 Aug 2024 10:50:13 + Subject: [PATCH] [lldb-dap] Add frame recognizers for libc++ `std::invoke` With this commit, we also hide the implementation details of `std::invoke`. To do so, the `LibCXXFrameRecognizer` got a couple more regular expressions. The regular expression passed into the `AddRecognizer` became problematic, as it was evaluated on the demangled name. Those names also included result types for C++ symbols. For `std::__invoke` the return type is a huge `decltype(...)`, making the regular expresison really hard to write. Instead, I added support for `AddRecognizer` to match on the demangled names without result type and argument types. By hiding the implementation details of `invoke`, also the back traces for `std::function` become even nicer, because `std::function` is using `__invoke` internally. --- .../lldb/Target/StackFrameRecognizer.h| 9 +++- lldb/source/Commands/Options.td | 2 +- .../CPlusPlus/CPPLanguageRuntime.cpp | 48 ++- lldb/source/Target/StackFrameRecognizer.cpp | 41 ++-- .../TestStdFunctionRecognizer.py | 21 +++- .../lang/cpp/std-invoke-recognizer/Makefile | 5 ++ .../TestStdInvokeRecognizer.py| 28 +++ .../lang/cpp/std-invoke-recognizer/main.cpp | 40 8 files changed, 173 insertions(+), 21 deletions(-) create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h index 8acebc12c4b1dc..585f0b0bb59009 100644 --- a/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -107,12 +107,14 @@ class StackFrameRecognizerManager { public: void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, ConstString module, llvm::ArrayRef symbols, - bool first_instruction_only = true); + bool first_instruction_only = true, + Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled); void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, lldb::RegularExpressionSP module, lldb::RegularExpressionSP symbol, - bool first_instruction_only = true); + bool first_instruction_only = true, + Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled); void ForEach(std::function< void(uint32_t recognizer_id, std::string recognizer_name, @@ -143,10 +145,13 @@ class StackFrameRecognizerManager { std::vector symbols; lldb::RegularExpressionSP symbol_regexp; bool first_instruction_only; +Mangled::NamePreference mangling_preference; }; std::deque m_recognizers; uint16_t m_generation; + std::unordered_set m_used_manglings; + }; /// \class ValueObjectRecognizerSynthesizedValue diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 9c4dbed6939ba9..df906e9d7c808f 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1049,7 +1049,7 @@ let Command = "thread backtrace" in { def thread_backtrace_extended : Option<"extended", "e">, Group<1>, Arg<"Boolean">, Desc<"Show the extended backtrace, if available">; def thread_backtrace_unfiltered : Option<"unfiltered", "u">, Group<1>, - Desc<"Filter out frames according to installed frame recognizers">; + Desc<"Do not filter out frames according to installed frame recognizers">; } let Command = "thread step scope" in { diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index c60200ab186d09..3665e1a4c77e55 100644 --- a/lldb/sourc
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/105695 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Enabling instruction breakpoint support to lldb-dap. (PR #105278)
@@ -4078,6 +4255,9 @@ void RegisterRequestCallbacks() { g_dap.RegisterRequestCallback("threads", request_threads); g_dap.RegisterRequestCallback("variables", request_variables); g_dap.RegisterRequestCallback("disassemble", request_disassemble); + // Instruction breapoint request vogelsgesang wrote: I don't really know about those differences on the gdb protocol. I was only reading https://microsoft.github.io/debug-adapter-protocol/specification#Requests_SetInstructionBreakpoints > When an instruction breakpoint is hit, a stopped event (with reason > `instruction breakpoint`) is generated. https://github.com/llvm/llvm-project/pull/105278 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
vogelsgesang wrote: @mordante @ldionne FYI. Would be interested which other functions come to mind that should be hidden. See https://github.com/llvm/llvm-project/pull/105457#issuecomment-226404 for screenshots of how this looks from a user's perspective https://github.com/llvm/llvm-project/pull/105695 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/105695 >From c7cc7e9eed1ef4b95cabec5f662ebe10607b178e Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Thu, 22 Aug 2024 10:50:13 + Subject: [PATCH] [lldb-dap] Add frame recognizers for libc++ `std::invoke` With this commit, we also hide the implementation details of `std::invoke`. To do so, the `LibCXXFrameRecognizer` got a couple more regular expressions. The regular expression passed into the `AddRecognizer` became problematic, as it was evaluated on the demangled name. Those names also included result types for C++ symbols. For `std::__invoke` the return type is a huge `decltype(...)`, making the regular expresison really hard to write. Instead, I added support for `AddRecognizer` to match on the demangled names without result type and argument types. By hiding the implementation details of `invoke`, also the back traces for `std::function` become even nicer, because `std::function` is using `__invoke` internally. --- .../lldb/Target/StackFrameRecognizer.h| 9 +++- lldb/source/Commands/Options.td | 2 +- .../CPlusPlus/CPPLanguageRuntime.cpp | 48 ++- lldb/source/Target/StackFrameRecognizer.cpp | 41 ++-- .../TestStdFunctionRecognizer.py | 21 +++- .../lang/cpp/std-invoke-recognizer/Makefile | 5 ++ .../TestStdInvokeRecognizer.py| 31 .../lang/cpp/std-invoke-recognizer/main.cpp | 40 8 files changed, 176 insertions(+), 21 deletions(-) create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h index 8acebc12c4b1dc..585f0b0bb59009 100644 --- a/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -107,12 +107,14 @@ class StackFrameRecognizerManager { public: void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, ConstString module, llvm::ArrayRef symbols, - bool first_instruction_only = true); + bool first_instruction_only = true, + Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled); void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, lldb::RegularExpressionSP module, lldb::RegularExpressionSP symbol, - bool first_instruction_only = true); + bool first_instruction_only = true, + Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled); void ForEach(std::function< void(uint32_t recognizer_id, std::string recognizer_name, @@ -143,10 +145,13 @@ class StackFrameRecognizerManager { std::vector symbols; lldb::RegularExpressionSP symbol_regexp; bool first_instruction_only; +Mangled::NamePreference mangling_preference; }; std::deque m_recognizers; uint16_t m_generation; + std::unordered_set m_used_manglings; + }; /// \class ValueObjectRecognizerSynthesizedValue diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 9c4dbed6939ba9..df906e9d7c808f 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1049,7 +1049,7 @@ let Command = "thread backtrace" in { def thread_backtrace_extended : Option<"extended", "e">, Group<1>, Arg<"Boolean">, Desc<"Show the extended backtrace, if available">; def thread_backtrace_unfiltered : Option<"unfiltered", "u">, Group<1>, - Desc<"Filter out frames according to installed frame recognizers">; + Desc<"Do not filter out frames according to installed frame recognizers">; } let Command = "thread step scope" in { diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index c60200ab186d09..3665e1a4c77e55 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -7,6 +7,7 @@ //===--===// #include +#include #include @@ -44,7 +45,7 @@ char CPPLanguageRuntime::ID = 0; /// A frame recognizer that is installed to hide libc++ implementation /// details from the backtrace. class LibCXXFrameRecognizer : public StackFrameRecognizer { - RegularExpression m_hidden_function_regex; + std::array m_hidden_regex; RecognizedStackFrameSP m_hidden_frame; struct LibCXXHiddenFrame : public RecognizedStackFrame { @@ -53,10 +54,32 @@ class LibCXXFrameRecognizer : public StackFram
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
https://github.com/vogelsgesang approved this pull request. https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] show dialog when executable is not found (PR #104711)
vogelsgesang wrote: Looks good to me! Thanks again for fixing this! https://github.com/llvm/llvm-project/pull/104711 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
@@ -53,10 +54,32 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer { public: LibCXXFrameRecognizer() - : m_hidden_function_regex( -R"(^std::__1::(__function.*::operator\(\)|__invoke))" -R"((\[.*\])?)"// ABI tag. -R"(( const)?$)"), // const. + : m_hidden_regex{ +// internal implementation details of std::function +//std::__1::__function::__alloc_func, void ()>::operator()[abi:ne20] +//std::__1::__function::__func, void ()>::operator() +//std::__1::__function::__value_func::operator()[abi:ne20]() const +RegularExpression{"" + R"(^std::__[0-9]*::)" // Namespace. + R"(__function::.*::operator\(\))" + R"((\[.*\])?)"// ABI tag. + R"(( const)?$)"}, // const. +// internal implementation details of std::invoke +// std::__1::__invoke[abi:ne20] +RegularExpression{ + R"(^std::__[0-9]*::)" // Namespace. + R"(__invoke)" vogelsgesang wrote: I wonder if we should simply hide everything starting with `^std::__[0-9]*::__.*`. Or are there any `__` functions in libc++ which are not implementation details and should be shown in stacktraces by default? https://github.com/llvm/llvm-project/pull/105695 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Support frame recognizer regexp on mangled names. (PR #105756)
@@ -92,11 +95,13 @@ void StackFrameRecognizerManager::ForEach( symbol_name = entry.symbol_regexp->GetText().str(); callback(entry.recognizer_id, entry.recognizer->GetName(), module_name, - llvm::ArrayRef(ConstString(symbol_name)), true); + llvm::ArrayRef(ConstString(symbol_name)), entry.symbol_mangling, + true); } else { callback(entry.recognizer_id, entry.recognizer->GetName(), - entry.module.GetCString(), entry.symbols, false); + entry.module.GetCString(), entry.symbols, entry.symbol_mangling, + false); } } } vogelsgesang wrote: afaict, this code is incomplete. The matching in `GetRecognizerForFrame` also needs to be adjusted. In https://github.com/llvm/llvm-project/pull/105695, you can find an implementation of pretty much the same idea. However, I implemented only `GetRecognizerForFrame` and skipped, e.g., `ForEach` https://github.com/llvm/llvm-project/pull/105756 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Support frame recognizer regexp on mangled names. (PR #105756)
@@ -92,11 +95,13 @@ void StackFrameRecognizerManager::ForEach( symbol_name = entry.symbol_regexp->GetText().str(); callback(entry.recognizer_id, entry.recognizer->GetName(), module_name, - llvm::ArrayRef(ConstString(symbol_name)), true); + llvm::ArrayRef(ConstString(symbol_name)), entry.symbol_mangling, + true); } else { callback(entry.recognizer_id, entry.recognizer->GetName(), - entry.module.GetCString(), entry.symbols, false); + entry.module.GetCString(), entry.symbols, entry.symbol_mangling, + false); } } } vogelsgesang wrote: Feel free to copy-paste / adjust whichever code from #105695 which you might find useful. I will rebase that commit later on, after your changes landed. (I cannot land #105695 before #104523 gets re-applied, anyway) https://github.com/llvm/llvm-project/pull/105756 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Support frame recognizer regexp on mangled names. (PR #105756)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/105756 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Support frame recognizer regexp on mangled names. (PR #105756)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/105756 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
@@ -145,6 +167,17 @@ StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) { if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue; +ConstString function_name = [&]() { + switch (entry.mangling_preference) { + case Mangled::ePreferMangled: +return function_name_mangled; + case Mangled::ePreferDemangled: +return function_name_demangled; + case Mangled::ePreferDemangledWithoutArguments: +return function_name_noargs; + } +}(); vogelsgesang wrote: I wasn't sure about performance here. The code previously computed the demanded name only once and then checked against all frame recognizers. I am not sure how expensive it is to demangle a name https://github.com/llvm/llvm-project/pull/105695 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
@@ -145,6 +167,17 @@ StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) { if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue; +ConstString function_name = [&]() { + switch (entry.mangling_preference) { + case Mangled::ePreferMangled: +return function_name_mangled; + case Mangled::ePreferDemangled: +return function_name_demangled; + case Mangled::ePreferDemangledWithoutArguments: +return function_name_noargs; + } +}(); vogelsgesang wrote: By the way: I don't think I will be merging this part of my commit in the end. https://github.com/llvm/llvm-project/pull/105756 is very similar, and I think I will just rebase on it, after it got merged https://github.com/llvm/llvm-project/pull/105695 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/105695 >From 19b4370c240cfcf4a57a5c38a64c8ba933d8102c Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Thu, 22 Aug 2024 10:50:13 + Subject: [PATCH 1/3] [lldb-dap] Add frame recognizers for libc++ `std::invoke` With this commit, we also hide the implementation details of `std::invoke`. To do so, the `LibCXXFrameRecognizer` got a couple more regular expressions. The regular expression passed into the `AddRecognizer` became problematic, as it was evaluated on the demangled name. Those names also included result types for C++ symbols. For `std::__invoke` the return type is a huge `decltype(...)`, making the regular expresison really hard to write. Instead, I added support for `AddRecognizer` to match on the demangled names without result type and argument types. By hiding the implementation details of `invoke`, also the back traces for `std::function` become even nicer, because `std::function` is using `__invoke` internally. --- .../lldb/Target/StackFrameRecognizer.h| 8 +++- lldb/source/Commands/Options.td | 2 +- .../CPlusPlus/CPPLanguageRuntime.cpp | 48 ++- lldb/source/Target/StackFrameRecognizer.cpp | 41 ++-- .../TestStdFunctionRecognizer.py | 21 +++- .../lang/cpp/std-invoke-recognizer/Makefile | 5 ++ .../TestStdInvokeRecognizer.py| 31 .../lang/cpp/std-invoke-recognizer/main.cpp | 40 8 files changed, 175 insertions(+), 21 deletions(-) create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h index 2f5c5caa6a4561..fe25dbbde745d1 100644 --- a/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -107,12 +107,14 @@ class StackFrameRecognizerManager { public: void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, ConstString module, llvm::ArrayRef symbols, - bool first_instruction_only = true); + bool first_instruction_only = true, + Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled); void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, lldb::RegularExpressionSP module, lldb::RegularExpressionSP symbol, - bool first_instruction_only = true); + bool first_instruction_only = true, + Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled); void ForEach(std::function< void(uint32_t recognizer_id, std::string recognizer_name, @@ -143,10 +145,12 @@ class StackFrameRecognizerManager { std::vector symbols; lldb::RegularExpressionSP symbol_regexp; bool first_instruction_only; +Mangled::NamePreference mangling_preference; }; std::deque m_recognizers; uint16_t m_generation = 0; + std::unordered_set m_used_manglings; }; /// \class ValueObjectRecognizerSynthesizedValue diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 9c4dbed6939ba9..df906e9d7c808f 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1049,7 +1049,7 @@ let Command = "thread backtrace" in { def thread_backtrace_extended : Option<"extended", "e">, Group<1>, Arg<"Boolean">, Desc<"Show the extended backtrace, if available">; def thread_backtrace_unfiltered : Option<"unfiltered", "u">, Group<1>, - Desc<"Filter out frames according to installed frame recognizers">; + Desc<"Do not filter out frames according to installed frame recognizers">; } let Command = "thread step scope" in { diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index c60200ab186d09..3665e1a4c77e55 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -7,6 +7,7 @@ //===--===// #include +#include #include @@ -44,7 +45,7 @@ char CPPLanguageRuntime::ID = 0; /// A frame recognizer that is installed to hide libc++ implementation /// details from the backtrace. class LibCXXFrameRecognizer : public StackFrameRecognizer { - RegularExpression m_hidden_function_regex; + std::array m_hidden_regex; RecognizedStackFrameSP m_hidden_frame; struct LibCXXHiddenFrame : public RecognizedStackFrame { @@ -53,10 +54,32 @@ class LibCXXFrameRecognizer : public Sta
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
@@ -145,6 +167,17 @@ StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) { if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue; +ConstString function_name = [&]() { + switch (entry.mangling_preference) { + case Mangled::ePreferMangled: +return function_name_mangled; + case Mangled::ePreferDemangled: +return function_name_demangled; + case Mangled::ePreferDemangledWithoutArguments: +return function_name_noargs; + } +}(); vogelsgesang wrote: > The demangling gets chached anyway (in the Mangled class). So wouldn't worry > about it ah, great! I didn't know this. I removed the additional caching from `StackFrameRecognizer` again https://github.com/llvm/llvm-project/pull/105695 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/105695 >From 19b4370c240cfcf4a57a5c38a64c8ba933d8102c Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Thu, 22 Aug 2024 10:50:13 + Subject: [PATCH 1/4] [lldb-dap] Add frame recognizers for libc++ `std::invoke` With this commit, we also hide the implementation details of `std::invoke`. To do so, the `LibCXXFrameRecognizer` got a couple more regular expressions. The regular expression passed into the `AddRecognizer` became problematic, as it was evaluated on the demangled name. Those names also included result types for C++ symbols. For `std::__invoke` the return type is a huge `decltype(...)`, making the regular expresison really hard to write. Instead, I added support for `AddRecognizer` to match on the demangled names without result type and argument types. By hiding the implementation details of `invoke`, also the back traces for `std::function` become even nicer, because `std::function` is using `__invoke` internally. --- .../lldb/Target/StackFrameRecognizer.h| 8 +++- lldb/source/Commands/Options.td | 2 +- .../CPlusPlus/CPPLanguageRuntime.cpp | 48 ++- lldb/source/Target/StackFrameRecognizer.cpp | 41 ++-- .../TestStdFunctionRecognizer.py | 21 +++- .../lang/cpp/std-invoke-recognizer/Makefile | 5 ++ .../TestStdInvokeRecognizer.py| 31 .../lang/cpp/std-invoke-recognizer/main.cpp | 40 8 files changed, 175 insertions(+), 21 deletions(-) create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h index 2f5c5caa6a4561..fe25dbbde745d1 100644 --- a/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -107,12 +107,14 @@ class StackFrameRecognizerManager { public: void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, ConstString module, llvm::ArrayRef symbols, - bool first_instruction_only = true); + bool first_instruction_only = true, + Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled); void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, lldb::RegularExpressionSP module, lldb::RegularExpressionSP symbol, - bool first_instruction_only = true); + bool first_instruction_only = true, + Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled); void ForEach(std::function< void(uint32_t recognizer_id, std::string recognizer_name, @@ -143,10 +145,12 @@ class StackFrameRecognizerManager { std::vector symbols; lldb::RegularExpressionSP symbol_regexp; bool first_instruction_only; +Mangled::NamePreference mangling_preference; }; std::deque m_recognizers; uint16_t m_generation = 0; + std::unordered_set m_used_manglings; }; /// \class ValueObjectRecognizerSynthesizedValue diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 9c4dbed6939ba9..df906e9d7c808f 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1049,7 +1049,7 @@ let Command = "thread backtrace" in { def thread_backtrace_extended : Option<"extended", "e">, Group<1>, Arg<"Boolean">, Desc<"Show the extended backtrace, if available">; def thread_backtrace_unfiltered : Option<"unfiltered", "u">, Group<1>, - Desc<"Filter out frames according to installed frame recognizers">; + Desc<"Do not filter out frames according to installed frame recognizers">; } let Command = "thread step scope" in { diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index c60200ab186d09..3665e1a4c77e55 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -7,6 +7,7 @@ //===--===// #include +#include #include @@ -44,7 +45,7 @@ char CPPLanguageRuntime::ID = 0; /// A frame recognizer that is installed to hide libc++ implementation /// details from the backtrace. class LibCXXFrameRecognizer : public StackFrameRecognizer { - RegularExpression m_hidden_function_regex; + std::array m_hidden_regex; RecognizedStackFrameSP m_hidden_frame; struct LibCXXHiddenFrame : public RecognizedStackFrame { @@ -53,10 +54,32 @@ class LibCXXFrameRecognizer : public Sta
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
@@ -145,6 +167,17 @@ StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) { if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue; +ConstString function_name = [&]() { + switch (entry.mangling_preference) { + case Mangled::ePreferMangled: +return function_name_mangled; + case Mangled::ePreferDemangled: +return function_name_demangled; + case Mangled::ePreferDemangledWithoutArguments: +return function_name_noargs; + } +}(); vogelsgesang wrote: > @vogelsgesang I closed my PR, feel free to copy&paste what you find useful. I did copy over: * the improved comments in `StackFrameRecognizer.h` * the printing improvements to `frame recognizer list` (but I am using a slightly different format) However, I did not change the `VerboseTrapFrameRecognizer` and `AssertFrameRecognizer` to use the mangled names. I will leave this for a follow-up commit. https://github.com/llvm/llvm-project/pull/105695 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)
@@ -1049,7 +1049,7 @@ let Command = "thread backtrace" in { def thread_backtrace_extended : Option<"extended", "e">, Group<1>, Arg<"Boolean">, Desc<"Show the extended backtrace, if available">; def thread_backtrace_unfiltered : Option<"unfiltered", "u">, Group<1>, - Desc<"Filter out frames according to installed frame recognizers">; + Desc<"Do not filter out frames according to installed frame recognizers">; vogelsgesang wrote: I don't have direct push-access and piggy-backing it in this PR is less effort for me https://github.com/llvm/llvm-project/pull/105695 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits