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