[llvm-symbolizer] Add inline stack traces for Windows.

This adds inline stack frames for symbolizing on Windows.

Differential Revision: https://reviews.llvm.org/D88988
This commit is contained in:
Amy Huang 2020-09-15 09:38:42 -07:00
parent eced4a8e6f
commit bc98034040
17 changed files with 916 additions and 131 deletions

View File

@ -6,8 +6,7 @@
// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s // RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
// RUN: %clangxx_asan -O3 %s -o %t && %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s // RUN: %clangxx_asan -O3 %s -o %t && %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
// FIXME: Windows symbolizer needs work to make this pass. // XFAIL: android
// XFAIL: android,windows-msvc
// UNSUPPORTED: ios // UNSUPPORTED: ios
// FIXME: atos does not work for inlined functions, yet llvm-symbolizer // FIXME: atos does not work for inlined functions, yet llvm-symbolizer

View File

@ -0,0 +1,302 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj %s -o %t.obj -triple x86_64-windows-msvc
# RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe -pdb:%t.pdb -debug
# RUN: llvm-symbolizer --obj=%t.exe --use-native-pdb-reader --relative-address \
# RUN: 0x1014 0x1018 0x101c 0x1023 0x1024 | FileCheck %s
# Compiled from this cpp code, with modifications to add extra inline line and
# file changes:
# clang -cc1 -triple x86_64-windows-msvc -gcodeview -S test.cpp
#
# __attribute__((always_inline)) int inlinee_2(int x) {
# return x + 1;
# }
# __attribute__((always_inline)) int inlinee_1(int x) {
# return inlinee_2(x) + 1;
# }
# int main() {
# return inlinee_1(33);
# }
# CHECK: inlinee_1
# CHECK-NEXT: C:\src\test.cpp:9:0
# CHECK-NEXT: main
# CHECK-NEXT: C:\src\test.cpp:13:10
# CHECK: inlinee_1
# CHECK-NEXT: C:\src\test.cpp:10:0
# CHECK-NEXT: main
# CHECK-NEXT: C:\src\test.cpp:13:10
# CHECK: inlinee_2
# CHECK-NEXT: C:\src\test.cpp:5:0
# CHECK-NEXT: inlinee_1
# CHECK-NEXT: C:\src\test.cpp:9:0
# CHECK-NEXT: main
# CHECK-NEXT: C:\src\test.cpp:13:10
# CHECK: inlinee_2
# CHECK-NEXT: C:\src\file.cpp:5:0
# CHECK-NEXT: inlinee_1
# CHECK-NEXT: C:\src\test.cpp:9:0
# CHECK-NEXT: main
# CHECK-NEXT: C:\src\test.cpp:13:10
# CHECK: inlinee_1
# CHECK-NEXT: C:\src\test.cpp:9:0
# CHECK-NEXT: main
# CHECK-NEXT: C:\src\test.cpp:13:10
.text
.def @feat.00;
.scl 3;
.type 0;
.endef
.globl @feat.00
.set @feat.00, 0
.file "test.cpp"
.def main;
.scl 2;
.type 32;
.endef
.globl main # -- Begin function main
.p2align 4, 0x90
main: # @main
.Lfunc_begin0:
.cv_func_id 0
.cv_file 1 "C:\\src\\test.cpp" "4BECA437CFE062C7D0B74B1851B65988" 1
.cv_file 2 "C:\\src\\file.cpp" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" 1
.cv_loc 0 1 12 0 # test.cpp:12:0
# %bb.0: # %entry
subq $16, %rsp
movl $0, 4(%rsp)
movl $33, 8(%rsp)
.Ltmp0:
.cv_inline_site_id 1 within 0 inlined_at 1 13 10
.cv_loc 1 1 9 20 # test.cpp:9:20
movl 8(%rsp), %eax
.cv_loc 1 1 10 0 # test.cpp:10:0
movl %eax, 12(%rsp)
.Ltmp1:
.cv_inline_site_id 2 within 1 inlined_at 1 9 10
.cv_loc 2 1 5 10 # test.cpp:5:10
movl 12(%rsp), %eax
.cv_loc 2 1 5 12 # test.cpp:5:12
addl $1, %eax
.cv_loc 2 2 5 13 # file.cpp:5:13
nop
.Ltmp2:
.cv_loc 1 1 9 23 # test.cpp:9:23
addl $1, %eax
.Ltmp3:
.cv_loc 0 1 13 3 # test.cpp:13:3
addq $16, %rsp
retq
.Ltmp4:
.Lfunc_end0:
# -- End function
.section .debug$S,"dr"
.p2align 2
.long 4 # Debug section magic
.long 241
.long .Ltmp6-.Ltmp5 # Subsection size
.Ltmp5:
.short .Ltmp8-.Ltmp7 # Record length
.Ltmp7:
.short 4412 # Record kind: S_COMPILE3
.long 1 # Flags and language
.short 208 # CPUType
.short 12 # Frontend version
.short 0
.short 0
.short 0
.short 12000 # Backend version
.short 0
.short 0
.short 0
.asciz "clang version 12.0.0 (https://github.com/llvm/llvm-project.git 6a4850e9c1cc74cc67f99f1f81a8fe060a7088d2)" # Null-terminated compiler version string
.p2align 2
.Ltmp8:
.Ltmp6:
.p2align 2
.long 246 # Inlinee lines subsection
.long .Ltmp10-.Ltmp9 # Subsection size
.Ltmp9:
.long 0 # Inlinee lines signature
# Inlined function inlinee_1 starts at test.cpp:8
.long 4098 # Type index of inlined function
.cv_filechecksumoffset 1 # Offset into filechecksum table
.long 8 # Starting line number
# Inlined function inlinee_2 starts at test.cpp:4
.long 4099 # Type index of inlined function
.cv_filechecksumoffset 1 # Offset into filechecksum table
.long 4 # Starting line number
.Ltmp10:
.p2align 2
.long 241 # Symbol subsection for main
.long .Ltmp12-.Ltmp11 # Subsection size
.Ltmp11:
.short .Ltmp14-.Ltmp13 # Record length
.Ltmp13:
.short 4423 # Record kind: S_GPROC32_ID
.long 0 # PtrParent
.long 0 # PtrEnd
.long 0 # PtrNext
.long .Lfunc_end0-main # Code size
.long 0 # Offset after prologue
.long 0 # Offset before epilogue
.long 4102 # Function type index
.secrel32 main # Function section relative address
.secidx main # Function section index
.byte 0 # Flags
.asciz "main" # Function name
.p2align 2
.Ltmp14:
.short .Ltmp16-.Ltmp15 # Record length
.Ltmp15:
.short 4114 # Record kind: S_FRAMEPROC
.long 16 # FrameSize
.long 0 # Padding
.long 0 # Offset of padding
.long 0 # Bytes of callee saved registers
.long 0 # Exception handler offset
.short 0 # Exception handler section
.long 81920 # Flags (defines frame register)
.p2align 2
.Ltmp16:
.short .Ltmp18-.Ltmp17 # Record length
.Ltmp17:
.short 4429 # Record kind: S_INLINESITE
.long 0 # PtrParent
.long 0 # PtrEnd
.long 4098 # Inlinee type index
.cv_inline_linetable 1 1 8 .Lfunc_begin0 .Lfunc_end0
.p2align 2
.Ltmp18:
.short .Ltmp20-.Ltmp19 # Record length
.Ltmp19:
.short 4414 # Record kind: S_LOCAL
.long 116 # TypeIndex
.short 1 # Flags
.asciz "x"
.p2align 2
.Ltmp20:
.cv_def_range .Ltmp0 .Ltmp3, frame_ptr_rel, 8
.short .Ltmp22-.Ltmp21 # Record length
.Ltmp21:
.short 4429 # Record kind: S_INLINESITE
.long 0 # PtrParent
.long 0 # PtrEnd
.long 4099 # Inlinee type index
.cv_inline_linetable 2 1 4 .Lfunc_begin0 .Lfunc_end0
.p2align 2
.Ltmp22:
.short .Ltmp24-.Ltmp23 # Record length
.Ltmp23:
.short 4414 # Record kind: S_LOCAL
.long 116 # TypeIndex
.short 1 # Flags
.asciz "x"
.p2align 2
.Ltmp24:
.cv_def_range .Ltmp1 .Ltmp2, frame_ptr_rel, 12
.short 2 # Record length
.short 4430 # Record kind: S_INLINESITE_END
.short 2 # Record length
.short 4430 # Record kind: S_INLINESITE_END
.short 2 # Record length
.short 4431 # Record kind: S_PROC_ID_END
.Ltmp12:
.p2align 2
.cv_linetable 0, main, .Lfunc_end0
.cv_filechecksums # File index to string table offset subsection
.cv_stringtable # String table
.long 241
.long .Ltmp26-.Ltmp25 # Subsection size
.Ltmp25:
.short .Ltmp28-.Ltmp27 # Record length
.Ltmp27:
.short 4428 # Record kind: S_BUILDINFO
.long 4105 # LF_BUILDINFO index
.p2align 2
.Ltmp28:
.Ltmp26:
.p2align 2
.section .debug$T,"dr"
.p2align 2
.long 4 # Debug section magic
# ArgList (0x1000)
.short 0xa # Record length
.short 0x1201 # Record kind: LF_ARGLIST
.long 0x1 # NumArgs
.long 0x74 # Argument: int
# Procedure (0x1001)
.short 0xe # Record length
.short 0x1008 # Record kind: LF_PROCEDURE
.long 0x74 # ReturnType: int
.byte 0x0 # CallingConvention: NearC
.byte 0x0 # FunctionOptions
.short 0x1 # NumParameters
.long 0x1000 # ArgListType: (int)
# FuncId (0x1002)
.short 0x16 # Record length
.short 0x1601 # Record kind: LF_FUNC_ID
.long 0x0 # ParentScope
.long 0x1001 # FunctionType: int (int)
.asciz "inlinee_1" # Name
.byte 242
.byte 241
# FuncId (0x1003)
.short 0x16 # Record length
.short 0x1601 # Record kind: LF_FUNC_ID
.long 0x0 # ParentScope
.long 0x1001 # FunctionType: int (int)
.asciz "inlinee_2" # Name
.byte 242
.byte 241
# ArgList (0x1004)
.short 0x6 # Record length
.short 0x1201 # Record kind: LF_ARGLIST
.long 0x0 # NumArgs
# Procedure (0x1005)
.short 0xe # Record length
.short 0x1008 # Record kind: LF_PROCEDURE
.long 0x74 # ReturnType: int
.byte 0x0 # CallingConvention: NearC
.byte 0x0 # FunctionOptions
.short 0x0 # NumParameters
.long 0x1004 # ArgListType: ()
# FuncId (0x1006)
.short 0x12 # Record length
.short 0x1601 # Record kind: LF_FUNC_ID
.long 0x0 # ParentScope
.long 0x1005 # FunctionType: int ()
.asciz "main" # Name
.byte 243
.byte 242
.byte 241
# StringId (0x1007)
.short 0xe # Record length
.short 0x1605 # Record kind: LF_STRING_ID
.long 0x0 # Id
.asciz "C:\\src" # StringData
.byte 241
# StringId (0x1008)
.short 0xe # Record length
.short 0x1605 # Record kind: LF_STRING_ID
.long 0x0 # Id
.asciz "<stdin>" # StringData
# BuildInfo (0x1009)
.short 0x1a # Record length
.short 0x1603 # Record kind: LF_BUILDINFO
.short 0x5 # NumArgs
.long 0x1007 # Argument: C:\src
.long 0x0 # Argument
.long 0x1008 # Argument: <stdin>
.long 0x0 # Argument
.long 0x0 # Argument
.byte 242
.byte 241

View File

@ -0,0 +1,41 @@
//==- NativeEnumSymbols.h - Native Symbols Enumerator impl -------*- C++ -*-==//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMSYMBOLS_H
#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMSYMBOLS_H
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
#include <vector>
namespace llvm {
namespace pdb {
class NativeSession;
class NativeEnumSymbols : public IPDBEnumChildren<PDBSymbol> {
public:
NativeEnumSymbols(NativeSession &Session, std::vector<SymIndexId> Symbols);
uint32_t getChildCount() const override;
std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override;
std::unique_ptr<PDBSymbol> getNext() override;
void reset() override;
private:
std::vector<SymIndexId> Symbols;
uint32_t Index;
NativeSession &Session;
};
} // namespace pdb
} // namespace llvm
#endif

View File

@ -20,7 +20,7 @@ namespace pdb {
class NativeFunctionSymbol : public NativeRawSymbol { class NativeFunctionSymbol : public NativeRawSymbol {
public: public:
NativeFunctionSymbol(NativeSession &Session, SymIndexId Id, NativeFunctionSymbol(NativeSession &Session, SymIndexId Id,
const codeview::ProcSym &Sym); const codeview::ProcSym &Sym, uint32_t RecordOffset);
~NativeFunctionSymbol() override; ~NativeFunctionSymbol() override;
@ -33,9 +33,12 @@ public:
uint64_t getLength() const override; uint64_t getLength() const override;
uint32_t getRelativeVirtualAddress() const override; uint32_t getRelativeVirtualAddress() const override;
uint64_t getVirtualAddress() const override; uint64_t getVirtualAddress() const override;
std::unique_ptr<IPDBEnumSymbols>
findInlineFramesByVA(uint64_t VA) const override;
protected: protected:
const codeview::ProcSym Sym; const codeview::ProcSym Sym;
uint32_t RecordOffset = 0;
}; };
} // namespace pdb } // namespace pdb

View File

@ -0,0 +1,46 @@
//===- NativeInlineSiteSymbol.h - info about inline sites -------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVEINLINESITESYMBOL_H
#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEINLINESITESYMBOL_H
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
namespace llvm {
namespace pdb {
class NativeInlineSiteSymbol : public NativeRawSymbol {
public:
NativeInlineSiteSymbol(NativeSession &Session, SymIndexId Id,
const codeview::InlineSiteSym &Sym,
uint64_t ParentAddr);
~NativeInlineSiteSymbol() override;
void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields,
PdbSymbolIdField RecurseIdFields) const override;
std::string getName() const override;
std::unique_ptr<IPDBEnumLineNumbers>
findInlineeLinesByVA(uint64_t VA, uint32_t Length) const override;
private:
const codeview::InlineSiteSym Sym;
uint64_t ParentAddr;
void getLineOffset(uint32_t OffsetInFunc, uint32_t &LineOffset,
uint32_t &FileOffset) const;
};
} // namespace pdb
} // namespace llvm
#endif // LLVM_DEBUGINFO_PDB_NATIVE_NATIVEINLINESITESYMBOL_H

View File

@ -110,9 +110,14 @@ public:
const SymbolCache &getSymbolCache() const { return Cache; } const SymbolCache &getSymbolCache() const { return Cache; }
uint32_t getRVAFromSectOffset(uint32_t Section, uint32_t Offset) const; uint32_t getRVAFromSectOffset(uint32_t Section, uint32_t Offset) const;
uint64_t getVAFromSectOffset(uint32_t Section, uint32_t Offset) const; uint64_t getVAFromSectOffset(uint32_t Section, uint32_t Offset) const;
bool moduleIndexForVA(uint64_t VA, uint16_t &ModuleIndex) const;
bool moduleIndexForSectOffset(uint32_t Sect, uint32_t Offset,
uint16_t &ModuleIndex) const;
Expected<ModuleDebugStreamRef> getModuleDebugStream(uint32_t Index) const;
private: private:
void initializeExeSymbol(); void initializeExeSymbol();
void parseSectionContribs();
std::unique_ptr<PDBFile> Pdb; std::unique_ptr<PDBFile> Pdb;
std::unique_ptr<BumpPtrAllocator> Allocator; std::unique_ptr<BumpPtrAllocator> Allocator;
@ -120,6 +125,12 @@ private:
SymbolCache Cache; SymbolCache Cache;
SymIndexId ExeSymbol = 0; SymIndexId ExeSymbol = 0;
uint64_t LoadAddress = 0; uint64_t LoadAddress = 0;
/// Map from virtual address to module index.
using IMap =
IntervalMap<uint64_t, uint16_t, 8, IntervalMapHalfOpenInfo<uint64_t>>;
IMap::Allocator IMapAllocator;
IMap AddrToModuleIndex;
}; };
} // namespace pdb } // namespace pdb
} // namespace llvm } // namespace llvm

View File

@ -37,40 +37,40 @@ class SymbolCache {
/// an Id. Id allocation is an implementation, with the only guarantee /// an Id. Id allocation is an implementation, with the only guarantee
/// being that once an Id is allocated, the symbol can be assumed to be /// being that once an Id is allocated, the symbol can be assumed to be
/// cached. /// cached.
std::vector<std::unique_ptr<NativeRawSymbol>> Cache; mutable std::vector<std::unique_ptr<NativeRawSymbol>> Cache;
/// For type records from the TPI stream which have been paresd and cached, /// For type records from the TPI stream which have been paresd and cached,
/// stores a mapping to SymIndexId of the cached symbol. /// stores a mapping to SymIndexId of the cached symbol.
DenseMap<codeview::TypeIndex, SymIndexId> TypeIndexToSymbolId; mutable DenseMap<codeview::TypeIndex, SymIndexId> TypeIndexToSymbolId;
/// For field list members which have been parsed and cached, stores a mapping /// For field list members which have been parsed and cached, stores a mapping
/// from (IndexOfClass, MemberIndex) to the corresponding SymIndexId of the /// from (IndexOfClass, MemberIndex) to the corresponding SymIndexId of the
/// cached symbol. /// cached symbol.
DenseMap<std::pair<codeview::TypeIndex, uint32_t>, SymIndexId> mutable DenseMap<std::pair<codeview::TypeIndex, uint32_t>, SymIndexId>
FieldListMembersToSymbolId; FieldListMembersToSymbolId;
/// List of SymIndexIds for each compiland, indexed by compiland index as they /// List of SymIndexIds for each compiland, indexed by compiland index as they
/// appear in the PDB file. /// appear in the PDB file.
std::vector<SymIndexId> Compilands; mutable std::vector<SymIndexId> Compilands;
/// List of source files, indexed by unique source file index. /// List of source files, indexed by unique source file index.
mutable std::vector<std::unique_ptr<NativeSourceFile>> SourceFiles; mutable std::vector<std::unique_ptr<NativeSourceFile>> SourceFiles;
/// Map from string table offset to source file Id.
mutable DenseMap<uint32_t, SymIndexId> FileNameOffsetToId; mutable DenseMap<uint32_t, SymIndexId> FileNameOffsetToId;
/// Map from global symbol offset to SymIndexId. /// Map from global symbol offset to SymIndexId.
DenseMap<uint32_t, SymIndexId> GlobalOffsetToSymbolId; mutable DenseMap<uint32_t, SymIndexId> GlobalOffsetToSymbolId;
/// Map from segment and code offset to SymIndexId. /// Map from segment and code offset to function symbols.
DenseMap<std::pair<uint32_t, uint32_t>, SymIndexId> AddressToSymbolId; mutable DenseMap<std::pair<uint32_t, uint32_t>, SymIndexId> AddressToSymbolId;
DenseMap<std::pair<uint32_t, uint32_t>, SymIndexId> AddressToPublicSymId; /// Map from segment and code offset to public symbols.
mutable DenseMap<std::pair<uint32_t, uint32_t>, SymIndexId>
AddressToPublicSymId;
/// Map from virtual address to module index. /// Map from module index and symbol table offset to SymIndexId.
using IMap = mutable DenseMap<std::pair<uint16_t, uint32_t>, SymIndexId>
IntervalMap<uint64_t, uint16_t, 8, IntervalMapHalfOpenInfo<uint64_t>>; SymTabOffsetToSymbolId;
IMap::Allocator IMapAllocator;
IMap AddrToModuleIndex;
Expected<ModuleDebugStreamRef> getModuleDebugStream(uint32_t Index) const;
struct LineTableEntry { struct LineTableEntry {
uint64_t Addr; uint64_t Addr;
@ -83,7 +83,7 @@ class SymbolCache {
std::vector<LineTableEntry> findLineTable(uint16_t Modi) const; std::vector<LineTableEntry> findLineTable(uint16_t Modi) const;
mutable DenseMap<uint16_t, std::vector<LineTableEntry>> LineTable; mutable DenseMap<uint16_t, std::vector<LineTableEntry>> LineTable;
SymIndexId createSymbolPlaceholder() { SymIndexId createSymbolPlaceholder() const {
SymIndexId Id = Cache.size(); SymIndexId Id = Cache.size();
Cache.push_back(nullptr); Cache.push_back(nullptr);
return Id; return Id;
@ -91,7 +91,7 @@ class SymbolCache {
template <typename ConcreteSymbolT, typename CVRecordT, typename... Args> template <typename ConcreteSymbolT, typename CVRecordT, typename... Args>
SymIndexId createSymbolForType(codeview::TypeIndex TI, codeview::CVType CVT, SymIndexId createSymbolForType(codeview::TypeIndex TI, codeview::CVType CVT,
Args &&... ConstructorArgs) { Args &&...ConstructorArgs) const {
CVRecordT Record; CVRecordT Record;
if (auto EC = if (auto EC =
codeview::TypeDeserializer::deserializeAs<CVRecordT>(CVT, Record)) { codeview::TypeDeserializer::deserializeAs<CVRecordT>(CVT, Record)) {
@ -104,10 +104,10 @@ class SymbolCache {
} }
SymIndexId createSymbolForModifiedType(codeview::TypeIndex ModifierTI, SymIndexId createSymbolForModifiedType(codeview::TypeIndex ModifierTI,
codeview::CVType CVT); codeview::CVType CVT) const;
SymIndexId createSimpleType(codeview::TypeIndex TI, SymIndexId createSimpleType(codeview::TypeIndex TI,
codeview::ModifierOptions Mods); codeview::ModifierOptions Mods) const;
std::unique_ptr<PDBSymbol> findFunctionSymbolBySectOffset(uint32_t Sect, std::unique_ptr<PDBSymbol> findFunctionSymbolBySectOffset(uint32_t Sect,
uint32_t Offset); uint32_t Offset);
@ -118,7 +118,7 @@ public:
SymbolCache(NativeSession &Session, DbiStream *Dbi); SymbolCache(NativeSession &Session, DbiStream *Dbi);
template <typename ConcreteSymbolT, typename... Args> template <typename ConcreteSymbolT, typename... Args>
SymIndexId createSymbol(Args &&... ConstructorArgs) { SymIndexId createSymbol(Args &&...ConstructorArgs) const {
SymIndexId Id = Cache.size(); SymIndexId Id = Cache.size();
// Initial construction must not access the cache, since it must be done // Initial construction must not access the cache, since it must be done
@ -145,7 +145,7 @@ public:
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
createGlobalsEnumerator(codeview::SymbolKind Kind); createGlobalsEnumerator(codeview::SymbolKind Kind);
SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI); SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI) const;
template <typename ConcreteSymbolT, typename... Args> template <typename ConcreteSymbolT, typename... Args>
SymIndexId getOrCreateFieldListMember(codeview::TypeIndex FieldListTI, SymIndexId getOrCreateFieldListMember(codeview::TypeIndex FieldListTI,
@ -163,6 +163,9 @@ public:
} }
SymIndexId getOrCreateGlobalSymbolByOffset(uint32_t Offset); SymIndexId getOrCreateGlobalSymbolByOffset(uint32_t Offset);
SymIndexId getOrCreateInlineSymbol(codeview::InlineSiteSym Sym,
uint64_t ParentAddr, uint16_t Modi,
uint32_t RecordOffset) const;
std::unique_ptr<PDBSymbol> std::unique_ptr<PDBSymbol>
findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, PDB_SymType Type); findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, PDB_SymType Type);
@ -185,9 +188,6 @@ public:
std::unique_ptr<IPDBSourceFile> getSourceFileById(SymIndexId FileId) const; std::unique_ptr<IPDBSourceFile> getSourceFileById(SymIndexId FileId) const;
SymIndexId SymIndexId
getOrCreateSourceFile(const codeview::FileChecksumEntry &Checksum) const; getOrCreateSourceFile(const codeview::FileChecksumEntry &Checksum) const;
void parseSectionContribs();
Optional<uint16_t> getModuleIndexForAddr(uint64_t Addr) const;
}; };
} // namespace pdb } // namespace pdb

View File

@ -140,7 +140,14 @@ public:
StringRef Name, StringRef Name,
PDB_NameSearchFlags Flags, PDB_NameSearchFlags Flags,
uint32_t RVA) const; uint32_t RVA) const;
std::unique_ptr<IPDBEnumSymbols> findInlineFramesByVA(uint64_t VA) const;
std::unique_ptr<IPDBEnumSymbols> findInlineFramesByRVA(uint32_t RVA) const; std::unique_ptr<IPDBEnumSymbols> findInlineFramesByRVA(uint32_t RVA) const;
std::unique_ptr<IPDBEnumLineNumbers>
findInlineeLinesByVA(uint64_t VA, uint32_t Length) const;
std::unique_ptr<IPDBEnumLineNumbers>
findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const;
std::string getName() const;
const IPDBRawSymbol &getRawSymbol() const { return *RawSymbol; } const IPDBRawSymbol &getRawSymbol() const { return *RawSymbol; }
IPDBRawSymbol &getRawSymbol() { return *RawSymbol; } IPDBRawSymbol &getRawSymbol() { return *RawSymbol; }

View File

@ -60,8 +60,10 @@ add_pdb_impl_folder(Native
Native/NativeEnumLineNumbers.cpp Native/NativeEnumLineNumbers.cpp
Native/NativeEnumModules.cpp Native/NativeEnumModules.cpp
Native/NativeEnumTypes.cpp Native/NativeEnumTypes.cpp
Native/NativeEnumSymbols.cpp
Native/NativeExeSymbol.cpp Native/NativeExeSymbol.cpp
Native/NativeFunctionSymbol.cpp Native/NativeFunctionSymbol.cpp
Native/NativeInlineSiteSymbol.cpp
Native/NativeLineNumber.cpp Native/NativeLineNumber.cpp
Native/NativePublicSymbol.cpp Native/NativePublicSymbol.cpp
Native/NativeRawSymbol.cpp Native/NativeRawSymbol.cpp

View File

@ -0,0 +1,41 @@
//==- NativeEnumSymbols.cpp - Native Symbol Enumerator impl ------*- C++ -*-==//
//
// 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 "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::pdb;
NativeEnumSymbols::NativeEnumSymbols(NativeSession &PDBSession,
std::vector<SymIndexId> Symbols)
: Symbols(std::move(Symbols)), Index(0), Session(PDBSession) {}
uint32_t NativeEnumSymbols::getChildCount() const {
return static_cast<uint32_t>(Symbols.size());
}
std::unique_ptr<PDBSymbol>
NativeEnumSymbols::getChildAtIndex(uint32_t N) const {
if (N < Symbols.size()) {
return Session.getSymbolCache().getSymbolById(Symbols[N]);
}
return nullptr;
}
std::unique_ptr<PDBSymbol> NativeEnumSymbols::getNext() {
return getChildAtIndex(Index++);
}
void NativeEnumSymbols::reset() { Index = 0; }

View File

@ -8,7 +8,9 @@
#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
@ -18,8 +20,10 @@ using namespace llvm::pdb;
NativeFunctionSymbol::NativeFunctionSymbol(NativeSession &Session, NativeFunctionSymbol::NativeFunctionSymbol(NativeSession &Session,
SymIndexId Id, SymIndexId Id,
const codeview::ProcSym &Sym) const codeview::ProcSym &Sym,
: NativeRawSymbol(Session, PDB_SymType::Function, Id), Sym(Sym) {} uint32_t Offset)
: NativeRawSymbol(Session, PDB_SymType::Function, Id), Sym(Sym),
RecordOffset(Offset) {}
NativeFunctionSymbol::~NativeFunctionSymbol() {} NativeFunctionSymbol::~NativeFunctionSymbol() {}
@ -51,3 +55,93 @@ uint32_t NativeFunctionSymbol::getRelativeVirtualAddress() const {
uint64_t NativeFunctionSymbol::getVirtualAddress() const { uint64_t NativeFunctionSymbol::getVirtualAddress() const {
return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset); return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
} }
static bool inlineSiteContainsAddress(InlineSiteSym &IS,
uint32_t OffsetInFunc) {
// Returns true if inline site contains the offset.
bool Found = false;
uint32_t CodeOffset = 0;
for (auto &Annot : IS.annotations()) {
switch (Annot.OpCode) {
case BinaryAnnotationsOpCode::CodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
CodeOffset += Annot.U1;
if (OffsetInFunc >= CodeOffset)
Found = true;
break;
case BinaryAnnotationsOpCode::ChangeCodeLength:
CodeOffset += Annot.U1;
if (Found && OffsetInFunc < CodeOffset)
return true;
Found = false;
break;
case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
CodeOffset += Annot.U2;
if (OffsetInFunc >= CodeOffset)
Found = true;
CodeOffset += Annot.U1;
if (Found && OffsetInFunc < CodeOffset)
return true;
Found = false;
break;
default:
break;
}
}
return false;
}
std::unique_ptr<IPDBEnumSymbols>
NativeFunctionSymbol::findInlineFramesByVA(uint64_t VA) const {
uint16_t Modi;
if (!Session.moduleIndexForVA(VA, Modi))
return nullptr;
Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi);
if (!ModS) {
consumeError(ModS.takeError());
return nullptr;
}
CVSymbolArray Syms = ModS->getSymbolArray();
// Search for inline sites. There should be one matching top level inline
// site. Then search in its nested inline sites.
std::vector<SymIndexId> Frames;
uint32_t CodeOffset = VA - getVirtualAddress();
auto Start = Syms.at(RecordOffset);
auto End = Syms.at(Sym.End);
while (Start != End) {
bool Found = false;
// Find matching inline site within Start and End.
for (; Start != End; ++Start) {
if (Start->kind() != S_INLINESITE)
continue;
InlineSiteSym IS =
cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(*Start));
if (inlineSiteContainsAddress(IS, CodeOffset)) {
fprintf(stderr, "inline: %d\n", Start.offset());
// Insert frames in reverse order.
SymIndexId Id = Session.getSymbolCache().getOrCreateInlineSymbol(
IS, getVirtualAddress(), Modi, Start.offset());
Frames.insert(Frames.begin(), Id);
// Update offsets to search within this inline site.
++Start;
End = Syms.at(IS.End);
Found = true;
break;
}
Start = Syms.at(IS.End);
if (Start == End)
break;
}
if (!Found)
break;
}
return std::make_unique<NativeEnumSymbols>(Session, std::move(Frames));
}

View File

@ -0,0 +1,177 @@
//===- NativeInlineSiteSymbol.cpp - info about inline sites -----*- C++ -*-===//
//
// 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 "llvm/DebugInfo/PDB/Native/NativeInlineSiteSymbol.h"
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::pdb;
NativeInlineSiteSymbol::NativeInlineSiteSymbol(
NativeSession &Session, SymIndexId Id, const codeview::InlineSiteSym &Sym,
uint64_t ParentAddr)
: NativeRawSymbol(Session, PDB_SymType::InlineSite, Id), Sym(Sym),
ParentAddr(ParentAddr) {}
NativeInlineSiteSymbol::~NativeInlineSiteSymbol() {}
void NativeInlineSiteSymbol::dump(raw_ostream &OS, int Indent,
PdbSymbolIdField ShowIdFields,
PdbSymbolIdField RecurseIdFields) const {
NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
dumpSymbolField(OS, "name", getName(), Indent);
}
static Optional<InlineeSourceLine>
findInlineeByTypeIndex(TypeIndex Id, ModuleDebugStreamRef &ModS) {
for (const auto &SS : ModS.getSubsectionsArray()) {
if (SS.kind() != DebugSubsectionKind::InlineeLines)
continue;
DebugInlineeLinesSubsectionRef InlineeLines;
BinaryStreamReader Reader(SS.getRecordData());
if (auto EC = InlineeLines.initialize(Reader)) {
consumeError(std::move(EC));
continue;
}
for (const InlineeSourceLine &Line : InlineeLines)
if (Line.Header->Inlinee == Id)
return Line;
}
return None;
}
std::string NativeInlineSiteSymbol::getName() const {
auto Tpi = Session.getPDBFile().getPDBTpiStream();
if (!Tpi) {
consumeError(Tpi.takeError());
return "";
}
auto Ipi = Session.getPDBFile().getPDBIpiStream();
if (!Ipi) {
consumeError(Ipi.takeError());
return "";
}
LazyRandomTypeCollection &Types = Tpi->typeCollection();
LazyRandomTypeCollection &Ids = Ipi->typeCollection();
CVType InlineeType = Ids.getType(Sym.Inlinee);
std::string QualifiedName;
if (InlineeType.kind() == LF_MFUNC_ID) {
MemberFuncIdRecord MFRecord;
cantFail(TypeDeserializer::deserializeAs<MemberFuncIdRecord>(InlineeType,
MFRecord));
TypeIndex ClassTy = MFRecord.getClassType();
QualifiedName.append(std::string(Types.getTypeName(ClassTy)));
QualifiedName.append("::");
} else if (InlineeType.kind() == LF_FUNC_ID) {
FuncIdRecord FRecord;
cantFail(
TypeDeserializer::deserializeAs<FuncIdRecord>(InlineeType, FRecord));
TypeIndex ParentScope = FRecord.getParentScope();
if (!ParentScope.isNoneType()) {
QualifiedName.append(std::string(Ids.getTypeName(ParentScope)));
QualifiedName.append("::");
}
}
QualifiedName.append(std::string(Ids.getTypeName(Sym.Inlinee)));
return QualifiedName;
}
void NativeInlineSiteSymbol::getLineOffset(uint32_t OffsetInFunc,
uint32_t &LineOffset,
uint32_t &FileOffset) const {
LineOffset = 0;
FileOffset = 0;
uint32_t CodeOffset = 0;
for (const auto &Annot : Sym.annotations()) {
switch (Annot.OpCode) {
case BinaryAnnotationsOpCode::CodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeLength:
CodeOffset += Annot.U1;
break;
case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
CodeOffset += Annot.U2;
break;
case BinaryAnnotationsOpCode::ChangeLineOffset:
case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
CodeOffset += Annot.U1;
LineOffset += Annot.S1;
break;
case BinaryAnnotationsOpCode::ChangeFile:
FileOffset = Annot.U1;
break;
default:
break;
}
if (CodeOffset >= OffsetInFunc)
return;
}
}
std::unique_ptr<IPDBEnumLineNumbers>
NativeInlineSiteSymbol::findInlineeLinesByVA(uint64_t VA,
uint32_t Length) const {
uint16_t Modi;
if (!Session.moduleIndexForVA(VA, Modi))
return nullptr;
Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi);
if (!ModS) {
consumeError(ModS.takeError());
return nullptr;
}
Expected<DebugChecksumsSubsectionRef> Checksums =
ModS->findChecksumsSubsection();
if (!Checksums) {
consumeError(Checksums.takeError());
return nullptr;
}
// Get the line number offset and source file offset.
uint32_t SrcLineOffset;
uint32_t SrcFileOffset;
getLineOffset(VA - ParentAddr, SrcLineOffset, SrcFileOffset);
// Get line info from inlinee line table.
Optional<InlineeSourceLine> Inlinee =
findInlineeByTypeIndex(Sym.Inlinee, ModS.get());
if (!Inlinee)
return nullptr;
uint32_t SrcLine = Inlinee->Header->SourceLineNum + SrcLineOffset;
uint32_t SrcCol = 0; // Inline sites don't seem to have column info.
uint32_t FileChecksumOffset =
(SrcFileOffset == 0) ? Inlinee->Header->FileID : SrcFileOffset;
auto ChecksumIter = Checksums->getArray().at(FileChecksumOffset);
uint32_t SrcFileId =
Session.getSymbolCache().getOrCreateSourceFile(*ChecksumIter);
uint32_t LineSect, LineOff;
Session.addressForVA(VA, LineSect, LineOff);
NativeLineNumber LineNum(Session, SrcLine, SrcCol, LineSect, LineOff, Length,
SrcFileId, Modi);
auto SrcFile = Session.getSymbolCache().getSourceFileById(SrcFileId);
std::vector<NativeLineNumber> Lines{LineNum};
return std::make_unique<NativeEnumLineNumbers>(std::move(Lines));
}

View File

@ -13,6 +13,7 @@
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
@ -56,7 +57,7 @@ static DbiStream *getDbiStreamPtr(PDBFile &File) {
NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile, NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile,
std::unique_ptr<BumpPtrAllocator> Allocator) std::unique_ptr<BumpPtrAllocator> Allocator)
: Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)), : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)),
Cache(*this, getDbiStreamPtr(*Pdb)) {} Cache(*this, getDbiStreamPtr(*Pdb)), AddrToModuleIndex(IMapAllocator) {}
NativeSession::~NativeSession() = default; NativeSession::~NativeSession() = default;
@ -255,6 +256,9 @@ std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA,
std::unique_ptr<PDBSymbol> std::unique_ptr<PDBSymbol>
NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
PDB_SymType Type) { PDB_SymType Type) {
if (AddrToModuleIndex.empty())
parseSectionContribs();
return Cache.findSymbolBySectOffset(Sect, Offset, Type); return Cache.findSymbolBySectOffset(Sect, Offset, Type);
} }
@ -386,3 +390,74 @@ uint64_t NativeSession::getVAFromSectOffset(uint32_t Section,
uint32_t Offset) const { uint32_t Offset) const {
return LoadAddress + getRVAFromSectOffset(Section, Offset); return LoadAddress + getRVAFromSectOffset(Section, Offset);
} }
bool NativeSession::moduleIndexForVA(uint64_t VA, uint16_t &ModuleIndex) const {
ModuleIndex = 0;
auto Iter = AddrToModuleIndex.find(VA);
if (Iter == AddrToModuleIndex.end())
return false;
ModuleIndex = Iter.value();
return true;
}
bool NativeSession::moduleIndexForSectOffset(uint32_t Sect, uint32_t Offset,
uint16_t &ModuleIndex) const {
ModuleIndex = 0;
auto Iter = AddrToModuleIndex.find(getVAFromSectOffset(Sect, Offset));
if (Iter == AddrToModuleIndex.end())
return false;
ModuleIndex = Iter.value();
return true;
}
void NativeSession::parseSectionContribs() {
auto Dbi = Pdb->getPDBDbiStream();
if (!Dbi)
return;
class Visitor : public ISectionContribVisitor {
NativeSession &Session;
IMap &AddrMap;
public:
Visitor(NativeSession &Session, IMap &AddrMap)
: Session(Session), AddrMap(AddrMap) {}
void visit(const SectionContrib &C) override {
if (C.Size == 0)
return;
uint64_t VA = Session.getVAFromSectOffset(C.ISect, C.Off);
uint64_t End = VA + C.Size;
// Ignore overlapping sections based on the assumption that a valid
// PDB file should not have overlaps.
if (!AddrMap.overlaps(VA, End))
AddrMap.insert(VA, End, C.Imod);
}
void visit(const SectionContrib2 &C) override { visit(C.Base); }
};
Visitor V(*this, AddrToModuleIndex);
Dbi->visitSectionContributions(V);
}
Expected<ModuleDebugStreamRef>
NativeSession::getModuleDebugStream(uint32_t Index) const {
auto *Dbi = getDbiStreamPtr(*Pdb);
assert(Dbi && "Dbi stream not present");
DbiModuleDescriptor Modi = Dbi->modules().getModuleDescriptor(Index);
uint16_t ModiStream = Modi.getModuleStreamIndex();
if (ModiStream == kInvalidStreamIndex)
return make_error<RawError>("Module stream not present");
std::unique_ptr<msf::MappedBlockStream> ModStreamData =
Pdb->createIndexedStream(ModiStream);
ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
if (auto EC = ModS.reload())
return std::move(EC);
return std::move(ModS);
}

View File

@ -1,5 +1,6 @@
#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" #include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
@ -10,8 +11,10 @@
#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeInlineSiteSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
@ -68,7 +71,7 @@ static const struct BuiltinTypeEntry {
}; };
SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi) SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi)
: Session(Session), Dbi(Dbi), AddrToModuleIndex(IMapAllocator) { : Session(Session), Dbi(Dbi) {
// Id 0 is reserved for the invalid symbol. // Id 0 is reserved for the invalid symbol.
Cache.push_back(nullptr); Cache.push_back(nullptr);
SourceFiles.push_back(nullptr); SourceFiles.push_back(nullptr);
@ -101,7 +104,7 @@ SymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) {
} }
SymIndexId SymbolCache::createSimpleType(TypeIndex Index, SymIndexId SymbolCache::createSimpleType(TypeIndex Index,
ModifierOptions Mods) { ModifierOptions Mods) const {
if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct)
return createSymbol<NativeTypePointer>(Index); return createSymbol<NativeTypePointer>(Index);
@ -116,7 +119,7 @@ SymIndexId SymbolCache::createSimpleType(TypeIndex Index,
SymIndexId SymIndexId
SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI, SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI,
codeview::CVType CVT) { codeview::CVType CVT) const {
ModifierRecord Record; ModifierRecord Record;
if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) { if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) {
consumeError(std::move(EC)); consumeError(std::move(EC));
@ -146,7 +149,7 @@ SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI,
return 0; return 0;
} }
SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) { SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) const {
// First see if it's already in our cache. // First see if it's already in our cache.
const auto Entry = TypeIndexToSymbolId.find(Index); const auto Entry = TypeIndexToSymbolId.find(Index);
if (Entry != TypeIndexToSymbolId.end()) if (Entry != TypeIndexToSymbolId.end())
@ -288,43 +291,32 @@ SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) {
return Id; return Id;
} }
Expected<ModuleDebugStreamRef> SymIndexId SymbolCache::getOrCreateInlineSymbol(InlineSiteSym Sym,
SymbolCache::getModuleDebugStream(uint32_t Index) const { uint64_t ParentAddr,
assert(Dbi && "Dbi stream not present"); uint16_t Modi,
uint32_t RecordOffset) const {
auto Iter = SymTabOffsetToSymbolId.find({Modi, RecordOffset});
if (Iter != SymTabOffsetToSymbolId.end())
return Iter->second;
DbiModuleDescriptor Modi = Dbi->modules().getModuleDescriptor(Index); SymIndexId Id = createSymbol<NativeInlineSiteSymbol>(Sym, ParentAddr);
SymTabOffsetToSymbolId.insert({{Modi, RecordOffset}, Id});
uint16_t ModiStream = Modi.getModuleStreamIndex(); return Id;
if (ModiStream == kInvalidStreamIndex)
return make_error<RawError>("Module stream not present");
std::unique_ptr<msf::MappedBlockStream> ModStreamData =
Session.getPDBFile().createIndexedStream(ModiStream);
ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
if (auto EC = ModS.reload())
return std::move(EC);
return std::move(ModS);
} }
std::unique_ptr<PDBSymbol> std::unique_ptr<PDBSymbol>
SymbolCache::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, SymbolCache::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
PDB_SymType Type) { PDB_SymType Type) {
if (AddrToModuleIndex.empty())
parseSectionContribs();
switch (Type) { switch (Type) {
case PDB_SymType::Function: case PDB_SymType::Function:
return findFunctionSymbolBySectOffset(Sect, Offset); return findFunctionSymbolBySectOffset(Sect, Offset);
case PDB_SymType::PublicSymbol: case PDB_SymType::PublicSymbol:
return findPublicSymbolBySectOffset(Sect, Offset); return findPublicSymbolBySectOffset(Sect, Offset);
case PDB_SymType::Compiland: { case PDB_SymType::Compiland: {
Optional<uint16_t> Modi = uint16_t Modi;
getModuleIndexForAddr(Session.getVAFromSectOffset(Sect, Offset)); if (!Session.moduleIndexForSectOffset(Sect, Offset, Modi))
if (!Modi)
return nullptr; return nullptr;
return getOrCreateCompiland(*Modi); return getOrCreateCompiland(Modi);
} }
case PDB_SymType::None: { case PDB_SymType::None: {
// FIXME: Implement for PDB_SymType::Data. The symbolizer calls this but // FIXME: Implement for PDB_SymType::Data. The symbolizer calls this but
@ -347,11 +339,12 @@ SymbolCache::findFunctionSymbolBySectOffset(uint32_t Sect, uint32_t Offset) {
if (!Dbi) if (!Dbi)
return nullptr; return nullptr;
auto Modi = getModuleIndexForAddr(Session.getVAFromSectOffset(Sect, Offset)); uint16_t Modi;
if (!Modi) if (!Session.moduleIndexForSectOffset(Sect, Offset, Modi))
return nullptr; return nullptr;
auto ExpectedModS = getModuleDebugStream(*Modi); Expected<ModuleDebugStreamRef> ExpectedModS =
Session.getModuleDebugStream(Modi);
if (!ExpectedModS) { if (!ExpectedModS) {
consumeError(ExpectedModS.takeError()); consumeError(ExpectedModS.takeError());
return nullptr; return nullptr;
@ -371,7 +364,7 @@ SymbolCache::findFunctionSymbolBySectOffset(uint32_t Sect, uint32_t Offset) {
return getSymbolById(Found->second); return getSymbolById(Found->second);
// Otherwise, create a new symbol. // Otherwise, create a new symbol.
SymIndexId Id = createSymbol<NativeFunctionSymbol>(PS); SymIndexId Id = createSymbol<NativeFunctionSymbol>(PS, I.offset());
AddressToSymbolId.insert({{PS.Segment, PS.CodeOffset}, Id}); AddressToSymbolId.insert({{PS.Segment, PS.CodeOffset}, Id});
return getSymbolById(Id); return getSymbolById(Id);
} }
@ -456,7 +449,8 @@ SymbolCache::findLineTable(uint16_t Modi) const {
// If there is an error or there are no lines, just return the // If there is an error or there are no lines, just return the
// empty vector. // empty vector.
Expected<ModuleDebugStreamRef> ExpectedModS = getModuleDebugStream(Modi); Expected<ModuleDebugStreamRef> ExpectedModS =
Session.getModuleDebugStream(Modi);
if (!ExpectedModS) { if (!ExpectedModS) {
consumeError(ExpectedModS.takeError()); consumeError(ExpectedModS.takeError());
return ModuleLineTable; return ModuleLineTable;
@ -527,10 +521,9 @@ SymbolCache::findLineTable(uint16_t Modi) const {
std::unique_ptr<IPDBEnumLineNumbers> std::unique_ptr<IPDBEnumLineNumbers>
SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const { SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const {
Optional<uint16_t> MaybeModi = getModuleIndexForAddr(VA); uint16_t Modi;
if (!MaybeModi) if (!Session.moduleIndexForVA(VA, Modi))
return nullptr; return nullptr;
uint16_t Modi = *MaybeModi;
std::vector<LineTableEntry> Lines = findLineTable(Modi); std::vector<LineTableEntry> Lines = findLineTable(Modi);
if (Lines.empty()) if (Lines.empty())
@ -549,7 +542,8 @@ SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const {
--LineIter; --LineIter;
} }
Expected<ModuleDebugStreamRef> ExpectedModS = getModuleDebugStream(Modi); Expected<ModuleDebugStreamRef> ExpectedModS =
Session.getModuleDebugStream(Modi);
if (!ExpectedModS) { if (!ExpectedModS) {
consumeError(ExpectedModS.takeError()); consumeError(ExpectedModS.takeError());
return nullptr; return nullptr;
@ -563,34 +557,8 @@ SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const {
// Populate a vector of NativeLineNumbers that have addresses in the given // Populate a vector of NativeLineNumbers that have addresses in the given
// address range. // address range.
Optional<uint16_t> EndModi = getModuleIndexForAddr(VA + Length);
if (!EndModi)
return nullptr;
std::vector<NativeLineNumber> LineNumbers; std::vector<NativeLineNumber> LineNumbers;
while (Modi <= *EndModi) { while (LineIter != Lines.end()) {
// If we reached the end of the current module, increment Modi and get the
// new line table and checksums array.
if (LineIter == Lines.end()) {
++Modi;
ExpectedModS = getModuleDebugStream(Modi);
if (!ExpectedModS) {
consumeError(ExpectedModS.takeError());
break;
}
ExpectedChecksums = ExpectedModS->findChecksumsSubsection();
if (!ExpectedChecksums) {
consumeError(ExpectedChecksums.takeError());
break;
}
Lines = findLineTable(Modi);
LineIter = Lines.begin();
if (Lines.empty())
continue;
}
if (LineIter->IsTerminalEntry) { if (LineIter->IsTerminalEntry) {
++LineIter; ++LineIter;
continue; continue;
@ -657,39 +625,4 @@ SymbolCache::getOrCreateSourceFile(const FileChecksumEntry &Checksums) const {
return Id; return Id;
} }
void SymbolCache::parseSectionContribs() {
if (!Dbi)
return;
class Visitor : public ISectionContribVisitor {
NativeSession &Session;
IMap &AddrMap;
public:
Visitor(NativeSession &Session, IMap &AddrMap)
: Session(Session), AddrMap(AddrMap) {}
void visit(const SectionContrib &C) override {
if (C.Size == 0)
return;
uint64_t VA = Session.getVAFromSectOffset(C.ISect, C.Off);
uint64_t End = VA + C.Size;
// Ignore overlapping sections based on the assumption that a valid
// PDB file should not have overlaps.
if (!AddrMap.overlaps(VA, End))
AddrMap.insert(VA, End, C.Imod);
}
void visit(const SectionContrib2 &C) override { visit(C.Base); }
};
Visitor V(Session, AddrToModuleIndex);
Dbi->visitSectionContributions(V);
}
Optional<uint16_t> SymbolCache::getModuleIndexForAddr(uint64_t Addr) const {
auto Iter = AddrToModuleIndex.find(Addr);
if (Iter == AddrToModuleIndex.end())
return None;
return Iter.value();
}

View File

@ -86,8 +86,43 @@ DIInliningInfo
PDBContext::getInliningInfoForAddress(object::SectionedAddress Address, PDBContext::getInliningInfoForAddress(object::SectionedAddress Address,
DILineInfoSpecifier Specifier) { DILineInfoSpecifier Specifier) {
DIInliningInfo InlineInfo; DIInliningInfo InlineInfo;
DILineInfo Frame = getLineInfoForAddress(Address, Specifier); DILineInfo CurrentLine = getLineInfoForAddress(Address, Specifier);
InlineInfo.addFrame(Frame);
// Find the function at this address.
std::unique_ptr<PDBSymbol> ParentFunc =
Session->findSymbolByAddress(Address.Address, PDB_SymType::Function);
if (!ParentFunc) {
InlineInfo.addFrame(CurrentLine);
return InlineInfo;
}
auto Frames = ParentFunc->findInlineFramesByVA(Address.Address);
if (!Frames || Frames->getChildCount() == 0) {
InlineInfo.addFrame(CurrentLine);
return InlineInfo;
}
while (auto Frame = Frames->getNext()) {
uint32_t Length = 1;
auto LineNumbers = Frame->findInlineeLinesByVA(Address.Address, Length);
if (!LineNumbers || LineNumbers->getChildCount() == 0)
break;
std::unique_ptr<IPDBLineNumber> Line = LineNumbers->getNext();
assert(Line);
DILineInfo LineInfo;
LineInfo.FunctionName = Frame->getName();
auto SourceFile = Session->getSourceFileById(Line->getSourceFileId());
if (SourceFile &&
Specifier.FLIKind != DILineInfoSpecifier::FileLineInfoKind::None)
LineInfo.FileName = SourceFile->getFileName();
LineInfo.Line = Line->getLineNumber();
LineInfo.Column = Line->getColumnNumber();
InlineInfo.addFrame(LineInfo);
}
InlineInfo.addFrame(CurrentLine);
return InlineInfo; return InlineInfo;
} }

View File

@ -160,11 +160,28 @@ PDBSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name,
return RawSymbol->findChildrenByRVA(Type, Name, Flags, RVA); return RawSymbol->findChildrenByRVA(Type, Name, Flags, RVA);
} }
std::unique_ptr<IPDBEnumSymbols>
PDBSymbol::findInlineFramesByVA(uint64_t VA) const {
return RawSymbol->findInlineFramesByVA(VA);
}
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
PDBSymbol::findInlineFramesByRVA(uint32_t RVA) const { PDBSymbol::findInlineFramesByRVA(uint32_t RVA) const {
return RawSymbol->findInlineFramesByRVA(RVA); return RawSymbol->findInlineFramesByRVA(RVA);
} }
std::unique_ptr<IPDBEnumLineNumbers>
PDBSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const {
return RawSymbol->findInlineeLinesByVA(VA, Length);
}
std::unique_ptr<IPDBEnumLineNumbers>
PDBSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const {
return RawSymbol->findInlineeLinesByRVA(RVA, Length);
}
std::string PDBSymbol::getName() const { return RawSymbol->getName(); }
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
PDBSymbol::getChildStats(TagStats &Stats) const { PDBSymbol::getChildStats(TagStats &Stats) const {
std::unique_ptr<IPDBEnumSymbols> Result(findAllChildren()); std::unique_ptr<IPDBEnumSymbols> Result(findAllChildren());

View File

@ -33,7 +33,9 @@ static_library("PDB") {
"Native/NativeEnumLineNumbers.cpp", "Native/NativeEnumLineNumbers.cpp",
"Native/NativeEnumModules.cpp", "Native/NativeEnumModules.cpp",
"Native/NativeEnumTypes.cpp", "Native/NativeEnumTypes.cpp",
"Native/NativeEnumSymbols.cpp",
"Native/NativeExeSymbol.cpp", "Native/NativeExeSymbol.cpp",
"Native/NativeInlineSiteSymbol.cpp",
"Native/NativeFunctionSymbol.cpp", "Native/NativeFunctionSymbol.cpp",
"Native/NativeLineNumber.cpp", "Native/NativeLineNumber.cpp",
"Native/NativePublicSymbol.cpp", "Native/NativePublicSymbol.cpp",