Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -644,8 +644,14 @@ SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id,

std::string uname = GetUnqualifiedTypeName(record);

// FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE.
llvm::Expected maybeDecl = ResolveUdtDeclaration(type_id);
Declaration decl;
if (maybeDecl)
decl = std::move(*maybeDecl);
else
LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), maybeDecl.takeError(),
"Failed to resolve declaration for '{1}': {0}", uname);

return MakeType(toOpaqueUid(type_id), ConstString(uname), size, nullptr,
LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
Type::ResolveState::Forward);
Expand All @@ -668,7 +674,14 @@ lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
CompilerType ct) {
std::string uname = GetUnqualifiedTypeName(er);

llvm::Expected maybeDecl = ResolveUdtDeclaration(type_id);
Declaration decl;
if (maybeDecl)
decl = std::move(*maybeDecl);
else
LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), maybeDecl.takeError(),
"Failed to resolve declaration for '{1}': {0}", uname);

TypeSP underlying_type = GetOrCreateType(er.UnderlyingType);

return MakeType(
Expand Down Expand Up @@ -2556,3 +2569,70 @@ SymbolFileNativePDB::GetContextForType(TypeIndex ti) {
}
return ctx;
}

void SymbolFileNativePDB::CacheUdtDeclarations() {
for (CVType cvt : m_index->ipi().typeArray()) {
switch (cvt.kind()) {
case LF_UDT_SRC_LINE: {
UdtSourceLineRecord udt_src;
llvm::cantFail(TypeDeserializer::deserializeAs(cvt, udt_src));
m_udt_declarations.try_emplace(
udt_src.UDT, UdtDeclaration{/*FileNameIndex=*/udt_src.SourceFile,
/*IsIpiIndex=*/true,
/*Line=*/udt_src.LineNumber});
} break;
case LF_UDT_MOD_SRC_LINE: {
UdtModSourceLineRecord udt_mod_src;
llvm::cantFail(TypeDeserializer::deserializeAs(cvt, udt_mod_src));
// Some types might be contributed by multiple modules. We assume that
// they all point to the same file and line because we can only provide
// one location.
m_udt_declarations.try_emplace(
udt_mod_src.UDT,
UdtDeclaration{/*FileNameIndex=*/udt_mod_src.SourceFile,
/*IsIpiIndex=*/false,
/*Line=*/udt_mod_src.LineNumber});
} break;
default:
break;
}
}
}

llvm::Expected<Declaration>
SymbolFileNativePDB::ResolveUdtDeclaration(PdbTypeSymId type_id) {
std::call_once(m_cached_udt_declarations, [this] { CacheUdtDeclarations(); });

auto it = m_udt_declarations.find(type_id.index);
if (it == m_udt_declarations.end())
return llvm::createStringError("No UDT declaration found");

llvm::StringRef file_name;
if (it->second.IsIpiIndex) {
CVType cvt = m_index->ipi().getType(it->second.FileNameIndex);
if (cvt.kind() != LF_STRING_ID)
return llvm::createStringError("File name was not a LF_STRING_ID");

StringIdRecord sid;
llvm::cantFail(TypeDeserializer::deserializeAs(cvt, sid));
file_name = sid.String;
} else {
// The file name index is an index into the string table
auto string_table = m_index->pdb().getStringTable();
if (!string_table)
return string_table.takeError();

llvm::Expected<llvm::StringRef> string =
string_table->getStringTable().getString(
it->second.FileNameIndex.getIndex());
if (!string)
return string.takeError();
file_name = *string;
}

// rustc sets the filename to "<unknown>" for some files
if (file_name == "\\<unknown>")
return Declaration();

return Declaration(FileSpec(file_name), it->second.Line);
}
15 changes: 15 additions & 0 deletions lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ class SymbolFileNativePDB : public SymbolFileCommon {

void CacheFunctionNames();

void CacheUdtDeclarations();
llvm::Expected<Declaration> ResolveUdtDeclaration(PdbTypeSymId type_id);

llvm::BumpPtrAllocator m_allocator;

lldb::addr_t m_obj_load_address = 0;
Expand All @@ -283,6 +286,18 @@ class SymbolFileNativePDB : public SymbolFileCommon {
llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
m_parent_types;

struct UdtDeclaration {
/// This could either be an index into the `/names` section (string table,
/// LF_UDT_MOD_SRC_LINE) or, this could be an index into the IPI stream to a
/// LF_STRING_ID record (LF_UDT_SRC_LINE).
llvm::codeview::TypeIndex FileNameIndex;
bool IsIpiIndex;

uint32_t Line;
};
llvm::DenseMap<llvm::codeview::TypeIndex, UdtDeclaration> m_udt_declarations;
std::once_flag m_cached_udt_declarations;

lldb_private::UniqueCStringMap<uint32_t> m_type_base_names;

/// mangled name/full function name -> Global ID(s)
Expand Down
56 changes: 56 additions & 0 deletions lldb/test/Shell/SymbolFile/NativePDB/unknown-udt-decl.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
; Test that the declaration for UDTs won't be "<unknown>" or "\<unknown>".
; Rustc sets the location of some builtin types to this string.

; REQUIRES: system-windows
; RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s
; RUN: lldb-test symbols %t.exe | FileCheck %s

; there shouldn't be a declaration (would be between size and compiler_type)
; CHECK: Type{{.*}} , name = "Foo", size = 1, compiler_type = {{.*}} struct Foo {

; This is edited output from clang simulates rustc behavior (see !17)
; Source:
; struct Foo {};
;
; int main() { Foo f; }


; ModuleID = 'main.cpp'
source_filename = "main.cpp"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.44.35207"

%struct.Foo = type { i8 }

; Function Attrs: mustprogress noinline norecurse nounwind optnone uwtable
define dso_local noundef i32 @main() #0 !dbg !9 {
%1 = alloca %struct.Foo, align 1
#dbg_declare(ptr %1, !14, !DIExpression(), !16)
ret i32 0, !dbg !16
}

attributes #0 = { mustprogress noinline norecurse nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
!llvm.ident = !{!8}

!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 20.1.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "main.cpp", directory: "F:\\Dev\\rust-dbg-test", checksumkind: CSK_MD5, checksum: "b8942260dadf9ec35328889f05afb954")
!2 = !{i32 2, !"CodeView", i32 1}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = !{i32 1, !"wchar_size", i32 2}
!5 = !{i32 8, !"PIC Level", i32 2}
!6 = !{i32 7, !"uwtable", i32 2}
!7 = !{i32 1, !"MaxTLSAlign", i32 65536}
!8 = !{!"clang version 20.1.6"}
!9 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !10, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13)
!10 = !DISubroutineType(types: !11)
!11 = !{!12}
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!13 = !{}
!14 = !DILocalVariable(name: "f", scope: !9, file: !1, line: 3, type: !15)
!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !17, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !13, identifier: ".?AUFoo@@")
!16 = !DILocation(line: 3, scope: !9)
; This is how rustc emits some types
!17 = !DIFile(filename: "<unknown>", directory: "")
12 changes: 11 additions & 1 deletion lldb/test/Shell/SymbolFile/PDB/class-layout.test
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,19 @@ RUN: lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix
RUN: lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=BASE %s
RUN: lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=FRIEND %s
RUN: lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=CLASS %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck %s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it a bit awkward that we have NativePDB tests running outside of the SymbolFile/NativePDB test directory. Can we just put this test into the NativePDB directory too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to reply to this...

My concern was that this would now duplicate the test input and the expected output. We do the mixed tests in Shell/SymbolFile/PDB a few times.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm ok, lets just make sure we don't lose this coverage when we remove the DIA PDB plugin

RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=ENUM %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=UNION %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=STRUCT %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=COMPLEX %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=LIST %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=UNNAMED-STRUCT %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=BASE %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=FRIEND %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=CLASS %s

CHECK: Module [[MOD:.*]]
CHECK: SymbolFile pdb ([[MOD]])
CHECK: SymbolFile {{(native-)?}}pdb ([[MOD]])
CHECK: {{^[0-9A-F]+}}: CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\ClassLayoutTest.cpp'

ENUM: name = "Enum", size = 4, decl = ClassLayoutTest.cpp:5
Expand Down
6 changes: 6 additions & 0 deletions lldb/test/Shell/SymbolFile/PDB/enums-layout.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ RUN: lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-
RUN: lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-prefix=UCHAR-ENUM %s
RUN: lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-prefix=CLASS-ENUM %s
RUN: lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-prefix=STRUCT-ENUM %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-prefix=ENUM %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-prefix=CONST-ENUM %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-prefix=EMPTY-ENUM %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-prefix=UCHAR-ENUM %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-prefix=CLASS-ENUM %s
RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/SimpleTypesTest.cpp.enums.exe | FileCheck --check-prefix=STRUCT-ENUM %s

; FIXME: PDB does not have information about scoped enumeration (Enum class) so the
; compiler type used is the same as the one for unscoped enumeration.
Expand Down
Loading