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

Reply via email to