Depends on:
* https://github.com/llvm/llvm-project/pull/187229
(only second commit and onwards are relevant)
This patch implements the base infrastructure described in this [RFC re.
Moving libc++ data-formatters out of
LLDB](https://discourse.llvm.org/t/rfc-lldb-moving-libc-data-formatters-out-of-lldb/89591)
The intention is to provide vendors with a way to pre-configure a set of
paths that LLDB can automatically ingest formatter scripts from.
Three main changes:
1. Adds a CMake variable `LLDB_SAFE_AUTO_LOAD_PATHS` which is a
semi-colon separated list of paths. This is intended to be set by
vendors when building LLDB for distribution.
2. Adds a setting that only exists in asserts mode called
`testing.safe-auto-load-paths` which allows setting the paths without a
CMake configuration. Used for local development and, more crucially, the
shell and unit tests
3. Adds a `LocateScriptingResourcesFromSafePaths` which
`Platform::LocateExecutableScriptingResources` calls by default (and
hence used by all platforms). I add a
`LocateExecutableScriptingResourcesImpl` that platforms can override if
they have platform-specific resource script locations (e.g., dSYMs on
Darwin).
Whenever we load an image, we check the safe path (starting with the
last appended path) for a directory called
`/safe/path/to/<module>/<module>.py`. If such script exists, we import
it as a Python module. If not, we move on to the next safe path.
Currently the default for `LLDB_SAFE_AUTO_LOAD_PATHS` is empty.
Eventually the plan is to make those point to the libc++ installation
(where the formatters will live) depending on platform/vendor. For macOS
we'll add a special `$SDK_ROOT` that can be used in the path variable,
which `LocateScriptingResourcesFromSafePaths` will resolve to an actual
SDK path.
*AI Usage*:
* Claude assisted with the CMake machinery which I then reviewed and
cleaned up. I'm not sure this is the most idiomatic way of letting a
user provide lists of paths, but I couldn't find a better way.
* Wrote the basic auto-load Shell tests myself and asked claude to stamp
out a bunch more for different scenarios. Reviewed and cleaned those up
myself.
I'm in the process of making `LoadScriptingResources` interactively ask
a user whether to load a script. I'd like to turn the existing warning
into the prompt. The simplest way to achieve this is to not print into a
`feedback_stream` parameter, and instead create a prompt right there.
This patch removes the `feedback_stream` parameter and emits a
`ReportWarning` instead. If we get around to adding the prompt instead
of the warning, those changes will be simpler to review. But even if we
don't end up replacing the warning with a prompt, moving away from
output parameters and towards more structured error reporting is a
nice-to-have (e.g., the `warning` prefix is now colored, IDEs have more
flexibility on how to present the warning, etc.).
For a command-line user nothing should change with this patch (apart
from `warning:` being highlighted).
In #162162, I added support for OSC 9;4 graphical progress. I put it
behind the `show-progress` setting because I didn't have a reliable way
to detect whether the escape code was supported by the terminal.
Since then, more tools have added support for it, most notably Claude
Code and Homebrew. While I still don't have a good way to detect this,
there are a handful of known terminals that are easy enough to identify.
This PR toggles the default of `show-progress` to on again and puts
showing the progress behind a check for those known terminals (Windows
Terminal, ConEmu & Ghostty).
This means that if you're running in one of those, you'll get the visual
progress by default unless you set `show-progress` to off. The downside
is that if you're on an unrecognized terminal, you can't force it on any
longer by setting `show-progress` to on. I think that's a fair trade-off
as the setting wasn't really advertised and I doubt many people are
using that. As a workaround, they can set `OSC_PROGRESS` to spoof an
OSC-supporting terminal.
The `testing.XXX` settings (added in
https://github.com/llvm/llvm-project/pull/177279 and currently just
`testing.inject-variable-location-error`) are supposed to only exist in
asserts builds. However, we never added it as a global property to the
`Debugger`, so the setting wasn't actually usable, in any build.
The one test that did use it [skipped the test on
error](230e465617/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py (L286-L288))
as a way to mimick "only run test in asserts mode". However, this just
meant the test never ran.
This patch registers the property and adds a test that ensures an
asserts-LLDB does allow access to it from the CLI.
In #184259, Jim noticed that Debugger::FindTargetWithProcess and
Debugger::FindTargetWithProcessID are rather poorly designed APIs as
tehy allow code running in one Debugger to mess with Targets from
another Debugger. The only use is Process::SetProcessExitStatus which
isn't actually used.
Roughly 10 years ago, in aacb80853a46bd544fa76a945667302be1de706c, Greg
deleted the call to delete g_debugger_list_ptr because of a race
condition:
> Fixed a threading race condition where we could crash after calling
Debugger::Terminate().
>
> The issue was we have two global variables: one that contains a
DebuggerList pointer and one that contains a std::mutex > pointer. These
get initialized in Debugger::Initialize(), and everywhere that uses
these does:
>
> if (g_debugger_list_ptr && g_debugger_list_mutex_ptr)
> {
> std::lock_guard<std::recursive_mutex>
guard(*g_debugger_list_mutex_ptr);
> // do work while mutex is locked
> }
>
> Debugger::Terminate() was deleting and nulling out g_debugger_list_ptr
which meant we had a race condition where someone might do the if
statement and it evaluates to true, then another thread calls
Debugger::Terminate() and deletes and nulls out g_debugger_list_ptr
while holding the mutex, and another thread then locks the mutex and
tries to use g_debugger_list_ptr. The fix is to just not delete and null
out the g_debugger_list_ptr variable.
However, this isn't necessary as long as we persist ("leak") the mutex
and always check it first. That's exactly what this patch does. Without
it, the assert in Debugger::Initialize is incorrect.
```
assert(g_debugger_list_ptr == nullptr &&
"Debugger::Initialize called more than once!");
```
This is a reland of https://github.com/llvm/llvm-project/pull/167550.
Instead of relying on libcpp for testing, we emulate our own hidden
frames. This was originally causing tests failures on Windows.
In #168245, I attempted to dump the available settings to Markdown. That
required a full build of LLDB. However, to build the docs, only the swig
wrappers should need to be compiled. The comment was that we should be
able to use the definitions from the TableGen files.
Currently, the property definitions in don't have information about the
path where they will be available. They only contain a `Definition`
which groups properties, so they can be added to
`OptionValueProperties`.
With this PR, I'm adding the path for each property definition. For
example, `symbols.enable-external-lookup` would have `Name =
enable-external-lookup, Path = symbols`. In LLDB itself, we don't need
this path, we only need it for the documentation. To avoid mismatches
between the actual path and the declared one, I added a debug-only check
when a property group is added to a parent
(`OptionValueProperties::AppendProperty`).
The TableGen emitter for the properties now additionally emits
`g_{definition}_properties_def`, which includes both the array of
properties and the expected path. This constant has to be used to
initialize a `OptionValueProperties`.
I couldn't test this for everything (e.g. IntelPT or ProcessKDP), but
the necessary changes are simple: (1) set the `Path` in the TableGen
file, (2) update `initialize` to use `_def`.
Writing testcases for error handling that depends on specific DWARF is
very difficult and the resulting tests tend not to be very portable.
This patch adds a new setting to inject an error into variable
materialization, thus making it possible to write very simple source
code based tests for error handling instead.
This is primarily motivated by the Swift language plugin, but
functionality is generic and should be useful for other languages as
well.
**This patch adds a marker to make hidden frames more explicit.**
---
Hidden frames can be confusing for some users, who see that the indexes
of the frames in a backtrace are not contiguous. This patch aims to
lessen the confusion by adding a delimiter for the first and last non
hidden frame, i.e the boundaries.
IDE's like Xcode and VSCode represent those in the UI by having the
hidden frames either greyed out or collapsed.
It's not possible to do this in the CLI, therefore, this patch makes use
of 2 unicode characters to mark the beginning and end of the hidden
frames range.
This patch depends on:
- https://github.com/llvm/llvm-project/pull/168603
# Examples
In the example below, frame `#2` to `#7` are is hidden, and therefore,
frame `#1` is the first non hidden frame of the range while frame `#8`
is the last non hidden frame:
<img width="488" height="112" alt="Screenshot 2025-11-18 at 18 41 11"
src="https://github.com/user-attachments/assets/a21431da-9729-4cf0-a6bc-024aa306fc45"
/>
If the selected frame is one of the 2 boundary frames, we replace the
delimiter character with the select character (`*`).
<img width="487" height="111" alt="Screenshot 2025-11-18 at 18 41 03"
src="https://github.com/user-attachments/assets/5616fa81-6db6-457d-9d1e-bbe46e710c26"
/>
<img width="488" height="111" alt="Screenshot 2025-11-18 at 18 40 55"
src="https://github.com/user-attachments/assets/93dfa6cf-0956-4718-b31c-f965ec72b56d"
/>
This patch creates a new `FormatEntity::Formatter` class and moves
`FormatEntity::Format` (and related APIs) into it. Most of the
parameters to `Format` are immutable across all recursive calls, so I
made them `const` member variables of `Formatter`. The main changes are
just mechanical renaming of:
```
FormatEntity::Format(...)
```
to
```
FormatEntity::Formatter(...).Format(stream, entry, valobj)
```
and making use of the member variables from inside `Format`.
We can probably make most of the parameters to the `Formatter`
constructor defaulted, but I chose not to in this patch to keep the diff
smaller.
The motivation for this is that I'm planning on adding logic to detect
recursive format entities (which would crash LLDB). That requires some
state, which in my opinion is best kept inside the `Formatter` class
instead of another parameter to `Format`.
The patch should be entirely NFC.
I know this is required for at least one feature, because
TestSectionAPI.py has failures if zlib isn't enabled. So I think it's
useful for users to be able to check.
Now that it's in the config, I have also used it to make a test
annotation so we don't get the failure in TestSectionAPI.py when zlib is
disabled.
Which for future reference was:
Traceback (most recent call last):
File
"/home/davspi01/llvm-project/lldb/packages/Python/lldbsuite/test/decorators.py",
line 452, in wrapper
return func(self, *args, **kwargs)
File
"/home/davspi01/llvm-project/lldb/test/API/python_api/section/TestSectionAPI.py",
line 67, in test_compressed_section_data
self.assertEqual(section_data, [0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
0x80, 0x90])
AssertionError: Lists differ: [] != [32, 48, 64, 80, 96, 112, 128, 144]
As it failed to decode the compressed section.
Add a verbose option to the version command and include the "build
configuration" in the command output. This allows users to quickly
identify if their version of LLDB was built with support for
xml/curl/python/lua etc. This data is already available through the SB
API using SBDebugger::GetBuildConfiguration, but this makes it more
discoverable.
```
(lldb) version -v
lldb version 22.0.0git (git@github.com:llvm/llvm-project.git revision 21a2aac5e5456f9181384406f3b3fcad621a7076)
clang revision 21a2aac5e5456f9181384406f3b3fcad621a7076
llvm revision 21a2aac5e5456f9181384406f3b3fcad621a7076
editline_wchar: yes
lzma: yes
curses: yes
editline: yes
fbsdvmcore: yes
xml: yes
lua: yes
python: yes
targets: [AArch64, AMDGPU, ARM, AVR, BPF, Hexagon, Lanai, LoongArch, Mips, MSP430, NVPTX, PowerPC, RISCV, Sparc, SPIRV, SystemZ, VE, WebAssembly, X86, XCore]
curl: yes
```
Resolves#170727
If we open a `NativeFile` with a `FILE*`, the OpenOptions default to
`eOpenOptionReadOnly`. This is an issue in python scripts if you try to
write to one of the files like `print("Hi",
file=lldb.debugger.GetOutputFileHandle())`.
To address this, we need to specify the access mode whenever we create a
`NativeFile` from a `FILE*`. I also added an assert on the `NativeFile`
that validates the file is opened with the correct access mode and
updated `NativeFile::Read` and `NativeFile::Write` to check the access
mode.
Before these changes:
```
$ lldb -b -O 'script lldb.debugger.GetOutputFileHandle().write("abc")'
(lldb) script lldb.debugger.GetOutputFileHandle().write("abc")
Traceback (most recent call last):
File "<input>", line 1, in <module>
io.UnsupportedOperation: not writable
```
After:
```
$ lldb -b -O 'script lldb.debugger.GetOutputFileHandle().write("abc")'
(lldb) script lldb.debugger.GetOutputFileHandle().write("abc")
abc3
```
Fixes#122387
This PR adds support for emitting the OSC `9;4` sequences to show a GUI
native progress bar.
There's a limited number of terminal emulators that support this, so for
now this requires explicit opt-in through a setting. I'm reusing the
existing `show-progress` setting, which became a NOOP with the
introduction of the statusline. The option now defaults to off.
Implements #160369
Currently, we always pass the "selected" execution context to the
statusline. When handling a process or thread event, we can be more
precise, and build an execution context from the event data. This PR
also adopts the new `StoppedExecutionContext` that was recently
introduced.
This PR ensures we correctly restore the cursor column after resizing
the statusline. To ensure we have space for the statusline, we have to
emit a newline to move up everything on screen. The newline causes the
cursor to move to the start of the next line, which needs to be undone.
Normally, we would use escape codes to save & restore the cursor
position, but that doesn't work here, as the cursor position may have
(purposely) changed. Instead, we move the cursor up one line using an
escape code, but we weren't restoring the column.
Interestingly, Editline was able to recover from this issue through the
LineInfo struct which contains the buffer and the cursor location, which
allows us to compute the column. This PR addresses the bug by having
Editline "refresh" the cursor position.
Fixes#134064
Rather than having one MCP server per debugger, make the MCP server
global and pass a debugger id along with tool invocations that require
one. This PR also adds a second tool to list the available debuggers
with their targets so the model can decide which debugger instance to
use.
This PR adds an MCP (Model Context Protocol ) server to LLDB. For
motivation and background, please refer to the corresponding RFC:
https://discourse.llvm.org/t/rfc-adding-mcp-support-to-lldb/86798
I implemented this as a new kind of plugin. The idea is that we could
support multiple protocol servers (e.g. if we want to support DAP from
within LLDB). This also introduces a corresponding top-level command
(`protocol-server`) with two subcommands to `start` and `stop` the
server.
```
(lldb) protocol-server start MCP tcp://localhost:1234
MCP server started with connection listeners: connection://[::1]:1234, connection://[127.0.0.1]:1234
```
The MCP sever supports one tool (`lldb_command`) which executes a
command, but can easily be extended with more commands.
This fixes a data race between the main thread and the default event
handler thread. The statusline format option value was protected by a
mutex, but it was returned as a pointer, allowing one thread to access
it while another was modifying it.
Avoid the data race by returning format values by value instead of by
pointer.
Something to do with control code handling in Windows terminals breaks
the statusline in various ways. It makes LLDB unusable and even if you
set the setting to disable statusline, it's too late, and the terminal
session is now in a weird state.
See https://github.com/llvm/llvm-project/issues/134846 for more details.
Until we figure this out, don't allow it to be used on Windows.
This patch is slightly different from other impl in that we dispatch
client-telemetry via a different helper method. This is to make it
easier for vendor to opt-out (simply by overriding the method to do
nothing). There is also a configuration option to disallow collecting
client telemetry.
---------
Co-authored-by: Pavel Labath <pavel@labath.sk>
Show assembly code when the source code for a frame is not available in
the debugger machine
Edit: this functionality will work only when using
`stop-disassembly-display = no-source` in the settings
Fix#136492
After the fix:
[Screencast From 2025-04-20
18-00-30.webm](https://github.com/user-attachments/assets/1ce41715-cf4f-42a1-8f5c-6196b9d685dc)
And use this functionality to replace the ASCII "|" with the same
full-geight line-drawing character used in diagnostics rendering on a
color terminal.
Fixes https://github.com/llvm/llvm-project/issues/22981
If `settings set use-color` is changed when lldb is running it does not take effect.
This is fixes that.
---------
Signed-off-by: Ebuka Ezike <yerimyah1@gmail.com>
Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
Eliminate the potential for a race between the main thread, the default
event handler thread and the signal handling thread, when accessing the
m_statusline member.
Include the LLDB version in the lldbassert error message, and prompt
users to include it in the bug report. The majority of users that bother
filing a bug report just copy past the stack trace and often forget to
include this important detail. By putting it after the backtrace and
before the prompt, I'm hoping it'll get copy-pasted in.
rdar://146793016
In the original SBProgress patch, #123837, I didn't ensure the debugger
was broadcasting these events to the CLI as SBProgress has far been
focused on DAP. We had an internal ask to have SBProgress events
broadcasted to the CLI so this patch addresses that.
<img width="387" alt="image"
src="https://github.com/user-attachments/assets/5eb93a46-1db6-4d46-a6b7-2b2f9bbe71db"
/>
There's no need to call RedrawStatusline from HandleProgressEvent. The
statusline gets redraw after handling all events, including progress
events, in the default event handler loop.
Add a statusline to command-line LLDB to display information about the
current state of the debugger. The statusline is a dedicated area
displayed at the bottom of the screen. The information displayed is
configurable through a setting consisting of LLDB’s format strings.
Enablement
----------
The statusline is enabled by default, but can be disabled with the
following setting:
```
(lldb) settings set show-statusline false
```
Configuration
-------------
The statusline is configurable through the `statusline-format` setting.
The default configuration shows the target name, the current file, the
stop reason and any ongoing progress events.
```
(lldb) settings show statusline-format
statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}"
```
The statusline supersedes the current progress reporting implementation.
Consequently, the following settings no longer have any effect (but
continue to exist to not break anyone's `.lldbinit`):
```
show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.
show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message.
show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.
```
Format Strings
--------------
LLDB's format strings are documented in the LLDB documentation and on
the website: https://lldb.llvm.org/use/formatting.html#format-strings.
The current implementation is relatively limited but various
improvements have been discussed in the RFC.
One such improvement is being to display a string when a format string
is empty. Right now, when launching LLDB without a target, the
statusline will be empty, which is expected, but looks rather odd.
RFC
---
The full RFC can be found on Discourse:
https://discourse.llvm.org/t/rfc-lldb-statusline/83948
Remove support for coalescing progress reports in LLDB. This
functionality was motivated by Xcode, which wanted to listen for less
frequent, aggregated progress events at the cost of losing some detail.
See the original RFC [1] for more details. Since then, they've
reevaluated this trade-off and opted to listen for the regular, full
fidelity progress events and do any post processing on their end.
rdar://146425487
This type of entry is used to collect data about the debugger
startup/exit
Also introduced a helper ScopedDispatcher
---------
Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
Co-authored-by: Pavel Labath <pavel@labath.sk>
Make StreamAsynchronousIO an unique_ptr instead of a shared_ptr. I tried
passing the class by value, but the llvm::raw_ostream forwarder stored
in the Stream parent class isn't movable and I don't think it's worth
changing that. Additionally, there's a few places that expect a
StreamSP, which are easily created from a StreamUP.
This patch improves the synchronization of the debugger's output and error
streams using two new abstractions: `LockableStreamFile` and
`LockedStreamFile`.
- `LockableStreamFile` is a wrapper around a `StreamFile` and a mutex. Client
cannot use the `StreamFile` without calling `Lock`, which returns a
`LockedStreamFile`.
- `LockedStreamFile` is an RAII object that locks the stream for the duration
of its existence. As long as you hold on to the returned object you are
permitted to write to the stream. The destruction of the object
automatically flush the output stream.
A handful of minor improvements to StreamAsynchronousIO:
- Document the class.
- Use a named enum value to distinguishing between stdout and stderr.
- Add missing period to comment.
- Clear the string instead of assigning to it.
- Eliminate color argument.
This makes GetOutputStreamSP and GetErrorStreamSP protected members of
Debugger. Users who want to print to the debugger's stream should use
GetAsyncOutputStreamSP and GetAsyncErrorStreamSP instead and the few
remaining stragglers have been migrated.
Remove Debugger::GetOutputStream and Debugger::GetErrorStream in
preparation for replacing both with a new variant that needs to be
locked and hence can't be handed out like we do right now.
The patch replaces most uses with GetAsyncOutputStream and
GetAsyncErrorStream respectively. There methods return new StreamSP
objects that automatically get flushed on destruction.
See #126630 for more details.
Recently I've been working on a lot of internal Python tooling, and in
certain cases I want to report async to the script over DAP. Progress.h
already handles this, so I've exposed Progress via the SB API so Python
scripts can also update progress objects.
I actually have no idea how to test this, so I just wrote a [toy command
to test
it](https://gist.github.com/Jlalond/48d85e75a91f7a137e3142e6a13d0947)

I also copied the first section of the extensive Progress.h class
documentation to the docstrings.
Currently, we arbitrarily paginate editline completions to 40 elements.
On large terminals, that leaves some real-estate unused. On small
terminals, it's pretty annoying to not see the first completions. We can
address both issues by using the terminal height for pagination.
This builds on the improvements of #116456.
Summary of Changes:
Replaced the ineffective call to `substr` with a more efficient use of
`resize` to truncate the string.
Adjusted the code to use 'resize' instead of 'substr' for better
performance and readability.
Removed unwanted file from the previous commit.
Fixes: #91209
---------
Co-authored-by: aabhinavg <tiwariabhinavak@gmail.com>