https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/136494
>From 0bf4cfcbd1fe2a006a68cb6f85af9a09a49b47e7 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 20 Apr 2025 17:07:09 +0200 Subject: [PATCH 1/3] fallback to assembly when source code is not available --- lldb/tools/lldb-dap/JSONUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 33f10c93d2ada..1a44df7740639 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -750,9 +750,10 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, EmplaceSafeString(object, "name", frame_name); auto line_entry = frame.GetLineEntry(); + auto file_spec = line_entry.GetFileSpec(); // A line entry of 0 indicates the line is compiler generated i.e. no source // file is associated with the frame. - if (line_entry.GetFileSpec().IsValid() && + if (file_spec.IsValid() && file_spec.Exists() && (line_entry.GetLine() != 0 || line_entry.GetLine() != LLDB_INVALID_LINE_NUMBER)) { object.try_emplace("source", CreateSource(line_entry)); >From cbcebed97b9ce9251aa27ee384347b283d0625d3 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 20 Apr 2025 21:03:02 +0200 Subject: [PATCH 2/3] fix TestDAP_coreFile.py with source maps --- .../API/tools/lldb-dap/coreFile/TestDAP_coreFile.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index 1896acea15a99..ce54133a61f3e 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -19,7 +19,9 @@ def test_core_file(self): core_file = os.path.join(current_dir, "linux-x86_64.core") self.create_debug_adapter() - self.attach(exe_file, coreFile=core_file) + + source_map = [["/home/labath/test", current_dir]] + self.attach(exe_file, coreFile=core_file, sourceMap=source_map) expected_frames = [ { @@ -27,7 +29,7 @@ def test_core_file(self): "id": 524288, "line": 4, "name": "bar", - "source": {"name": "main.c", "path": "/home/labath/test/main.c"}, + "source": {"name": "main.c", "path": os.path.join(current_dir, "main.c")}, "instructionPointerReference": "0x40011C", }, { @@ -35,7 +37,7 @@ def test_core_file(self): "id": 524289, "line": 10, "name": "foo", - "source": {"name": "main.c", "path": "/home/labath/test/main.c"}, + "source": {"name": "main.c", "path": os.path.join(current_dir, "main.c")}, "instructionPointerReference": "0x400142", }, { @@ -43,7 +45,7 @@ def test_core_file(self): "id": 524290, "line": 16, "name": "_start", - "source": {"name": "main.c", "path": "/home/labath/test/main.c"}, + "source": {"name": "main.c", "path": os.path.join(current_dir, "main.c")}, "instructionPointerReference": "0x40015F", }, ] >From dd8735e1eb7c9582a7f16d45f8106cbfcda2d02f Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 20 Apr 2025 21:04:46 +0200 Subject: [PATCH 3/3] use stop-disassembly-display setting to determine when to show disassembly --- .../lldb-dap/coreFile/TestDAP_coreFile.py | 10 +- .../stackTraceDisassemblyDisplay/Makefile | 3 + .../TestDAP_stackTraceDisassemblyDisplay.py | 195 ++++++++++++++++++ .../stackTraceDisassemblyDisplay/main.c | 10 + lldb/tools/lldb-dap/DAP.h | 4 + .../lldb-dap/Handler/AttachRequestHandler.cpp | 1 + .../lldb-dap/Handler/LaunchRequestHandler.cpp | 1 + .../tools/lldb-dap/Handler/RequestHandler.cpp | 4 + lldb/tools/lldb-dap/Handler/RequestHandler.h | 3 + .../Handler/StackTraceRequestHandler.cpp | 3 +- lldb/tools/lldb-dap/JSONUtils.cpp | 34 ++- lldb/tools/lldb-dap/JSONUtils.h | 21 +- lldb/tools/lldb-dap/LLDBUtils.cpp | 19 ++ lldb/tools/lldb-dap/LLDBUtils.h | 9 + 14 files changed, 300 insertions(+), 17 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py create mode 100644 lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/main.c diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index ce54133a61f3e..1896acea15a99 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -19,9 +19,7 @@ def test_core_file(self): core_file = os.path.join(current_dir, "linux-x86_64.core") self.create_debug_adapter() - - source_map = [["/home/labath/test", current_dir]] - self.attach(exe_file, coreFile=core_file, sourceMap=source_map) + self.attach(exe_file, coreFile=core_file) expected_frames = [ { @@ -29,7 +27,7 @@ def test_core_file(self): "id": 524288, "line": 4, "name": "bar", - "source": {"name": "main.c", "path": os.path.join(current_dir, "main.c")}, + "source": {"name": "main.c", "path": "/home/labath/test/main.c"}, "instructionPointerReference": "0x40011C", }, { @@ -37,7 +35,7 @@ def test_core_file(self): "id": 524289, "line": 10, "name": "foo", - "source": {"name": "main.c", "path": os.path.join(current_dir, "main.c")}, + "source": {"name": "main.c", "path": "/home/labath/test/main.c"}, "instructionPointerReference": "0x400142", }, { @@ -45,7 +43,7 @@ def test_core_file(self): "id": 524290, "line": 16, "name": "_start", - "source": {"name": "main.c", "path": os.path.join(current_dir, "main.c")}, + "source": {"name": "main.c", "path": "/home/labath/test/main.c"}, "instructionPointerReference": "0x40015F", }, ] diff --git a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/Makefile b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/Makefile new file mode 100644 index 0000000000000..118f0aa59ef6f --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c other.c + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py new file mode 100644 index 0000000000000..e56b87b0d52c3 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py @@ -0,0 +1,195 @@ +""" +Test lldb-dap stack trace when some of the source paths are missing +""" + +from lldbsuite.test.decorators import skipIfWindows +from lldbsuite.test.lldbtest import line_number +import lldbdap_testcase +from contextlib import contextmanager +import os + + +OTHER_C_SOURCE_CODE = """ +int fibonacci(int n) { + if (n < 0) return -1; + if (n == 0) return 0; + if (n == 1) return 1; + int a = 0, b = 1, c; + for (int i = 2; i <= n; ++i) { + c = a + b; + a = b; + b = c; + } + + return b; // Break here +} +""" + + +@contextmanager +def delete_file_on_exit(path): + try: + yield path + finally: + if os.path.exists(path): + os.remove(path) + + +class TestDAP_stackTraceMissingSourcePath(lldbdap_testcase.DAPTestCaseBase): + def build_and_run_until_breakpoint(self, stop_disassembly_display: str): + """ + Build the program and run until the breakpoint is hit, and return the stack frames. + """ + other_source_file = "other.c" + with delete_file_on_exit(other_source_file): + with open(other_source_file, "w") as f: + f.write(OTHER_C_SOURCE_CODE) + + breakpoint_line = line_number(other_source_file, "// Break here") + + program = self.getBuildArtifact("a.out") + init_commands = [ + f"settings set stop-disassembly-display {stop_disassembly_display}" + ] + self.build_and_launch(program, initCommands=init_commands) + + breakpoint_ids = self.set_source_breakpoints( + other_source_file, [breakpoint_line] + ) + self.assertEqual( + len(breakpoint_ids), 1, "expect correct number of breakpoints" + ) + + self.continue_to_breakpoints(breakpoint_ids) + + frames = self.get_stackFrames() + self.assertLessEqual(2, len(frames), "expect at least 2 frames") + + self.assertIn( + "path", + frames[0]["source"], + "Expect source path to always be in frame (other.c)", + ) + self.assertIn( + "path", + frames[1]["source"], + "Expect source path in always be in frame (main.c)", + ) + + return frames + + @skipIfWindows + def test_stopDisassemblyDispay_noSource(self): + """ + Test that with with stop-disassembly-display = no-source - frames without source available give assembly code. + """ + frames = self.build_and_run_until_breakpoint("no-source") + + self.assertNotIn( + "other.c", + frames[0]["source"]["path"], + "Expect original source path to not be in unavailable source frame (other.c)", + ) + self.assertIn( + "sourceReference", + frames[0]["source"], + "Expect sourceReference source path in to be in unavailable source frame (other.c)", + ) + + self.assertIn( + "main.c", + frames[1]["source"]["path"], + "Expect original source path to be in source code frame (main.c)", + ) + self.assertNotIn( + "sourceReference", + frames[1]["source"], + "Expect no sourceReference in source code frame (main.c)", + ) + + @skipIfWindows + def test_stopDisassemblyDispay_noDebuginfo(self): + """ + Test that with with stop-disassembly-display = no-debuginfo - all frames give source code even when source not available. + """ + frames = self.build_and_run_until_breakpoint("no-debuginfo") + + self.assertIn( + "other.c", + frames[0]["source"]["path"], + "Expect original source path to be in unavailable source frame (other.c)", + ) + self.assertNotIn( + "sourceReference", + frames[0]["source"], + "Expect sourceReference source path in to be in unavailable source frame (other.c)", + ) + + self.assertIn( + "main.c", + frames[1]["source"]["path"], + "Expect original source path to be in source code frame (main.c)", + ) + self.assertNotIn( + "sourceReference", + frames[1]["source"], + "Expect no sourceReference in source code frame (main.c)", + ) + + @skipIfWindows + def test_stopDisassemblyDispay_never(self): + """ + Test that with with stop-disassembly-display = never - all frames don't give assembly code. + """ + frames = self.build_and_run_until_breakpoint("never") + + self.assertIn( + "other.c", + frames[0]["source"]["path"], + "Expect original source path to be in unavailable source frame (other.c)", + ) + self.assertNotIn( + "sourceReference", + frames[0]["source"], + "Expect sourceReference source path in to be in unavailable source frame (other.c)", + ) + + self.assertIn( + "main.c", + frames[1]["source"]["path"], + "Expect original source path to be in source code frame (main.c)", + ) + self.assertNotIn( + "sourceReference", + frames[1]["source"], + "Expect no sourceReference in source code frame (main.c)", + ) + + @skipIfWindows + def test_stopDisassemblyDispay_always(self): + """ + Test that with with stop-disassembly-display = always - all frames give source code. + """ + frames = self.build_and_run_until_breakpoint("always") + + self.assertNotIn( + "other.c", + frames[0]["source"]["path"], + "Expect original source path to not be in unavailable source frame (other.c)", + ) + self.assertIn( + "sourceReference", + frames[0]["source"], + "Expect sourceReference source path in to be in unavailable source frame (other.c)", + ) + + self.assertNotIn( + "main.c", + frames[1]["source"]["path"], + "Expect original source path to not be in source code frame (main.c)", + ) + self.assertIn( + "sourceReference", + frames[1]["source"], + "Expect sourceReference in source code frame (main.c)", + ) diff --git a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/main.c b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/main.c new file mode 100644 index 0000000000000..760f60092d5c8 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/main.c @@ -0,0 +1,10 @@ +#include <stdint.h> +#include <stdio.h> + +int fibonacci(int n); + +int main(int argc, char const *argv[]) { + int result = fibonacci(10); + printf("Fibonacci of 10 is: %d\n", result); + return 0; +} diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index b79a0d9d0f25c..91ae6e341aa1c 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -202,6 +202,10 @@ struct DAP { lldb::SBFormat frame_format; lldb::SBFormat thread_format; + + /// The value of stop-disassembly-display setting in LLDB. + std::string stop_disassembly_display; + // This is used to allow request_evaluate to handle empty expressions // (ie the user pressed 'return' and expects the previous expression to // repeat). If the previous expression was a command, this string will be diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 5e622f3d3dcd4..ce7444304a97d 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -108,6 +108,7 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const { } SetSourceMapFromArguments(*arguments); + SetStopDisassemblyDisplayFromSettings(); lldb::SBError status; dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status)); diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 5f14cb074e37e..7b66b9b08ee55 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -95,6 +95,7 @@ void LaunchRequestHandler::operator()(const llvm::json::Object &request) const { } SetSourceMapFromArguments(*arguments); + SetStopDisassemblyDisplayFromSettings(); lldb::SBError status; dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status)); diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 3520dc2c71a55..a4e120f914b14 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -98,6 +98,10 @@ void BaseRequestHandler::SetSourceMapFromArguments( } } +void BaseRequestHandler::SetStopDisassemblyDisplayFromSettings() const { + dap.stop_disassembly_display = GetStopDisassemblyDisplay(dap.debugger); +} + static llvm::Error RunInTerminal(DAP &dap, const llvm::json::Object &launch_request, const uint64_t timeout_seconds) { diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 7e56c258ad78a..4a52a946336b5 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -63,6 +63,9 @@ class BaseRequestHandler { /// argument (or neither), from which we need to set the target.source-map. void SetSourceMapFromArguments(const llvm::json::Object &arguments) const; + /// Sets the stop-disassembly-display setting + void SetStopDisassemblyDisplayFromSettings() const; + /// Prints a welcome message on the editor if the preprocessor variable /// LLDB_DAP_WELCOME_MESSAGE is defined. void PrintWelcomeMessage() const; diff --git a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp index a58e3325af100..acf16dbcd5a2f 100644 --- a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp @@ -67,7 +67,8 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread, break; } - stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format)); + stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format, + dap.stop_disassembly_display)); } if (dap.configuration.displayExtendedBacktrace && reached_end_of_stack) { diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 1a44df7740639..d3e0f2a050a36 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -658,6 +658,28 @@ llvm::json::Value CreateSource(llvm::StringRef source_path) { return llvm::json::Value(std::move(source)); } +bool ShouldDisplayAssemblySource(const lldb::SBLineEntry &line_entry, + const std::string &stop_disassembly_display) { + if (stop_disassembly_display == "never") + return false; + + if (stop_disassembly_display == "always") + return true; + + // A line entry of 0 indicates the line is compiler generated i.e. no source + // file is associated with the frame. + auto file_spec = line_entry.GetFileSpec(); + if (!file_spec.IsValid() || line_entry.GetLine() == 0 || + line_entry.GetLine() == LLDB_INVALID_LINE_NUMBER) + return true; + + if (stop_disassembly_display == "no-source" && !file_spec.Exists()) { + return true; + } + + return false; +} + // "StackFrame": { // "type": "object", // "description": "A Stackframe contains the source location.", @@ -719,8 +741,9 @@ llvm::json::Value CreateSource(llvm::StringRef source_path) { // }, // "required": [ "id", "name", "line", "column" ] // } -llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, - lldb::SBFormat &format) { +llvm::json::Value +CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, + const std::string &stop_disassembly_display) { llvm::json::Object object; int64_t frame_id = MakeDAPFrameID(frame); object.try_emplace("id", frame_id); @@ -750,12 +773,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, EmplaceSafeString(object, "name", frame_name); auto line_entry = frame.GetLineEntry(); - auto file_spec = line_entry.GetFileSpec(); - // A line entry of 0 indicates the line is compiler generated i.e. no source - // file is associated with the frame. - if (file_spec.IsValid() && file_spec.Exists() && - (line_entry.GetLine() != 0 || - line_entry.GetLine() != LLDB_INVALID_LINE_NUMBER)) { + if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) { object.try_emplace("source", CreateSource(line_entry)); object.try_emplace("line", line_entry.GetLine()); auto column = line_entry.GetColumn(); diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index b8c53353bf42d..7186f222b04e8 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -345,6 +345,20 @@ llvm::json::Value CreateSource(const lldb::SBLineEntry &line_entry); /// definition outlined by Microsoft. llvm::json::Value CreateSource(llvm::StringRef source_path); +/// Return true if the given line entry should be displayed as assembly. +/// +/// \param[in] line_entry +/// The LLDB line entry to check. +/// +/// \param[in] stop_disassembly_display +/// The value of the "stop-disassembly-display" setting. +/// +/// \return +/// True if the line entry should be displayed as assembly, false +/// otherwise. +bool ShouldDisplayAssemblySource(const lldb::SBLineEntry &line_entry, + const std::string &stop_disassembly_display); + /// Create a "StackFrame" object for a LLDB frame object. /// /// This function will fill in the following keys in the returned @@ -363,11 +377,14 @@ llvm::json::Value CreateSource(llvm::StringRef source_path); /// The LLDB format to use when populating out the "StackFrame" /// object. /// +/// \param[in] stop_disassembly_display +/// The value of the "stop-disassembly-display" setting. +/// /// \return /// A "StackFrame" JSON object with that follows the formal JSON /// definition outlined by Microsoft. -llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, - lldb::SBFormat &format); +llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format, + const std::string &stop_disassembly_display); /// Create a "StackFrame" label object for a LLDB thread. /// diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index a27beff0b030d..7dd7d41d96a6a 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -163,6 +163,25 @@ GetEnvironmentFromArguments(const llvm::json::Object &arguments) { return envs; } +std::string GetStopDisassemblyDisplay(lldb::SBDebugger &debugger) { + std::string stop_disassembly_display = "no-debuginfo"; // default value + lldb::SBCommandReturnObject result; + debugger.GetCommandInterpreter().HandleCommand( + "settings show stop-disassembly-display", result); + if (result.Succeeded()) { + std::string output = result.GetOutput(); + size_t pos = output.find("stop-disassembly-display"); + if (pos != std::string::npos) { + size_t start = output.find("= ", pos) + 2; + size_t end = output.find("\n", start); + stop_disassembly_display = + output.substr(start, end - start); // trim whitespace + } + } + + return stop_disassembly_display; +} + llvm::Error ToError(const lldb::SBError &error) { if (error.Success()) return llvm::Error::success(); diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index 2c57847303cb3..1ecb95122da04 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -156,6 +156,15 @@ uint32_t GetLLDBFrameID(uint64_t dap_frame_id); lldb::SBEnvironment GetEnvironmentFromArguments(const llvm::json::Object &arguments); +/// Get the stop-disassembly-display settings +/// +/// \param[in] debugger +/// The debugger that will execute the lldb commands. +/// +/// \return +/// The value of the stop-disassembly-display setting +std::string GetStopDisassemblyDisplay(lldb::SBDebugger &debugger); + /// Take ownership of the stored error. llvm::Error ToError(const lldb::SBError &error); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits