[Lldb-commits] [lldb] [lldb-dap] Implement a MemoryMonitor for macOS & Linux (PR #129332)
https://github.com/ashgti approved this pull request. Looks great! https://github.com/llvm/llvm-project/pull/129332 ___ 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 process picker command to VS Code extension (PR #128943)
@@ -0,0 +1,38 @@ +import { ChildProcessWithoutNullStreams, spawn } from "child_process"; +import { BaseProcessTree, ProcessTreeParser } from "../base-process-tree"; + +export class LinuxProcessTree extends BaseProcessTree { + protected override spawnProcess(): ChildProcessWithoutNullStreams { +return spawn( + "ps", + ["-axo", `pid=PID,lstart=START,comm:128=COMMAND,command=ARGUMENTS`], + { +stdio: "pipe", + }, ashgti wrote: `stdio: "pipe"` is the default https://github.com/llvm/llvm-project/pull/128943 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add terminfo dependency for ncurses support (PR #126810)
ajordanr-google wrote: /cherry-pick 8d017e6c0178f2628b246c18b2a634909815e54f eec242aa97c8d153574923f8237754ca3fa6f0a6 https://github.com/llvm/llvm-project/pull/126810 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add terminfo dependency for ncurses support (PR #126810)
llvmbot wrote: >/cherry-pick 8d017e6c0178f2628b246c18b2a634909815e54f >eec242aa97c8d153574923f8237754ca3fa6f0a6 Error: Command failed due to missing milestone. https://github.com/llvm/llvm-project/pull/126810 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 11b9466 - [lldb] Add ability to inspect backing threads with `thread info` (#129275)
Author: Felipe de Azevedo Piovezan Date: 2025-02-28T16:13:12-08:00 New Revision: 11b9466c04db4da7439fc1d9d8ba7241a9d68705 URL: https://github.com/llvm/llvm-project/commit/11b9466c04db4da7439fc1d9d8ba7241a9d68705 DIFF: https://github.com/llvm/llvm-project/commit/11b9466c04db4da7439fc1d9d8ba7241a9d68705.diff LOG: [lldb] Add ability to inspect backing threads with `thread info` (#129275) When OS plugins are present, it can be helpful to query information about the backing thread behind an OS thread, if it exists. There is no mechanism to do so prior to this commit. As a first step, this commit enhances `thread info` with a `--backing-thread` flag, causing the command to use the backing thread of the selected thread, if it exists. Added: Modified: lldb/source/Commands/CommandObjectThread.cpp lldb/source/Commands/Options.td lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py Removed: diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index cd3d2d89333f1..224c523e69c5c 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1270,6 +1270,7 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { void OptionParsingStarting(ExecutionContext *execution_context) override { m_json_thread = false; m_json_stopinfo = false; + m_backing_thread = false; } Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, @@ -1286,6 +1287,10 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { m_json_stopinfo = true; break; + case 'b': +m_backing_thread = true; +break; + default: llvm_unreachable("Unimplemented option"); } @@ -1298,6 +1303,7 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { bool m_json_thread; bool m_json_stopinfo; +bool m_backing_thread; }; CommandObjectThreadInfo(CommandInterpreter &interpreter) @@ -1334,6 +1340,8 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { } Thread *thread = thread_sp.get(); +if (m_options.m_backing_thread && thread->GetBackingThread()) + thread = thread->GetBackingThread().get(); Stream &strm = result.GetOutputStream(); if (!thread->GetDescription(strm, eDescriptionLevelFull, diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 8831fed38435b..cc579d767eb06 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1108,6 +1108,9 @@ let Command = "thread info" in { " JSON format.">; def thread_info_stop_info : Option<"stop-info", "s">, Desc<"Display the " "extended stop info in JSON format.">; + def thread_info_backing_thread : Option<"backing-thread", "b">, +Desc<"If this is an OS plugin thread, query the backing thread instead; has" +" no effect otherwise.">; } let Command = "thread return" in { diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py b/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py index fe78edd98f4d4..e4997f0742d02 100644 --- a/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py @@ -131,6 +131,26 @@ def run_python_os_funcionality(self): "Make sure there is no thread 0x3 after we unload the python OS plug-in", ) +tid_regex = re.compile(r"tid = ((0x)?[0-9a-fA-F]+)") + +def get_tid_from_thread_info_command(self, thread, use_backing_thread): +interp = self.dbg.GetCommandInterpreter() +result = lldb.SBCommandReturnObject() + +backing_thread_arg = "" +if use_backing_thread: +backing_thread_arg = "--backing-thread" + +interp.HandleCommand( +"thread info {0} {1}".format(thread.GetIndexID(), backing_thread_arg), +result, +True, +) +self.assertTrue(result.Succeeded(), "failed to run thread info") +match = self.tid_regex.search(result.GetOutput()) +self.assertNotEqual(match, None) +return int(match.group(1), 0) + def run_python_os_step(self): """Test that the Python operating system plugin works correctly and allows single stepping of a virtual thread that is backed by a real thread""" @@ -209,6 +229,11 @@ def run_python_os_step(self): # it to thread.StepOver() +tid_os = self.get_tid_from_thread_info_command(thread, False) +self.assertEqual(tid_os, 0x1) +tid_real = self.get_tid_from_thread_info_command(thread, True) +self.assertNotEqual(tid_os, tid_real) +
[Lldb-commits] [lldb] [lldb] Add terminfo dependency for ncurses support (PR #126810)
ajordanr-google wrote: /cherry-pick 8fff0c181f26a5e8b2344c061ebf2559118b1160 bb6a273d9ab9ee90dbb957e541f4d810fffb22ee https://github.com/llvm/llvm-project/pull/126810 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Fix a bug copying the stop hooks from the dummy target. (PR #129340)
https://github.com/jimingham created https://github.com/llvm/llvm-project/pull/129340 We didn't also copy over the next stop hook id, which meant we would overwrite the stop hooks from the dummy target with stop hooks set after they are copied over. >From 02e908312518e85f1d637529c9f62e3dd9551035 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 28 Feb 2025 15:55:03 -0800 Subject: [PATCH] Fix a bug copying the stop hooks from the dummy target. We didn't also copy over the next stop hook id, which meant we would overwrite the stop hooks from the dummy target with stop hooks set after they are copied over. --- lldb/source/Target/Target.cpp | 1 + .../target/stop-hooks/TestStopHooks.py| 24 +-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index db289fe9c4b64..550424720e095 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -211,6 +211,7 @@ Target::~Target() { void Target::PrimeFromDummyTarget(Target &target) { m_stop_hooks = target.m_stop_hooks; + m_stop_hook_next_id = target.m_stop_hook_next_id; for (const auto &breakpoint_sp : target.m_breakpoint_list.Breakpoints()) { if (breakpoint_sp->IsInternal()) diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py index fe59bd8a5d007..5215ec7258d14 100644 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py @@ -26,10 +26,15 @@ def test_stop_hooks_step_out(self): self.step_out_test() def test_stop_hooks_after_expr(self): -"""Test that a stop hook fires when hitting a breakpoint -that runs an expression""" +"""Test that a stop hook fires when hitting a breakpoint that + runs an expression""" self.after_expr_test() +def test_stop_hooks_before_and_after_creation(self): +"""Test that if we add a stop hook in the dummy target, we can + they don't collide with ones set directly in the target.""" +self.before_and_after_target() + def step_out_test(self): (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set a breakpoint here", self.main_source_file @@ -85,3 +90,18 @@ def after_expr_test(self): var = target.FindFirstGlobalVariable("g_var") self.assertTrue(var.IsValid()) self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var") + +def before_and_after_target(self): +interp = self.dbg.GetCommandInterpreter() +result = lldb.SBCommandReturnObject() +interp.HandleCommand("target stop-hook add -o 'expr g_var++'", result) +self.assertTrue(result.Succeeded(), "Set the target stop hook") + +(target, process, thread, first_bkpt) = lldbutil.run_to_source_breakpoint( +self, "Set a breakpoint here", self.main_source_file +) + +interp.HandleCommand("target stop-hook add -o 'thread backtrace'", result) +self.assertTrue(result.Succeeded(), "Set the target stop hook") +self.expect("target stop-hook list", substrs=["expr g_var++", "thread backtrace"]) + ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Fix a bug copying the stop hooks from the dummy target. (PR #129340)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: None (jimingham) Changes We didn't also copy over the next stop hook id, which meant we would overwrite the stop hooks from the dummy target with stop hooks set after they are copied over. --- Full diff: https://github.com/llvm/llvm-project/pull/129340.diff 2 Files Affected: - (modified) lldb/source/Target/Target.cpp (+1) - (modified) lldb/test/API/commands/target/stop-hooks/TestStopHooks.py (+22-2) ``diff diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index db289fe9c4b64..550424720e095 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -211,6 +211,7 @@ Target::~Target() { void Target::PrimeFromDummyTarget(Target &target) { m_stop_hooks = target.m_stop_hooks; + m_stop_hook_next_id = target.m_stop_hook_next_id; for (const auto &breakpoint_sp : target.m_breakpoint_list.Breakpoints()) { if (breakpoint_sp->IsInternal()) diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py index fe59bd8a5d007..5215ec7258d14 100644 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py @@ -26,10 +26,15 @@ def test_stop_hooks_step_out(self): self.step_out_test() def test_stop_hooks_after_expr(self): -"""Test that a stop hook fires when hitting a breakpoint -that runs an expression""" +"""Test that a stop hook fires when hitting a breakpoint that + runs an expression""" self.after_expr_test() +def test_stop_hooks_before_and_after_creation(self): +"""Test that if we add a stop hook in the dummy target, we can + they don't collide with ones set directly in the target.""" +self.before_and_after_target() + def step_out_test(self): (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set a breakpoint here", self.main_source_file @@ -85,3 +90,18 @@ def after_expr_test(self): var = target.FindFirstGlobalVariable("g_var") self.assertTrue(var.IsValid()) self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var") + +def before_and_after_target(self): +interp = self.dbg.GetCommandInterpreter() +result = lldb.SBCommandReturnObject() +interp.HandleCommand("target stop-hook add -o 'expr g_var++'", result) +self.assertTrue(result.Succeeded(), "Set the target stop hook") + +(target, process, thread, first_bkpt) = lldbutil.run_to_source_breakpoint( +self, "Set a breakpoint here", self.main_source_file +) + +interp.HandleCommand("target stop-hook add -o 'thread backtrace'", result) +self.assertTrue(result.Succeeded(), "Set the target stop hook") +self.expect("target stop-hook list", substrs=["expr g_var++", "thread backtrace"]) + `` https://github.com/llvm/llvm-project/pull/129340 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Minidump]Update MinidumpFileBuilder to read and write in chunks (PR #129307)
https://github.com/Jlalond edited https://github.com/llvm/llvm-project/pull/129307 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Fix a bug copying the stop hooks from the dummy target. (PR #129340)
github-actions[bot] wrote: :warning: Python code formatter, darker found issues in your code. :warning: You can test this locally with the following command: ``bash darker --check --diff -r 273fca94d4c4896df15f967a1388b7c533b76062...02e908312518e85f1d637529c9f62e3dd9551035 lldb/test/API/commands/target/stop-hooks/TestStopHooks.py `` View the diff from darker here. ``diff --- TestStopHooks.py2025-02-28 23:55:03.00 + +++ TestStopHooks.py2025-03-01 00:01:09.460330 + @@ -25,16 +25,16 @@ """Test that stop hooks fire on step-out.""" self.step_out_test() def test_stop_hooks_after_expr(self): """Test that a stop hook fires when hitting a breakpoint that - runs an expression""" +runs an expression""" self.after_expr_test() def test_stop_hooks_before_and_after_creation(self): """Test that if we add a stop hook in the dummy target, we can - they don't collide with ones set directly in the target.""" +they don't collide with ones set directly in the target.""" self.before_and_after_target() def step_out_test(self): (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set a breakpoint here", self.main_source_file @@ -101,7 +101,8 @@ self, "Set a breakpoint here", self.main_source_file ) interp.HandleCommand("target stop-hook add -o 'thread backtrace'", result) self.assertTrue(result.Succeeded(), "Set the target stop hook") -self.expect("target stop-hook list", substrs=["expr g_var++", "thread backtrace"]) - +self.expect( +"target stop-hook list", substrs=["expr g_var++", "thread backtrace"] +) `` https://github.com/llvm/llvm-project/pull/129340 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add terminfo dependency for ncurses support (PR #126810)
llvmbot wrote: /pull-request llvm/llvm-project#129342 https://github.com/llvm/llvm-project/pull/126810 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add ability to inspect backing threads with `thread info` (PR #129275)
https://github.com/felipepiovezan closed https://github.com/llvm/llvm-project/pull/129275 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Fix a bug copying the stop hooks from the dummy target. (PR #129340)
https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/129340 >From 02e908312518e85f1d637529c9f62e3dd9551035 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 28 Feb 2025 15:55:03 -0800 Subject: [PATCH 1/2] Fix a bug copying the stop hooks from the dummy target. We didn't also copy over the next stop hook id, which meant we would overwrite the stop hooks from the dummy target with stop hooks set after they are copied over. --- lldb/source/Target/Target.cpp | 1 + .../target/stop-hooks/TestStopHooks.py| 24 +-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index db289fe9c4b64..550424720e095 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -211,6 +211,7 @@ Target::~Target() { void Target::PrimeFromDummyTarget(Target &target) { m_stop_hooks = target.m_stop_hooks; + m_stop_hook_next_id = target.m_stop_hook_next_id; for (const auto &breakpoint_sp : target.m_breakpoint_list.Breakpoints()) { if (breakpoint_sp->IsInternal()) diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py index fe59bd8a5d007..5215ec7258d14 100644 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py @@ -26,10 +26,15 @@ def test_stop_hooks_step_out(self): self.step_out_test() def test_stop_hooks_after_expr(self): -"""Test that a stop hook fires when hitting a breakpoint -that runs an expression""" +"""Test that a stop hook fires when hitting a breakpoint that + runs an expression""" self.after_expr_test() +def test_stop_hooks_before_and_after_creation(self): +"""Test that if we add a stop hook in the dummy target, we can + they don't collide with ones set directly in the target.""" +self.before_and_after_target() + def step_out_test(self): (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set a breakpoint here", self.main_source_file @@ -85,3 +90,18 @@ def after_expr_test(self): var = target.FindFirstGlobalVariable("g_var") self.assertTrue(var.IsValid()) self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var") + +def before_and_after_target(self): +interp = self.dbg.GetCommandInterpreter() +result = lldb.SBCommandReturnObject() +interp.HandleCommand("target stop-hook add -o 'expr g_var++'", result) +self.assertTrue(result.Succeeded(), "Set the target stop hook") + +(target, process, thread, first_bkpt) = lldbutil.run_to_source_breakpoint( +self, "Set a breakpoint here", self.main_source_file +) + +interp.HandleCommand("target stop-hook add -o 'thread backtrace'", result) +self.assertTrue(result.Succeeded(), "Set the target stop hook") +self.expect("target stop-hook list", substrs=["expr g_var++", "thread backtrace"]) + >From 72e6f179525f1e13e7a1617ab04853304d116537 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 28 Feb 2025 16:23:31 -0800 Subject: [PATCH 2/2] uglify --- .../test/API/commands/target/stop-hooks/TestStopHooks.py | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py index 5215ec7258d14..c2cdcf0e2af52 100644 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py @@ -27,12 +27,12 @@ def test_stop_hooks_step_out(self): def test_stop_hooks_after_expr(self): """Test that a stop hook fires when hitting a breakpoint that - runs an expression""" +runs an expression""" self.after_expr_test() def test_stop_hooks_before_and_after_creation(self): """Test that if we add a stop hook in the dummy target, we can - they don't collide with ones set directly in the target.""" +they don't collide with ones set directly in the target.""" self.before_and_after_target() def step_out_test(self): @@ -103,5 +103,6 @@ def before_and_after_target(self): interp.HandleCommand("target stop-hook add -o 'thread backtrace'", result) self.assertTrue(result.Succeeded(), "Set the target stop hook") -self.expect("target stop-hook list", substrs=["expr g_var++", "thread backtrace"]) - +self.expect( +"target stop-hook list", substrs=["expr g_var++", "thread backtrace"] +) ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
https://github.com/matthewbastien updated https://github.com/llvm/llvm-project/pull/129262 >From b40c3e7e4ebb154c5f231676451acbd17e1f39f7 Mon Sep 17 00:00:00 2001 From: Matthew Bastien Date: Fri, 28 Feb 2025 11:08:25 -0500 Subject: [PATCH 1/2] allow providing debug adapter arguments --- lldb/tools/lldb-dap/package.json | 23 ++ .../lldb-dap/src-ts/debug-adapter-factory.ts | 72 +-- 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index cd450a614b3f7..aa11d8bcaa66e 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -75,6 +75,15 @@ "type": "string", "description": "The path to the lldb-dap binary." }, +"lldb-dap.arguments": { + "scope": "resource", + "type": "array", + "default": [], + "items": { +"type": "string" + }, + "description": "The arguments provided to the lldb-dap process." +}, "lldb-dap.log-path": { "scope": "resource", "type": "string", @@ -162,6 +171,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to debug." @@ -352,6 +368,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to attach to." diff --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts index 1f76fe31b00ad..51f45f87d660a 100644 --- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts +++ b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts @@ -25,7 +25,7 @@ async function findWithXcrun(executable: string): Promise { if (stdout) { return stdout.toString().trimEnd(); } -} catch (error) { } +} catch (error) {} } return undefined; } @@ -93,13 +93,33 @@ async function getDAPExecutable( return undefined; } +function getDAPArguments(session: vscode.DebugSession): string[] { + // Check the debug configuration for arguments first + const debugConfigArgs = session.configuration.debugAdapterArgs; + if ( +Array.isArray(debugConfigArgs) && +debugConfigArgs.findIndex((entry) => typeof entry !== "string") === -1 + ) { +return debugConfigArgs; + } + // Fall back on the workspace configuration + return vscode.workspace +.getConfiguration("lldb-dap") +.get("arguments", []); +} + /** * This class defines a factory used to find the lldb-dap binary to use * depending on the session configuration. */ export class LLDBDapDescriptorFactory - implements vscode.DebugAdapterDescriptorFactory, vscode.Disposable { - private server?: Promise<{ process: child_process.ChildProcess, host: string, port: number }>; + implements vscode.DebugAdapterDescriptorFactory, vscode.Disposable +{ + private server?: Promise<{ +process: child_process.ChildProcess; +host: string; +port: number; + }>; dispose() { this.server?.then(({ process }) => { @@ -109,7 +129,7 @@ export class LLDBDapDescriptorFactory async createDebugAdapterDescriptor( session: vscode.DebugSession, -executable: vscode.DebugAdapterExecutable | undefined, +_executable: vscode.DebugAdapterExecutable | undefined, ): Promise { const config = vscode.workspace.getConfiguration( "lldb-dap", @@ -123,7 +143,7 @@ export class LLDBDapDescriptorFactory } const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; -const dapPath = (await getDAPExecutable(session)) ?? executable?.command; +const dapPath = await getDAPExecutable(session); if (!dapPath) { LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(); @@ -137,32 +157,38 @@ export class LLDBDapDescriptorFactory const dbgOptions = { env: { -...executable?.options?.env, ...configEnvironment, ...env, }, }; -const dbgArgs = executable?.args ?? []; +
[Lldb-commits] [lldb] Update MinidumpFileBuilder to read and write in chunks (PR #129307)
https://github.com/Jlalond created https://github.com/llvm/llvm-project/pull/129307 I recently received an internal error report that LLDB was OOM'ing when creating a Minidump. In my 64b refactor we made a decision to acquire buffers the size of the largest memory region so we could read all of the contents in one call. This made error handling very simple (and simpler coding for me!) but had the trade off of large allocations if huge pages were enabled. This patch is one I've had on the back burner for awhile, but we can read and write the Minidump memory sections in discrete chunks which we already do for writing to disk. I had to refactor the error handling a bit, but it remains the same. We make a best effort attempt to read as much of the memory region as possible, but fail immediately if we receive an error writing to disk. I did not add new tests for this because our existing test suite is quite good, but I did manually verify a few Minidumps couldn't read beyond the red_zone. ``` (lldb) reg read $sp rsp = 0x7fffc3b0 (lldb) p/x 0x7fffc3b0 - 128 (long) 0x7fffc330 (lldb) memory read 0x7fffc330 0x7fffc330: 60 c3 ff ff ff 7f 00 00 60 cd ff ff ff 7f 00 00 `...`... 0x7fffc340: 60 c3 ff ff ff 7f 00 00 65 e6 26 00 00 00 00 00 `...e.&. (lldb) memory read 0x7fffc329 error: could not parse memory info ``` I'm not sure how to quantify the memory improvement other than we would allocate the largest size regardless of the size. So a 2gb unreadable region would cause a 2gb allocation even if we were reading 4096 kb. Now we will take the range size or the max chunk size of 128 mb. >From 2f77beefb752ffdae908101d75381268203311d6 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Fri, 28 Feb 2025 11:38:35 -0800 Subject: [PATCH] Update MinidumpFileBuilder to read and write in chunks --- .../Minidump/MinidumpFileBuilder.cpp | 130 -- .../ObjectFile/Minidump/MinidumpFileBuilder.h | 7 + 2 files changed, 97 insertions(+), 40 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index c5013ea5e3be4..e88b606f279cd 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -969,12 +969,82 @@ Status MinidumpFileBuilder::DumpDirectories() const { return error; } -static uint64_t -GetLargestRangeSize(const std::vector &ranges) { - uint64_t max_size = 0; - for (const auto &core_range : ranges) -max_size = std::max(max_size, core_range.range.size()); - return max_size; +Status MinidumpFileBuilder::ReadWriteMemoryInChunks( +const lldb_private::CoreFileMemoryRange &range, uint64_t *bytes_read) { + Log *log = GetLog(LLDBLog::Object); + lldb::addr_t addr = range.range.start(); + lldb::addr_t size = range.range.size(); + // First we set the byte tally to 0, so if we do exit gracefully + // the caller doesn't think the random garbage on the stack is a + // success. + if (bytes_read) +*bytes_read = 0; + + uint64_t bytes_remaining = size; + uint64_t total_bytes_read = 0; + auto data_up = std::make_unique( + std::min(bytes_remaining, MAX_WRITE_CHUNK_SIZE), 0); + Status error; + while (bytes_remaining > 0) { +// Get the next read chunk size as the minimum of the remaining bytes and +// the write chunk max size. +const size_t bytes_to_read = +std::min(bytes_remaining, MAX_WRITE_CHUNK_SIZE); +const size_t bytes_read_for_chunk = +m_process_sp->ReadMemory(range.range.start() + total_bytes_read, + data_up->GetBytes(), bytes_to_read, error); +if (error.Fail() || bytes_read_for_chunk == 0) { + LLDB_LOGF(log, +"Failed to read memory region at: %" PRIx64 +". Bytes read: %zu, error: %s", +addr, bytes_read_for_chunk, error.AsCString()); + // If we've only read one byte we can just give up and return + if (total_bytes_read == 0) +return Status(); + + // If we've read some bytes, we stop trying to read more and return + // this best effort attempt + bytes_remaining = 0; +} else if (bytes_read_for_chunk != bytes_to_read) { + LLDB_LOGF( + log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes", + addr, size); + + // If we've read some bytes, we stop trying to read more and return + // this best effort attempt + bytes_remaining = 0; +} + +// Write to the minidump file with the chunk potentially flushing to disk. +// this is the only place we want to return a true error, so that we can +// fail. If we get an error writing to disk we can't easily gaurauntee +// that we won't corrupt the minidump. +error = AddData(data_up->GetBytes(), bytes_read_for_chunk); +if (error.Fail(
[Lldb-commits] [lldb] [lldb-dap] Add process picker command to VS Code extension (PR #128943)
https://github.com/matthewbastien updated https://github.com/llvm/llvm-project/pull/128943 >From b9083ea16c7b1dba70cc04acf78f5001f0fb86c6 Mon Sep 17 00:00:00 2001 From: Matthew Bastien Date: Wed, 26 Feb 2025 11:18:21 -0500 Subject: [PATCH 1/5] add a process picker for attaching by PID --- lldb/tools/lldb-dap/package.json | 30 +- .../lldb-dap/src-ts/commands/pick-process.ts | 37 +++ lldb/tools/lldb-dap/src-ts/extension.ts | 7 +- .../src-ts/process-tree/base-process-tree.ts | 102 ++ .../lldb-dap/src-ts/process-tree/index.ts | 36 +++ .../platforms/darwin-process-tree.ts | 16 +++ .../platforms/linux-process-tree.ts | 38 +++ .../platforms/windows-process-tree.ts | 52 + 8 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 lldb/tools/lldb-dap/src-ts/commands/pick-process.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/base-process-tree.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/index.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/platforms/darwin-process-tree.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/platforms/linux-process-tree.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/platforms/windows-process-tree.ts diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 31d808eda4c35..1bbdbf045dd1b 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -146,6 +146,9 @@ "windows": { "program": "./bin/lldb-dap.exe" }, +"variables": { + "PickProcess": "lldb-dap.pickProcess" +}, "configurationAttributes": { "launch": { "required": [ @@ -517,6 +520,16 @@ "cwd": "^\"\\${workspaceRoot}\"" } }, + { +"label": "LLDB: Attach to Process", +"description": "", +"body": { + "type": "lldb-dap", + "request": "attach", + "name": "${1:Attach}", + "pid": "^\"\\${command:PickProcess}\"" +} + }, { "label": "LLDB: Attach", "description": "", @@ -541,6 +554,21 @@ } ] } -] +], +"commands": [ + { +"command": "lldb-dap.pickProcess", +"title": "Pick Process", +"category": "LLDB DAP" + } +], +"menus": { + "commandPalette": [ +{ + "command": "lldb-dap.pickProcess", + "when": "false" +} + ] +} } } diff --git a/lldb/tools/lldb-dap/src-ts/commands/pick-process.ts b/lldb/tools/lldb-dap/src-ts/commands/pick-process.ts new file mode 100644 index 0..b83e749e7da7b --- /dev/null +++ b/lldb/tools/lldb-dap/src-ts/commands/pick-process.ts @@ -0,0 +1,37 @@ +import * as path from "path"; +import * as vscode from "vscode"; +import { createProcessTree } from "../process-tree"; + +interface ProcessQuickPick extends vscode.QuickPickItem { + processId: number; +} + +/** + * Prompts the user to select a running process. + * + * @returns The pid of the process as a string or undefined if cancelled. + */ +export async function pickProcess(): Promise { + const processTree = createProcessTree(); + const selectedProcess = await vscode.window.showQuickPick( +processTree.listAllProcesses().then((processes): ProcessQuickPick[] => { + return processes +.sort((a, b) => b.start - a.start) // Sort by start date in descending order +.map((proc) => { + return { +processId: proc.id, +label: path.basename(proc.command), +description: proc.id.toString(), +detail: proc.arguments, + } satisfies ProcessQuickPick; +}); +}), +{ + placeHolder: "Select a process to attach the debugger to", +}, + ); + if (!selectedProcess) { +return; + } + return selectedProcess.processId.toString(); +} diff --git a/lldb/tools/lldb-dap/src-ts/extension.ts b/lldb/tools/lldb-dap/src-ts/extension.ts index 71fd48298f8f5..3532a2143155b 100644 --- a/lldb/tools/lldb-dap/src-ts/extension.ts +++ b/lldb/tools/lldb-dap/src-ts/extension.ts @@ -1,7 +1,6 @@ -import * as path from "path"; -import * as util from "util"; import * as vscode from "vscode"; +import { pickProcess } from "./commands/pick-process"; import { LLDBDapDescriptorFactory, isExecutable, @@ -38,6 +37,10 @@ export class LLDBDapExtension extends DisposableContext { } }), ); + +this.pushSubscription( + vscode.commands.registerCommand("lldb-dap.pickProcess", pickProcess), +); } } diff --git a/lldb/tools/lldb-dap/src-ts/process-tree/base-process-tree.ts b/lldb/tools/lldb-dap/src-ts/process-tree/base-process-tree.ts new file mode 100644 index 0..3c08f49035b35 --- /dev/null
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/129294 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
@@ -0,0 +1,22 @@ +#include "DAPLog.h" JDevlieghere wrote: Missing copyright header https://github.com/llvm/llvm-project/pull/129294 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/129294 >From 8d466e5c4b1b6913e788fd11d46689af8f0b8eec Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 27 Feb 2025 15:33:51 -0800 Subject: [PATCH 1/2] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog.h helpers. This only creates the basic types need to start using the LLDBLog.h helpers. Today, logging is handling by a simple `std::ofstream *` for handling logging. LLDBLog.h can help improve logging by adding new categories of logs and give us additional formatting support for log messages. --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/DAP.cpp | 62 lldb/tools/lldb-dap/DAP.h | 11 ++--- lldb/tools/lldb-dap/DAPLog.cpp | 22 + lldb/tools/lldb-dap/DAPLog.h| 34 + lldb/tools/lldb-dap/EventHelper.cpp | 17 --- lldb/tools/lldb-dap/IOStream.cpp| 19 lldb/tools/lldb-dap/IOStream.h | 7 ++- lldb/tools/lldb-dap/lldb-dap.cpp| 75 - 9 files changed, 146 insertions(+), 102 deletions(-) create mode 100644 lldb/tools/lldb-dap/DAPLog.cpp create mode 100644 lldb/tools/lldb-dap/DAPLog.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 8b3c520ec4360..d9f09f6d022ed 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_tool(lldb-dap Breakpoint.cpp BreakpointBase.cpp DAP.cpp + DAPLog.cpp EventHelper.cpp ExceptionBreakpoint.cpp FifoFiles.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 53c514b790f38..81f5205d4f6bd 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -7,6 +7,7 @@ //===--===// #include "DAP.h" +#include "DAPLog.h" #include "Handler/ResponseHandler.h" #include "JSONUtils.h" #include "LLDBUtils.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" #include "lldb/Utility/IOObject.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -50,6 +52,7 @@ #endif using namespace lldb_dap; +using namespace lldb_private; namespace { #ifdef _WIN32 @@ -61,13 +64,12 @@ const char DEV_NULL[] = "/dev/null"; namespace lldb_dap { -DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log, - lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode, +DAP::DAP(std::string name, llvm::StringRef path, lldb::IOObjectSP input, + lldb::IOObjectSP output, ReplMode repl_mode, std::vector pre_init_commands) -: name(std::move(name)), debug_adapter_path(path), log(log), - input(std::move(input)), output(std::move(output)), - broadcaster("lldb-dap"), exception_breakpoints(), - pre_init_commands(std::move(pre_init_commands)), +: name(std::move(name)), debug_adapter_path(path), input(std::move(input)), + output(std::move(output)), broadcaster("lldb-dap"), + exception_breakpoints(), pre_init_commands(std::move(pre_init_commands)), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), enable_auto_variable_summaries(false), enable_synthetic_child_debugging(false), @@ -245,6 +247,8 @@ void DAP::SendJSON(const std::string &json_str) { output.write_full(llvm::utostr(json_str.size())); output.write_full("\r\n\r\n"); output.write_full(json_str); + + LLDB_LOG(GetLog(DAPLog::Transport), "{0} <-- {1}", name, json_str); } // Serialize the JSON value into a string and send the JSON packet to @@ -256,15 +260,6 @@ void DAP::SendJSON(const llvm::json::Value &json) { static std::mutex mutex; std::lock_guard locker(mutex); SendJSON(json_str); - - if (log) { -auto now = std::chrono::duration( -std::chrono::system_clock::now().time_since_epoch()); -*log << llvm::formatv("{0:f9} {1} <-- ", now.count(), name).str() - << std::endl - << "Content-Length: " << json_str.size() << "\r\n\r\n" - << llvm::formatv("{0:2}", json).str() << std::endl; - } } // Read a JSON packet from the "in" stream. @@ -273,28 +268,22 @@ std::string DAP::ReadJSON() { std::string json_str; int length; - if (!input.read_expected(log, "Content-Length: ")) + if (!input.read_expected("Content-Length: ")) return json_str; - if (!input.read_line(log, length_str)) + if (!input.read_line(length_str)) return json_str; if (!llvm::to_integer(length_str, length)) return json_str; - if (!input.read_expected(log, "\r\n")) + if (!input.read_expected("\r\n")) return json_str; - if (!input.read_full(log, length, json_str)) + if (!input.read_full(length, json_str)) return json_str; - if (log) { -auto now = std::chrono::duration( -
[Lldb-commits] [lldb] [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (PR #128957)
https://github.com/ashgti edited https://github.com/llvm/llvm-project/pull/128957 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add ability to inspect backing threads with `thread info` (PR #129275)
https://github.com/felipepiovezan updated https://github.com/llvm/llvm-project/pull/129275 >From cd6661b5fb7a9a71352c79740d4b0c0601e61d43 Mon Sep 17 00:00:00 2001 From: Felipe de Azevedo Piovezan Date: Fri, 28 Feb 2025 09:11:11 -0800 Subject: [PATCH 1/4] [lldb] Add ability to inspect backing threads with `thread info` When OS plugins are present, it can be helpful to query information about the backing thread behind an OS thread, if it exists. There is no mechanism to do so prior to this commit. As a first step, this commit enhances `thread info` with a `--backing-thread` flag, causing the command to use the backing thread of the selected thread, if it exists. --- lldb/source/Commands/CommandObjectThread.cpp | 8 +++ lldb/source/Commands/Options.td | 3 +++ .../python_os_plugin/TestPythonOSPlugin.py| 24 +++ 3 files changed, 35 insertions(+) diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index cd3d2d89333f1..224c523e69c5c 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1270,6 +1270,7 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { void OptionParsingStarting(ExecutionContext *execution_context) override { m_json_thread = false; m_json_stopinfo = false; + m_backing_thread = false; } Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, @@ -1286,6 +1287,10 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { m_json_stopinfo = true; break; + case 'b': +m_backing_thread = true; +break; + default: llvm_unreachable("Unimplemented option"); } @@ -1298,6 +1303,7 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { bool m_json_thread; bool m_json_stopinfo; +bool m_backing_thread; }; CommandObjectThreadInfo(CommandInterpreter &interpreter) @@ -1334,6 +1340,8 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { } Thread *thread = thread_sp.get(); +if (m_options.m_backing_thread && thread->GetBackingThread()) + thread = thread->GetBackingThread().get(); Stream &strm = result.GetOutputStream(); if (!thread->GetDescription(strm, eDescriptionLevelFull, diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 8831fed38435b..cc579d767eb06 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1108,6 +1108,9 @@ let Command = "thread info" in { " JSON format.">; def thread_info_stop_info : Option<"stop-info", "s">, Desc<"Display the " "extended stop info in JSON format.">; + def thread_info_backing_thread : Option<"backing-thread", "b">, +Desc<"If this is an OS plugin thread, query the backing thread instead; has" +" no effect otherwise.">; } let Command = "thread return" in { diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py b/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py index fe78edd98f4d4..33e4f75adc0d0 100644 --- a/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py @@ -131,6 +131,25 @@ def run_python_os_funcionality(self): "Make sure there is no thread 0x3 after we unload the python OS plug-in", ) +tid_regex = re.compile("tid = (0x[0-9a-fA-F]+)") +def get_tid_from_thread_info_command(self, thread, use_backing_thread): +interp = self.dbg.GetCommandInterpreter() +result = lldb.SBCommandReturnObject() + +backing_thread_arg = "" +if use_backing_thread: +backing_thread_arg = "--backing-thread" + +interp.HandleCommand( +"thread info {0} {1}".format(thread.GetIndexID(), backing_thread_arg), +result, +True, +) +self.assertTrue(result.Succeeded(), "failed to run thread info") +match = self.tid_regex.search(result.GetOutput()) +self.assertNotEqual(match, None) +return match.group(1) + def run_python_os_step(self): """Test that the Python operating system plugin works correctly and allows single stepping of a virtual thread that is backed by a real thread""" @@ -209,6 +228,11 @@ def run_python_os_step(self): # it to thread.StepOver() +tid_os = self.get_tid_from_thread_info_command(thread, False) +self.assertEqual(tid_os, "0x1") +tid_real = self.get_tid_from_thread_info_command(thread, True) +self.assertNotEqual(tid_os, tid_real) + frame = thread.GetFrameAtIndex(0) self.assertTrue( frame.IsValid(), "Make sure we get a frame from thread 0x1" >Fro
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
ashgti wrote: Also, for reference, this does change the output format. ``` $ cat lldb-test-build.noindex/tools/lldb-dap/launch/TestDAP_launch.test_termination/dap.txt 1740771506.578514099 stdin/stdout --> {"command":"disconnect","type":"request","arguments":{},"seq":1} 1740771506.578675032 stdin/stdout <-- {"event":"terminated","seq":0,"type":"event"} 1740771506.579591990 stdin/stdout <-- {"command":"disconnect","request_seq":1,"seq":0,"success":true,"type":"response"} ``` Is an example of what things look like with this change. Before this was formatted like: ``` (<--|-->) Content-Length: {...} ``` So its more compact now since we don't include the full protocol encoding header ("Content-Length: {size}\r\n\r\n"). https://github.com/llvm/llvm-project/pull/129294 ___ 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 process picker command to VS Code extension (PR #128943)
https://github.com/matthewbastien updated https://github.com/llvm/llvm-project/pull/128943 >From b9083ea16c7b1dba70cc04acf78f5001f0fb86c6 Mon Sep 17 00:00:00 2001 From: Matthew Bastien Date: Wed, 26 Feb 2025 11:18:21 -0500 Subject: [PATCH 1/5] add a process picker for attaching by PID --- lldb/tools/lldb-dap/package.json | 30 +- .../lldb-dap/src-ts/commands/pick-process.ts | 37 +++ lldb/tools/lldb-dap/src-ts/extension.ts | 7 +- .../src-ts/process-tree/base-process-tree.ts | 102 ++ .../lldb-dap/src-ts/process-tree/index.ts | 36 +++ .../platforms/darwin-process-tree.ts | 16 +++ .../platforms/linux-process-tree.ts | 38 +++ .../platforms/windows-process-tree.ts | 52 + 8 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 lldb/tools/lldb-dap/src-ts/commands/pick-process.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/base-process-tree.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/index.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/platforms/darwin-process-tree.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/platforms/linux-process-tree.ts create mode 100644 lldb/tools/lldb-dap/src-ts/process-tree/platforms/windows-process-tree.ts diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 31d808eda4c35..1bbdbf045dd1b 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -146,6 +146,9 @@ "windows": { "program": "./bin/lldb-dap.exe" }, +"variables": { + "PickProcess": "lldb-dap.pickProcess" +}, "configurationAttributes": { "launch": { "required": [ @@ -517,6 +520,16 @@ "cwd": "^\"\\${workspaceRoot}\"" } }, + { +"label": "LLDB: Attach to Process", +"description": "", +"body": { + "type": "lldb-dap", + "request": "attach", + "name": "${1:Attach}", + "pid": "^\"\\${command:PickProcess}\"" +} + }, { "label": "LLDB: Attach", "description": "", @@ -541,6 +554,21 @@ } ] } -] +], +"commands": [ + { +"command": "lldb-dap.pickProcess", +"title": "Pick Process", +"category": "LLDB DAP" + } +], +"menus": { + "commandPalette": [ +{ + "command": "lldb-dap.pickProcess", + "when": "false" +} + ] +} } } diff --git a/lldb/tools/lldb-dap/src-ts/commands/pick-process.ts b/lldb/tools/lldb-dap/src-ts/commands/pick-process.ts new file mode 100644 index 0..b83e749e7da7b --- /dev/null +++ b/lldb/tools/lldb-dap/src-ts/commands/pick-process.ts @@ -0,0 +1,37 @@ +import * as path from "path"; +import * as vscode from "vscode"; +import { createProcessTree } from "../process-tree"; + +interface ProcessQuickPick extends vscode.QuickPickItem { + processId: number; +} + +/** + * Prompts the user to select a running process. + * + * @returns The pid of the process as a string or undefined if cancelled. + */ +export async function pickProcess(): Promise { + const processTree = createProcessTree(); + const selectedProcess = await vscode.window.showQuickPick( +processTree.listAllProcesses().then((processes): ProcessQuickPick[] => { + return processes +.sort((a, b) => b.start - a.start) // Sort by start date in descending order +.map((proc) => { + return { +processId: proc.id, +label: path.basename(proc.command), +description: proc.id.toString(), +detail: proc.arguments, + } satisfies ProcessQuickPick; +}); +}), +{ + placeHolder: "Select a process to attach the debugger to", +}, + ); + if (!selectedProcess) { +return; + } + return selectedProcess.processId.toString(); +} diff --git a/lldb/tools/lldb-dap/src-ts/extension.ts b/lldb/tools/lldb-dap/src-ts/extension.ts index 71fd48298f8f5..3532a2143155b 100644 --- a/lldb/tools/lldb-dap/src-ts/extension.ts +++ b/lldb/tools/lldb-dap/src-ts/extension.ts @@ -1,7 +1,6 @@ -import * as path from "path"; -import * as util from "util"; import * as vscode from "vscode"; +import { pickProcess } from "./commands/pick-process"; import { LLDBDapDescriptorFactory, isExecutable, @@ -38,6 +37,10 @@ export class LLDBDapExtension extends DisposableContext { } }), ); + +this.pushSubscription( + vscode.commands.registerCommand("lldb-dap.pickProcess", pickProcess), +); } } diff --git a/lldb/tools/lldb-dap/src-ts/process-tree/base-process-tree.ts b/lldb/tools/lldb-dap/src-ts/process-tree/base-process-tree.ts new file mode 100644 index 0..3c08f49035b35 --- /dev/null
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/129294 Today, logging is handling by a simple `std::ofstream *` for handling logging. LLDBLog.h can help improve logging by adding new categories of logs and give us additional formatting support for log messages. We link against the libHost, which includes lldbUtility. >From 71f82c81f04207f46713e9bf2c0c6bc84e3c5216 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 27 Feb 2025 15:33:51 -0800 Subject: [PATCH] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog.h helpers. This only creates the basic types need to start using the LLDBLog.h helpers. Today, logging is handling by a simple `std::ofstream *` for handling logging. LLDBLog.h can help improve logging by adding new categories of logs and give us additional formatting support for log messages. --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/DAP.cpp | 62 lldb/tools/lldb-dap/DAP.h | 11 ++--- lldb/tools/lldb-dap/DAPLog.cpp | 22 + lldb/tools/lldb-dap/DAPLog.h| 34 + lldb/tools/lldb-dap/EventHelper.cpp | 17 --- lldb/tools/lldb-dap/IOStream.cpp| 19 lldb/tools/lldb-dap/IOStream.h | 7 ++- lldb/tools/lldb-dap/lldb-dap.cpp| 75 - 9 files changed, 146 insertions(+), 102 deletions(-) create mode 100644 lldb/tools/lldb-dap/DAPLog.cpp create mode 100644 lldb/tools/lldb-dap/DAPLog.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 8b3c520ec4360..d9f09f6d022ed 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_tool(lldb-dap Breakpoint.cpp BreakpointBase.cpp DAP.cpp + DAPLog.cpp EventHelper.cpp ExceptionBreakpoint.cpp FifoFiles.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 53c514b790f38..81f5205d4f6bd 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -7,6 +7,7 @@ //===--===// #include "DAP.h" +#include "DAPLog.h" #include "Handler/ResponseHandler.h" #include "JSONUtils.h" #include "LLDBUtils.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" #include "lldb/Utility/IOObject.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -50,6 +52,7 @@ #endif using namespace lldb_dap; +using namespace lldb_private; namespace { #ifdef _WIN32 @@ -61,13 +64,12 @@ const char DEV_NULL[] = "/dev/null"; namespace lldb_dap { -DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log, - lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode, +DAP::DAP(std::string name, llvm::StringRef path, lldb::IOObjectSP input, + lldb::IOObjectSP output, ReplMode repl_mode, std::vector pre_init_commands) -: name(std::move(name)), debug_adapter_path(path), log(log), - input(std::move(input)), output(std::move(output)), - broadcaster("lldb-dap"), exception_breakpoints(), - pre_init_commands(std::move(pre_init_commands)), +: name(std::move(name)), debug_adapter_path(path), input(std::move(input)), + output(std::move(output)), broadcaster("lldb-dap"), + exception_breakpoints(), pre_init_commands(std::move(pre_init_commands)), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), enable_auto_variable_summaries(false), enable_synthetic_child_debugging(false), @@ -245,6 +247,8 @@ void DAP::SendJSON(const std::string &json_str) { output.write_full(llvm::utostr(json_str.size())); output.write_full("\r\n\r\n"); output.write_full(json_str); + + LLDB_LOG(GetLog(DAPLog::Transport), "{0} <-- {1}", name, json_str); } // Serialize the JSON value into a string and send the JSON packet to @@ -256,15 +260,6 @@ void DAP::SendJSON(const llvm::json::Value &json) { static std::mutex mutex; std::lock_guard locker(mutex); SendJSON(json_str); - - if (log) { -auto now = std::chrono::duration( -std::chrono::system_clock::now().time_since_epoch()); -*log << llvm::formatv("{0:f9} {1} <-- ", now.count(), name).str() - << std::endl - << "Content-Length: " << json_str.size() << "\r\n\r\n" - << llvm::formatv("{0:2}", json).str() << std::endl; - } } // Read a JSON packet from the "in" stream. @@ -273,28 +268,22 @@ std::string DAP::ReadJSON() { std::string json_str; int length; - if (!input.read_expected(log, "Content-Length: ")) + if (!input.read_expected("Content-Length: ")) return json_str; - if (!input.read_line(log, length_str)) + if (!input.read_line(length_str)) return json_str; if (!llvm::to_integer(length_str, length)) return json_str; - if (!
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
https://github.com/ashgti ready_for_review https://github.com/llvm/llvm-project/pull/129294 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
https://github.com/ashgti edited https://github.com/llvm/llvm-project/pull/129294 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add terminfo dependency for ncurses support (PR #126810)
ajordanr-google wrote: We haven't had any issues since on our end. I'll check with Fuchsia again to be sure, then will try to backport. https://github.com/llvm/llvm-project/pull/126810 ___ 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 process picker command to VS Code extension (PR #128943)
@@ -0,0 +1,102 @@ +import { ChildProcessWithoutNullStreams } from "child_process"; +import { Process, ProcessTree } from "."; +import { Transform } from "stream"; + +/** Parses process information from a given line of process output. */ +export type ProcessTreeParser = (line: string) => Process | undefined; + +/** + * Implements common behavior between the different {@link ProcessTree} implementations. + */ +export abstract class BaseProcessTree implements ProcessTree { + /** + * Spawn the process responsible for collecting all processes on the system. + */ + protected abstract spawnProcess(): ChildProcessWithoutNullStreams; matthewbastien wrote: So it does! Fixed. Thanks! https://github.com/llvm/llvm-project/pull/128943 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Control the "step out through thunk" logic explicitly when pushing thread plans (PR #129301)
https://github.com/jimingham closed https://github.com/llvm/llvm-project/pull/129301 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add ability to inspect backing threads with `thread info` (PR #129275)
https://github.com/felipepiovezan updated https://github.com/llvm/llvm-project/pull/129275 >From cd6661b5fb7a9a71352c79740d4b0c0601e61d43 Mon Sep 17 00:00:00 2001 From: Felipe de Azevedo Piovezan Date: Fri, 28 Feb 2025 09:11:11 -0800 Subject: [PATCH 1/3] [lldb] Add ability to inspect backing threads with `thread info` When OS plugins are present, it can be helpful to query information about the backing thread behind an OS thread, if it exists. There is no mechanism to do so prior to this commit. As a first step, this commit enhances `thread info` with a `--backing-thread` flag, causing the command to use the backing thread of the selected thread, if it exists. --- lldb/source/Commands/CommandObjectThread.cpp | 8 +++ lldb/source/Commands/Options.td | 3 +++ .../python_os_plugin/TestPythonOSPlugin.py| 24 +++ 3 files changed, 35 insertions(+) diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index cd3d2d89333f1..224c523e69c5c 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1270,6 +1270,7 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { void OptionParsingStarting(ExecutionContext *execution_context) override { m_json_thread = false; m_json_stopinfo = false; + m_backing_thread = false; } Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, @@ -1286,6 +1287,10 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { m_json_stopinfo = true; break; + case 'b': +m_backing_thread = true; +break; + default: llvm_unreachable("Unimplemented option"); } @@ -1298,6 +1303,7 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { bool m_json_thread; bool m_json_stopinfo; +bool m_backing_thread; }; CommandObjectThreadInfo(CommandInterpreter &interpreter) @@ -1334,6 +1340,8 @@ class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { } Thread *thread = thread_sp.get(); +if (m_options.m_backing_thread && thread->GetBackingThread()) + thread = thread->GetBackingThread().get(); Stream &strm = result.GetOutputStream(); if (!thread->GetDescription(strm, eDescriptionLevelFull, diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 8831fed38435b..cc579d767eb06 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1108,6 +1108,9 @@ let Command = "thread info" in { " JSON format.">; def thread_info_stop_info : Option<"stop-info", "s">, Desc<"Display the " "extended stop info in JSON format.">; + def thread_info_backing_thread : Option<"backing-thread", "b">, +Desc<"If this is an OS plugin thread, query the backing thread instead; has" +" no effect otherwise.">; } let Command = "thread return" in { diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py b/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py index fe78edd98f4d4..33e4f75adc0d0 100644 --- a/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py @@ -131,6 +131,25 @@ def run_python_os_funcionality(self): "Make sure there is no thread 0x3 after we unload the python OS plug-in", ) +tid_regex = re.compile("tid = (0x[0-9a-fA-F]+)") +def get_tid_from_thread_info_command(self, thread, use_backing_thread): +interp = self.dbg.GetCommandInterpreter() +result = lldb.SBCommandReturnObject() + +backing_thread_arg = "" +if use_backing_thread: +backing_thread_arg = "--backing-thread" + +interp.HandleCommand( +"thread info {0} {1}".format(thread.GetIndexID(), backing_thread_arg), +result, +True, +) +self.assertTrue(result.Succeeded(), "failed to run thread info") +match = self.tid_regex.search(result.GetOutput()) +self.assertNotEqual(match, None) +return match.group(1) + def run_python_os_step(self): """Test that the Python operating system plugin works correctly and allows single stepping of a virtual thread that is backed by a real thread""" @@ -209,6 +228,11 @@ def run_python_os_step(self): # it to thread.StepOver() +tid_os = self.get_tid_from_thread_info_command(thread, False) +self.assertEqual(tid_os, "0x1") +tid_real = self.get_tid_from_thread_info_command(thread, True) +self.assertNotEqual(tid_os, tid_real) + frame = thread.GetFrameAtIndex(0) self.assertTrue( frame.IsValid(), "Make sure we get a frame from thread 0x1" >Fro
[Lldb-commits] [lldb] Control the "step out through thunk" logic explicitly when pushing thread plans (PR #129301)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: None (jimingham) Changes Jonas recently added a trampoline handling strategy for simple language thunks that does: "step through language thunks stepping in one level deep and stopping if you hit user code". That was actually pulled over from the swift implementation. However, this strategy and the strategy we have to "step out past language thunks" when stepping out come into conflict if the thunk you are stepping through calls some other function before dispatching to the intended method. When you step out of the called function back into the thunk, should you keep stepping out past the thunk or not? In most cases, you want to step out past the thunk, but in this particular case you don't. This patch adds a way to inform the thread plan (or really it's ShouldStopHere behavior) of which behavior it should have, and passes the don't step through thunks to the step through plan it uses to step through thunks. I didn't add a test for this because I couldn't find a C++ thunk that calls another function before getting to the target function. I asked the clang folks here if they could think of a case where clang would do this, and they couldn't. If anyone can think of such a construct, it will be easy to write the step through test for it... This does happen in swift, however, so when I cherry-pick this to the swift fork I'll test it there. --- Full diff: https://github.com/llvm/llvm-project/pull/129301.diff 3 Files Affected: - (modified) lldb/include/lldb/Target/ThreadPlanShouldStopHere.h (+2-1) - (modified) lldb/source/Target/ThreadPlanShouldStopHere.cpp (+11-4) - (modified) lldb/source/Target/ThreadPlanStepInRange.cpp (+2-1) ``diff diff --git a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h index 54b30291c3995..d0094c90b91a5 100644 --- a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h +++ b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h @@ -59,7 +59,8 @@ class ThreadPlanShouldStopHere { eNone = 0, eAvoidInlines = (1 << 0), eStepInAvoidNoDebug = (1 << 1), -eStepOutAvoidNoDebug = (1 << 2) +eStepOutAvoidNoDebug = (1 << 2), +eStepOutPastThunks = (1 << 3) }; // Constructors and Destructors diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp index fa6bc08a9914d..be6bd981c72bc 100644 --- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -8,6 +8,7 @@ #include "lldb/Target/ThreadPlanShouldStopHere.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" @@ -83,7 +84,11 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( if (Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol) { ProcessSP process_sp(current_plan->GetThread().GetProcess()); for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*symbol)) { +if (runtime->IsSymbolARuntimeThunk(*symbol) + && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); should_stop_here = false; break; } @@ -131,9 +136,11 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( // because it's marked line 0. bool is_thunk = false; for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*sc.symbol)) { - LLDB_LOGF(log, "In runtime thunk %s - stepping out.", -sc.symbol->GetName().GetCString()); +if (runtime->IsSymbolARuntimeThunk(*sc.symbol) + && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); is_thunk = true; break; } diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 109d1b6b3435b..3affeae1ee388 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -27,7 +27,8 @@ using namespace lldb; using namespace lldb_private; uint32_t ThreadPlanStepInRange::s_default_flag_values = -ThreadPlanShouldStopHere::eStepInAvoidNoDebug; +ThreadPlanShouldStopHere::eStepInAvoidNoDebug | +ThreadPlanShouldStopHere::eStepOutPastThunks; // ThreadPlanStepInRange: Step through a stack range, either steppi
[Lldb-commits] [lldb] [lldb] Add ability to inspect backing threads with `thread info` (PR #129275)
felipepiovezan wrote: Linux bots seem to print the TID using decimal numbers, so I updated the regex. https://github.com/llvm/llvm-project/pull/129275 ___ 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 process picker command to VS Code extension (PR #128943)
@@ -0,0 +1,102 @@ +import { ChildProcessWithoutNullStreams } from "child_process"; +import { Process, ProcessTree } from "."; +import { Transform } from "stream"; + +/** Parses process information from a given line of process output. */ +export type ProcessTreeParser = (line: string) => Process | undefined; + +/** + * Implements common behavior between the different {@link ProcessTree} implementations. + */ +export abstract class BaseProcessTree implements ProcessTree { + /** + * Spawn the process responsible for collecting all processes on the system. + */ + protected abstract spawnProcess(): ChildProcessWithoutNullStreams; ashgti wrote: You can use `execFile`, which takes the program and arguments separately https://github.com/llvm/llvm-project/pull/128943 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/129294 >From 8d466e5c4b1b6913e788fd11d46689af8f0b8eec Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 27 Feb 2025 15:33:51 -0800 Subject: [PATCH 1/3] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog.h helpers. This only creates the basic types need to start using the LLDBLog.h helpers. Today, logging is handling by a simple `std::ofstream *` for handling logging. LLDBLog.h can help improve logging by adding new categories of logs and give us additional formatting support for log messages. --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/DAP.cpp | 62 lldb/tools/lldb-dap/DAP.h | 11 ++--- lldb/tools/lldb-dap/DAPLog.cpp | 22 + lldb/tools/lldb-dap/DAPLog.h| 34 + lldb/tools/lldb-dap/EventHelper.cpp | 17 --- lldb/tools/lldb-dap/IOStream.cpp| 19 lldb/tools/lldb-dap/IOStream.h | 7 ++- lldb/tools/lldb-dap/lldb-dap.cpp| 75 - 9 files changed, 146 insertions(+), 102 deletions(-) create mode 100644 lldb/tools/lldb-dap/DAPLog.cpp create mode 100644 lldb/tools/lldb-dap/DAPLog.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 8b3c520ec4360..d9f09f6d022ed 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_tool(lldb-dap Breakpoint.cpp BreakpointBase.cpp DAP.cpp + DAPLog.cpp EventHelper.cpp ExceptionBreakpoint.cpp FifoFiles.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 53c514b790f38..81f5205d4f6bd 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -7,6 +7,7 @@ //===--===// #include "DAP.h" +#include "DAPLog.h" #include "Handler/ResponseHandler.h" #include "JSONUtils.h" #include "LLDBUtils.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" #include "lldb/Utility/IOObject.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -50,6 +52,7 @@ #endif using namespace lldb_dap; +using namespace lldb_private; namespace { #ifdef _WIN32 @@ -61,13 +64,12 @@ const char DEV_NULL[] = "/dev/null"; namespace lldb_dap { -DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log, - lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode, +DAP::DAP(std::string name, llvm::StringRef path, lldb::IOObjectSP input, + lldb::IOObjectSP output, ReplMode repl_mode, std::vector pre_init_commands) -: name(std::move(name)), debug_adapter_path(path), log(log), - input(std::move(input)), output(std::move(output)), - broadcaster("lldb-dap"), exception_breakpoints(), - pre_init_commands(std::move(pre_init_commands)), +: name(std::move(name)), debug_adapter_path(path), input(std::move(input)), + output(std::move(output)), broadcaster("lldb-dap"), + exception_breakpoints(), pre_init_commands(std::move(pre_init_commands)), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), enable_auto_variable_summaries(false), enable_synthetic_child_debugging(false), @@ -245,6 +247,8 @@ void DAP::SendJSON(const std::string &json_str) { output.write_full(llvm::utostr(json_str.size())); output.write_full("\r\n\r\n"); output.write_full(json_str); + + LLDB_LOG(GetLog(DAPLog::Transport), "{0} <-- {1}", name, json_str); } // Serialize the JSON value into a string and send the JSON packet to @@ -256,15 +260,6 @@ void DAP::SendJSON(const llvm::json::Value &json) { static std::mutex mutex; std::lock_guard locker(mutex); SendJSON(json_str); - - if (log) { -auto now = std::chrono::duration( -std::chrono::system_clock::now().time_since_epoch()); -*log << llvm::formatv("{0:f9} {1} <-- ", now.count(), name).str() - << std::endl - << "Content-Length: " << json_str.size() << "\r\n\r\n" - << llvm::formatv("{0:2}", json).str() << std::endl; - } } // Read a JSON packet from the "in" stream. @@ -273,28 +268,22 @@ std::string DAP::ReadJSON() { std::string json_str; int length; - if (!input.read_expected(log, "Content-Length: ")) + if (!input.read_expected("Content-Length: ")) return json_str; - if (!input.read_line(log, length_str)) + if (!input.read_line(length_str)) return json_str; if (!llvm::to_integer(length_str, length)) return json_str; - if (!input.read_expected(log, "\r\n")) + if (!input.read_expected("\r\n")) return json_str; - if (!input.read_full(log, length, json_str)) + if (!input.read_full(length, json_str)) return json_str; - if (log) { -auto now = std::chrono::duration( -
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
@@ -0,0 +1,34 @@ +//===-- DAPLog.h *- C++ -*-===// ashgti wrote: Done. https://github.com/llvm/llvm-project/pull/129294 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
@@ -0,0 +1,22 @@ +#include "DAPLog.h" ashgti wrote: Added https://github.com/llvm/llvm-project/pull/129294 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Control the "step out through thunk" logic explicitly when pushing thread plans (PR #129301)
https://github.com/jimingham created https://github.com/llvm/llvm-project/pull/129301 Jonas recently added a trampoline handling strategy for simple language thunks that does: "step through language thunks stepping in one level deep and stopping if you hit user code". That was actually pulled over from the swift implementation. However, this strategy and the strategy we have to "step out past language thunks" when stepping out come into conflict if the thunk you are stepping through calls some other function before dispatching to the intended method. When you step out of the called function back into the thunk, should you keep stepping out past the thunk or not? In most cases, you want to step out past the thunk, but in this particular case you don't. This patch adds a way to inform the thread plan (or really it's ShouldStopHere behavior) of which behavior it should have, and passes the don't step through thunks to the step through plan it uses to step through thunks. I didn't add a test for this because I couldn't find a C++ thunk that calls another function before getting to the target function. I asked the clang folks here if they could think of a case where clang would do this, and they couldn't. If anyone can think of such a construct, it will be easy to write the step through test for it... This does happen in swift, however, so when I cherry-pick this to the swift fork I'll test it there. >From a26c5596ac599f1b51cffebd658f3823388e Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 28 Feb 2025 11:45:51 -0800 Subject: [PATCH] Control the "step out through thunk" logic explicitly when pushing thread plans. That allow the thread plan that is trying to step through a thunk to its target to step out of a function it has stepped into without also stepping out past the thunk we were trying to step through. --- .../lldb/Target/ThreadPlanShouldStopHere.h| 3 ++- lldb/source/Target/ThreadPlanShouldStopHere.cpp | 15 +++ lldb/source/Target/ThreadPlanStepInRange.cpp | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h index 54b30291c3995..d0094c90b91a5 100644 --- a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h +++ b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h @@ -59,7 +59,8 @@ class ThreadPlanShouldStopHere { eNone = 0, eAvoidInlines = (1 << 0), eStepInAvoidNoDebug = (1 << 1), -eStepOutAvoidNoDebug = (1 << 2) +eStepOutAvoidNoDebug = (1 << 2), +eStepOutPastThunks = (1 << 3) }; // Constructors and Destructors diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp index fa6bc08a9914d..be6bd981c72bc 100644 --- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -8,6 +8,7 @@ #include "lldb/Target/ThreadPlanShouldStopHere.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" @@ -83,7 +84,11 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( if (Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol) { ProcessSP process_sp(current_plan->GetThread().GetProcess()); for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*symbol)) { +if (runtime->IsSymbolARuntimeThunk(*symbol) + && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); should_stop_here = false; break; } @@ -131,9 +136,11 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( // because it's marked line 0. bool is_thunk = false; for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*sc.symbol)) { - LLDB_LOGF(log, "In runtime thunk %s - stepping out.", -sc.symbol->GetName().GetCString()); +if (runtime->IsSymbolARuntimeThunk(*sc.symbol) + && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); is_thunk = true; break; } diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 109d1b6b3435b..3affeae1ee388 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRa
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
https://github.com/JDevlieghere approved this pull request. LGMT modulo copyright header & the patch file removed. https://github.com/llvm/llvm-project/pull/129294 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
@@ -0,0 +1,34 @@ +//===-- DAPLog.h *- C++ -*-===// JDevlieghere wrote: ```suggestion //===-- DAPLog.h --===// ``` https://github.com/llvm/llvm-project/pull/129294 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Minidump]Update MinidumpFileBuilder to read and write in chunks (PR #129307)
https://github.com/Jlalond edited https://github.com/llvm/llvm-project/pull/129307 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: John Harrison (ashgti) Changes Today, logging is handling by a simple `std::ofstream *` for handling logging. LLDBLog.h can help improve logging by adding new categories of logs and give us additional formatting support for log messages. We link against the libHost, which includes lldbUtility. This also simplifies logging by not requiring the `std::ofstream *` pointer being passed to every function that includes logging. --- Full diff: https://github.com/llvm/llvm-project/pull/129294.diff 9 Files Affected: - (modified) lldb/tools/lldb-dap/CMakeLists.txt (+1) - (modified) lldb/tools/lldb-dap/DAP.cpp (+20-42) - (modified) lldb/tools/lldb-dap/DAP.h (+5-6) - (added) lldb/tools/lldb-dap/DAPLog.cpp (+22) - (added) lldb/tools/lldb-dap/DAPLog.h (+34) - (modified) lldb/tools/lldb-dap/EventHelper.cpp (+10-7) - (modified) lldb/tools/lldb-dap/IOStream.cpp (+9-10) - (modified) lldb/tools/lldb-dap/IOStream.h (+3-4) - (modified) lldb/tools/lldb-dap/lldb-dap.cpp (+42-33) ``diff diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 8b3c520ec4360..d9f09f6d022ed 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_tool(lldb-dap Breakpoint.cpp BreakpointBase.cpp DAP.cpp + DAPLog.cpp EventHelper.cpp ExceptionBreakpoint.cpp FifoFiles.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 53c514b790f38..81f5205d4f6bd 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -7,6 +7,7 @@ //===--===// #include "DAP.h" +#include "DAPLog.h" #include "Handler/ResponseHandler.h" #include "JSONUtils.h" #include "LLDBUtils.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" #include "lldb/Utility/IOObject.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -50,6 +52,7 @@ #endif using namespace lldb_dap; +using namespace lldb_private; namespace { #ifdef _WIN32 @@ -61,13 +64,12 @@ const char DEV_NULL[] = "/dev/null"; namespace lldb_dap { -DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log, - lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode, +DAP::DAP(std::string name, llvm::StringRef path, lldb::IOObjectSP input, + lldb::IOObjectSP output, ReplMode repl_mode, std::vector pre_init_commands) -: name(std::move(name)), debug_adapter_path(path), log(log), - input(std::move(input)), output(std::move(output)), - broadcaster("lldb-dap"), exception_breakpoints(), - pre_init_commands(std::move(pre_init_commands)), +: name(std::move(name)), debug_adapter_path(path), input(std::move(input)), + output(std::move(output)), broadcaster("lldb-dap"), + exception_breakpoints(), pre_init_commands(std::move(pre_init_commands)), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), enable_auto_variable_summaries(false), enable_synthetic_child_debugging(false), @@ -245,6 +247,8 @@ void DAP::SendJSON(const std::string &json_str) { output.write_full(llvm::utostr(json_str.size())); output.write_full("\r\n\r\n"); output.write_full(json_str); + + LLDB_LOG(GetLog(DAPLog::Transport), "{0} <-- {1}", name, json_str); } // Serialize the JSON value into a string and send the JSON packet to @@ -256,15 +260,6 @@ void DAP::SendJSON(const llvm::json::Value &json) { static std::mutex mutex; std::lock_guard locker(mutex); SendJSON(json_str); - - if (log) { -auto now = std::chrono::duration( -std::chrono::system_clock::now().time_since_epoch()); -*log << llvm::formatv("{0:f9} {1} <-- ", now.count(), name).str() - << std::endl - << "Content-Length: " << json_str.size() << "\r\n\r\n" - << llvm::formatv("{0:2}", json).str() << std::endl; - } } // Read a JSON packet from the "in" stream. @@ -273,28 +268,22 @@ std::string DAP::ReadJSON() { std::string json_str; int length; - if (!input.read_expected(log, "Content-Length: ")) + if (!input.read_expected("Content-Length: ")) return json_str; - if (!input.read_line(log, length_str)) + if (!input.read_line(length_str)) return json_str; if (!llvm::to_integer(length_str, length)) return json_str; - if (!input.read_expected(log, "\r\n")) + if (!input.read_expected("\r\n")) return json_str; - if (!input.read_full(log, length, json_str)) + if (!input.read_full(length, json_str)) return json_str; - if (log) { -auto now = std::chrono::duration( -std::chrono::system_clock::now().time_since_epoch()); -*log << llvm::formatv("{0:f9} {1} --> ", now.count(), name).str() - << std::endl - << "Content-Length: "
[Lldb-commits] [lldb] [lldb-dap] Implement a MemoryMonitor for macOS & Linux (PR #129332)
@@ -0,0 +1,114 @@ +//===-- MemoryMonitor.cpp -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "MemoryMonitor.h" +#include "llvm/ADT/ScopeExit.h" +#include +#include +#include +#include + +#if defined(__APPLE__) +#include +#endif + +#if defined(__linux__) +#include +#include +#include +#endif + +using namespace lldb_dap; + +#if defined(__APPLE__) +class MemoryMonitorDarwin : public MemoryMonitor { + using MemoryMonitor::MemoryMonitor; + void Start() override { +m_memory_pressure_source = dispatch_source_create( +DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, +0, // system-wide monitoring +DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL, +dispatch_get_main_queue()); JDevlieghere wrote: Good catch, I meant to use `dispatch_get_global_queue` and I confused it with `dispatch_get_main_queue` . https://github.com/llvm/llvm-project/pull/129332 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Minidump]Update MinidumpFileBuilder to read and write in chunks (PR #129307)
https://github.com/Jlalond updated https://github.com/llvm/llvm-project/pull/129307 >From 2f77beefb752ffdae908101d75381268203311d6 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde Date: Fri, 28 Feb 2025 11:38:35 -0800 Subject: [PATCH 1/2] Update MinidumpFileBuilder to read and write in chunks --- .../Minidump/MinidumpFileBuilder.cpp | 130 -- .../ObjectFile/Minidump/MinidumpFileBuilder.h | 7 + 2 files changed, 97 insertions(+), 40 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index c5013ea5e3be4..e88b606f279cd 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -969,12 +969,82 @@ Status MinidumpFileBuilder::DumpDirectories() const { return error; } -static uint64_t -GetLargestRangeSize(const std::vector &ranges) { - uint64_t max_size = 0; - for (const auto &core_range : ranges) -max_size = std::max(max_size, core_range.range.size()); - return max_size; +Status MinidumpFileBuilder::ReadWriteMemoryInChunks( +const lldb_private::CoreFileMemoryRange &range, uint64_t *bytes_read) { + Log *log = GetLog(LLDBLog::Object); + lldb::addr_t addr = range.range.start(); + lldb::addr_t size = range.range.size(); + // First we set the byte tally to 0, so if we do exit gracefully + // the caller doesn't think the random garbage on the stack is a + // success. + if (bytes_read) +*bytes_read = 0; + + uint64_t bytes_remaining = size; + uint64_t total_bytes_read = 0; + auto data_up = std::make_unique( + std::min(bytes_remaining, MAX_WRITE_CHUNK_SIZE), 0); + Status error; + while (bytes_remaining > 0) { +// Get the next read chunk size as the minimum of the remaining bytes and +// the write chunk max size. +const size_t bytes_to_read = +std::min(bytes_remaining, MAX_WRITE_CHUNK_SIZE); +const size_t bytes_read_for_chunk = +m_process_sp->ReadMemory(range.range.start() + total_bytes_read, + data_up->GetBytes(), bytes_to_read, error); +if (error.Fail() || bytes_read_for_chunk == 0) { + LLDB_LOGF(log, +"Failed to read memory region at: %" PRIx64 +". Bytes read: %zu, error: %s", +addr, bytes_read_for_chunk, error.AsCString()); + // If we've only read one byte we can just give up and return + if (total_bytes_read == 0) +return Status(); + + // If we've read some bytes, we stop trying to read more and return + // this best effort attempt + bytes_remaining = 0; +} else if (bytes_read_for_chunk != bytes_to_read) { + LLDB_LOGF( + log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes", + addr, size); + + // If we've read some bytes, we stop trying to read more and return + // this best effort attempt + bytes_remaining = 0; +} + +// Write to the minidump file with the chunk potentially flushing to disk. +// this is the only place we want to return a true error, so that we can +// fail. If we get an error writing to disk we can't easily gaurauntee +// that we won't corrupt the minidump. +error = AddData(data_up->GetBytes(), bytes_read_for_chunk); +if (error.Fail()) + return error; + +// This check is so we don't overflow when the error code above sets the +// bytes to read to 0 (the graceful exit condition). +if (bytes_remaining > 0) + bytes_remaining -= bytes_read_for_chunk; + +total_bytes_read += bytes_read_for_chunk; +// If the caller wants a tally back of the bytes_read, update it as we +// write. We do this in the loop so if we encounter an error we can +// report the accurate total. +if (bytes_read) + *bytes_read += bytes_read_for_chunk; + +// We clear the heap per loop, without checking if we +// read the expected bytes this is so we don't allocate +// more than the MAX_WRITE_CHUNK_SIZE. But we do check if +// this is even worth clearing before we return and +// destruct the heap. +if (bytes_remaining > 0) + data_up->Clear(); + } + + return error; } Status @@ -987,8 +1057,6 @@ MinidumpFileBuilder::AddMemoryList_32(std::vector &ranges, Log *log = GetLog(LLDBLog::Object); size_t region_index = 0; - auto data_up = - std::make_unique(GetLargestRangeSize(ranges), 0); for (const auto &core_range : ranges) { // Take the offset before we write. const offset_t offset_for_data = GetCurrentDataEndOffset(); @@ -1003,18 +1071,15 @@ MinidumpFileBuilder::AddMemoryList_32(std::vector &ranges, ++region_index; progress.Increment(1, "Adding Memory Range " + core_range.Dump()); -const size_t bytes_read = -m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); -if (error.Fail() || bytes_read == 0) {
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff a3ac1f2278dec155e0e0b4d06ec816ba325f6979 8d466e5c4b1b6913e788fd11d46689af8f0b8eec --extensions h,cpp -- lldb/tools/lldb-dap/DAPLog.cpp lldb/tools/lldb-dap/DAPLog.h lldb/tools/lldb-dap/DAP.cpp lldb/tools/lldb-dap/DAP.h lldb/tools/lldb-dap/EventHelper.cpp lldb/tools/lldb-dap/IOStream.cpp lldb/tools/lldb-dap/IOStream.h lldb/tools/lldb-dap/lldb-dap.cpp `` View the diff from clang-format here. ``diff diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index ea5e17eb5d..d587d36b9e 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -125,21 +125,21 @@ struct Variables { struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; - explicit StartDebuggingRequestHandler(DAP &d) : dap(d){}; + explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; bool DoExecute(lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) override; }; struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; - explicit ReplModeRequestHandler(DAP &d) : dap(d){}; + explicit ReplModeRequestHandler(DAP &d) : dap(d) {}; bool DoExecute(lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) override; }; struct SendEventRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; - explicit SendEventRequestHandler(DAP &d) : dap(d){}; + explicit SendEventRequestHandler(DAP &d) : dap(d) {}; bool DoExecute(lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) override; }; `` https://github.com/llvm/llvm-project/pull/129294 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Control the "step out through thunk" logic explicitly when pushing thread plans (PR #129301)
https://github.com/felipepiovezan approved this pull request. LGTM! https://github.com/llvm/llvm-project/pull/129301 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Control the "step out through thunk" logic explicitly when pushing thread plans (PR #129301)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 56cc9299b7804257549edb4a7ba15999cbb5 a26c5596ac599f1b51cffebd658f3823388e --extensions cpp,h -- lldb/include/lldb/Target/ThreadPlanShouldStopHere.h lldb/source/Target/ThreadPlanShouldStopHere.cpp lldb/source/Target/ThreadPlanStepInRange.cpp `` View the diff from clang-format here. ``diff diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp index be6bd981c7..d2cca49987 100644 --- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -84,11 +84,12 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( if (Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol) { ProcessSP process_sp(current_plan->GetThread().GetProcess()); for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*symbol) - && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { - LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s", - frame->GetFunctionName(), - Language::GetNameForLanguageType(runtime->GetLanguageType())); +if (runtime->IsSymbolARuntimeThunk(*symbol) && +flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF( + log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); should_stop_here = false; break; } @@ -136,11 +137,12 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( // because it's marked line 0. bool is_thunk = false; for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*sc.symbol) - && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { - LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s", - frame->GetFunctionName(), - Language::GetNameForLanguageType(runtime->GetLanguageType())); +if (runtime->IsSymbolARuntimeThunk(*sc.symbol) && +flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF( + log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); is_thunk = true; break; } diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 3affeae1ee..8a2417e9da 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -27,7 +27,7 @@ using namespace lldb; using namespace lldb_private; uint32_t ThreadPlanStepInRange::s_default_flag_values = -ThreadPlanShouldStopHere::eStepInAvoidNoDebug | +ThreadPlanShouldStopHere::eStepInAvoidNoDebug | ThreadPlanShouldStopHere::eStepOutPastThunks; // ThreadPlanStepInRange: Step through a stack range, either stepping over or `` https://github.com/llvm/llvm-project/pull/129301 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Control the "step out through thunk" logic explicitly when pushing thread plans (PR #129301)
https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/129301 >From a26c5596ac599f1b51cffebd658f3823388e Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 28 Feb 2025 11:45:51 -0800 Subject: [PATCH 1/2] Control the "step out through thunk" logic explicitly when pushing thread plans. That allow the thread plan that is trying to step through a thunk to its target to step out of a function it has stepped into without also stepping out past the thunk we were trying to step through. --- .../lldb/Target/ThreadPlanShouldStopHere.h| 3 ++- lldb/source/Target/ThreadPlanShouldStopHere.cpp | 15 +++ lldb/source/Target/ThreadPlanStepInRange.cpp | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h index 54b30291c3995..d0094c90b91a5 100644 --- a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h +++ b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h @@ -59,7 +59,8 @@ class ThreadPlanShouldStopHere { eNone = 0, eAvoidInlines = (1 << 0), eStepInAvoidNoDebug = (1 << 1), -eStepOutAvoidNoDebug = (1 << 2) +eStepOutAvoidNoDebug = (1 << 2), +eStepOutPastThunks = (1 << 3) }; // Constructors and Destructors diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp index fa6bc08a9914d..be6bd981c72bc 100644 --- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -8,6 +8,7 @@ #include "lldb/Target/ThreadPlanShouldStopHere.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" @@ -83,7 +84,11 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( if (Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol) { ProcessSP process_sp(current_plan->GetThread().GetProcess()); for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*symbol)) { +if (runtime->IsSymbolARuntimeThunk(*symbol) + && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); should_stop_here = false; break; } @@ -131,9 +136,11 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( // because it's marked line 0. bool is_thunk = false; for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*sc.symbol)) { - LLDB_LOGF(log, "In runtime thunk %s - stepping out.", -sc.symbol->GetName().GetCString()); +if (runtime->IsSymbolARuntimeThunk(*sc.symbol) + && flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF(log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); is_thunk = true; break; } diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 109d1b6b3435b..3affeae1ee388 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -27,7 +27,8 @@ using namespace lldb; using namespace lldb_private; uint32_t ThreadPlanStepInRange::s_default_flag_values = -ThreadPlanShouldStopHere::eStepInAvoidNoDebug; +ThreadPlanShouldStopHere::eStepInAvoidNoDebug | +ThreadPlanShouldStopHere::eStepOutPastThunks; // ThreadPlanStepInRange: Step through a stack range, either stepping over or // into based on the value of \a type. >From 2ce4ca483a7f6a812d35b94a99425b250fe4a43a Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 28 Feb 2025 13:40:05 -0800 Subject: [PATCH 2/2] clang-format --- .../Target/ThreadPlanShouldStopHere.cpp | 22 ++- lldb/source/Target/ThreadPlanStepInRange.cpp | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp index be6bd981c72bc..d2cca49987f0f 100644 --- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -84,11 +84,12 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( if (Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol) { ProcessSP process_sp(current_plan->GetThread().GetProcess()); for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymb
[Lldb-commits] [lldb] [LLDB][Minidump]Update MinidumpFileBuilder to read and write in chunks (PR #129307)
Jlalond wrote: @labath / @clayborg to preempt some expected feedback, I intend to expose this chunk size in a future setting https://github.com/llvm/llvm-project/pull/129307 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Update MinidumpFileBuilder to read and write in chunks (PR #129307)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jacob Lalonde (Jlalond) Changes I recently received an internal error report that LLDB was OOM'ing when creating a Minidump. In my 64b refactor we made a decision to acquire buffers the size of the largest memory region so we could read all of the contents in one call. This made error handling very simple (and simpler coding for me!) but had the trade off of large allocations if huge pages were enabled. This patch is one I've had on the back burner for awhile, but we can read and write the Minidump memory sections in discrete chunks which we already do for writing to disk. I had to refactor the error handling a bit, but it remains the same. We make a best effort attempt to read as much of the memory region as possible, but fail immediately if we receive an error writing to disk. I did not add new tests for this because our existing test suite is quite good, but I did manually verify a few Minidumps couldn't read beyond the red_zone. ``` (lldb) reg read $sp rsp = 0x7fffc3b0 (lldb) p/x 0x7fffc3b0 - 128 (long) 0x7fffc330 (lldb) memory read 0x7fffc330 0x7fffc330: 60 c3 ff ff ff 7f 00 00 60 cd ff ff ff 7f 00 00 `...`... 0x7fffc340: 60 c3 ff ff ff 7f 00 00 65 e6 26 00 00 00 00 00 `...e.&. (lldb) memory read 0x7fffc329 error: could not parse memory info ``` I'm not sure how to quantify the memory improvement other than we would allocate the largest size regardless of the size. So a 2gb unreadable region would cause a 2gb allocation even if we were reading 4096 kb. Now we will take the range size or the max chunk size of 128 mb. --- Full diff: https://github.com/llvm/llvm-project/pull/129307.diff 2 Files Affected: - (modified) lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp (+90-40) - (modified) lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h (+7) ``diff diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index c5013ea5e3be4..e88b606f279cd 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -969,12 +969,82 @@ Status MinidumpFileBuilder::DumpDirectories() const { return error; } -static uint64_t -GetLargestRangeSize(const std::vector &ranges) { - uint64_t max_size = 0; - for (const auto &core_range : ranges) -max_size = std::max(max_size, core_range.range.size()); - return max_size; +Status MinidumpFileBuilder::ReadWriteMemoryInChunks( +const lldb_private::CoreFileMemoryRange &range, uint64_t *bytes_read) { + Log *log = GetLog(LLDBLog::Object); + lldb::addr_t addr = range.range.start(); + lldb::addr_t size = range.range.size(); + // First we set the byte tally to 0, so if we do exit gracefully + // the caller doesn't think the random garbage on the stack is a + // success. + if (bytes_read) +*bytes_read = 0; + + uint64_t bytes_remaining = size; + uint64_t total_bytes_read = 0; + auto data_up = std::make_unique( + std::min(bytes_remaining, MAX_WRITE_CHUNK_SIZE), 0); + Status error; + while (bytes_remaining > 0) { +// Get the next read chunk size as the minimum of the remaining bytes and +// the write chunk max size. +const size_t bytes_to_read = +std::min(bytes_remaining, MAX_WRITE_CHUNK_SIZE); +const size_t bytes_read_for_chunk = +m_process_sp->ReadMemory(range.range.start() + total_bytes_read, + data_up->GetBytes(), bytes_to_read, error); +if (error.Fail() || bytes_read_for_chunk == 0) { + LLDB_LOGF(log, +"Failed to read memory region at: %" PRIx64 +". Bytes read: %zu, error: %s", +addr, bytes_read_for_chunk, error.AsCString()); + // If we've only read one byte we can just give up and return + if (total_bytes_read == 0) +return Status(); + + // If we've read some bytes, we stop trying to read more and return + // this best effort attempt + bytes_remaining = 0; +} else if (bytes_read_for_chunk != bytes_to_read) { + LLDB_LOGF( + log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes", + addr, size); + + // If we've read some bytes, we stop trying to read more and return + // this best effort attempt + bytes_remaining = 0; +} + +// Write to the minidump file with the chunk potentially flushing to disk. +// this is the only place we want to return a true error, so that we can +// fail. If we get an error writing to disk we can't easily gaurauntee +// that we won't corrupt the minidump. +error = AddData(data_up->GetBytes(), bytes_read_for_chunk); +if (error.Fail()) + return error; + +// This check is so we don't overflow when the error code above sets the +
[Lldb-commits] [lldb] ddbce2f - Control the "step out through thunk" logic explicitly when pushing thread plans (#129301)
Author: jimingham Date: 2025-02-28T13:44:17-08:00 New Revision: ddbce2fd2380a4eafce9065ad991318f46a3292b URL: https://github.com/llvm/llvm-project/commit/ddbce2fd2380a4eafce9065ad991318f46a3292b DIFF: https://github.com/llvm/llvm-project/commit/ddbce2fd2380a4eafce9065ad991318f46a3292b.diff LOG: Control the "step out through thunk" logic explicitly when pushing thread plans (#129301) Jonas recently added a trampoline handling strategy for simple language thunks that does: "step through language thunks stepping in one level deep and stopping if you hit user code". That was actually pulled over from the swift implementation. However, this strategy and the strategy we have to "step out past language thunks" when stepping out come into conflict if the thunk you are stepping through calls some other function before dispatching to the intended method. When you step out of the called function back into the thunk, should you keep stepping out past the thunk or not? In most cases, you want to step out past the thunk, but in this particular case you don't. This patch adds a way to inform the thread plan (or really it's ShouldStopHere behavior) of which behavior it should have, and passes the don't step through thunks to the step through plan it uses to step through thunks. I didn't add a test for this because I couldn't find a C++ thunk that calls another function before getting to the target function. I asked the clang folks here if they could think of a case where clang would do this, and they couldn't. If anyone can think of such a construct, it will be easy to write the step through test for it... This does happen in swift, however, so when I cherry-pick this to the swift fork I'll test it there. Added: Modified: lldb/include/lldb/Target/ThreadPlanShouldStopHere.h lldb/source/Target/ThreadPlanShouldStopHere.cpp lldb/source/Target/ThreadPlanStepInRange.cpp Removed: diff --git a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h index 54b30291c3995..d0094c90b91a5 100644 --- a/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h +++ b/lldb/include/lldb/Target/ThreadPlanShouldStopHere.h @@ -59,7 +59,8 @@ class ThreadPlanShouldStopHere { eNone = 0, eAvoidInlines = (1 << 0), eStepInAvoidNoDebug = (1 << 1), -eStepOutAvoidNoDebug = (1 << 2) +eStepOutAvoidNoDebug = (1 << 2), +eStepOutPastThunks = (1 << 3) }; // Constructors and Destructors diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp index fa6bc08a9914d..d2cca49987f0f 100644 --- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -8,6 +8,7 @@ #include "lldb/Target/ThreadPlanShouldStopHere.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" @@ -83,7 +84,12 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( if (Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol) { ProcessSP process_sp(current_plan->GetThread().GetProcess()); for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*symbol)) { +if (runtime->IsSymbolARuntimeThunk(*symbol) && +flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF( + log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); should_stop_here = false; break; } @@ -131,9 +137,12 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( // because it's marked line 0. bool is_thunk = false; for (auto *runtime : process_sp->GetLanguageRuntimes()) { -if (runtime->IsSymbolARuntimeThunk(*sc.symbol)) { - LLDB_LOGF(log, "In runtime thunk %s - stepping out.", -sc.symbol->GetName().GetCString()); +if (runtime->IsSymbolARuntimeThunk(*sc.symbol) && +flags.Test(ThreadPlanShouldStopHere::eStepOutPastThunks)) { + LLDB_LOGF( + log, "Stepping out past a language thunk %s for: %s", + frame->GetFunctionName(), + Language::GetNameForLanguageType(runtime->GetLanguageType())); is_thunk = true; break; } diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 109d1b6b3435b..8a2417e9da326 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -27,7 +27,8 @@ using namespace lldb; using namespace lldb_private; uint32_t Threa
[Lldb-commits] [lldb] [lldb-dap] Implement a MemoryMonitor for macOS & Linux (PR #129332)
https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/129332 This implements a memory monitor for macOS & Linux, and registers a callback that invokes SBDebugger::MemoryPressureDetected() when a low memory event is detected. >From c63350db79ac6bcc6f180cc84a37e829d1c8b2a8 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 28 Feb 2025 14:54:42 -0600 Subject: [PATCH] [lldb-dap] Implement a MemoryMonitor for macOS & Linux This implements a memory monitor for macOS & Linux, and registers a callback that invokes SBDebugger::MemoryPressureDetected() when a low memory event is detected. --- lldb/tools/lldb-dap/CMakeLists.txt| 1 + lldb/tools/lldb-dap/MemoryMonitor.cpp | 114 ++ lldb/tools/lldb-dap/MemoryMonitor.h | 41 + lldb/tools/lldb-dap/lldb-dap.cpp | 17 +++- 4 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 lldb/tools/lldb-dap/MemoryMonitor.cpp create mode 100644 lldb/tools/lldb-dap/MemoryMonitor.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 8b3c520ec4360..8db377e31c3c6 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -36,6 +36,7 @@ add_lldb_tool(lldb-dap RunInTerminal.cpp SourceBreakpoint.cpp Watchpoint.cpp + MemoryMonitor.cpp Handler/ResponseHandler.cpp Handler/AttachRequestHandler.cpp diff --git a/lldb/tools/lldb-dap/MemoryMonitor.cpp b/lldb/tools/lldb-dap/MemoryMonitor.cpp new file mode 100644 index 0..da3da42fe9b0f --- /dev/null +++ b/lldb/tools/lldb-dap/MemoryMonitor.cpp @@ -0,0 +1,114 @@ +//===-- MemoryMonitor.cpp -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "MemoryMonitor.h" +#include "llvm/ADT/ScopeExit.h" +#include +#include +#include +#include + +#if defined(__APPLE__) +#include +#endif + +#if defined(__linux__) +#include +#include +#include +#endif + +using namespace lldb_dap; + +#if defined(__APPLE__) +class MemoryMonitorDarwin : public MemoryMonitor { + using MemoryMonitor::MemoryMonitor; + void Start() override { +m_memory_pressure_source = dispatch_source_create( +DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, +0, // system-wide monitoring +DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL, +dispatch_get_main_queue()); + +dispatch_source_set_event_handler(m_memory_pressure_source, ^{ + dispatch_source_memorypressure_flags_t pressureLevel = + dispatch_source_get_data(m_memory_pressure_source); + if (pressureLevel & + (DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL)) { +m_callback(); + } +}); + } + + void Stop() override { dispatch_source_cancel(m_memory_pressure_source); } + +private: + dispatch_source_t m_memory_pressure_source; +}; +#endif + +#if defined(__linux__) +static void MonitorThread(std::atomic &done, + MemoryMonitor::Callback callback) { + struct pollfd fds; + fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK); + if (fds.fd < 0) +return; + fds.events = POLLPRI; + + auto cleanup = llvm::make_scope_exit([&]() { close(fds.fd); }); + + // Detect a 50ms stall in a 2 second time window. + const char trig[] = "some 5 200"; + if (write(fds.fd, trig, strlen(trig) + 1) < 0) +return; + + while (!done) { +int n = poll(&fds, 1, 1000); +if (n > 0) { + if (fds.revents & POLLERR) +return; + if (fds.revents & POLLPRI) +callback(); +} + } +} + +class MemoryMonitorLinux : public MemoryMonitor { +public: + using MemoryMonitor::MemoryMonitor; + + void Start() override { +m_memory_pressure_thread = +std::thread(MonitorThread, std::ref(m_done), m_callback); + } + + void Stop() override { +if (m_memory_pressure_thread.joinable()) { + m_done = true; + m_memory_pressure_thread.join(); +} + } + +private: + std::atomic m_done = false; + std::thread m_memory_pressure_thread; +}; +#endif + +std::unique_ptr MemoryMonitor::Create(Callback callback) { +#if defined(__APPLE__) + return std::make_unique(callback); +#endif + +#if defined(__linux__) + return std::make_unique(callback); +#endif + + return nullptr; +} diff --git a/lldb/tools/lldb-dap/MemoryMonitor.h b/lldb/tools/lldb-dap/MemoryMonitor.h new file mode 100644 index 0..e07c3bde9e85c --- /dev/null +++ b/lldb/tools/lldb-dap/MemoryMonitor.h @@ -0,0 +1,41 @@ +//===-- MemoryMonitor.h ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/L
[Lldb-commits] [lldb] [lldb-dap] Implement a MemoryMonitor for macOS & Linux (PR #129332)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) Changes This implements a memory monitor for macOS & Linux, and registers a callback that invokes SBDebugger::MemoryPressureDetected() when a low memory event is detected. --- Full diff: https://github.com/llvm/llvm-project/pull/129332.diff 4 Files Affected: - (modified) lldb/tools/lldb-dap/CMakeLists.txt (+1) - (added) lldb/tools/lldb-dap/MemoryMonitor.cpp (+114) - (added) lldb/tools/lldb-dap/MemoryMonitor.h (+41) - (modified) lldb/tools/lldb-dap/lldb-dap.cpp (+15-2) ``diff diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 8b3c520ec4360..8db377e31c3c6 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -36,6 +36,7 @@ add_lldb_tool(lldb-dap RunInTerminal.cpp SourceBreakpoint.cpp Watchpoint.cpp + MemoryMonitor.cpp Handler/ResponseHandler.cpp Handler/AttachRequestHandler.cpp diff --git a/lldb/tools/lldb-dap/MemoryMonitor.cpp b/lldb/tools/lldb-dap/MemoryMonitor.cpp new file mode 100644 index 0..da3da42fe9b0f --- /dev/null +++ b/lldb/tools/lldb-dap/MemoryMonitor.cpp @@ -0,0 +1,114 @@ +//===-- MemoryMonitor.cpp -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "MemoryMonitor.h" +#include "llvm/ADT/ScopeExit.h" +#include +#include +#include +#include + +#if defined(__APPLE__) +#include +#endif + +#if defined(__linux__) +#include +#include +#include +#endif + +using namespace lldb_dap; + +#if defined(__APPLE__) +class MemoryMonitorDarwin : public MemoryMonitor { + using MemoryMonitor::MemoryMonitor; + void Start() override { +m_memory_pressure_source = dispatch_source_create( +DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, +0, // system-wide monitoring +DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL, +dispatch_get_main_queue()); + +dispatch_source_set_event_handler(m_memory_pressure_source, ^{ + dispatch_source_memorypressure_flags_t pressureLevel = + dispatch_source_get_data(m_memory_pressure_source); + if (pressureLevel & + (DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL)) { +m_callback(); + } +}); + } + + void Stop() override { dispatch_source_cancel(m_memory_pressure_source); } + +private: + dispatch_source_t m_memory_pressure_source; +}; +#endif + +#if defined(__linux__) +static void MonitorThread(std::atomic &done, + MemoryMonitor::Callback callback) { + struct pollfd fds; + fds.fd = open("/proc/pressure/memory", O_RDWR | O_NONBLOCK); + if (fds.fd < 0) +return; + fds.events = POLLPRI; + + auto cleanup = llvm::make_scope_exit([&]() { close(fds.fd); }); + + // Detect a 50ms stall in a 2 second time window. + const char trig[] = "some 5 200"; + if (write(fds.fd, trig, strlen(trig) + 1) < 0) +return; + + while (!done) { +int n = poll(&fds, 1, 1000); +if (n > 0) { + if (fds.revents & POLLERR) +return; + if (fds.revents & POLLPRI) +callback(); +} + } +} + +class MemoryMonitorLinux : public MemoryMonitor { +public: + using MemoryMonitor::MemoryMonitor; + + void Start() override { +m_memory_pressure_thread = +std::thread(MonitorThread, std::ref(m_done), m_callback); + } + + void Stop() override { +if (m_memory_pressure_thread.joinable()) { + m_done = true; + m_memory_pressure_thread.join(); +} + } + +private: + std::atomic m_done = false; + std::thread m_memory_pressure_thread; +}; +#endif + +std::unique_ptr MemoryMonitor::Create(Callback callback) { +#if defined(__APPLE__) + return std::make_unique(callback); +#endif + +#if defined(__linux__) + return std::make_unique(callback); +#endif + + return nullptr; +} diff --git a/lldb/tools/lldb-dap/MemoryMonitor.h b/lldb/tools/lldb-dap/MemoryMonitor.h new file mode 100644 index 0..e07c3bde9e85c --- /dev/null +++ b/lldb/tools/lldb-dap/MemoryMonitor.h @@ -0,0 +1,41 @@ +//===-- MemoryMonitor.h ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H +#define LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H + +#include +#include + +namespace lldb_dap { + +class MemoryMonitor { +public: + using Callback = std::function; + + MemoryMonitor(Callback callback) : m_callback
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/129294 >From 8d466e5c4b1b6913e788fd11d46689af8f0b8eec Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 27 Feb 2025 15:33:51 -0800 Subject: [PATCH 1/3] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog.h helpers. This only creates the basic types need to start using the LLDBLog.h helpers. Today, logging is handling by a simple `std::ofstream *` for handling logging. LLDBLog.h can help improve logging by adding new categories of logs and give us additional formatting support for log messages. --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/DAP.cpp | 62 lldb/tools/lldb-dap/DAP.h | 11 ++--- lldb/tools/lldb-dap/DAPLog.cpp | 22 + lldb/tools/lldb-dap/DAPLog.h| 34 + lldb/tools/lldb-dap/EventHelper.cpp | 17 --- lldb/tools/lldb-dap/IOStream.cpp| 19 lldb/tools/lldb-dap/IOStream.h | 7 ++- lldb/tools/lldb-dap/lldb-dap.cpp| 75 - 9 files changed, 146 insertions(+), 102 deletions(-) create mode 100644 lldb/tools/lldb-dap/DAPLog.cpp create mode 100644 lldb/tools/lldb-dap/DAPLog.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 8b3c520ec4360..d9f09f6d022ed 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_tool(lldb-dap Breakpoint.cpp BreakpointBase.cpp DAP.cpp + DAPLog.cpp EventHelper.cpp ExceptionBreakpoint.cpp FifoFiles.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 53c514b790f38..81f5205d4f6bd 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -7,6 +7,7 @@ //===--===// #include "DAP.h" +#include "DAPLog.h" #include "Handler/ResponseHandler.h" #include "JSONUtils.h" #include "LLDBUtils.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" #include "lldb/Utility/IOObject.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -50,6 +52,7 @@ #endif using namespace lldb_dap; +using namespace lldb_private; namespace { #ifdef _WIN32 @@ -61,13 +64,12 @@ const char DEV_NULL[] = "/dev/null"; namespace lldb_dap { -DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log, - lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode, +DAP::DAP(std::string name, llvm::StringRef path, lldb::IOObjectSP input, + lldb::IOObjectSP output, ReplMode repl_mode, std::vector pre_init_commands) -: name(std::move(name)), debug_adapter_path(path), log(log), - input(std::move(input)), output(std::move(output)), - broadcaster("lldb-dap"), exception_breakpoints(), - pre_init_commands(std::move(pre_init_commands)), +: name(std::move(name)), debug_adapter_path(path), input(std::move(input)), + output(std::move(output)), broadcaster("lldb-dap"), + exception_breakpoints(), pre_init_commands(std::move(pre_init_commands)), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), enable_auto_variable_summaries(false), enable_synthetic_child_debugging(false), @@ -245,6 +247,8 @@ void DAP::SendJSON(const std::string &json_str) { output.write_full(llvm::utostr(json_str.size())); output.write_full("\r\n\r\n"); output.write_full(json_str); + + LLDB_LOG(GetLog(DAPLog::Transport), "{0} <-- {1}", name, json_str); } // Serialize the JSON value into a string and send the JSON packet to @@ -256,15 +260,6 @@ void DAP::SendJSON(const llvm::json::Value &json) { static std::mutex mutex; std::lock_guard locker(mutex); SendJSON(json_str); - - if (log) { -auto now = std::chrono::duration( -std::chrono::system_clock::now().time_since_epoch()); -*log << llvm::formatv("{0:f9} {1} <-- ", now.count(), name).str() - << std::endl - << "Content-Length: " << json_str.size() << "\r\n\r\n" - << llvm::formatv("{0:2}", json).str() << std::endl; - } } // Read a JSON packet from the "in" stream. @@ -273,28 +268,22 @@ std::string DAP::ReadJSON() { std::string json_str; int length; - if (!input.read_expected(log, "Content-Length: ")) + if (!input.read_expected("Content-Length: ")) return json_str; - if (!input.read_line(log, length_str)) + if (!input.read_line(length_str)) return json_str; if (!llvm::to_integer(length_str, length)) return json_str; - if (!input.read_expected(log, "\r\n")) + if (!input.read_expected("\r\n")) return json_str; - if (!input.read_full(log, length, json_str)) + if (!input.read_full(length, json_str)) return json_str; - if (log) { -auto now = std::chrono::duration( -
[Lldb-commits] [lldb] Fix a bug copying the stop hooks from the dummy target. (PR #129340)
https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/129340 >From 02e908312518e85f1d637529c9f62e3dd9551035 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 28 Feb 2025 15:55:03 -0800 Subject: [PATCH 1/3] Fix a bug copying the stop hooks from the dummy target. We didn't also copy over the next stop hook id, which meant we would overwrite the stop hooks from the dummy target with stop hooks set after they are copied over. --- lldb/source/Target/Target.cpp | 1 + .../target/stop-hooks/TestStopHooks.py| 24 +-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index db289fe9c4b64..550424720e095 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -211,6 +211,7 @@ Target::~Target() { void Target::PrimeFromDummyTarget(Target &target) { m_stop_hooks = target.m_stop_hooks; + m_stop_hook_next_id = target.m_stop_hook_next_id; for (const auto &breakpoint_sp : target.m_breakpoint_list.Breakpoints()) { if (breakpoint_sp->IsInternal()) diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py index fe59bd8a5d007..5215ec7258d14 100644 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py @@ -26,10 +26,15 @@ def test_stop_hooks_step_out(self): self.step_out_test() def test_stop_hooks_after_expr(self): -"""Test that a stop hook fires when hitting a breakpoint -that runs an expression""" +"""Test that a stop hook fires when hitting a breakpoint that + runs an expression""" self.after_expr_test() +def test_stop_hooks_before_and_after_creation(self): +"""Test that if we add a stop hook in the dummy target, we can + they don't collide with ones set directly in the target.""" +self.before_and_after_target() + def step_out_test(self): (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set a breakpoint here", self.main_source_file @@ -85,3 +90,18 @@ def after_expr_test(self): var = target.FindFirstGlobalVariable("g_var") self.assertTrue(var.IsValid()) self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var") + +def before_and_after_target(self): +interp = self.dbg.GetCommandInterpreter() +result = lldb.SBCommandReturnObject() +interp.HandleCommand("target stop-hook add -o 'expr g_var++'", result) +self.assertTrue(result.Succeeded(), "Set the target stop hook") + +(target, process, thread, first_bkpt) = lldbutil.run_to_source_breakpoint( +self, "Set a breakpoint here", self.main_source_file +) + +interp.HandleCommand("target stop-hook add -o 'thread backtrace'", result) +self.assertTrue(result.Succeeded(), "Set the target stop hook") +self.expect("target stop-hook list", substrs=["expr g_var++", "thread backtrace"]) + >From 72e6f179525f1e13e7a1617ab04853304d116537 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 28 Feb 2025 16:23:31 -0800 Subject: [PATCH 2/3] uglify --- .../test/API/commands/target/stop-hooks/TestStopHooks.py | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py index 5215ec7258d14..c2cdcf0e2af52 100644 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py @@ -27,12 +27,12 @@ def test_stop_hooks_step_out(self): def test_stop_hooks_after_expr(self): """Test that a stop hook fires when hitting a breakpoint that - runs an expression""" +runs an expression""" self.after_expr_test() def test_stop_hooks_before_and_after_creation(self): """Test that if we add a stop hook in the dummy target, we can - they don't collide with ones set directly in the target.""" +they don't collide with ones set directly in the target.""" self.before_and_after_target() def step_out_test(self): @@ -103,5 +103,6 @@ def before_and_after_target(self): interp.HandleCommand("target stop-hook add -o 'thread backtrace'", result) self.assertTrue(result.Succeeded(), "Set the target stop hook") -self.expect("target stop-hook list", substrs=["expr g_var++", "thread backtrace"]) - +self.expect( +"target stop-hook list", substrs=["expr g_var++", "thread backtrace"] +) >From 1f2d82a0d89c7eef48753840d06d63624b1fb8fd Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 28 Feb 2025 16:59:54 -0800 Subject: [PATCH 3/3] Better comment on the test. --- lldb/test/API/commands/target/sto
[Lldb-commits] [lldb] [lldb] Restore register state if PrepareTrivialCall fails (PR #129038)
https://github.com/DavidSpickett edited https://github.com/llvm/llvm-project/pull/129038 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (PR #128957)
https://github.com/vogelsgesang commented: Thank you for your persistence to get this across the finish line! 🎉 A couple of (late) review comments below. Sorry for the late review :/ https://github.com/llvm/llvm-project/pull/128957 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (PR #128957)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/128957 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (PR #128957)
@@ -115,41 +123,71 @@ export class LLDBDapDescriptorFactory } const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; -const dapPath = await getDAPExecutable(session); +const dapPath = (await getDAPExecutable(session)) ?? executable?.command; + +if (!dapPath) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(); + return undefined; +} + +if (!(await isExecutable(dapPath))) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); + return; +} + const dbgOptions = { env: { ...executable?.options?.env, ...configEnvironment, ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions); -} else if (executable) { - if (!(await isExecutable(executable.command))) { - LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(executable.command); -return undefined; - } - return new vscode.DebugAdapterExecutable( -executable.command, -executable.args, -dbgOptions, - ); +const dbgArgs = executable?.args ?? []; + +const serverMode = config.get('serverMode', false); +if (serverMode) { + const { host, port } = await this.startServer(dapPath, dbgArgs, dbgOptions); + return new vscode.DebugAdapterServer(port, host); } -return undefined; + +return new vscode.DebugAdapterExecutable(dapPath, dbgArgs, dbgOptions); + } + + startServer(dapPath: string, args: string[], options: child_process.CommonSpawnOptions): Promise<{ host: string, port: number }> { +if (this.server) return this.server; vogelsgesang wrote: afaict, this does not work correctly in combination with #126803. We might end up reusing the wrong lldb-dap binary Not sure what this means for us, though... We also can't just kill the old server when we receive a different lldb-dap path, because we could have two separate debugging sessions running at the same time, each one using a different server binary. I guess the most robust solution would be to use a `Map` to associate each lldb-dap path with its own `Promise<{ process: child_process.ChildProcess, host: string, port: number }>`? https://github.com/llvm/llvm-project/pull/128957 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (PR #128957)
@@ -115,41 +123,71 @@ export class LLDBDapDescriptorFactory } const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; -const dapPath = await getDAPExecutable(session); +const dapPath = (await getDAPExecutable(session)) ?? executable?.command; + +if (!dapPath) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(); + return undefined; +} + +if (!(await isExecutable(dapPath))) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); + return; +} + const dbgOptions = { env: { ...executable?.options?.env, ...configEnvironment, ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions); -} else if (executable) { - if (!(await isExecutable(executable.command))) { - LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(executable.command); -return undefined; - } - return new vscode.DebugAdapterExecutable( -executable.command, -executable.args, -dbgOptions, - ); +const dbgArgs = executable?.args ?? []; + +const serverMode = config.get('serverMode', false); +if (serverMode) { + const { host, port } = await this.startServer(dapPath, dbgArgs, dbgOptions); + return new vscode.DebugAdapterServer(port, host); } -return undefined; + +return new vscode.DebugAdapterExecutable(dapPath, dbgArgs, dbgOptions); + } + + startServer(dapPath: string, args: string[], options: child_process.CommonSpawnOptions): Promise<{ host: string, port: number }> { +if (this.server) return this.server; + +this.server = new Promise(resolve => { + args.push( +'--connection', +'connect://localhost:0' + ); + const server = child_process.spawn(dapPath, args, options); + server.stdout!.setEncoding('utf8').once('data', (data: string) => { vogelsgesang wrote: Is this actually "race-free" (for lack of a better term)? Looking at https://nodejs.org/api/stream.html#event-data I am not sure if we have a guarantee that the complete stdout content will be delivered in a single `data` event or if the `connection://...` string could be split across multiple `data` events? https://github.com/llvm/llvm-project/pull/128957 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Fix a bug copying the stop hooks from the dummy target. (PR #129340)
@@ -26,10 +26,15 @@ def test_stop_hooks_step_out(self): self.step_out_test() def test_stop_hooks_after_expr(self): -"""Test that a stop hook fires when hitting a breakpoint -that runs an expression""" +"""Test that a stop hook fires when hitting a breakpoint that +runs an expression""" self.after_expr_test() +def test_stop_hooks_before_and_after_creation(self): +"""Test that if we add a stop hook in the dummy target, we can +they don't collide with ones set directly in the target.""" bulbazord wrote: I think you forgot a word? `we can they don't collide` https://github.com/llvm/llvm-project/pull/129340 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/127696 >From 24e9f78744f98ecf3ac01f1f719f1eac9b3479f0 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Tue, 18 Feb 2025 15:58:08 -0500 Subject: [PATCH 01/25] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods - This type of entry is used to collect data about the debugger startup/exit - Tests will be added (They may need to be shell test with a "test-only" TelemetryManager plugin defined. I'm trying to figure out how to get that linked only when tests are running and not to the LLDB binary all the time. --- lldb/include/lldb/Core/Telemetry.h | 78 +++ lldb/source/Core/Debugger.cpp | 40 ++ lldb/source/Core/Telemetry.cpp | 115 + 3 files changed, 220 insertions(+), 13 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index b72556ecaf3c9..d6eec5dc687be 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -13,6 +13,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-forward.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/JSON.h" @@ -29,6 +30,9 @@ namespace telemetry { struct LLDBEntryKind : public ::llvm::telemetry::EntryKind { static const llvm::telemetry::KindType BaseInfo = 0b11000; + static const llvm::telemetry::KindType DebuggerInfo = 0b11001; + // There are other entries in between (added in separate PRs) + static const llvm::telemetry::KindType MiscInfo = 0b0; }; /// Defines a convenient type for timestamp of various events. @@ -56,6 +60,71 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { void serialize(llvm::telemetry::Serializer &serializer) const override; }; +/// Describes the exit status of a debugger. +struct ExitDescription { + int exit_code; + std::string description; +}; + +struct DebuggerTelemetryInfo : public LLDBBaseTelemetryInfo { + std::string username; + std::string lldb_git_sha; + std::string lldb_path; + std::string cwd; + std::optional exit_desc; + + DebuggerTelemetryInfo() = default; + + // Provide a copy ctor because we may need to make a copy before + // sanitizing the data. + // (The sanitization might differ between different Destination classes). + DebuggerTelemetryInfo(const DebuggerTelemetryInfo &other) { +username = other.username; +lldb_git_sha = other.lldb_git_sha; +lldb_path = other.lldb_path; +cwd = other.cwd; + }; + + llvm::telemetry::KindType getKind() const override { +return LLDBEntryKind::DebuggerInfo; + } + + static bool classof(const llvm::telemetry::TelemetryInfo *T) { +return T->getKind() == LLDBEntryKind::DebuggerInfo; + } + + void serialize(llvm::telemetry::Serializer &serializer) const override; +}; + +/// The "catch-all" entry to store a set of non-standard data, such as +/// error-messages, etc. +struct MiscTelemetryInfo : public LLDBBaseTelemetryInfo { + /// If the event is/can be associated with a target entry, + /// this field contains that target's UUID. + /// otherwise. + std::string target_uuid; + + /// Set of key-value pairs for any optional (or impl-specific) data + std::map meta_data; + + MiscTelemetryInfo() = default; + + MiscTelemetryInfo(const MiscTelemetryInfo &other) { +target_uuid = other.target_uuid; +meta_data = other.meta_data; + } + + llvm::telemetry::KindType getKind() const override { +return LLDBEntryKind::MiscInfo; + } + + static bool classof(const llvm::telemetry::TelemetryInfo *T) { +return T->getKind() == LLDBEntryKind::MiscInfo; + } + + void serialize(llvm::telemetry::Serializer &serializer) const override; +}; + /// The base Telemetry manager instance in LLDB. /// This class declares additional instrumentation points /// applicable to LLDB. @@ -63,6 +132,11 @@ class TelemetryManager : public llvm::telemetry::Manager { public: llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override; + const llvm::telemetry::Config *getConfig(); + + void atDebuggerStartup(DebuggerTelemetryInfo *entry); + void atDebuggerExit(DebuggerTelemetryInfo *entry); + virtual llvm::StringRef GetInstanceName() const = 0; static TelemetryManager *getInstance(); @@ -73,6 +147,10 @@ class TelemetryManager : public llvm::telemetry::Manager { private: std::unique_ptr m_config; + // Each debugger is assigned a unique ID (session_id). + // All TelemetryInfo entries emitted for the same debugger instance + // will get the same session_id. + llvm::DenseMap session_ids; static std::unique_ptr g_instance; }; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 18569e155b517..b458abc798a9e 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -62,6 +62,7 @@
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
@@ -137,53 +157,59 @@ export class LLDBDapDescriptorFactory const dbgOptions = { env: { -...executable?.options?.env, ...configEnvironment, ...env, }, }; -const dbgArgs = executable?.args ?? []; vogelsgesang wrote: There might be some downstream users who are actually bundling an `lldb-dap` binary into their re-packaged distribution of this VS-Code extension. At least the commit message from https://github.com/llvm/llvm-project/commit/b5d4332286154838557a8ab5c76b794e85d946b3 indicates, that there were some thoughts that downstream consumers might inject the lldb-dap path when using this extension as a library. @JDevlieghere @walter-erquinigo are you aware if anyone is re-packaging this VS-Code extension together with an lldb-dap binary and might be relying on setting the lldb-dap path through the `package.json`? https://github.com/llvm/llvm-project/pull/129262 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
@@ -137,53 +157,59 @@ export class LLDBDapDescriptorFactory const dbgOptions = { env: { -...executable?.options?.env, ...configEnvironment, ...env, }, }; -const dbgArgs = executable?.args ?? []; +const dbgArgs = getDAPArguments(session); -const serverMode = config.get('serverMode', false); +const serverMode = config.get("serverMode", false); if (serverMode) { - const { host, port } = await this.startServer(dapPath, dbgArgs, dbgOptions); + const { host, port } = await this.startServer( +dapPath, +dbgArgs, +dbgOptions, + ); return new vscode.DebugAdapterServer(port, host); } return new vscode.DebugAdapterExecutable(dapPath, dbgArgs, dbgOptions); } - startServer(dapPath: string, args: string[], options: child_process.CommonSpawnOptions): Promise<{ host: string, port: number }> { -if (this.server) return this.server; + startServer( +dapPath: string, +args: string[], +options: child_process.CommonSpawnOptions, + ): Promise<{ host: string; port: number }> { +if (this.server) { + return this.server; +} -this.server = new Promise(resolve => { - args.push( -'--connection', -'connect://localhost:0' - ); +this.server = new Promise((resolve) => { + args.push("--connection", "connect://localhost:0"); const server = child_process.spawn(dapPath, args, options); - server.stdout!.setEncoding('utf8').once('data', (data: string) => { + server.stdout!.setEncoding("utf8").once("data", (data: string) => { const connection = /connection:\/\/\[([^\]]+)\]:(\d+)/.exec(data); if (connection) { const host = connection[1]; const port = Number(connection[2]); resolve({ process: server, host, port }); } }); - server.on('exit', () => { + server.on("exit", () => { this.server = undefined; - }) + }); }); return this.server; } /** * Shows a message box when the debug adapter's path is not found */ - static async showLLDBDapNotFoundMessage(path?: string) { + static async showLLDBDapNotFoundMessage(path?: string | undefined) { vogelsgesang wrote: Afaict, the `?` already marks `path` as potentially `undefined`? Why add the `| undefined` in addition? https://github.com/llvm/llvm-project/pull/129262 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
https://github.com/vogelsgesang edited https://github.com/llvm/llvm-project/pull/129262 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
@@ -137,53 +157,59 @@ export class LLDBDapDescriptorFactory const dbgOptions = { env: { -...executable?.options?.env, ...configEnvironment, ...env, }, }; -const dbgArgs = executable?.args ?? []; +const dbgArgs = getDAPArguments(session); -const serverMode = config.get('serverMode', false); +const serverMode = config.get("serverMode", false); if (serverMode) { - const { host, port } = await this.startServer(dapPath, dbgArgs, dbgOptions); + const { host, port } = await this.startServer( +dapPath, +dbgArgs, +dbgOptions, + ); return new vscode.DebugAdapterServer(port, host); } return new vscode.DebugAdapterExecutable(dapPath, dbgArgs, dbgOptions); } - startServer(dapPath: string, args: string[], options: child_process.CommonSpawnOptions): Promise<{ host: string, port: number }> { -if (this.server) return this.server; + startServer( +dapPath: string, +args: string[], +options: child_process.CommonSpawnOptions, + ): Promise<{ host: string; port: number }> { +if (this.server) { + return this.server; +} vogelsgesang wrote: This does not interact correctly with the new `session.configuration.debugAdapterArgs` settings. We might be reusing a lldb-dap instance which was launched with different arguments, effectively ignoring the `debugAdapterArgs` specified in the launch config. We already have the same issue with the `dapPath`, where we might end up reusing the wrong lldb-dap binary (see my other comment in https://github.com/llvm/llvm-project/pull/128957#discussion_r1976226941). But I think this commit is unfortunately further into the direction of incorrectly caching the server processes. Not sure how we want to proceed here... WDYT, @ashgti and @JDevlieghere ? Is it fine merging this PR as is? Or should we first fix our logic on when to reuse the server and when not? https://github.com/llvm/llvm-project/pull/129262 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (PR #128957)
@@ -115,41 +123,71 @@ export class LLDBDapDescriptorFactory } const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; -const dapPath = await getDAPExecutable(session); +const dapPath = (await getDAPExecutable(session)) ?? executable?.command; + +if (!dapPath) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(); + return undefined; +} + +if (!(await isExecutable(dapPath))) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); + return; +} + const dbgOptions = { env: { ...executable?.options?.env, ...configEnvironment, ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions); -} else if (executable) { - if (!(await isExecutable(executable.command))) { - LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(executable.command); -return undefined; - } - return new vscode.DebugAdapterExecutable( -executable.command, -executable.args, -dbgOptions, - ); +const dbgArgs = executable?.args ?? []; + +const serverMode = config.get('serverMode', false); +if (serverMode) { + const { host, port } = await this.startServer(dapPath, dbgArgs, dbgOptions); + return new vscode.DebugAdapterServer(port, host); } -return undefined; + +return new vscode.DebugAdapterExecutable(dapPath, dbgArgs, dbgOptions); + } + + startServer(dapPath: string, args: string[], options: child_process.CommonSpawnOptions): Promise<{ host: string, port: number }> { +if (this.server) return this.server; ashgti wrote: I think a simple solution could be to just ask the user if we can kill the running server or if they want to reuse the existing server. I don't expect that users will be changing lldb-dap paths often, I hope. https://github.com/llvm/llvm-project/pull/128957 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog. (PR #129294)
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/129294 >From 8d466e5c4b1b6913e788fd11d46689af8f0b8eec Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 27 Feb 2025 15:33:51 -0800 Subject: [PATCH] [lldb-dap] Updating the logging of lldb-dap to use existing LLDBLog.h helpers. This only creates the basic types need to start using the LLDBLog.h helpers. Today, logging is handling by a simple `std::ofstream *` for handling logging. LLDBLog.h can help improve logging by adding new categories of logs and give us additional formatting support for log messages. --- lldb/tools/lldb-dap/CMakeLists.txt | 1 + lldb/tools/lldb-dap/DAP.cpp | 62 lldb/tools/lldb-dap/DAP.h | 11 ++--- lldb/tools/lldb-dap/DAPLog.cpp | 22 + lldb/tools/lldb-dap/DAPLog.h| 34 + lldb/tools/lldb-dap/EventHelper.cpp | 17 --- lldb/tools/lldb-dap/IOStream.cpp| 19 lldb/tools/lldb-dap/IOStream.h | 7 ++- lldb/tools/lldb-dap/lldb-dap.cpp| 75 - 9 files changed, 146 insertions(+), 102 deletions(-) create mode 100644 lldb/tools/lldb-dap/DAPLog.cpp create mode 100644 lldb/tools/lldb-dap/DAPLog.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 8b3c520ec4360..d9f09f6d022ed 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -23,6 +23,7 @@ add_lldb_tool(lldb-dap Breakpoint.cpp BreakpointBase.cpp DAP.cpp + DAPLog.cpp EventHelper.cpp ExceptionBreakpoint.cpp FifoFiles.cpp diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 53c514b790f38..81f5205d4f6bd 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -7,6 +7,7 @@ //===--===// #include "DAP.h" +#include "DAPLog.h" #include "Handler/ResponseHandler.h" #include "JSONUtils.h" #include "LLDBUtils.h" @@ -19,6 +20,7 @@ #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" #include "lldb/Utility/IOObject.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -50,6 +52,7 @@ #endif using namespace lldb_dap; +using namespace lldb_private; namespace { #ifdef _WIN32 @@ -61,13 +64,12 @@ const char DEV_NULL[] = "/dev/null"; namespace lldb_dap { -DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log, - lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode, +DAP::DAP(std::string name, llvm::StringRef path, lldb::IOObjectSP input, + lldb::IOObjectSP output, ReplMode repl_mode, std::vector pre_init_commands) -: name(std::move(name)), debug_adapter_path(path), log(log), - input(std::move(input)), output(std::move(output)), - broadcaster("lldb-dap"), exception_breakpoints(), - pre_init_commands(std::move(pre_init_commands)), +: name(std::move(name)), debug_adapter_path(path), input(std::move(input)), + output(std::move(output)), broadcaster("lldb-dap"), + exception_breakpoints(), pre_init_commands(std::move(pre_init_commands)), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), enable_auto_variable_summaries(false), enable_synthetic_child_debugging(false), @@ -245,6 +247,8 @@ void DAP::SendJSON(const std::string &json_str) { output.write_full(llvm::utostr(json_str.size())); output.write_full("\r\n\r\n"); output.write_full(json_str); + + LLDB_LOG(GetLog(DAPLog::Transport), "{0} <-- {1}", name, json_str); } // Serialize the JSON value into a string and send the JSON packet to @@ -256,15 +260,6 @@ void DAP::SendJSON(const llvm::json::Value &json) { static std::mutex mutex; std::lock_guard locker(mutex); SendJSON(json_str); - - if (log) { -auto now = std::chrono::duration( -std::chrono::system_clock::now().time_since_epoch()); -*log << llvm::formatv("{0:f9} {1} <-- ", now.count(), name).str() - << std::endl - << "Content-Length: " << json_str.size() << "\r\n\r\n" - << llvm::formatv("{0:2}", json).str() << std::endl; - } } // Read a JSON packet from the "in" stream. @@ -273,28 +268,22 @@ std::string DAP::ReadJSON() { std::string json_str; int length; - if (!input.read_expected(log, "Content-Length: ")) + if (!input.read_expected("Content-Length: ")) return json_str; - if (!input.read_line(log, length_str)) + if (!input.read_line(length_str)) return json_str; if (!llvm::to_integer(length_str, length)) return json_str; - if (!input.read_expected(log, "\r\n")) + if (!input.read_expected("\r\n")) return json_str; - if (!input.read_full(log, length, json_str)) + if (!input.read_full(length, json_str)) return json_str; - if (log) { -auto now = std::chrono::duration( -
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments (PR #129262)
https://github.com/matthewbastien created https://github.com/llvm/llvm-project/pull/129262 Added a new setting called lldb-dap.arguments and a debug configuration attribute called debugAdapterArgs that can be used to set the arguments used to launch the debug adapter. Right now this is mostly useful for debugging purposes to add the `--wait-for-debugger` option to lldb-dap. I've also removed the check for the `executable` argument in `LLDBDapDescriptorFactory.createDebugAdapterDescriptor()`. This argument is only set by VS Code when the debug adapter executable properties are set in the `package.json`. The LLDB DAP extension does not currently do this (and I don't think it ever will). So, this makes the debug adapter descriptor factory a little easier to read. >From 8926756d800b9ecd171b6d645a459b01342e9458 Mon Sep 17 00:00:00 2001 From: Matthew Bastien Date: Fri, 28 Feb 2025 11:08:25 -0500 Subject: [PATCH] allow providing debug adapter arguments --- lldb/tools/lldb-dap/package.json | 23 + .../lldb-dap/src-ts/debug-adapter-factory.ts | 48 +++ 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 31d808eda4c35..0859b6e388a4e 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -75,6 +75,15 @@ "type": "string", "description": "The path to the lldb-dap binary." }, +"lldb-dap.arguments": { + "scope": "resource", + "type": "array", + "default": [], + "items": { +"type": "string" + }, + "description": "The arguments provided to the lldb-dap process." +}, "lldb-dap.log-path": { "scope": "resource", "type": "string", @@ -156,6 +165,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to debug." @@ -346,6 +362,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to attach to." diff --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts index 36107336ebc4d..ea7b4ce97ac1d 100644 --- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts +++ b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts @@ -92,6 +92,21 @@ async function getDAPExecutable( return undefined; } +function getDAPArguments(session: vscode.DebugSession): string[] { + // Check the debug configuration for arguments first + const debugConfigArgs = session.configuration.debugAdapterArgs; + if ( +Array.isArray(debugConfigArgs) && +debugConfigArgs.findIndex((entry) => typeof entry !== "string") === -1 + ) { +return debugConfigArgs; + } + // Fall back on the workspace configuration + return vscode.workspace +.getConfiguration("lldb-dap") +.get("arguments", []); +} + /** * This class defines a factory used to find the lldb-dap binary to use * depending on the session configuration. @@ -101,7 +116,7 @@ export class LLDBDapDescriptorFactory { async createDebugAdapterDescriptor( session: vscode.DebugSession, -executable: vscode.DebugAdapterExecutable | undefined, +_executable: vscode.DebugAdapterExecutable | undefined, ): Promise { const config = vscode.workspace.getConfiguration( "lldb-dap", @@ -116,40 +131,31 @@ export class LLDBDapDescriptorFactory const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; const dapPath = await getDAPExecutable(session); +const dapArgs = getDAPArguments(session); const dbgOptions = { env: { -...executable?.options?.env, ...configEnvironment, ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgO
[Lldb-commits] [lldb] [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (PR #128957)
@@ -115,41 +123,71 @@ export class LLDBDapDescriptorFactory } const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; -const dapPath = await getDAPExecutable(session); +const dapPath = (await getDAPExecutable(session)) ?? executable?.command; + +if (!dapPath) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(); + return undefined; +} + +if (!(await isExecutable(dapPath))) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); + return; +} + const dbgOptions = { env: { ...executable?.options?.env, ...configEnvironment, ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions); -} else if (executable) { - if (!(await isExecutable(executable.command))) { - LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(executable.command); -return undefined; - } - return new vscode.DebugAdapterExecutable( -executable.command, -executable.args, -dbgOptions, - ); +const dbgArgs = executable?.args ?? []; + +const serverMode = config.get('serverMode', false); +if (serverMode) { + const { host, port } = await this.startServer(dapPath, dbgArgs, dbgOptions); + return new vscode.DebugAdapterServer(port, host); } -return undefined; + +return new vscode.DebugAdapterExecutable(dapPath, dbgArgs, dbgOptions); + } + + startServer(dapPath: string, args: string[], options: child_process.CommonSpawnOptions): Promise<{ host: string, port: number }> { +if (this.server) return this.server; + +this.server = new Promise(resolve => { + args.push( +'--connection', +'connect://localhost:0' + ); + const server = child_process.spawn(dapPath, args, options); + server.stdout!.setEncoding('utf8').once('data', (data: string) => { ashgti wrote: A single 'data' event usually corresponds to a single 'write' event which https://github.com/llvm/llvm-project/blob/cef6dbbe544ff4c49fca65cdc50df783d8c39c28/lldb/tools/lldb-dap/lldb-dap.cpp#L298 should correspond to one call. https://github.com/llvm/llvm-project/pull/128957 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (PR #128957)
ashgti wrote: > Random question: what happens when the server crashes? Do you get a popup in > the UI telling you? If the server is killed while the debug session is running then the debug session stops. This is the same behavior as today when running not in server mode. If the server crashes between debug sessions a new one will be spawned on demand. I don't currently alert the user if it shuts down or is killed and I don't have an idle timeout or anything. The server is running under the extension host process and VS Code uses one extension host process per window. That means the server will be around until the window is closed or the user quits VS Code. As far as server management goes, I don't have any explicit logic for that at the moment, but we could add it in the future. Some thoughts: * The server could shut itself down if the process gets a low memory warning and there are no active clients. * The server could have an idle timeout and shutdown if there are not active clients after some configurable period. * The extension could alert the user to unexpected crashes or exits. * The extension could have commands to manually start / stop the server. At the moment though, I am keeping this relatively simple. https://github.com/llvm/llvm-project/pull/128957 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add terminfo dependency for ncurses support (PR #126810)
DavidSpickett wrote: If this and the follow up are working well, consider backporting them to 20.x. https://github.com/llvm/llvm-project/pull/126810 ___ 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 `runInTerminal` for Windows (PR #121269)
https://github.com/SuibianP edited https://github.com/llvm/llvm-project/pull/121269 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
@@ -987,6 +998,16 @@ void Debugger::Clear() { // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp); // static void Debugger::Terminate(); llvm::call_once(m_clear_once, [this]() { +lldb_private::telemetry::ScopedDispatcher< +lldb_private::telemetry::DebuggerInfo> labath wrote: ```suggestion telemetry::ScopedDispatcher ``` https://github.com/llvm/llvm-project/pull/127696 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
@@ -18,25 +18,35 @@ namespace lldb_private { -struct FakeTelemetryInfo : public llvm::telemetry::TelemetryInfo { +struct FakeTelemetryInfo : public telemetry::LLDBBaseTelemetryInfo { std::string msg; + int num; + + ::llvm::telemetry::KindType getKind() const override { return 0b1; } }; class TestDestination : public llvm::telemetry::Destination { public: - TestDestination(std::vector *entries) + TestDestination(std::vector *entries) labath wrote: ```suggestion explicit TestDestination(std::vector> &entries) ``` https://github.com/llvm/llvm-project/pull/127696 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
@@ -761,7 +765,14 @@ void Debugger::InstanceInitialize() { DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback, void *baton) { + lldb_private::telemetry::ScopedDispatcher< + lldb_private::telemetry::DebuggerInfo> + helper([](lldb_private::telemetry::DebuggerInfo *entry) { +entry->lldb_version = lldb_private::GetVersion(); + }); DebuggerSP debugger_sp(new Debugger(log_callback, baton)); + helper.SetDebugger(debugger_sp.get()); labath wrote: This is definitely better, but lambdas tend to add some boilerplate of their own. They may be useful in some cases (if you need to set some field at the very end) but I think that in many cases (this one included) we could just set the field directly, so I want to float this idea: I think this would be shorter if we had the dispatcher object expose the telemetry entry it is managing directly: ```suggestion telemetry::ScopedDispatcher helper; DebuggerSP debugger_sp(new Debugger(log_callback, baton)); if (telemetry::DebuggerInfo *info = helper.GetEntry()) {// returns NULL if telemetry is disabled info->debugger = debugger_sp.get(); info->lldb_version = lldb_private::GetVersion(); } ``` (and if we do need a callback, I don't see a reason why this couldn't coexist with that) Any thoughts @JDevlieghere ? https://github.com/llvm/llvm-project/pull/127696 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/127696 >From 24e9f78744f98ecf3ac01f1f719f1eac9b3479f0 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Tue, 18 Feb 2025 15:58:08 -0500 Subject: [PATCH 01/23] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods - This type of entry is used to collect data about the debugger startup/exit - Tests will be added (They may need to be shell test with a "test-only" TelemetryManager plugin defined. I'm trying to figure out how to get that linked only when tests are running and not to the LLDB binary all the time. --- lldb/include/lldb/Core/Telemetry.h | 78 +++ lldb/source/Core/Debugger.cpp | 40 ++ lldb/source/Core/Telemetry.cpp | 115 + 3 files changed, 220 insertions(+), 13 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index b72556ecaf3c9..d6eec5dc687be 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -13,6 +13,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-forward.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/JSON.h" @@ -29,6 +30,9 @@ namespace telemetry { struct LLDBEntryKind : public ::llvm::telemetry::EntryKind { static const llvm::telemetry::KindType BaseInfo = 0b11000; + static const llvm::telemetry::KindType DebuggerInfo = 0b11001; + // There are other entries in between (added in separate PRs) + static const llvm::telemetry::KindType MiscInfo = 0b0; }; /// Defines a convenient type for timestamp of various events. @@ -56,6 +60,71 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { void serialize(llvm::telemetry::Serializer &serializer) const override; }; +/// Describes the exit status of a debugger. +struct ExitDescription { + int exit_code; + std::string description; +}; + +struct DebuggerTelemetryInfo : public LLDBBaseTelemetryInfo { + std::string username; + std::string lldb_git_sha; + std::string lldb_path; + std::string cwd; + std::optional exit_desc; + + DebuggerTelemetryInfo() = default; + + // Provide a copy ctor because we may need to make a copy before + // sanitizing the data. + // (The sanitization might differ between different Destination classes). + DebuggerTelemetryInfo(const DebuggerTelemetryInfo &other) { +username = other.username; +lldb_git_sha = other.lldb_git_sha; +lldb_path = other.lldb_path; +cwd = other.cwd; + }; + + llvm::telemetry::KindType getKind() const override { +return LLDBEntryKind::DebuggerInfo; + } + + static bool classof(const llvm::telemetry::TelemetryInfo *T) { +return T->getKind() == LLDBEntryKind::DebuggerInfo; + } + + void serialize(llvm::telemetry::Serializer &serializer) const override; +}; + +/// The "catch-all" entry to store a set of non-standard data, such as +/// error-messages, etc. +struct MiscTelemetryInfo : public LLDBBaseTelemetryInfo { + /// If the event is/can be associated with a target entry, + /// this field contains that target's UUID. + /// otherwise. + std::string target_uuid; + + /// Set of key-value pairs for any optional (or impl-specific) data + std::map meta_data; + + MiscTelemetryInfo() = default; + + MiscTelemetryInfo(const MiscTelemetryInfo &other) { +target_uuid = other.target_uuid; +meta_data = other.meta_data; + } + + llvm::telemetry::KindType getKind() const override { +return LLDBEntryKind::MiscInfo; + } + + static bool classof(const llvm::telemetry::TelemetryInfo *T) { +return T->getKind() == LLDBEntryKind::MiscInfo; + } + + void serialize(llvm::telemetry::Serializer &serializer) const override; +}; + /// The base Telemetry manager instance in LLDB. /// This class declares additional instrumentation points /// applicable to LLDB. @@ -63,6 +132,11 @@ class TelemetryManager : public llvm::telemetry::Manager { public: llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override; + const llvm::telemetry::Config *getConfig(); + + void atDebuggerStartup(DebuggerTelemetryInfo *entry); + void atDebuggerExit(DebuggerTelemetryInfo *entry); + virtual llvm::StringRef GetInstanceName() const = 0; static TelemetryManager *getInstance(); @@ -73,6 +147,10 @@ class TelemetryManager : public llvm::telemetry::Manager { private: std::unique_ptr m_config; + // Each debugger is assigned a unique ID (session_id). + // All TelemetryInfo entries emitted for the same debugger instance + // will get the same session_id. + llvm::DenseMap session_ids; static std::unique_ptr g_instance; }; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 18569e155b517..b458abc798a9e 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -62,6 +62,7 @@
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
@@ -56,13 +58,38 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { void serialize(llvm::telemetry::Serializer &serializer) const override; }; +/// Describes the exit status of a debugger. +struct ExitDescription { + int exit_code; + std::string description; +}; + +struct DebuggerInfo : public LLDBBaseTelemetryInfo { oontvoo wrote: I definitely need this class to be extensible. Can you clarify what changes are needed to allow this? https://github.com/llvm/llvm-project/pull/127696 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
oontvoo wrote: @labath > IOW, can we drop the exit_desc field from this struct? Well, we need a way to distinguish the start and the exit entries How about just keeping `exit_code` (which is set to zero) > I still think it's important to have a simple and succinct way to check > whether telemetry is "actually" enabled at a given moment We can have a `static TelemetryManager::TelemetryCurrentEnabled()` which does the check. https://github.com/llvm/llvm-project/pull/127696 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
labath wrote: > @labath > > > IOW, can we drop the exit_desc field from this struct? > > Well, we need a way to distinguish the start and the exit entries How about > just keeping `exit_code` (which is set to zero) You could distinguish them with a bool or enum field. I don't think an exit_code field makes sense if it's always going to be set to zero. I think it would make sense if you set it to `GetCommandInterpreter().GetQuitExitCode()`. > > > I still think it's important to have a simple and succinct way to check > > whether telemetry is "actually" enabled at a given moment > > We can have a `static TelemetryManager::TelemetryCurrentEnabled()` which does > the check. Maybe. Or maybe `TelemetryManager::GetInstanceIfEnabled` (not necessarily with that name) so you don't have to follow this up with a call to GetInstance(). Let's see how the code develops... https://github.com/llvm/llvm-project/pull/127696 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
@@ -73,9 +100,50 @@ class TelemetryManager : public llvm::telemetry::Manager { private: std::unique_ptr m_config; + // Each instance of a TelemetryManager is assigned a unique ID. + const std::string m_id; oontvoo wrote: > One reason for storing it in the UUID form might be if we think that someone > could be interested in storing/transmitting the UUID in a binary form This is the TelemetryManager - it is never transmitted or serialised anywhere. So why does compactness matter? If you mean storing the id as UUID in the `TelemetryInfo` object, then we'd need to update the llvm base interface. However, the reason the id was a string in the base interface was because people wanted flexibility in what the id could be in each implementation. Also the downside of storing it as UUID object is that you may have different `telemetry::Serializer` objects generating different values for the same UUID (ie.,different separators?). That's potentially problematic because ultimately, the point of this field is for grouping entries from the same session. We need the key to be identical across entries and not "accidentally" differ because of serialisation methods. https://github.com/llvm/llvm-project/pull/127696 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
@@ -56,13 +58,38 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { void serialize(llvm::telemetry::Serializer &serializer) const override; }; +/// Describes the exit status of a debugger. +struct ExitDescription { + int exit_code; + std::string description; +}; + +struct DebuggerInfo : public LLDBBaseTelemetryInfo { labath wrote: `DebuggerInfo::classof(subclass_of_debugger_info)` should return true, which I guess means changing the implementation to something like `return T->getKind()&LLDBEntryKind::DebuggerInfo == LLDBEntryKind::DebuggerInfo` https://github.com/llvm/llvm-project/pull/127696 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
https://github.com/matthewbastien edited https://github.com/llvm/llvm-project/pull/129262 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
https://github.com/matthewbastien edited https://github.com/llvm/llvm-project/pull/129262 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
@@ -75,6 +75,15 @@ "type": "string", "description": "The path to the lldb-dap binary." }, +"lldb-dap.arguments": { + "scope": "resource", + "type": "array", + "default": [], + "items": { +"type": "string" + }, + "description": "The arguments provided to the lldb-dap process." JDevlieghere wrote: Any reason the description here is different from the ones below? Also, should the description say "The list of _additional_ arguments", as the extension itself might specify others (e.g. with #128957 if you enable server mode)? https://github.com/llvm/llvm-project/pull/129262 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
https://github.com/matthewbastien updated https://github.com/llvm/llvm-project/pull/129262 >From 8926756d800b9ecd171b6d645a459b01342e9458 Mon Sep 17 00:00:00 2001 From: Matthew Bastien Date: Fri, 28 Feb 2025 11:08:25 -0500 Subject: [PATCH 1/2] allow providing debug adapter arguments --- lldb/tools/lldb-dap/package.json | 23 + .../lldb-dap/src-ts/debug-adapter-factory.ts | 48 +++ 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 31d808eda4c35..0859b6e388a4e 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -75,6 +75,15 @@ "type": "string", "description": "The path to the lldb-dap binary." }, +"lldb-dap.arguments": { + "scope": "resource", + "type": "array", + "default": [], + "items": { +"type": "string" + }, + "description": "The arguments provided to the lldb-dap process." +}, "lldb-dap.log-path": { "scope": "resource", "type": "string", @@ -156,6 +165,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to debug." @@ -346,6 +362,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to attach to." diff --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts index 36107336ebc4d..ea7b4ce97ac1d 100644 --- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts +++ b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts @@ -92,6 +92,21 @@ async function getDAPExecutable( return undefined; } +function getDAPArguments(session: vscode.DebugSession): string[] { + // Check the debug configuration for arguments first + const debugConfigArgs = session.configuration.debugAdapterArgs; + if ( +Array.isArray(debugConfigArgs) && +debugConfigArgs.findIndex((entry) => typeof entry !== "string") === -1 + ) { +return debugConfigArgs; + } + // Fall back on the workspace configuration + return vscode.workspace +.getConfiguration("lldb-dap") +.get("arguments", []); +} + /** * This class defines a factory used to find the lldb-dap binary to use * depending on the session configuration. @@ -101,7 +116,7 @@ export class LLDBDapDescriptorFactory { async createDebugAdapterDescriptor( session: vscode.DebugSession, -executable: vscode.DebugAdapterExecutable | undefined, +_executable: vscode.DebugAdapterExecutable | undefined, ): Promise { const config = vscode.workspace.getConfiguration( "lldb-dap", @@ -116,40 +131,31 @@ export class LLDBDapDescriptorFactory const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; const dapPath = await getDAPExecutable(session); +const dapArgs = getDAPArguments(session); const dbgOptions = { env: { -...executable?.options?.env, ...configEnvironment, ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions); -} else if (executable) { - if (!(await isExecutable(executable.command))) { - LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(executable.command); -return undefined; - } - return new vscode.DebugAdapterExecutable( -executable.command, -executable.args, -dbgOptions, - ); +if (dapPath === undefined || !(await isExecutable(dapPath))) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); + return undefined; } -return undefined; +return new vscode.DebugAdapterExecutable(dapPath, dapArgs, dbgOptions); } /** * Shows a message box when the debug adapter's pat
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
https://github.com/matthewbastien updated https://github.com/llvm/llvm-project/pull/129262 >From 8926756d800b9ecd171b6d645a459b01342e9458 Mon Sep 17 00:00:00 2001 From: Matthew Bastien Date: Fri, 28 Feb 2025 11:08:25 -0500 Subject: [PATCH 1/2] allow providing debug adapter arguments --- lldb/tools/lldb-dap/package.json | 23 + .../lldb-dap/src-ts/debug-adapter-factory.ts | 48 +++ 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 31d808eda4c35..0859b6e388a4e 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -75,6 +75,15 @@ "type": "string", "description": "The path to the lldb-dap binary." }, +"lldb-dap.arguments": { + "scope": "resource", + "type": "array", + "default": [], + "items": { +"type": "string" + }, + "description": "The arguments provided to the lldb-dap process." +}, "lldb-dap.log-path": { "scope": "resource", "type": "string", @@ -156,6 +165,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to debug." @@ -346,6 +362,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to attach to." diff --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts index 36107336ebc4d..ea7b4ce97ac1d 100644 --- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts +++ b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts @@ -92,6 +92,21 @@ async function getDAPExecutable( return undefined; } +function getDAPArguments(session: vscode.DebugSession): string[] { + // Check the debug configuration for arguments first + const debugConfigArgs = session.configuration.debugAdapterArgs; + if ( +Array.isArray(debugConfigArgs) && +debugConfigArgs.findIndex((entry) => typeof entry !== "string") === -1 + ) { +return debugConfigArgs; + } + // Fall back on the workspace configuration + return vscode.workspace +.getConfiguration("lldb-dap") +.get("arguments", []); +} + /** * This class defines a factory used to find the lldb-dap binary to use * depending on the session configuration. @@ -101,7 +116,7 @@ export class LLDBDapDescriptorFactory { async createDebugAdapterDescriptor( session: vscode.DebugSession, -executable: vscode.DebugAdapterExecutable | undefined, +_executable: vscode.DebugAdapterExecutable | undefined, ): Promise { const config = vscode.workspace.getConfiguration( "lldb-dap", @@ -116,40 +131,31 @@ export class LLDBDapDescriptorFactory const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; const dapPath = await getDAPExecutable(session); +const dapArgs = getDAPArguments(session); const dbgOptions = { env: { -...executable?.options?.env, ...configEnvironment, ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions); -} else if (executable) { - if (!(await isExecutable(executable.command))) { - LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(executable.command); -return undefined; - } - return new vscode.DebugAdapterExecutable( -executable.command, -executable.args, -dbgOptions, - ); +if (dapPath === undefined || !(await isExecutable(dapPath))) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); + return undefined; } -return undefined; +return new vscode.DebugAdapterExecutable(dapPath, dapArgs, dbgOptions); } /** * Shows a message box when the debug adapter's pat
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
@@ -75,6 +75,15 @@ "type": "string", "description": "The path to the lldb-dap binary." }, +"lldb-dap.arguments": { + "scope": "resource", + "type": "array", + "default": [], + "items": { +"type": "string" + }, + "description": "The arguments provided to the lldb-dap process." matthewbastien wrote: No reason in particular. You're right. I've updated the wording with your suggestions. https://github.com/llvm/llvm-project/pull/129262 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
@@ -116,40 +131,31 @@ export class LLDBDapDescriptorFactory const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; const dapPath = await getDAPExecutable(session); +const dapArgs = getDAPArguments(session); const dbgOptions = { env: { -...executable?.options?.env, ...configEnvironment, ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions); -} else if (executable) { - if (!(await isExecutable(executable.command))) { - LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(executable.command); -return undefined; - } - return new vscode.DebugAdapterExecutable( -executable.command, -executable.args, -dbgOptions, - ); +if (dapPath === undefined || !(await isExecutable(dapPath))) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); + return undefined; } -return undefined; +return new vscode.DebugAdapterExecutable(dapPath, dapArgs, dbgOptions); } /** * Shows a message box when the debug adapter's path is not found */ - static async showLLDBDapNotFoundMessage(path: string) { + static async showLLDBDapNotFoundMessage(path: string | undefined) { const openSettingsAction = "Open Settings"; +const message = + path === undefined +? "Unable to find the LLDB debug adapter executable." +: `Debug adapter path: ${path} is not a valid file`; matthewbastien wrote: Good call. This is the only place that we show notifications as far as I can tell. So, I'm leaning towards having the period at the end and changed both to match. https://github.com/llvm/llvm-project/pull/129262 ___ 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 process picker command to VS Code extension (PR #128943)
@@ -0,0 +1,102 @@ +import { ChildProcessWithoutNullStreams } from "child_process"; +import { Process, ProcessTree } from "."; +import { Transform } from "stream"; + +/** Parses process information from a given line of process output. */ +export type ProcessTreeParser = (line: string) => Process | undefined; + +/** + * Implements common behavior between the different {@link ProcessTree} implementations. + */ +export abstract class BaseProcessTree implements ProcessTree { + /** + * Spawn the process responsible for collecting all processes on the system. + */ + protected abstract spawnProcess(): ChildProcessWithoutNullStreams; ashgti wrote: It may be easer to use the `exec`/`execFile`. If you use the promise form of the `exec`/`execFile` call you get the output as a single chunk which simplifies processing. You could use something like: ``` const exec = util.promisify(child_process.execFile); // this can go at the top of the file const { stdout } = await exec("ps", [...]); for (const line of stdout.split('\n')) { /* process lines */ } ``` https://github.com/llvm/llvm-project/pull/128943 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] a3ac1f2 - [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (#128957)
Author: John Harrison Date: 2025-02-28T10:49:24-08:00 New Revision: a3ac1f2278dec155e0e0b4d06ec816ba325f6979 URL: https://github.com/llvm/llvm-project/commit/a3ac1f2278dec155e0e0b4d06ec816ba325f6979 DIFF: https://github.com/llvm/llvm-project/commit/a3ac1f2278dec155e0e0b4d06ec816ba325f6979.diff LOG: [lldb-dap] Adding server mode support to lldb-dap VSCode extension. (#128957) This adds support for launching lldb-dap in server mode. The extension will start lldb-dap in server mode on-demand and retain the server until the VSCode window is closed (when the extension context is disposed). While running in server mode, launch performance for binaries is greatly improved by improving caching between debug sessions. For example, on my local M1 Max laptop it takes ~5s to attach for the first attach to an iOS Simulator process and ~0.5s to attach each time after the first. Added: Modified: lldb/tools/lldb-dap/package.json lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts lldb/tools/lldb-dap/src-ts/extension.ts Removed: diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 31d808eda4c35..cd450a614b3f7 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -88,6 +88,12 @@ "additionalProperties": { "type": "string" } +}, +"lldb-dap.serverMode": { + "scope": "resource", + "type": "boolean", + "markdownDescription": "Run lldb-dap in server mode.\n\nWhen enabled, lldb-dap will start a background server that will be reused between debug sessions. This allows caching of debug symbols between sessions and improves launch performance.", + "default": false } } }, @@ -543,4 +549,4 @@ } ] } -} +} \ No newline at end of file diff --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts index 36107336ebc4d..1f76fe31b00ad 100644 --- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts +++ b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts @@ -4,6 +4,8 @@ import * as vscode from "vscode"; import * as child_process from "child_process"; import * as fs from "node:fs/promises"; +const exec = util.promisify(child_process.execFile); + export async function isExecutable(path: string): Promise { try { await fs.access(path, fs.constants.X_OK); @@ -16,7 +18,6 @@ export async function isExecutable(path: string): Promise { async function findWithXcrun(executable: string): Promise { if (process.platform === "darwin") { try { - const exec = util.promisify(child_process.execFile); let { stdout, stderr } = await exec("/usr/bin/xcrun", [ "-find", executable, @@ -24,7 +25,7 @@ async function findWithXcrun(executable: string): Promise { if (stdout) { return stdout.toString().trimEnd(); } -} catch (error) {} +} catch (error) { } } return undefined; } @@ -97,8 +98,15 @@ async function getDAPExecutable( * depending on the session configuration. */ export class LLDBDapDescriptorFactory - implements vscode.DebugAdapterDescriptorFactory -{ + implements vscode.DebugAdapterDescriptorFactory, vscode.Disposable { + private server?: Promise<{ process: child_process.ChildProcess, host: string, port: number }>; + + dispose() { +this.server?.then(({ process }) => { + process.kill(); +}); + } + async createDebugAdapterDescriptor( session: vscode.DebugSession, executable: vscode.DebugAdapterExecutable | undefined, @@ -115,7 +123,18 @@ export class LLDBDapDescriptorFactory } const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; -const dapPath = await getDAPExecutable(session); +const dapPath = (await getDAPExecutable(session)) ?? executable?.command; + +if (!dapPath) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(); + return undefined; +} + +if (!(await isExecutable(dapPath))) { + LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); + return; +} + const dbgOptions = { env: { ...executable?.options?.env, @@ -123,33 +142,52 @@ export class LLDBDapDescriptorFactory ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions); -} else if (executable) { - if (!(await isExecutable(executable.command))) { - LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(executable.command); -return undefined; - } - return new vscode.DebugAdapterExecutable( -executable.command, -executable.arg
[Lldb-commits] [lldb] [lldb] fix(lldb/**.py): fix invalid escape sequences (PR #94034)
https://github.com/DavidSpickett closed https://github.com/llvm/llvm-project/pull/94034 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] fix(lldb/**.py): fix invalid escape sequences (PR #94034)
https://github.com/DavidSpickett approved this pull request. LGTM https://github.com/llvm/llvm-project/pull/94034 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Restore register state if PrepareTrivialCall fails (PR #129038)
https://github.com/DavidSpickett updated https://github.com/llvm/llvm-project/pull/129038 >From 67e0bd38889c1a62c9f457432f9e9d46c6ece8dc Mon Sep 17 00:00:00 2001 From: David Spickett Date: Wed, 26 Feb 2025 10:01:39 + Subject: [PATCH] [lldb] Restore register state if PrepareTrivialCall fails Fixes #124269 PrepareTrivalCall always had the possibility of failing, but given that it only wrote to general purpose registers, if it did, you had bigger problems. When it failed, we did not mark the thread plan valid and when it was torn down we didn't try to restore the register state. This meant that if you tried to continue, the program unlikely to work. When I added GCS, I needed to handle the situation where the GCS pointer points to unmapped memory and we fail to write the extra entry we need. So I added code to restore the gcspr_el0 register specifically if this happened, and ordered the operations such that we tried this first. In this change I've made the teardown of an invalid thread plan restore the register state if one was saved. It may be there isn't one if ConstructorSetup fails, but this is ok because that function does not modify anything. Now that we're doing that, I don't need the GCS specific code anymore, and all thread plans are protected from this in the rare event something does fail. Testing is done by the existing GCS test case that points the gcspr into unmapped memory which causes PrepareTrivialCall to fail. I tried adding a simulated test using a mock gdb server. This was not possible because they all use DynamicLoaderStatic which disables all JIT features. --- lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp | 7 +-- lldb/source/Target/ThreadPlanCallFunction.cpp | 13 - 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp index 280ec5ba37100..4bca879143a33 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -102,12 +102,7 @@ static Status PushToLinuxGuardedControlStack(addr_t return_addr, size_t wrote = thread.GetProcess()->WriteMemory(gcspr_el0, &return_addr, sizeof(return_addr), error); if ((wrote != sizeof(return_addr) || error.Fail())) { -// When PrepareTrivialCall fails, the register context is not restored, -// unlike when an expression fails to execute. This is arguably a bug, -// see https://github.com/llvm/llvm-project/issues/124269. -// For now we are handling this here specifically. We can assume this -// write will work as the one to decrement the register did. -reg_ctx->WriteRegisterFromUnsigned(gcspr_el0_info, gcspr_el0 + 8); +// gcspr_el0 will be restored by the ThreadPlan's DoTakedown. return Status("Failed to write new Guarded Control Stack entry."); } diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 50dcb66b9719f..218111d4faf60 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -174,8 +174,20 @@ void ThreadPlanCallFunction::ReportRegisterState(const char *message) { void ThreadPlanCallFunction::DoTakedown(bool success) { Log *log = GetLog(LLDBLog::Step); + Thread &thread = GetThread(); if (!m_valid) { +// If ConstructorSetup was succesfull but PrepareTrivialCall was not, +// we will have a saved register state and potentially modified registers. +// Restore those. +if (m_stored_thread_state.register_backup_sp) + if (!thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) +LLDB_LOGF( +log, +"ThreadPlanCallFunction(%p): Failed to restore register state from " +"invalid plan that contained a saved register state.", +static_cast(this)); + // Don't call DoTakedown if we were never valid to begin with. LLDB_LOGF(log, "ThreadPlanCallFunction(%p): Log called on " @@ -185,7 +197,6 @@ void ThreadPlanCallFunction::DoTakedown(bool success) { } if (!m_takedown_done) { -Thread &thread = GetThread(); if (success) { SetReturnValue(); } ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add ability to inspect backing threads with `thread info` (PR #129275)
jimingham wrote: Apparently I need more coffee... This is just in the info command (somehow I thought the change was to ThreadObjectIterateOverThreads... Done this way, that's okay. https://github.com/llvm/llvm-project/pull/129275 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Add ability to inspect backing threads with `thread info` (PR #129275)
https://github.com/jimingham approved this pull request. LGTM https://github.com/llvm/llvm-project/pull/129275 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] fix(lldb/**.py): fix invalid escape sequences (PR #94034)
github-actions[bot] wrote: @e-kwsm Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our [build bots](https://lab.llvm.org/buildbot/). If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail [here](https://llvm.org/docs/MyFirstTypoFix.html#myfirsttypofix-issues-after-landing-your-pr). If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of [LLVM development](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy). You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! https://github.com/llvm/llvm-project/pull/94034 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Push down the swig module to avoid an import cycle (PR #129135)
https://github.com/JDevlieghere approved this pull request. LGTM. Thanks for adding the comment with the motivation! https://github.com/llvm/llvm-project/pull/129135 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods (PR #127696)
https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/127696 >From 24e9f78744f98ecf3ac01f1f719f1eac9b3479f0 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Tue, 18 Feb 2025 15:58:08 -0500 Subject: [PATCH 01/24] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods - This type of entry is used to collect data about the debugger startup/exit - Tests will be added (They may need to be shell test with a "test-only" TelemetryManager plugin defined. I'm trying to figure out how to get that linked only when tests are running and not to the LLDB binary all the time. --- lldb/include/lldb/Core/Telemetry.h | 78 +++ lldb/source/Core/Debugger.cpp | 40 ++ lldb/source/Core/Telemetry.cpp | 115 + 3 files changed, 220 insertions(+), 13 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index b72556ecaf3c9..d6eec5dc687be 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -13,6 +13,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-forward.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/JSON.h" @@ -29,6 +30,9 @@ namespace telemetry { struct LLDBEntryKind : public ::llvm::telemetry::EntryKind { static const llvm::telemetry::KindType BaseInfo = 0b11000; + static const llvm::telemetry::KindType DebuggerInfo = 0b11001; + // There are other entries in between (added in separate PRs) + static const llvm::telemetry::KindType MiscInfo = 0b0; }; /// Defines a convenient type for timestamp of various events. @@ -56,6 +60,71 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { void serialize(llvm::telemetry::Serializer &serializer) const override; }; +/// Describes the exit status of a debugger. +struct ExitDescription { + int exit_code; + std::string description; +}; + +struct DebuggerTelemetryInfo : public LLDBBaseTelemetryInfo { + std::string username; + std::string lldb_git_sha; + std::string lldb_path; + std::string cwd; + std::optional exit_desc; + + DebuggerTelemetryInfo() = default; + + // Provide a copy ctor because we may need to make a copy before + // sanitizing the data. + // (The sanitization might differ between different Destination classes). + DebuggerTelemetryInfo(const DebuggerTelemetryInfo &other) { +username = other.username; +lldb_git_sha = other.lldb_git_sha; +lldb_path = other.lldb_path; +cwd = other.cwd; + }; + + llvm::telemetry::KindType getKind() const override { +return LLDBEntryKind::DebuggerInfo; + } + + static bool classof(const llvm::telemetry::TelemetryInfo *T) { +return T->getKind() == LLDBEntryKind::DebuggerInfo; + } + + void serialize(llvm::telemetry::Serializer &serializer) const override; +}; + +/// The "catch-all" entry to store a set of non-standard data, such as +/// error-messages, etc. +struct MiscTelemetryInfo : public LLDBBaseTelemetryInfo { + /// If the event is/can be associated with a target entry, + /// this field contains that target's UUID. + /// otherwise. + std::string target_uuid; + + /// Set of key-value pairs for any optional (or impl-specific) data + std::map meta_data; + + MiscTelemetryInfo() = default; + + MiscTelemetryInfo(const MiscTelemetryInfo &other) { +target_uuid = other.target_uuid; +meta_data = other.meta_data; + } + + llvm::telemetry::KindType getKind() const override { +return LLDBEntryKind::MiscInfo; + } + + static bool classof(const llvm::telemetry::TelemetryInfo *T) { +return T->getKind() == LLDBEntryKind::MiscInfo; + } + + void serialize(llvm::telemetry::Serializer &serializer) const override; +}; + /// The base Telemetry manager instance in LLDB. /// This class declares additional instrumentation points /// applicable to LLDB. @@ -63,6 +132,11 @@ class TelemetryManager : public llvm::telemetry::Manager { public: llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override; + const llvm::telemetry::Config *getConfig(); + + void atDebuggerStartup(DebuggerTelemetryInfo *entry); + void atDebuggerExit(DebuggerTelemetryInfo *entry); + virtual llvm::StringRef GetInstanceName() const = 0; static TelemetryManager *getInstance(); @@ -73,6 +147,10 @@ class TelemetryManager : public llvm::telemetry::Manager { private: std::unique_ptr m_config; + // Each debugger is assigned a unique ID (session_id). + // All TelemetryInfo entries emitted for the same debugger instance + // will get the same session_id. + llvm::DenseMap session_ids; static std::unique_ptr g_instance; }; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 18569e155b517..b458abc798a9e 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -62,6 +62,7 @@
[Lldb-commits] [lldb] [lldb][HostInfoMacOSX] Search CommandLineTools directory when looking up SDK paths (PR #128712)
https://github.com/JDevlieghere commented: I definitely like this approach much better. Two suggestions: - Should this use a FileSpec instead of a `std::string` for the sysroot? - I like the simplicity of a `std::pair` but on the other hand it's hard to tell what the string represents. I think it would help to either store the `sysroot` in the `XcodeSDK` (potentially as an `std::optional`) or having this return a `struct` with named fiels (e.g. `xcode_sdk`, `sysroot`). Putting the sysroot in the XcodeSDK means you don't have to update the Doxygen comments which are now all outdated. https://github.com/llvm/llvm-project/pull/128712 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Allow providing debug adapter arguments in the extension (PR #129262)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: Matthew Bastien (matthewbastien) Changes Added a new setting called lldb-dap.arguments and a debug configuration attribute called debugAdapterArgs that can be used to set the arguments used to launch the debug adapter. Right now this is mostly useful for debugging purposes to add the `--wait-for-debugger` option to lldb-dap. I've also removed the check for the `executable` argument in `LLDBDapDescriptorFactory.createDebugAdapterDescriptor()`. This argument is only set by VS Code when the debug adapter executable properties are set in the `package.json`. The LLDB DAP extension does not currently do this (and I don't think it ever will). So, this makes the debug adapter descriptor factory a little easier to read. --- Full diff: https://github.com/llvm/llvm-project/pull/129262.diff 2 Files Affected: - (modified) lldb/tools/lldb-dap/package.json (+23) - (modified) lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts (+27-21) ``diff diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 31d808eda4c35..0859b6e388a4e 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -75,6 +75,15 @@ "type": "string", "description": "The path to the lldb-dap binary." }, +"lldb-dap.arguments": { + "scope": "resource", + "type": "array", + "default": [], + "items": { +"type": "string" + }, + "description": "The arguments provided to the lldb-dap process." +}, "lldb-dap.log-path": { "scope": "resource", "type": "string", @@ -156,6 +165,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to debug." @@ -346,6 +362,13 @@ "type": "string", "markdownDescription": "The absolute path to the LLDB debug adapter executable to use." }, + "debugAdapterArgs": { +"type": "array", +"items": { + "type": "string" +}, +"markdownDescription": "The list of arguments used to launch the debug adapter executable." + }, "program": { "type": "string", "description": "Path to the program to attach to." diff --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts index 36107336ebc4d..ea7b4ce97ac1d 100644 --- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts +++ b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts @@ -92,6 +92,21 @@ async function getDAPExecutable( return undefined; } +function getDAPArguments(session: vscode.DebugSession): string[] { + // Check the debug configuration for arguments first + const debugConfigArgs = session.configuration.debugAdapterArgs; + if ( +Array.isArray(debugConfigArgs) && +debugConfigArgs.findIndex((entry) => typeof entry !== "string") === -1 + ) { +return debugConfigArgs; + } + // Fall back on the workspace configuration + return vscode.workspace +.getConfiguration("lldb-dap") +.get("arguments", []); +} + /** * This class defines a factory used to find the lldb-dap binary to use * depending on the session configuration. @@ -101,7 +116,7 @@ export class LLDBDapDescriptorFactory { async createDebugAdapterDescriptor( session: vscode.DebugSession, -executable: vscode.DebugAdapterExecutable | undefined, +_executable: vscode.DebugAdapterExecutable | undefined, ): Promise { const config = vscode.workspace.getConfiguration( "lldb-dap", @@ -116,40 +131,31 @@ export class LLDBDapDescriptorFactory const configEnvironment = config.get<{ [key: string]: string }>("environment") || {}; const dapPath = await getDAPExecutable(session); +const dapArgs = getDAPArguments(session); const dbgOptions = { env: { -...executable?.options?.env, ...configEnvironment, ...env, }, }; -if (dapPath) { - if (!(await isExecutable(dapPath))) { -LLDBDapDescriptorFactory.showLLDBDapNotFoundMessage(dapPath); -return undefined; - } - return new vscode.DebugAdapterExecutable(dapPath, [], dbgOptions); -} else if (executable) { - if (!(await isExecutable(executable.command))) { - LLDBDapDescriptorFactory.showLLDBDapN