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