| Issue |
209099
|
| Summary |
[lldb] DW_OP_piece 0 does not consume its source location
|
| Labels |
|
| Assignees |
|
| Reporter |
firmiana402
|
LLDB returns success for `DW_OP_piece 0` before consuming its preceding source location. The stale source remains on the _expression_ stack and can later override the actual composite result.
[DWARF v5](https://dwarfstd.org/doc/DWARF5.pdf) Section 2.6.1.2 describes composite locations as a sequence of simple location descriptions followed by composition operations. LLVM's [location-description stack extension](https://llvm.org/docs/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack.html) similarly defines `DW_OP_piece` as an incremental composite-location operation.
DWARF does not explicitly prohibit a zero-sized `DW_OP_piece`. If LLDB accepts it as a piece that contributes no bytes, it must still treat the operation as a composition boundary rather than leave its source live as an ordinary stack entry.
On x86-64, one compact equivalent case is:
```text
DW_OP_reg0
DW_OP_piece 4
```
and:
```text
DW_OP_reg3
DW_OP_piece 0
DW_OP_reg0
DW_OP_piece 4
```
Here `DW_OP_reg0` is RAX and `DW_OP_reg3` is RBX. The first _expression_ describes the first four bytes of RAX. The second _expression_ adds a zero-sized RBX piece before it. That piece contributes no bytes, so the resulting composite location should still describe the same four-byte RAX fragment.
GDB treats the zero-piece form consistently with the base form. In LLDB, the stale RBX source remains on the _expression_ stack and masks the four-byte composite result assembled from RAX.
## Source Evidence
In [`DWARFExpression.cpp`](https://github.com/llvm/llvm-project/blob/main/lldb/source/_expression_/DWARFExpression.cpp), `Evaluate_DW_OP_piece` resets the evaluator's location-description kind and then immediately returns for zero-sized pieces:
```cpp
static llvm::Error Evaluate_DW_OP_piece(EvalContext &eval_ctx,
uint64_t piece_byte_size) {
LocationDescriptionKind piece_locdesc = eval_ctx.loc_desc_kind;
// Reset for the next piece.
eval_ctx.loc_desc_kind = Memory;
if (piece_byte_size == 0)
return llvm::Error::success();
Value curr_piece;
if (eval_ctx.stack.empty()) {
...
} else {
Value curr_piece_source_value(eval_ctx.stack.back());
eval_ctx.stack.pop_back();
UpdateValueTypeFromLocationDescription(eval_ctx, piece_locdesc,
&curr_piece_source_value);
...
}
```
The stack-pop path is below the zero-size early return, so `DW_OP_piece 0` does not consume the current source fragment.
This matters because LLDB returns the composite piece buffer only when the _expression_ stack is empty:
```cpp
if (stack.empty()) {
if (eval_ctx.pieces.GetBuffer().GetByteSize())
return eval_ctx.pieces;
return llvm::createStringError("stack empty after evaluation");
}
UpdateValueTypeFromLocationDescription(eval_ctx, eval_ctx.loc_desc_kind,
&stack.back());
return stack.back();
```
After the final `DW_OP_piece 4` appends the real RAX fragment to `eval_ctx.pieces`, the RBX source left by `DW_OP_piece 0` keeps the stack nonempty. LLDB consequently returns that stale register location instead of returning the completed composite value.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs