While looking at the '[raw]' value of a std::vector I noticed we didn't
handle the anonymous inner struct very well. The 'evaluateName' was
incorrect (e.g. the evaluateName would return `<var>.` for the anonymous
struct).
This improves support for variables with anonymous fields and anonymous
types.
* Changed the name of anonymous fields from `<null>` to `(anonymous)`,
which matches other tooling like clangd's representation and how types
are presented if the field is not defined.
* Adjusts variables to not return an 'evaluateName' for anonymous
fields.
* Adjusted '[raw]' values to be marked as 'internal' which deemphasizes
them in the UI.
While working in this area, I also consolidated some helpers that are
only used within Variables.cpp.
Before my changes:
<img width="513" height="460" alt="before"
src="https://github.com/user-attachments/assets/3da0aada-8ba3-415d-bbec-56b41a9b9415"
/>
After my changes:
<img width="414" height="467" alt="after"
src="https://github.com/user-attachments/assets/66a47108-ee44-4e01-8eab-e89edb348fde"
/>
This paths allows expressions in `setVariable` request. It is small
extension of original semantics from DAP specification. DAP has
`setExpression` request to this purpose, but it is too general. So I
prefer to keep this simple solution.
In PR#183176 there was a regression mixing up `GetSyntheticValue` and
`GetNonSyntheticValue` that results in `[raw]` variables not correctly
representing the underlying value.
Addressing this regression and adjusting the naming of a few helpers to
better match existing naming styles in lldb.
Adjusting `VariableReferenceStorage` to only need to track permanent vs
temporary storage by making `VariableStore` the common base class.
Moved the subclasses of `VariableStore` into the Variables.cpp file,
since they're no long referenced externally.
Expanding on the tests by adding an updated core dump with variables in
the argument scope we can use to validate variable storage.
Update the test to more cleanly handle making a 'blocking' call using a
custom command instead of python `time.sleep`, which we cannot easily
interrupt.
This should improve the overall performance of the tests, locally they
took around 30s and now finish in around 6s.
The method claims to check if a is a subset of b, but the implementation
`a | b ==a` actually checks if b is a subset of a. This patch updated
the docstring.
This patch fixes cross platform Makefile.rules macros and adds the
`ECHO_TO_EXISTING_FILE` macros.
Using `echo` in a macro to write to a file had quoting issues.
This changes Python API tests to use a single build shared across all
test functions, instead of the previous default behavior of a separate
build dir for each test function.
This build behavior opt-out, tests can use the previous behavior of one
individual (unshared) build directory per test function, by setting
`SHARED_BUILD_TESTCASE` to False (in the test class).
The motivation is to make the test suite more efficient, by not
repeatedly building the same test source. When running tests on my macOS
machine, this reduces the time of `ninja check-lldb-api` by almost 60%
(sample numbers: from ~492s down to ~207s = 58%). Almost 5min time
saved.
Each test function still calls `self.build()`, but only the first call
will do a build, in the subsequent tests `make` will be a no-op because
the sources won't have changed.
I ran into this while debugging a different issue, but when we calcualte
the 'value' field of a variable we were not ensuring the contents were
valid utf8. If assertions are enabled then llvm::json::Value will assert
that the string contains invalid utf8.
To address this I added a wrapper type (`lldb_dap::protocol::String`)
that can be used as a thin wrapper around `std::string` to ensure a
field contains valid utf8. This is now used throughout the
`lldb_dap::protocol::*` types.
This commit refactors the Variables class into a
VariableReferenceStorage with variableReferences of different
ReferenceKinds.
The variablesReference is now a uint32_t.
The most significant byte (bits 24 - 31) holds the reference kind and
the remaining 3 bytes (bits 0 -23) holds the actual reference.
We have (at the moment) 3 reference kinds.
Temporary => 0b0000 => 0x00
Permanent => 0b0001 => 0x01
Scope => 0b0010 => 0x03
The actual variablesReference can be used to get a `VariableStore`.
VariableStore holds variables in a group.
It has two implementations:
- ScopeStore: Holds variables within frame scopes (locals, globals,
registers). This is lazy-loaded and only fetched when variable(s) in the
scope is requested.
- ExpandableValueStore: Holds SBValue and fetches it's variable children
when requested.
ReferenceKindPool:
The variablesReference created starts from 1 with the mask of the
Reference kind applied.
It holds vector of VariableStore of one Referencekind,
This allows constant lookup of a reference
Example:
```md
| maskedVariablesReference | Mask | variablesReference | RefrenceKind | VariableStore |
|--------------------------|------|--------------------|--------------|---------------|
| 20 -> 0x00000014 | 0x00 | 20 -> 0x00000014 | temporary | ValueStore |
| 268435476 -> 0x01000014 | 0x01 | 20 -> 0x00000014 | permanent | ValueStore |
| 536870932 -> 0x01000014 | 0x02 | 20 -> 0x00000014 | scope | ScopeStore |
```
Adding more supported operators to DIL breaks tests in `DWIMPrint` and
`lldb-dap`, which shouldn't be simply adjusted for new DIL capabilities.
They act as a check for the boundaries of what subset of expressions
`DWIMPrint` and `lldb-dap` expect to be evaluated when using
`GetValueForVariableExpressionPath` function. With this patch, the
caller can now pick a mode that limits the expressions DIL can evaluate,
which ensures the expected preexisting behavior. More operators can now
be safely added to DIL, which can still be evaluated by DIL when using
`frame var` command or the API call with Full mode selected (or not
specified at all).
DIL will only attempt evaluating expressions that contain operations
allowed by a selected mode:
- Simple: identifiers, operators: '.'
- Legacy: identifiers, integers, operators: '.', '->', '*', '&', '[]'
- Full: everything supported by DIL
Previously the test was written in a way that may be flaky, fixed with
the following changes.
- The breakpoint are placed on functions and set during the
configuration stage of the protocol.
- Add the rpath to the test binary.
- Check we also hit the breakpoint we set directly using lldb.
Improving stability of the TestDAP_launch_commands test.
When collecting output for verifying 'stopCommands' we were not waiting
for the output to finish, which could cause issues if the test is
running very fast.
EvaluateRequests handler now uses the target's context if no valid
frameId is provided, enabling evaluation of
global variables without requiring a valid stack frame.
In repl mode it now uses the last `successful` variable or command
expression, if the provided user's expression is empty.
Try to evaluate the expression if the evaluation context is `Unknown`
We are waiting for both stopped event at once.
We may not get both events within the (0.25 seconds) time interval to
fetch more events. Retry with the `DEFAULT TIMEOUT` if we got one of the
event.
Increase the `EVENT_QUIET_PERIOD`'s value for ASAN mode
Fixes#179648
Updates the 'stopped' event to use structure types.
Additionally, I adjusted the description to include the full
`GetStopDescription` that can have more details.
Closes#119784
Probably closes#147105 as well, but I couldn't test due to #156473:
This PR fixes two bugs:
1. It generates unique variable reference IDs per suspended debuggee
state.
2. It stores all created variables in a stopped state instead of
dropping variables in unselected scopes. So it can properly handle all
scope/variable requests
It does this by storing all variables in their respective scopes and
using that mapping in request handlers that relied on the old mapping.
It dynamically creates new variable/scope IDs instead of resetting IDs
whenever a new scope is created.
I also removed some unused code as well.
---------
Co-authored-by: Med Ismail Bennani <ismail@bennani.ma>
Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
Co-authored-by: Ebuka Ezike <yerimyah1@gmail.com>
non-darwin platforms may have incorrect stop information location
heuristics. Enable assertion once UBSan stopInfo heuristic is updated.
I hit this locally, I don't see it hitting any CI bot but should, Mostly
likely the CI linux bots may not have `compiler_rt` run time enabled.
see
https://github.com/llvm/llvm-project/pull/177964#discussion_r2732271531
In the exceptionInfo request I've added additional information for crash
data, instrumentation data and more detailed exception data.
For example, when UBSan is enabled, you now see additional information
in the exception stack trace about the detected issue:
<img width="1728" height="538" alt="Screenshot 2026-01-15 at 3 05 08 PM"
src="https://github.com/user-attachments/assets/b761af2c-90ac-4eb7-9926-3ab133f1b753"
/>
I included a new test for stopping at `lldb::eStopReasonInstrumentation`
and ensuring we have additional information reported.
---------
Co-authored-by: Ebuka Ezike <yerimyah1@gmail.com>
Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
Investigating some of the biggest slow downs during tests, the biggest
offender is 'wait_for_stopped' requiring a negative assertion around the
'stopped' event.
It currently waits for a negative predicate to fail before continuing.
This means it must wait for the full DEFAULT_TIMEOUT (50s) before the
test is allowed to continue.
To mitigate this, I added a new `collect_events` helper that will wait
for the given event to occur with the DEFAULT_TIMEOUT, then wait for a
quiet period (0.25s) before returning.
This greatly reduces the amount of idle waiting during tests.
Additionally, looking a the performance of individual test files,
`TestDAP_launch` is the slowest overall test. No individual test is that
slow, but the fact it has so many tests in the same file results in the
test harness waiting for that one file to finish.
To mitigate that, I split `TestDAP_launch` into individual test files
that run in parallel, reducing the runtime locally from over 2mins to
~5s.
# Summary
This patch ensures lldb will not try to read from a PseudoConsole if it
has not been opened.
# Original issue
https://github.com/llvm/llvm-project/pull/168729 introduces support for
the Windows ConPTY in `lldb-dap`. This caused a regression in `lldb`
which was not caught by our tests:
https://github.com/llvm/llvm-project/issues/175652.
This patch fixes https://github.com/llvm/llvm-project/issues/175652.
`lldb_private::ProcessLauncherWindows::LaunchProcess` connects the
debuggee to a PseudoConsole only if:
```cpp
if (hPC != INVALID_HANDLE_VALUE && launch_info.GetNumFileActions() == 0 && launch_info.GetFlags().Test(lldb::eLaunchFlagLaunchInTTY))
```
lldb needs to check the same condition in
`lldb_private::PlatformWindows::DebugProcess` to ensure that it does not
read from a PseudoConsole which has not been opened.
# Side effect
This patch reverts what https://github.com/llvm/llvm-project/pull/168729
did by adding ConPTY support.
https://github.com/llvm/llvm-project/pull/175812 is the proper fix,
however it's causing tests failures which we can't reliably reproduce at
desk. Given https://github.com/llvm/llvm-project/pull/168729 breaks
`22.x` lldb, it's better to revert the change ahead of the release of
`22.x` rather than pushing for the proper fix.
"memory region" can be given an address once and then when repeated,
it will try to find a region just beyond the last one it printed.
This continues until the end of the address space.
Then it gives you an error showing the usage, which is odd because
you just saw a bunch of "memory region" with no options work.
So I've improved the error a bit to imply its to do with the repetition.
Then described the repeating behaviour in the help text.
Previously, completion behavior was inconsistent,
sometimes including the partial token or removing existing user text.
Since LLDB completions includes the partial token by default, we now
strip it before sending to the client.
The completion heuristic:
1. Strip the commandEscapePrefix
2. Request completions from the debugger
3. Get the line at cursor position
4. Calculate the length of any partial token
5. Offset each completion by the partial token length
In all cases, the completion starts from the cursor position. then
offsets by `Length` to the left and inserts the completion.
Examples (single quotes show whitespace and are not part of the input):
```md
| Input | Partial Token | Length | Completion |
|------------|---------------|--------|---------------|
| m | m | 1 | memory |
| `m | m | 1 | memory |
| myfoo. | myfoo. | 6 | myfoo.method( |
| myfoo.fi | myfoo.fi | 7 | myfoo.field |
| myfoo. b | b | 1 | myfoo. bar |
| 'memory ' | | 0 | memory read |
| memory | memory | 6 | memory |
| settings s | s | 1 | settings show |
```
Fixes#176424
Two out of three TestDAP_launch_io.py's test's classes have been failing
on ASAN builds ever since it was added into the repo. The ASAN failure
is not easy to debug, so skip these tests until we fix it.
lldb-dap currently crashes when the first character is non ascii. This
is because we assume that the request column is ascii based instead of
UTF16 code units,
and end up in the middle of a character code point. causing an assertion
since we cannot not send invalid UTF-8 values.
This also handles the case in multilines and the column is outside the
range of the text.
Move completion description to the `CompletionItem.detail` property.
This makes it clear the fields required for attaching to an existing
debug session.
It also makes it easier to check mutually exclusive fields required to
attach.
There are some bugs when launching in terminal with args and stdio
redirection.
- lldb-dap `--stdio` args is passed to the debuggee (should we change
this to use `--` to separate debuggee args from lldb-dap args, similar
to how we handle the `--client` args? ).
#### It also changes the behaviour of stdio redirection.
If a redirection is not specified, it uses to lldb default value. e.g.
```jsonc
"stdio": ["./stdin"]`
// now becomes
"stdio", ["./stdio", "./default_stdout", "./default_stderr"]
// instead of
"stdio", ["./stdin", "./stdin", "./stdin"]
// took quite some time to figure out where my output is going to.
```
Fixes [#174445](https://github.com/llvm/llvm-project/issues/174445)
Other bug I noticed but should be in a different PR.
- debuggee args that contains newline are not properly escaped when sent
to the terminal.
This patch introduces support for `clipboard` context from
[DAP](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Capabilities).
This feature is very useful when you want to copy all nested values from
a structure or a container instead of a summary (e.g. `size = 3` for
vector). I added new short mode for description generation to reduce
output verbosity, which is particularly useful for primitive types.
This patch fixes the indentation of 2 docstrings in
`TestDAP_runInTerminal.py`.
Running `black` on that file with the default settings causes this
change. `darker` does not seem to catch it.
This is a prelude to https://github.com/llvm/llvm-project/pull/174635.