| Issue |
203186
|
| Summary |
[lldb] lldb incorrectly treats DW_OP_reg* register location descriptions as arithmetic operands
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
firmiana402
|
LLDB currently accepts DWARF expressions that use `DW_OP_reg*` as an operand to arithmetic and dereference operations.
That looks non-conforming to DWARF v5. [DWARF v5](https://dwarfstd.org/doc/DWARF5.pdf) describes `DW_OP_regN` /
`DW_OP_regx` as a **register location description**.
The standard text is quite explicit: **a register location description must stand alone as the entire description of an object or a piece of an object**.
DWARF v5 also says:
> These operations (i.e., DW_OP_reg*) name a register location. To fetch the contents of a register, it is necessary to use one of the register-based addressing operations, such as DW_OP_bregx.
So an _expression_ such as:
```text
DW_OP_reg3
DW_OP_constu 16
DW_OP_minus
DW_OP_deref_size 1
DW_OP_stack_value
```
should be rejected.
If the intended meaning is "dereference the address at register 3 minus 16", the DWARF spelling is:
```text
DW_OP_breg3 -16
DW_OP_deref_size 1
DW_OP_stack_value
```
These are not two interchangeable encodings. The first one uses a register location description where DWARF requires a value-producing operation.
This is also hard to justify as a permissive extension, because DWARF already provides `DW_OP_breg*` / `DW_OP_bregx` for the "use the register contents and then apply an offset" case quoted above. Treating `DW_OP_reg*` as if it had that meaning collapses two distinct standard encodings into one implementation path.
## Comparison with GDB
GDB rejects this kind of _expression_ with:
```text
DW_OP_reg operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.
```
LLDB does not reject it. It continues evaluation and produces a concrete result.
That difference matters because GDB's behavior matches the DWARF distinction above: `DW_OP_reg*` is being used in a place where DWARF expects a value-producing operation such as `DW_OP_breg*`.
## Affected DWARF Opcodes
While reviewing [lldb/source/_expression_/DWARFExpression.cpp](https://github.com/llvm/llvm-project/blob/main/lldb/source/_expression_/DWARFExpression.cpp), I noticed that this is not limited to a single opcode handler.
LLDB already treats some opcodes, such as `DW_OP_piece`, as dependent on the current stack/location-description state. For this issue, the relevant precondition is whether the top stack item is still a register location description produced by `DW_OP_regN` / `DW_OP_regx`.
However, many handlers continue evaluation without rejecting that state first. The same missing check appears across at least these opcode families:
- Dereference: `DW_OP_deref`, `DW_OP_deref_size`
- Unary arithmetic/logical: `DW_OP_abs`, `DW_OP_neg`, `DW_OP_not`
- Binary arithmetic/logical: `DW_OP_plus_uconst`, `DW_OP_plus`, `DW_OP_minus`, `DW_OP_mul`, `DW_OP_div`, `DW_OP_mod`, `DW_OP_and`, `DW_OP_or`, `DW_OP_xor`
- Shifts: `DW_OP_shl`, `DW_OP_shr`, `DW_OP_shra`
- Comparisons: `DW_OP_eq`, `DW_OP_ne`, `DW_OP_lt`, `DW_OP_le`, `DW_OP_gt`, `DW_OP_ge`
In other words, once `DW_OP_reg*` has marked the current value as a register location description, these handlers still proceed as if the stack held an ordinary numeric operand.
## Potential Fix Direction
Before executing these stack-consuming operations, LLDB should check whether the current operand state is a register location description and reject it, unless the opcode is one of the standard location-description composition forms that DWARF allows, such as piece-based composition.
That would keep `DW_OP_reg*` in its standard role instead of silently treating it as a generic numeric stack value.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs