1 //===- NativeFunctionSymbol.cpp - info about function symbols----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h"
10
11 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
12 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
13 #include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h"
14 #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
15 #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
16
17 using namespace llvm;
18 using namespace llvm::codeview;
19 using namespace llvm::pdb;
20
NativeFunctionSymbol(NativeSession & Session,SymIndexId Id,const codeview::ProcSym & Sym,uint32_t Offset)21 NativeFunctionSymbol::NativeFunctionSymbol(NativeSession &Session,
22 SymIndexId Id,
23 const codeview::ProcSym &Sym,
24 uint32_t Offset)
25 : NativeRawSymbol(Session, PDB_SymType::Function, Id), Sym(Sym),
26 RecordOffset(Offset) {}
27
~NativeFunctionSymbol()28 NativeFunctionSymbol::~NativeFunctionSymbol() {}
29
dump(raw_ostream & OS,int Indent,PdbSymbolIdField ShowIdFields,PdbSymbolIdField RecurseIdFields) const30 void NativeFunctionSymbol::dump(raw_ostream &OS, int Indent,
31 PdbSymbolIdField ShowIdFields,
32 PdbSymbolIdField RecurseIdFields) const {
33 NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
34 dumpSymbolField(OS, "name", getName(), Indent);
35 dumpSymbolField(OS, "length", getLength(), Indent);
36 dumpSymbolField(OS, "offset", getAddressOffset(), Indent);
37 dumpSymbolField(OS, "section", getAddressSection(), Indent);
38 }
39
getAddressOffset() const40 uint32_t NativeFunctionSymbol::getAddressOffset() const {
41 return Sym.CodeOffset;
42 }
43
getAddressSection() const44 uint32_t NativeFunctionSymbol::getAddressSection() const { return Sym.Segment; }
getName() const45 std::string NativeFunctionSymbol::getName() const {
46 return std::string(Sym.Name);
47 }
48
getLength() const49 uint64_t NativeFunctionSymbol::getLength() const { return Sym.CodeSize; }
50
getRelativeVirtualAddress() const51 uint32_t NativeFunctionSymbol::getRelativeVirtualAddress() const {
52 return Session.getRVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
53 }
54
getVirtualAddress() const55 uint64_t NativeFunctionSymbol::getVirtualAddress() const {
56 return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
57 }
58
inlineSiteContainsAddress(InlineSiteSym & IS,uint32_t OffsetInFunc)59 static bool inlineSiteContainsAddress(InlineSiteSym &IS,
60 uint32_t OffsetInFunc) {
61 // Returns true if inline site contains the offset.
62 bool Found = false;
63 uint32_t CodeOffset = 0;
64 for (auto &Annot : IS.annotations()) {
65 switch (Annot.OpCode) {
66 case BinaryAnnotationsOpCode::CodeOffset:
67 case BinaryAnnotationsOpCode::ChangeCodeOffset:
68 case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
69 CodeOffset += Annot.U1;
70 if (OffsetInFunc >= CodeOffset)
71 Found = true;
72 break;
73 case BinaryAnnotationsOpCode::ChangeCodeLength:
74 CodeOffset += Annot.U1;
75 if (Found && OffsetInFunc < CodeOffset)
76 return true;
77 Found = false;
78 break;
79 case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
80 CodeOffset += Annot.U2;
81 if (OffsetInFunc >= CodeOffset && OffsetInFunc < CodeOffset + Annot.U1)
82 return true;
83 Found = false;
84 break;
85 default:
86 break;
87 }
88 }
89 return false;
90 }
91
92 std::unique_ptr<IPDBEnumSymbols>
findInlineFramesByVA(uint64_t VA) const93 NativeFunctionSymbol::findInlineFramesByVA(uint64_t VA) const {
94 uint16_t Modi;
95 if (!Session.moduleIndexForVA(VA, Modi))
96 return nullptr;
97
98 Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi);
99 if (!ModS) {
100 consumeError(ModS.takeError());
101 return nullptr;
102 }
103 CVSymbolArray Syms = ModS->getSymbolArray();
104
105 // Search for inline sites. There should be one matching top level inline
106 // site. Then search in its nested inline sites.
107 std::vector<SymIndexId> Frames;
108 uint32_t CodeOffset = VA - getVirtualAddress();
109 auto Start = Syms.at(RecordOffset);
110 auto End = Syms.at(Sym.End);
111 while (Start != End) {
112 bool Found = false;
113 // Find matching inline site within Start and End.
114 for (; Start != End; ++Start) {
115 if (Start->kind() != S_INLINESITE)
116 continue;
117
118 InlineSiteSym IS =
119 cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(*Start));
120 if (inlineSiteContainsAddress(IS, CodeOffset)) {
121 // Insert frames in reverse order.
122 SymIndexId Id = Session.getSymbolCache().getOrCreateInlineSymbol(
123 IS, getVirtualAddress(), Modi, Start.offset());
124 Frames.insert(Frames.begin(), Id);
125
126 // Update offsets to search within this inline site.
127 ++Start;
128 End = Syms.at(IS.End);
129 Found = true;
130 break;
131 }
132
133 Start = Syms.at(IS.End);
134 if (Start == End)
135 break;
136 }
137
138 if (!Found)
139 break;
140 }
141
142 return std::make_unique<NativeEnumSymbols>(Session, std::move(Frames));
143 }
144