diff options
author | Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> | 2021-02-08 16:48:39 +0100 |
---|---|---|
committer | Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> | 2021-04-14 18:55:36 +0200 |
commit | 34dc0f95968f835d4c4ac01373de63dec2902c70 (patch) | |
tree | 03e69d91b460534624c2b2620387b7193e6afd61 /gdb/testsuite/gdb.opt/inline-locals.c | |
parent | b9de3b915ce27308adc7e39d11c1fb7aa1f73a54 (diff) | |
download | gdb-34dc0f95968f835d4c4ac01373de63dec2902c70.zip gdb-34dc0f95968f835d4c4ac01373de63dec2902c70.tar.gz gdb-34dc0f95968f835d4c4ac01373de63dec2902c70.tar.bz2 |
gdb/dwarf2: fix "info locals" for clang-compiled inlined functions
GDB reports duplicate local vars with "<optimized out>" values for
inlined functions that are compiled with Clang.
Suppose we have
__attribute__((always_inline))
static void aFunction() {
int a = 42;
if(a > 2) {
int value = a;
value += 10; /* break here */
}
}
The "info locals" command at the "break here" line gives the following
output:
...
Breakpoint 1, aFunction () at test.c:6
6 value += 10; /* break here */
(gdb) info locals
value = 42
a = 42
value = <optimized out>
(gdb)
The reason is, inlined functions that are compiled by Clang do not
contain DW_AT_abstract_origin attributes in the DW_TAG_lexical_block
entries. See
https://bugs.llvm.org/show_bug.cgi?id=49953
E.g. the DIE of the inlined function above is
0x00000087: DW_TAG_inlined_subroutine
DW_AT_abstract_origin (0x0000002a "aFunction")
DW_AT_low_pc (0x00000000004004b2)
DW_AT_high_pc (0x00000000004004d2)
DW_AT_call_file ("/tmp/test.c")
DW_AT_call_line (11)
DW_AT_call_column (0x03)
0x0000009b: DW_TAG_variable
DW_AT_location (DW_OP_fbreg -4)
DW_AT_abstract_origin (0x00000032 "a")
0x000000a3: DW_TAG_lexical_block
DW_AT_low_pc (0x00000000004004c3)
DW_AT_high_pc (0x00000000004004d2)
0x000000b0: DW_TAG_variable
DW_AT_location (DW_OP_fbreg -8)
DW_AT_abstract_origin (0x0000003e "value")
This causes GDB to fail matching the concrete lexical scope with the
corresponding abstract entry. Hence, the local vars of the abstract
function that are contained in the lexical scope are read separately
(and thus, in addition to) the local vars of the concrete scope.
Because the abstract definitions of the vars do not contain location
information, we see the extra 'value = <optimized out>' above.
This bug is highly related to PR gdb/25695, but the root cause is not
exactly the same. In PR gdb/25695, GCC emits an extra
DW_TAG_lexical_block without an DW_AT_abstract_origin that wraps the
body of the inlined function. That is, the trees of the abstract DIE
for the function and its concrete instance are structurally not the
same. In the case of using Clang, the trees have the same structure.
To tackle the Clang case, when traversing the children of the concrete
instance root, keep a reference to the child of the abstract DIE that
corresponds to the concrete child, so that we can match the two DIEs
heuristically in case of missing DW_AT_abstract_origin attributes.
The updated gdb.opt/inline-locals.exp test has been checked with GCC
5-10 and Clang 5-11.
gdb/ChangeLog:
2021-04-14 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
* dwarf2/read.c (inherit_abstract_dies): Keep a reference to the
corresponding child of the abstract DIE when iterating the
children of the concrete DIE.
gdb/testsuite/ChangeLog:
2021-04-14 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
* gdb.opt/inline-locals.c (scoped): New function.
(main): Call 'scoped'.
* gdb.opt/inline-locals.exp: Update with "info locals" tests
for scoped variables.
* gdb.dwarf2/dw2-inline-with-lexical-scope.c: New file.
* gdb.dwarf2/dw2-inline-with-lexical-scope.exp: New file.
Diffstat (limited to 'gdb/testsuite/gdb.opt/inline-locals.c')
-rw-r--r-- | gdb/testsuite/gdb.opt/inline-locals.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.opt/inline-locals.c b/gdb/testsuite/gdb.opt/inline-locals.c index b949152..f8910da 100644 --- a/gdb/testsuite/gdb.opt/inline-locals.c +++ b/gdb/testsuite/gdb.opt/inline-locals.c @@ -53,6 +53,24 @@ inline ATTR int func2(int arg2) return x * func1 (arg2); } +inline ATTR +void +scoped (int s) +{ + int loc1 = 10; + if (s > 0) + { + int loc2 = 20; + s++; /* bp for locals 1 */ + if (s > 1) + { + int loc3 = 30; + s++; /* bp for locals 2 */ + } + } + s++; /* bp for locals 3 */ +} + int main (void) { int val; @@ -67,5 +85,7 @@ int main (void) val = func2 (result); result = val; + scoped (40); + return 0; } |