[LLDB][NativePDB] Create functions with mangled name (#149701)

Before, functions created using the NativePDB plugin would not know
about their mangled name. This showed when printing a stacktrace. There,
only the function name was shown. For
https://github.com/llvm/llvm-project/issues/143149, the mangled function
name is required to separate different parts.

This PR adds that name if available.

The Clang AST nodes also take in a mangled name, which was previously
unset. I don't think this unblocks anything further, because Clang can
mangle the function anyway.
This commit is contained in:
nerix
2025-09-24 16:12:54 +02:00
committed by GitHub
parent fc525bf422
commit e98f34eb08
11 changed files with 72 additions and 31 deletions

View File

@@ -38,16 +38,18 @@ struct CreateMethodDecl : public TypeVisitorCallbacks {
TypeIndex func_type_index,
clang::FunctionDecl *&function_decl,
lldb::opaque_compiler_type_t parent_ty,
llvm::StringRef proc_name, CompilerType func_ct)
llvm::StringRef proc_name, ConstString mangled_name,
CompilerType func_ct)
: m_index(m_index), m_clang(m_clang), func_type_index(func_type_index),
function_decl(function_decl), parent_ty(parent_ty),
proc_name(proc_name), func_ct(func_ct) {}
proc_name(proc_name), mangled_name(mangled_name), func_ct(func_ct) {}
PdbIndex &m_index;
TypeSystemClang &m_clang;
TypeIndex func_type_index;
clang::FunctionDecl *&function_decl;
lldb::opaque_compiler_type_t parent_ty;
llvm::StringRef proc_name;
ConstString mangled_name;
CompilerType func_ct;
llvm::Error visitKnownMember(CVMemberRecord &cvr,
@@ -87,8 +89,7 @@ struct CreateMethodDecl : public TypeVisitorCallbacks {
bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
MethodOptions::CompilerGenerated;
function_decl = m_clang.AddMethodToCXXRecordType(
parent_ty, proc_name,
/*asm_label=*/{}, func_ct, /*access=*/access_type,
parent_ty, proc_name, mangled_name, func_ct, /*access=*/access_type,
/*is_virtual=*/is_virtual, /*is_static=*/is_static,
/*is_inline=*/false, /*is_explicit=*/false,
/*is_attr_used=*/false, /*is_artificial=*/is_artificial);
@@ -892,6 +893,10 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
tag_record = CVTagRecord::create(index.tpi().getType(*eti)).asTag();
}
}
ConstString mangled_name(
pdb->FindMangledFunctionName(func_id).value_or(llvm::StringRef()));
if (!tag_record.FieldList.isSimple()) {
CVType field_list_cvt = index.tpi().getType(tag_record.FieldList);
FieldListRecord field_list;
@@ -899,15 +904,15 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
field_list_cvt, field_list))
llvm::consumeError(std::move(error));
CreateMethodDecl process(index, m_clang, func_ti, function_decl,
parent_opaque_ty, func_name, func_ct);
parent_opaque_ty, func_name, mangled_name,
func_ct);
if (llvm::Error err = visitMemberRecordStream(field_list.Data, process))
llvm::consumeError(std::move(err));
}
if (!function_decl) {
function_decl = m_clang.AddMethodToCXXRecordType(
parent_opaque_ty, func_name,
/*asm_label=*/{}, func_ct,
parent_opaque_ty, func_name, mangled_name, func_ct,
/*access=*/lldb::AccessType::eAccessPublic,
/*is_virtual=*/false, /*is_static=*/false,
/*is_inline=*/false, /*is_explicit=*/false,

View File

@@ -501,7 +501,9 @@ lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id,
return nullptr;
PdbTypeSymId sig_id(proc.FunctionType, false);
Mangled mangled(proc.Name);
std::optional<llvm::StringRef> mangled_opt =
FindMangledSymbol(SegmentOffset(proc.Segment, proc.CodeOffset));
Mangled mangled(mangled_opt.value_or(proc.Name));
FunctionSP func_sp = std::make_shared<Function>(
&comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled,
func_type.get(), func_addr,
@@ -2662,6 +2664,31 @@ SymbolFileNativePDB::GetContextForType(TypeIndex ti) {
return ctx;
}
std::optional<llvm::StringRef>
SymbolFileNativePDB::FindMangledFunctionName(PdbCompilandSymId func_id) {
const CompilandIndexItem *cci =
m_index->compilands().GetCompiland(func_id.modi);
if (!cci)
return std::nullopt;
CVSymbol sym_record = cci->m_debug_stream.readSymbolAtOffset(func_id.offset);
if (sym_record.kind() != S_LPROC32 && sym_record.kind() != S_GPROC32)
return std::nullopt;
ProcSym proc(static_cast<SymbolRecordKind>(sym_record.kind()));
cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym_record, proc));
return FindMangledSymbol(SegmentOffset(proc.Segment, proc.CodeOffset));
}
std::optional<llvm::StringRef>
SymbolFileNativePDB::FindMangledSymbol(SegmentOffset so) {
auto symbol = m_index->publics().findByAddress(m_index->symrecords(),
so.segment, so.offset);
if (!symbol)
return std::nullopt;
return symbol->first.Name;
}
void SymbolFileNativePDB::CacheUdtDeclarations() {
for (CVType cvt : m_index->ipi().typeArray()) {
switch (cvt.kind()) {

View File

@@ -140,6 +140,12 @@ public:
std::optional<PdbCompilandSymId> FindSymbolScope(PdbCompilandSymId id);
/// Find the mangled name for a function
///
/// \param id A symbol ID of a S_LPROC32/S_GPROC32 record
/// \returns The mangled name of the function (if available)
std::optional<llvm::StringRef> FindMangledFunctionName(PdbCompilandSymId id);
void FindTypes(const lldb_private::TypeQuery &match,
lldb_private::TypeResults &results) override;
@@ -269,6 +275,8 @@ private:
void CacheUdtDeclarations();
llvm::Expected<Declaration> ResolveUdtDeclaration(PdbTypeSymId type_id);
std::optional<llvm::StringRef> FindMangledSymbol(SegmentOffset so);
llvm::BumpPtrAllocator m_allocator;
lldb::addr_t m_obj_load_address = 0;

View File

@@ -50,9 +50,9 @@ int main(int argc, char **argv) {
// CHECK: 1: name = 'main', locations = 1
// CHECK: 1.1: where = break-by-function.cpp.tmp.exe`main + {{[0-9]+}}
// CHECK: 2: name = 'OvlGlobalFn', locations = 3
// CHECK: 2.1: where = break-by-function.cpp.tmp.exe`OvlGlobalFn + {{[0-9]+}}
// CHECK: 2.2: where = break-by-function.cpp.tmp.exe`OvlGlobalFn
// CHECK: 2.3: where = break-by-function.cpp.tmp.exe`OvlGlobalFn + {{[0-9]+}}
// CHECK: 2.1: where = break-by-function.cpp.tmp.exe`int OvlGlobalFn(int) + {{[0-9]+}}
// CHECK: 2.2: where = break-by-function.cpp.tmp.exe`int OvlGlobalFn(int, int)
// CHECK: 2.3: where = break-by-function.cpp.tmp.exe`int OvlGlobalFn(int, int, int) + {{[0-9]+}}
// CHECK: 3: name = 'StaticFn', locations = 1
// CHECK: 3.1: where = break-by-function.cpp.tmp.exe`StaticFn + {{[0-9]+}}
// CHECK: 4: name = 'DoesntExist', locations = 0 (pending)

View File

@@ -24,4 +24,4 @@ int main(int argc, char **argv) {
// CHECK: (lldb) target create "{{.*}}break-by-line.cpp.tmp.exe"
// CHECK: Current executable set to '{{.*}}break-by-line.cpp.tmp.exe'
// CHECK: (lldb) break set -f break-by-line.cpp -l 15
// CHECK: Breakpoint 1: where = break-by-line.cpp.tmp.exe`NS::NamespaceFn + {{[0-9]+}} at break-by-line.cpp:15
// CHECK: Breakpoint 1: where = break-by-line.cpp.tmp.exe`int NS::NamespaceFn(int) + {{[0-9]+}} at break-by-line.cpp:15

View File

@@ -25,7 +25,7 @@ int main(int argc, char **argv) {
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+12>: mov qword ptr [rsp + 0x28], rdx
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+17>: mov dword ptr [rsp + 0x24], ecx
// CHECK: ** 15 foo();
// CHECK: disassembly.cpp.tmp.exe[{{.*}}] <+21>: call {{.*}} ; foo at disassembly.cpp:12
// CHECK: disassembly.cpp.tmp.exe[{{.*}}] <+21>: call {{.*}} ; int foo(void) at disassembly.cpp:12
// CHECK: ** 16 return 0;
// CHECK-NEXT: 17 }
// CHECK-NEXT: 18

View File

@@ -148,11 +148,12 @@ int main(int argc, char **argv) {
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (void)"
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (char)"
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (char, int, ...)"
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "Class::overloaded_method"
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "int Class::overloaded_method(bool)"
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (void)"
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (int)"
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (_Bool)"
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "overloaded_method"
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "char overloaded_method(void)"
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "char overloaded_method(int)"
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "char (void)"
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "char (int)"
@@ -160,6 +161,6 @@ int main(int argc, char **argv) {
// FIND-OVERLOAD-METHOD-DAG: Function: id = {{.*}}, name = "{{.*}}Struct::overloaded_method{{.*}}"
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "int (void)"
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "int (char)"
// FIND-OVERLOAD-METHOD-DAG: Function: id = {{.*}}, name = "Class::overloaded_method"
// FIND-OVERLOAD-METHOD-DAG: Function: id = {{.*}}, name = "bool Class::overloaded_method(void)"
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (void)"
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (int)"

View File

@@ -55,7 +55,7 @@ int main(int argc, char **argv) {
// CHECK-NEXT: (lldb) step
// CHECK-NEXT: Process {{.*}} stopped
// CHECK-NEXT: * thread #1, stop reason = step in
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: 6
// CHECK-NEXT: 7
// CHECK-NEXT: 8 int Function(int Param1, char Param2) {
@@ -71,7 +71,7 @@ int main(int argc, char **argv) {
// CHECK-NEXT: (lldb) step
// CHECK-NEXT: Process {{.*}} stopped
// CHECK-NEXT: * thread #1, stop reason = step in
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: 7
// CHECK-NEXT: 8 int Function(int Param1, char Param2) {
// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1;
@@ -89,7 +89,7 @@ int main(int argc, char **argv) {
// CHECK-NEXT: (lldb) step
// CHECK-NEXT: Process {{.*}} stopped
// CHECK-NEXT: * thread #1, stop reason = step in
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: 8 int Function(int Param1, char Param2) {
// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1;
// CHECK-NEXT: 10 char Local2 = Param2 + 1;
@@ -109,7 +109,7 @@ int main(int argc, char **argv) {
// CHECK-NEXT: (lldb) step
// CHECK-NEXT: Process {{.*}} stopped
// CHECK-NEXT: * thread #1, stop reason = step in
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1;
// CHECK-NEXT: 10 char Local2 = Param2 + 1;
// CHECK-NEXT: 11 ++Local1;
@@ -129,7 +129,7 @@ int main(int argc, char **argv) {
// CHECK-NEXT: (lldb) step
// CHECK-NEXT: Process {{.*}} stopped
// CHECK-NEXT: * thread #1, stop reason = step in
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
// CHECK-NEXT: 10 char Local2 = Param2 + 1;
// CHECK-NEXT: 11 ++Local1;
// CHECK-NEXT: 12 ++Local2;

View File

@@ -24,19 +24,19 @@ int main(int argc, char **argv) {
// CHECK: (lldb) thread backtrace
// CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`main(argc={{.*}}, argv={{.*}}) at stack_unwinding01.cpp:20
// CHECK: (lldb) thread backtrace
// CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: frame #2: {{.*}} stack_unwinding01.cpp.tmp.exe`main(argc={{.*}}, argv={{.*}}) at stack_unwinding01.cpp:20
// CHECK: (lldb) thread backtrace
// CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=4, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: frame #2: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=4, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: frame #2: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
// CHECK-NEXT: frame #3: {{.*}} stack_unwinding01.cpp.tmp.exe`main(argc={{.*}}, argv={{.*}}) at stack_unwinding01.cpp:20

View File

@@ -4,7 +4,7 @@ RUN: lldb-test symbols -find=function -file FunctionNestedBlockTest.cpp -line 4
RUN: lldb-test symbols -find=block -file FunctionNestedBlockTest.cpp -line 4 %t.exe | FileCheck --check-prefix=CHECK-BLOCK %s
CHECK-FUNCTION: Found 1 functions:
CHECK-FUNCTION: name = "{{.*}}", mangled = "{{_?}}main"
CHECK-FUNCTION: name = "main"
CHECK-BLOCK: Found 1 blocks:
CHECK-BLOCK: Blocks: id = {{.*}}, range = {{.*}}

View File

@@ -42,7 +42,7 @@ GLOBALS-DAG: Variable{{.*}}, name = "g_Const"
GLOBALS-SAME: scope = ??? (2)
GLOBALS: Function
FUNC-F: Function{{.*}}, {{mangled = \?f@@YAHHH@Z|demangled = f}}
FUNC-F: Function{{.*}}, mangled = ?f@@YAHHH@Z
FUNC-F-NEXT: Block
FUNC-F-NEXT: Variable{{.*}}, name = "var_arg1"
FUNC-F-SAME: scope = parameter
@@ -64,14 +64,14 @@ FUNC-MAIN-SAME: scope = local
FUNC-MAIN-NEXT: Variable{{.*}}, name = "a"
FUNC-MAIN-SAME: scope = local
FUNC-CONSTRUCTOR: Function{{.*}}, {{(de)?}}mangled = {{.*}}Class::Class{{.*}}
FUNC-CONSTRUCTOR: Function{{.*}}, {{mangled = \?\?0Class@@QEAA@H@Z|demangled = .*Class::Class}}
FUNC-CONSTRUCTOR-NEXT: Block
FUNC-CONSTRUCTOR-NEXT: Variable{{.*}}, name = "this"
FUNC-CONSTRUCTOR-SAME: scope = parameter
FUNC-CONSTRUCTOR-NEXT: Variable{{.*}}, name = "a"
FUNC-CONSTRUCTOR-SAME: scope = parameter
FUNC-MEMBER: Function{{.*}}, {{(de)?}}mangled = {{.*}}{{(Class::)?}}Func{{.*}}
FUNC-MEMBER: Function{{.*}}, {{mangled = \?Func@Class@@QEAAXXZ|demangled = .*Class::Func}}
FUNC-MEMBER-NEXT: Block
FUNC-MEMBER-NEXT: Variable{{.*}}, name = "this"
FUNC-MEMBER-SAME: scope = parameter