You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
So this is going to be a long issue, but the gist is, to put it semi dramatically, is that I think that all of rust debugging info might be slightly broken, but workable enough for say gdb, that it has gone unnoticed. At the very least, I think:
In contrast to the cpp version, which (correctly) has none. I believe the rust DIE that is emitted is outright incorrect, and is the cause of the issue in #33172
Note, although this issue was closed in favor of #32574 that issue does notno_mangle the static.
Unfortunately, that issue also noted (but did not seem to pursue further):
Now, this variable is not actually emitted. There's no ELF symbol for it.
which I believe may be the crux of the major problem at large here: the linkage_name on all non-mangled Rust DWARF DIEs references a non-existent symbol - I think this is at best highly unusual, and at worst problematic.
Missing Symbols
Considering only ELF at the moment, we can verify that for TEST, TEST2, and deadbeef, there is no symbol referenced by the linkage_name on the DIE:
565d0 LOCAL OBJECT _ZN4test5TEST217h8314c5b1b9028ef4E 0x10 .rodata(16)
73b0 LOCAL FUNC _ZN4test8deadbeef17hc8e13bcb4738fc41E 0xf7 .text(14)
565c0 GLOBAL OBJECT TEST 0x10 .rodata(16)
You will note that the symbols include the symbol hash.
In contrast with the cpp version, the symbol name (including parameter types, see the v (for void) in _ZN4test8deadbeefEv) is identical to the linkage_name, as I think, expected:
201040 GLOBAL OBJECT TEST 0x10 .data(22)
670 GLOBAL FUNC _ZN4test8deadbeefEv 0x4c .text(12)
201030 GLOBAL OBJECT _ZN4test4TESTE 0x10 .data(22)
Debuggers
I would now like to present a debugging session (primarily in gdb) for the two binaries to attempt to illustrate some of the oddities that occur, and motivate why I think there is something wrong here, at the very least.
There are general ergonomic issues and other oddities that I think are surfacing because of the current debug info situation. I have used gdb to illustrate, as lldb is essentially non-functioning for me, and when it doesn't segfault, I cannot break on un-mangled names for the rust binaries.
GDB
First the rust binary:
(gdb) ptype TEST
No symbol 'TEST' in current context
(gdb) ptype test::TEST
No symbol 'test::TEST' in current context
(gdb) ptype test::TEST2
Reading in symbols for test.rs...done.
type = struct test::Foo {
x: u64,
y: i32,
}
(gdb) ptype test::deadbeef
type = fn ()
(gdb) whatis TEST
No symbol 'TEST' in current context
(gdb) whatis test::TEST
No symbol 'test::TEST' in current context
(gdb) whatis test::TEST2
type = test::Foo
(gdb) whatis test::deadbeef
type = fn ()
(gdb) info addr TEST
Symbol "TEST" is at 0x565c0 in a file compiled without debugging.
(gdb) info addr test::TEST
No symbol "test::TEST" in current context.
(gdb) info addr test::TEST2
Symbol "test::TEST2" is static storage at address 0x565d0.
(gdb) info addr test::deadbeef
Symbol "test::deadbeef" is a function at address 0x73b0.
(gdb) info addr _ZN4test5TEST217h8314c5b1b9028ef4E
Symbol "test::TEST2" is at 0x565d0 in a file compiled without debugging.
(gdb) info addr _ZN4test8deadbeef17hc8e13bcb4738fc41E
Symbol "test::deadbeef" is at 0x73b0 in a file compiled without debugging.
The last two are particularly troubling. This certainly looks like a direct consequence of mapping the unmangled, symbol name + hash, in the ELF symbol table to the mangled-without-hash linkage name in the DWARF DIE.
If we compare this to the exact same c++ debugging sequence, it is exactly what one would expect:
(gdb) ptype TEST
type = struct test::Foo {
uint64_t x;
int64_t y;
}
(gdb) ptype test::TEST
type = struct test::Foo {
uint64_t x;
int64_t y;
}
(gdb) ptype test::deadbeef
type = void (void)
(gdb) whatis TEST
type = test::Foo
(gdb) whatis test::TEST
type = test::Foo
(gdb) whatis test::deadbeef
type = void (void)
(gdb) info addr TEST
Symbol "TEST" is static storage at address 0x201040.
(gdb) info addr test::TEST
Symbol "test::TEST" is static storage at address 0x201030.
(gdb) info addr test::deadbeef
Symbol "test::deadbeef()" is a function at address 0x670.
(gdb) info addr _ZN4test4TESTE
Symbol "test::TEST" is static storage at address 0x201030.
(gdb) info addr _ZN4test8deadbeefEv
Symbol "test::deadbeef()" is a function at address 0x670.
LLDB
As of lldb with llvm 5.0.0 I cannot even auto-complete or break on non-mangled names, which further increases my suspicion something is wrong, and the fact that it segfaults occasionally when I auto-complete using test:: as a seed and the stack trace indicates its in the dwarf DIE parsing logic is equally suspicious:
Output non-hash versions of symbols into the symbol table that point to the same address, etc., but which reference the non-hash name in the string table. This is a hack imho, and I've already tried this via binary editing and it did not seem to have any noticeable effect.
Eventually, I think that the final, correct solution imho is to exactly mirror the dwarf output of both the gcc and clang backends, which means:
Making the linkage_name = the symbol table name
Adding parameters, etc., into the symbol table name?
Final Considerations
I believe I've also found some weirdness w.r.t. other symbol names, specifically:
So this is going to be a long issue, but the gist is, to put it semi dramatically, is that I think that all of rust debugging info might be slightly broken, but workable enough for say gdb, that it has gone unnoticed. At the very least, I think:
linkage_name/cc @philipc @fitzgen @tromey @rkruppe @michaelwoerister
Discussion
I've created some test files in rust and c++, and also grepped the binaries for dwarf dies and also symbol table values, which I explain below.
Repro / Test files
and an approximating C++ file:
I've compiled the rust and c++ versions as follows:
I will use the clang output for the c++ examples below, since it shares the same backend infrastructure, though the g++ does output the same.
Analysis
First I will show the dwarf values for
TEST,TEST2, and the functiondeadbeeffor thetestbinary, then thetest_cpp_clangbinary.I would like to direct the reader's attention to the
DW_AT_linkage_namefield, and the corresponding linkage name it shows for each binary.And now for the cpp version:
The first thing to note is that for the rust,
no_manglestatic,TEST, it is given a linkage name:In contrast to the cpp version, which (correctly) has none. I believe the rust DIE that is emitted is outright incorrect, and is the cause of the issue in #33172
Note, although this issue was closed in favor of #32574 that issue does not
no_manglethe static.Unfortunately, that issue also noted (but did not seem to pursue further):
which I believe may be the crux of the major problem at large here: the
linkage_nameon all non-mangled Rust DWARF DIEs references a non-existent symbol - I think this is at best highly unusual, and at worst problematic.Missing Symbols
Considering only ELF at the moment, we can verify that for
TEST,TEST2, anddeadbeef, there is no symbol referenced by thelinkage_nameon the DIE:You will note that the symbols include the symbol hash.
In contrast with the cpp version, the symbol name (including parameter types, see the
v(for void) in_ZN4test8deadbeefEv) is identical to the linkage_name, as I think, expected:Debuggers
I would now like to present a debugging session (primarily in
gdb) for the two binaries to attempt to illustrate some of the oddities that occur, and motivate why I think there is something wrong here, at the very least.There are general ergonomic issues and other oddities that I think are surfacing because of the current debug info situation. I have used
gdbto illustrate, aslldbis essentially non-functioning for me, and when it doesn't segfault, I cannot break on un-mangled names for the rust binaries.GDB
First the rust binary:
The last two are particularly troubling. This certainly looks like a direct consequence of mapping the unmangled, symbol name + hash, in the ELF symbol table to the mangled-without-hash linkage name in the DWARF DIE.
If we compare this to the exact same c++ debugging sequence, it is exactly what one would expect:
LLDB
As of lldb with llvm 5.0.0 I cannot even auto-complete or break on non-mangled names, which further increases my suspicion something is wrong, and the fact that it segfaults occasionally when I auto-complete using
test::as a seed and the stack trace indicates its in the dwarf DIE parsing logic is equally suspicious:Solutions
I believe 1. is the first that should be attempted, but I am not an expert in the compiler internals.
Eventually, I think that the final, correct solution imho is to exactly mirror the dwarf output of both the gcc and clang backends, which means:
Final Considerations
I believe I've also found some weirdness w.r.t. other symbol names, specifically:
examples of which are:
at lines:
0.0appended to a mangled name is not a valid mangled name afaik), respectively.
But I think this is another story for another time ;)