[lldb] DW_OP_drop leaves stale location state after dropping register or implicit entries
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
LLDB removes the top stack entry for `DW_OP_drop`, but leaves the evaluator-wide location-description state set by that entry instead of restoring the state for the new stack top, or clearing it when the stack becomes empty.
`EvalContext` stores all stack entries in `stack`, but stores only one evaluator-wide `loc_desc_kind`. `DW_OP_reg*` sets this field to `Register`, and `DW_OP_implicit_value` sets it to `Implicit`. However, [`DW_OP_drop`](https://github.com/llvm/llvm-project/blob/main/lldb/source/Expression/DWARFExpression.cpp) only removes the value:
```cpp
case DW_OP_drop:
...
stack.pop_back();
break;
```
LLVM's [location-description stack extension](https://llvm.org/docs/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack.html#a-2-5-4) defines `DW_OP_drop` as discarding the top stack entry. The location state belonging to that entry must therefore stop affecting evaluation, but LLDB leaves it active and applies it to later entries.
## Examples
Let `A` be a valid target-memory address. The first example is:
```text
DW_OP_reg0
DW_OP_drop
DW_OP_addr A
DW_OP_deref_size 2
```
The second example reaches the same problem through an implicit location:
```text
DW_OP_implicit_value 1, [0x00]
DW_OP_drop
DW_OP_addr A
DW_OP_deref_size 2
```
In both expressions, the first two operations are semantically dead. Each expression must therefore behave like:
```text
DW_OP_addr A
DW_OP_deref_size 2
```
However, `DW_OP_addr` pushes a `FileAddress` without changing `loc_desc_kind`. The stale `Register` or `Implicit` state therefore reaches `Evaluate_DW_OP_deref`, which takes this early branch:
```cpp
if (eval_ctx.loc_desc_kind == Register ||
eval_ctx.loc_desc_kind == Implicit) {
eval_ctx.loc_desc_kind = Memory;
...
scalar.TruncOrExtendTo(size * 8, /*sign=*/false);
...
return llvm::Error::success();
}
```
Consequently, LLDB truncates the scalar representation of `A` and returns instead of following the normal `FileAddress` path that reads `size` bytes from target memory. This explains why either dead prefix changes the evaluation.
`DW_OP_deref_size` is not the only affected operation. For example, `Evaluate_DW_OP_piece` also captures the same evaluator-wide state and uses it to interpret the current piece source:
```cpp
LocationDescriptionKind piece_locdesc = eval_ctx.loc_desc_kind;
...
UpdateValueTypeFromLocationDescription(eval_ctx, piece_locdesc,
&curr_piece_source_value);
```
Contributor guide
Research direction
Start in lldb/source/Expression/DWARFExpression.cpp at the DW_OP_drop handling, then trace Evaluate_DW_OP_deref and Evaluate_DW_OP_piece to understand how loc_desc_kind is consumed. Add regression coverage for the register and implicit-value prefixes shown in the issue, and verify they behave like the equivalent expression without the dropped entries.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100