xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/NativeFunctionSymbol.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
15ffd83dbSDimitry Andric //===- NativeFunctionSymbol.cpp - info about function symbols----*- C++ -*-===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric 
95ffd83dbSDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h"
105ffd83dbSDimitry Andric 
11*81ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/CVRecord.h"
12*81ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
13e8d8bef9SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
145ffd83dbSDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
15*81ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
16e8d8bef9SDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h"
17*81ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
18*81ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
19*81ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/PDBExtras.h"
205ffd83dbSDimitry Andric 
215ffd83dbSDimitry Andric using namespace llvm;
225ffd83dbSDimitry Andric using namespace llvm::codeview;
235ffd83dbSDimitry Andric using namespace llvm::pdb;
245ffd83dbSDimitry Andric 
NativeFunctionSymbol(NativeSession & Session,SymIndexId Id,const codeview::ProcSym & Sym,uint32_t Offset)255ffd83dbSDimitry Andric NativeFunctionSymbol::NativeFunctionSymbol(NativeSession &Session,
265ffd83dbSDimitry Andric                                            SymIndexId Id,
27e8d8bef9SDimitry Andric                                            const codeview::ProcSym &Sym,
28e8d8bef9SDimitry Andric                                            uint32_t Offset)
29e8d8bef9SDimitry Andric     : NativeRawSymbol(Session, PDB_SymType::Function, Id), Sym(Sym),
30e8d8bef9SDimitry Andric       RecordOffset(Offset) {}
315ffd83dbSDimitry Andric 
32*81ad6265SDimitry Andric NativeFunctionSymbol::~NativeFunctionSymbol() = default;
335ffd83dbSDimitry Andric 
dump(raw_ostream & OS,int Indent,PdbSymbolIdField ShowIdFields,PdbSymbolIdField RecurseIdFields) const345ffd83dbSDimitry Andric void NativeFunctionSymbol::dump(raw_ostream &OS, int Indent,
355ffd83dbSDimitry Andric                                 PdbSymbolIdField ShowIdFields,
365ffd83dbSDimitry Andric                                 PdbSymbolIdField RecurseIdFields) const {
375ffd83dbSDimitry Andric   NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
385ffd83dbSDimitry Andric   dumpSymbolField(OS, "name", getName(), Indent);
395ffd83dbSDimitry Andric   dumpSymbolField(OS, "length", getLength(), Indent);
405ffd83dbSDimitry Andric   dumpSymbolField(OS, "offset", getAddressOffset(), Indent);
415ffd83dbSDimitry Andric   dumpSymbolField(OS, "section", getAddressSection(), Indent);
425ffd83dbSDimitry Andric }
435ffd83dbSDimitry Andric 
getAddressOffset() const445ffd83dbSDimitry Andric uint32_t NativeFunctionSymbol::getAddressOffset() const {
455ffd83dbSDimitry Andric   return Sym.CodeOffset;
465ffd83dbSDimitry Andric }
475ffd83dbSDimitry Andric 
getAddressSection() const485ffd83dbSDimitry Andric uint32_t NativeFunctionSymbol::getAddressSection() const { return Sym.Segment; }
getName() const495ffd83dbSDimitry Andric std::string NativeFunctionSymbol::getName() const {
505ffd83dbSDimitry Andric   return std::string(Sym.Name);
515ffd83dbSDimitry Andric }
525ffd83dbSDimitry Andric 
getLength() const535ffd83dbSDimitry Andric uint64_t NativeFunctionSymbol::getLength() const { return Sym.CodeSize; }
545ffd83dbSDimitry Andric 
getRelativeVirtualAddress() const555ffd83dbSDimitry Andric uint32_t NativeFunctionSymbol::getRelativeVirtualAddress() const {
565ffd83dbSDimitry Andric   return Session.getRVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
575ffd83dbSDimitry Andric }
585ffd83dbSDimitry Andric 
getVirtualAddress() const595ffd83dbSDimitry Andric uint64_t NativeFunctionSymbol::getVirtualAddress() const {
605ffd83dbSDimitry Andric   return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
615ffd83dbSDimitry Andric }
62e8d8bef9SDimitry Andric 
inlineSiteContainsAddress(InlineSiteSym & IS,uint32_t OffsetInFunc)63e8d8bef9SDimitry Andric static bool inlineSiteContainsAddress(InlineSiteSym &IS,
64e8d8bef9SDimitry Andric                                       uint32_t OffsetInFunc) {
65e8d8bef9SDimitry Andric   // Returns true if inline site contains the offset.
66e8d8bef9SDimitry Andric   bool Found = false;
67e8d8bef9SDimitry Andric   uint32_t CodeOffset = 0;
68e8d8bef9SDimitry Andric   for (auto &Annot : IS.annotations()) {
69e8d8bef9SDimitry Andric     switch (Annot.OpCode) {
70e8d8bef9SDimitry Andric     case BinaryAnnotationsOpCode::CodeOffset:
71e8d8bef9SDimitry Andric     case BinaryAnnotationsOpCode::ChangeCodeOffset:
72e8d8bef9SDimitry Andric     case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
73e8d8bef9SDimitry Andric       CodeOffset += Annot.U1;
74e8d8bef9SDimitry Andric       if (OffsetInFunc >= CodeOffset)
75e8d8bef9SDimitry Andric         Found = true;
76e8d8bef9SDimitry Andric       break;
77e8d8bef9SDimitry Andric     case BinaryAnnotationsOpCode::ChangeCodeLength:
78e8d8bef9SDimitry Andric       CodeOffset += Annot.U1;
79e8d8bef9SDimitry Andric       if (Found && OffsetInFunc < CodeOffset)
80e8d8bef9SDimitry Andric         return true;
81e8d8bef9SDimitry Andric       Found = false;
82e8d8bef9SDimitry Andric       break;
83e8d8bef9SDimitry Andric     case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
84e8d8bef9SDimitry Andric       CodeOffset += Annot.U2;
85e8d8bef9SDimitry Andric       if (OffsetInFunc >= CodeOffset && OffsetInFunc < CodeOffset + Annot.U1)
86e8d8bef9SDimitry Andric         return true;
87e8d8bef9SDimitry Andric       Found = false;
88e8d8bef9SDimitry Andric       break;
89e8d8bef9SDimitry Andric     default:
90e8d8bef9SDimitry Andric       break;
91e8d8bef9SDimitry Andric     }
92e8d8bef9SDimitry Andric   }
93e8d8bef9SDimitry Andric   return false;
94e8d8bef9SDimitry Andric }
95e8d8bef9SDimitry Andric 
96e8d8bef9SDimitry Andric std::unique_ptr<IPDBEnumSymbols>
findInlineFramesByVA(uint64_t VA) const97e8d8bef9SDimitry Andric NativeFunctionSymbol::findInlineFramesByVA(uint64_t VA) const {
98e8d8bef9SDimitry Andric   uint16_t Modi;
99e8d8bef9SDimitry Andric   if (!Session.moduleIndexForVA(VA, Modi))
100e8d8bef9SDimitry Andric     return nullptr;
101e8d8bef9SDimitry Andric 
102e8d8bef9SDimitry Andric   Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi);
103e8d8bef9SDimitry Andric   if (!ModS) {
104e8d8bef9SDimitry Andric     consumeError(ModS.takeError());
105e8d8bef9SDimitry Andric     return nullptr;
106e8d8bef9SDimitry Andric   }
107e8d8bef9SDimitry Andric   CVSymbolArray Syms = ModS->getSymbolArray();
108e8d8bef9SDimitry Andric 
109e8d8bef9SDimitry Andric   // Search for inline sites. There should be one matching top level inline
110e8d8bef9SDimitry Andric   // site. Then search in its nested inline sites.
111e8d8bef9SDimitry Andric   std::vector<SymIndexId> Frames;
112e8d8bef9SDimitry Andric   uint32_t CodeOffset = VA - getVirtualAddress();
113e8d8bef9SDimitry Andric   auto Start = Syms.at(RecordOffset);
114e8d8bef9SDimitry Andric   auto End = Syms.at(Sym.End);
115e8d8bef9SDimitry Andric   while (Start != End) {
116e8d8bef9SDimitry Andric     bool Found = false;
117e8d8bef9SDimitry Andric     // Find matching inline site within Start and End.
118e8d8bef9SDimitry Andric     for (; Start != End; ++Start) {
119e8d8bef9SDimitry Andric       if (Start->kind() != S_INLINESITE)
120e8d8bef9SDimitry Andric         continue;
121e8d8bef9SDimitry Andric 
122e8d8bef9SDimitry Andric       InlineSiteSym IS =
123e8d8bef9SDimitry Andric           cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(*Start));
124e8d8bef9SDimitry Andric       if (inlineSiteContainsAddress(IS, CodeOffset)) {
125e8d8bef9SDimitry Andric         // Insert frames in reverse order.
126e8d8bef9SDimitry Andric         SymIndexId Id = Session.getSymbolCache().getOrCreateInlineSymbol(
127e8d8bef9SDimitry Andric             IS, getVirtualAddress(), Modi, Start.offset());
128e8d8bef9SDimitry Andric         Frames.insert(Frames.begin(), Id);
129e8d8bef9SDimitry Andric 
130e8d8bef9SDimitry Andric         // Update offsets to search within this inline site.
131e8d8bef9SDimitry Andric         ++Start;
132e8d8bef9SDimitry Andric         End = Syms.at(IS.End);
133e8d8bef9SDimitry Andric         Found = true;
134e8d8bef9SDimitry Andric         break;
135e8d8bef9SDimitry Andric       }
136e8d8bef9SDimitry Andric 
137e8d8bef9SDimitry Andric       Start = Syms.at(IS.End);
138e8d8bef9SDimitry Andric       if (Start == End)
139e8d8bef9SDimitry Andric         break;
140e8d8bef9SDimitry Andric     }
141e8d8bef9SDimitry Andric 
142e8d8bef9SDimitry Andric     if (!Found)
143e8d8bef9SDimitry Andric       break;
144e8d8bef9SDimitry Andric   }
145e8d8bef9SDimitry Andric 
146e8d8bef9SDimitry Andric   return std::make_unique<NativeEnumSymbols>(Session, std::move(Frames));
147e8d8bef9SDimitry Andric }
148