Description
While poking around looking at something else, I tripped over this. A
set of files compiled without LTO has perfectly reasonable debug info,
in particular "main" shows a call-site for calling "foo" and one for
"printf". The info for "foo" shows a call-site for calling
"A::Method1". All totally good.
But when built with LTO, we're able to inline "foo" into "main", and
something gets messed up. "main" shows a DW_TAG_inlined_subroutine for
"foo" followed by 3 call-sites like so:
0x000000a2: DW_TAG_call_site
DW_AT_call_origin (0x000000b5)
DW_AT_call_return_pc (0x00000000000016fb)
0x000000a8: DW_TAG_call_site
DW_AT_call_origin (0x000000b6 "printf")
DW_AT_call_return_pc (0x000000000000170b)
0x000000ae: DW_TAG_call_site
DW_AT_call_origin (0x000000b5)
DW_AT_call_return_pc (0x0000000000001715)
0x000000b4: NULL
0x000000b5: DW_TAG_subprogram
0x000000b6: DW_TAG_subprogram
DW_AT_name ("printf")
DW_AT_decl_file ("/usr/include/stdio.h")
DW_AT_decl_line (356)
DW_AT_type (0x0000005a "int")
DW_AT_declaration (true)
DW_AT_external (true)
Two call-sites pointing to a DW_TAG_subprogram that is... empty??
The call-site for "printf" shows that we are perfectly capable of
emitting a call-site that points to a declaration DIE. My guess is
that LTO is throwing something away that we don't want thrown away,
but because it's gone we end up with the bizarre attribute-free
subprogram DIE.
Because it's LTO, the repro requires multiple files.
// ----- 8< -----
// header.h
struct A {
int Method1(int);
int Method2(int);
};
int foo();
// ----- 8< -----
// header.cpp
#include "header.h"
__attribute__((noinline))
int A::Method1(int x) {
return 5 + x;
}
int A::Method2(int x) {
return 6 + x;
}
extern A a;
int foo() {
return a.Method1(2);
}
// ----- 8< -----
// main.cpp
#include "header.h"
#include <stdio.h>
A a;
int main() {
printf("%d\n", foo());
return a.Method1(3) + a.Method2(4);
}
// ----- 8< -----
# Define CLANG and LLD to point to your build, then execute:
$CLANG -I. -O2 -g -fuse-ld=$LLD main.cpp header.cpp -o normal.elf
$CLANG -I. -O2 -g -fuse-ld=$LLD main.cpp header.cpp -o lto.elf -flto
# and dump the debug info for the two files.