llvm / llvm/llvm-project

[lldb] DW_OP_entry_value fails when a call site is nested in an inline instance

Open
#219,198 1 comment 0 reactions 0 assignees View on GitHub
lldb
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

GCC can emit a `DW_TAG_call_site` as a child of the `DW_TAG_inlined_subroutine` that contains the call. LLDB fails to use that call-site information when evaluating a callee parameter described by `DW_OP_entry_value`.

For example, GCC 15.1 with `-O1 -g` emits the following shape for the attached reproducer:

```text
DW_TAG_subprogram "caller"
DW_AT_call_all_calls (true)
DW_TAG_inlined_subroutine "middle"
DW_TAG_call_site
DW_AT_call_return_pc (...)
DW_AT_call_origin ("callee")
DW_TAG_call_site_parameter
```

After the callee's entry register has been overwritten, LLDB reports:

```text
(uint8_t) value =
```

`DW_OP_entry_value` evaluation correctly skips the inline frame and looks for the edge in the first non-inline parent function. However, `SymbolFileDWARF::CollectCallEdges` only scans direct children of the concrete subprogram DIE, so it never records the call site nested in the inline instance. The function still contains a TODO noting that a recursive scan is required for DWARF v5 compliance.

LLDB should collect call sites from nested inline and lexical scopes owned by the concrete function, so the entry value can be recovered.

Minimal reproducer:

```c
#include

uint32_t state;
uint32_t table[256];

__attribute__((noinline)) static void callee(uint8_t value) {
state = (state >> 8) ^ table[(state ^ value) & 0xff];
state++;
}

__attribute__((always_inline)) static inline void middle(uint64_t value) {
callee(value >> 24);
}

__attribute__((noinline)) static void caller(uint64_t value) { middle(value); }

int main(void) {
caller(UINT64_C(0xff000000));
return 0;
}
```

Build with:

```shell
gcc -O1 -g -fno-pie -no-pie reproducer.c -o reproducer
```

Contributor guide

Open the contributing guide

Research direction

Start at SymbolFileDWARF::CollectCallEdges and the TODO about recursive scanning, then build the supplied reproducer with GCC 15.1 using the shown command. Done means call sites nested in inline or lexical scopes are collected and LLDB can recover the callee parameter through DW_OP_entry_value instead of reporting no call edge.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.