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 
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 
34 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 
44 uint32_t NativeFunctionSymbol::getAddressOffset() const {
45   return Sym.CodeOffset;
46 }
47 
48 uint32_t NativeFunctionSymbol::getAddressSection() const { return Sym.Segment; }
49 std::string NativeFunctionSymbol::getName() const {
50   return std::string(Sym.Name);
51 }
52 
53 uint64_t NativeFunctionSymbol::getLength() const { return Sym.CodeSize; }
54 
55 uint32_t NativeFunctionSymbol::getRelativeVirtualAddress() const {
56   return Session.getRVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
57 }
58 
59 uint64_t NativeFunctionSymbol::getVirtualAddress() const {
60   return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
61 }
62 
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>
97 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