llvm-project/lldb/unittests/Core/MangledTest.cpp
Alexander Mols 0a2d4f3f24 [lldb] Enable Rust v0 symbol demangling
Rust's v0 name mangling scheme [1] is easy to disambiguate from other
name mangling schemes because symbols always start with `_R`. The llvm
Demangle library supports demangling the Rust v0 scheme. Use it to
demangle Rust symbols.

Added unit tests that check simple symbols. Ran LLDB built with this
patch to debug some Rust programs compiled with the v0 name mangling
scheme. Confirmed symbol names were demangled as expected.

Note: enabling the new name mangling scheme requires a nightly
toolchain:

```
$ cat main.rs
fn main() {
    println!("Hello world!");
}
$ $(rustup which --toolchain nightly rustc) -Z symbol-mangling-version=v0 main.rs -g
$ /home/asm/hacking/llvm/build/bin/lldb ./main --one-line 'b main.rs:2'
(lldb) target create "./main"
Current executable set to '/home/asm/hacking/llvm/rust/main' (x86_64).
(lldb) b main.rs:2
Breakpoint 1: where = main`main::main + 4 at main.rs:2:5, address = 0x00000000000076a4
(lldb) r
Process 948449 launched: '/home/asm/hacking/llvm/rust/main' (x86_64)
warning: (x86_64) /lib64/libgcc_s.so.1 No LZMA support found for reading .gnu_debugdata section
Process 948449 stopped
* thread #1, name = 'main', stop reason = breakpoint 1.1
    frame #0: 0x000055555555b6a4 main`main::main at main.rs:2:5
   1    fn main() {
-> 2        println!("Hello world!");
   3    }
(lldb) bt
error: need to add support for DW_TAG_base_type '()' encoded with DW_ATE = 0x7, bit_size = 0
* thread #1, name = 'main', stop reason = breakpoint 1.1
  * frame #0: 0x000055555555b6a4 main`main::main at main.rs:2:5
    frame #1: 0x000055555555b78b main`<fn() as core::ops::function::FnOnce<()>>::call_once((null)=(main`main::main at main.rs:1), (null)=<unavailable>) at function.rs:227:5
    frame #2: 0x000055555555b66e main`std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>(f=(main`main::main at main.rs:1)) at backtrace.rs:125:18
    frame #3: 0x000055555555b851 main`std::rt::lang_start::<()>::{closure#0} at rt.rs:49:18
    frame #4: 0x000055555556c9f9 main`std::rt::lang_start_internal::hc51399759a90501a [inlined] core::ops::function::impls::_$LT$impl$u20$core..ops..function..FnOnce$LT$A$GT$$u20$for$u20$$RF$F$GT$::call_once::h04259e4a34d07c2f at function.rs:259:13
    frame #5: 0x000055555556c9f2 main`std::rt::lang_start_internal::hc51399759a90501a [inlined] std::panicking::try::do_call::hb8da45704d5cfbbf at panicking.rs:401:40
    frame #6: 0x000055555556c9f2 main`std::rt::lang_start_internal::hc51399759a90501a [inlined] std::panicking::try::h4beadc19a78fec52 at panicking.rs:365:19
    frame #7: 0x000055555556c9f2 main`std::rt::lang_start_internal::hc51399759a90501a [inlined] std::panic::catch_unwind::hc58016cd36ba81a4 at panic.rs:433:14
    frame #8: 0x000055555556c9f2 main`std::rt::lang_start_internal::hc51399759a90501a at rt.rs:34:21
    frame #9: 0x000055555555b830 main`std::rt::lang_start::<()>(main=(main`main::main at main.rs:1), argc=1, argv=0x00007fffffffcb18) at rt.rs:48:5
    frame #10: 0x000055555555b6fc main`main + 28
    frame #11: 0x00007ffff73f2493 libc.so.6`__libc_start_main + 243
    frame #12: 0x000055555555b59e main`_start + 46
(lldb)
```

[1]: https://github.com/rust-lang/rust/issues/60705

Reviewed By: clayborg, teemperor

Differential Revision: https://reviews.llvm.org/D104054
2021-06-21 18:20:15 +02:00

267 lines
9.7 KiB
C++

//===-- MangledTest.cpp ---------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/SymbolContext.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using namespace lldb;
using namespace lldb_private;
TEST(MangledTest, ResultForValidName) {
ConstString MangledName("_ZN1a1b1cIiiiEEvm");
Mangled TheMangled(MangledName);
ConstString TheDemangled = TheMangled.GetDemangledName();
ConstString ExpectedResult("void a::b::c<int, int, int>(unsigned long)");
EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString());
}
TEST(MangledTest, ResultForBlockInvocation) {
ConstString MangledName("___Z1fU13block_pointerFviE_block_invoke");
Mangled TheMangled(MangledName);
ConstString TheDemangled = TheMangled.GetDemangledName();
ConstString ExpectedResult(
"invocation function for block in f(void (int) block_pointer)");
EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString());
}
TEST(MangledTest, EmptyForInvalidName) {
ConstString MangledName("_ZN1a1b1cmxktpEEvm");
Mangled TheMangled(MangledName);
ConstString TheDemangled = TheMangled.GetDemangledName();
EXPECT_STREQ("", TheDemangled.GetCString());
}
TEST(MangledTest, ResultForValidRustV0Name) {
ConstString mangled_name("_RNvC1a4main");
Mangled the_mangled(mangled_name);
ConstString the_demangled = the_mangled.GetDemangledName();
ConstString expected_result("a::main");
EXPECT_STREQ(expected_result.GetCString(), the_demangled.GetCString());
}
TEST(MangledTest, EmptyForInvalidRustV0Name) {
ConstString mangled_name("_RRR");
Mangled the_mangled(mangled_name);
ConstString the_demangled = the_mangled.GetDemangledName();
EXPECT_STREQ("", the_demangled.GetCString());
}
TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
subsystems;
auto ExpectedFile = TestFile::fromYaml(R"(
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
AddressAlign: 0x0000000000000010
Size: 0x20
- Name: .anothertext
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x0000000000000010
AddressAlign: 0x0000000000000010
Size: 0x40
- Name: .data
Type: SHT_PROGBITS
Flags: [ SHF_WRITE, SHF_ALLOC ]
Address: 0x00000000000000A8
AddressAlign: 0x0000000000000004
Content: '01000000'
Symbols:
- Name: somedata
Type: STT_OBJECT
Section: .anothertext
Value: 0x0000000000000045
Binding: STB_GLOBAL
- Name: main
Type: STT_FUNC
Section: .anothertext
Value: 0x0000000000000010
Size: 0x000000000000003F
Binding: STB_GLOBAL
- Name: _Z3foov
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: puts@GLIBC_2.5
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: puts@GLIBC_2.6
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: _Z5annotv@VERSION3
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: _ZN1AC2Ev
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: _ZN1AD2Ev
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: _ZN1A3barEv
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: _ZGVZN4llvm4dbgsEvE7thestrm
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: _ZZN4llvm4dbgsEvE7thestrm
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: _ZTVN5clang4DeclE
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: -[ObjCfoo]
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: +[B ObjCbar(WithCategory)]
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
- Name: _Z12undemangableEvx42
Type: STT_FUNC
Section: .text
Size: 0x000000000000000D
Binding: STB_GLOBAL
...
)");
ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
auto M = std::make_shared<Module>(ExpectedFile->moduleSpec());
auto Count = [M](const char *Name, FunctionNameType Type) -> int {
SymbolContextList SymList;
M->FindFunctionSymbols(ConstString(Name), Type, SymList);
return SymList.GetSize();
};
// Unmangled
EXPECT_EQ(1, Count("main", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("main", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("main", eFunctionNameTypeMethod));
// Itanium mangled
EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeBase));
EXPECT_EQ(1, Count("foo", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("foo", eFunctionNameTypeMethod));
// Unmangled with linker annotation
EXPECT_EQ(1, Count("puts@GLIBC_2.5", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("puts@GLIBC_2.6", eFunctionNameTypeFull));
EXPECT_EQ(2, Count("puts", eFunctionNameTypeFull));
EXPECT_EQ(2, Count("puts", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("puts", eFunctionNameTypeMethod));
// Itanium mangled with linker annotation
EXPECT_EQ(1, Count("_Z5annotv@VERSION3", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("annot", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("annot", eFunctionNameTypeMethod));
// Itanium mangled ctor A::A()
EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeBase));
EXPECT_EQ(1, Count("A", eFunctionNameTypeMethod));
EXPECT_EQ(0, Count("A", eFunctionNameTypeBase));
// Itanium mangled dtor A::~A()
EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeBase));
EXPECT_EQ(1, Count("~A", eFunctionNameTypeMethod));
EXPECT_EQ(0, Count("~A", eFunctionNameTypeBase));
// Itanium mangled method A::bar()
EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeBase));
EXPECT_EQ(1, Count("bar", eFunctionNameTypeMethod));
EXPECT_EQ(0, Count("bar", eFunctionNameTypeBase));
// Itanium mangled names that are explicitly excluded from parsing
EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("Decl", eFunctionNameTypeMethod));
EXPECT_EQ(0, Count("Decl", eFunctionNameTypeBase));
// ObjC mangled static
EXPECT_EQ(1, Count("-[ObjCfoo]", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("-[ObjCfoo]", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("ObjCfoo", eFunctionNameTypeMethod));
// ObjC mangled method with category
EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("ObjCbar", eFunctionNameTypeMethod));
// Invalid things: unable to decode but still possible to find by full name
EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeFull));
EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("_Z12undemangableEvx42", eFunctionNameTypeMethod));
EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeBase));
EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
}