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: "name" , Value: getName(), Indent); |
39 | dumpSymbolField(OS, Name: "length" , Value: getLength(), Indent); |
40 | dumpSymbolField(OS, Name: "offset" , Value: getAddressOffset(), Indent); |
41 | dumpSymbolField(OS, Name: "section" , Value: 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(Section: Sym.Segment, Offset: Sym.CodeOffset); |
57 | } |
58 | |
59 | uint64_t NativeFunctionSymbol::getVirtualAddress() const { |
60 | return Session.getVAFromSectOffset(Section: Sym.Segment, Offset: 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, ModuleIndex&: Modi)) |
100 | return nullptr; |
101 | |
102 | Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Index: Modi); |
103 | if (!ModS) { |
104 | consumeError(Err: 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(Offset: RecordOffset); |
114 | auto End = Syms.at(Offset: 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(ValOrErr: SymbolDeserializer::deserializeAs<InlineSiteSym>(Symbol: *Start)); |
124 | if (inlineSiteContainsAddress(IS, OffsetInFunc: CodeOffset)) { |
125 | // Insert frames in reverse order. |
126 | SymIndexId Id = Session.getSymbolCache().getOrCreateInlineSymbol( |
127 | Sym: IS, ParentAddr: getVirtualAddress(), Modi, RecordOffset: Start.offset()); |
128 | Frames.insert(position: Frames.begin(), x: Id); |
129 | |
130 | // Update offsets to search within this inline site. |
131 | ++Start; |
132 | End = Syms.at(Offset: IS.End); |
133 | Found = true; |
134 | break; |
135 | } |
136 | |
137 | Start = Syms.at(Offset: IS.End); |
138 | if (Start == End) |
139 | break; |
140 | } |
141 | |
142 | if (!Found) |
143 | break; |
144 | } |
145 | |
146 | return std::make_unique<NativeEnumSymbols>(args&: Session, args: std::move(Frames)); |
147 | } |
148 | |