File: | llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp |
Warning: | line 658, column 35 Access to field 'FragmentBeginLabel' results in a dereference of a null pointer (loaded from variable 'LandingPadRange') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- CodeGen/AsmPrinter/EHStreamer.cpp - Exception Directive Streamer ---===// | ||||
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 | // This file contains support for writing exception info into assembly files. | ||||
10 | // | ||||
11 | //===----------------------------------------------------------------------===// | ||||
12 | |||||
13 | #include "EHStreamer.h" | ||||
14 | #include "llvm/ADT/SmallVector.h" | ||||
15 | #include "llvm/ADT/Twine.h" | ||||
16 | #include "llvm/ADT/iterator_range.h" | ||||
17 | #include "llvm/BinaryFormat/Dwarf.h" | ||||
18 | #include "llvm/CodeGen/AsmPrinter.h" | ||||
19 | #include "llvm/CodeGen/MachineFunction.h" | ||||
20 | #include "llvm/CodeGen/MachineInstr.h" | ||||
21 | #include "llvm/CodeGen/MachineOperand.h" | ||||
22 | #include "llvm/IR/DataLayout.h" | ||||
23 | #include "llvm/IR/Function.h" | ||||
24 | #include "llvm/MC/MCAsmInfo.h" | ||||
25 | #include "llvm/MC/MCContext.h" | ||||
26 | #include "llvm/MC/MCStreamer.h" | ||||
27 | #include "llvm/MC/MCSymbol.h" | ||||
28 | #include "llvm/MC/MCTargetOptions.h" | ||||
29 | #include "llvm/Support/Casting.h" | ||||
30 | #include "llvm/Support/LEB128.h" | ||||
31 | #include "llvm/Target/TargetLoweringObjectFile.h" | ||||
32 | #include <algorithm> | ||||
33 | #include <cassert> | ||||
34 | #include <cstdint> | ||||
35 | #include <vector> | ||||
36 | |||||
37 | using namespace llvm; | ||||
38 | |||||
39 | EHStreamer::EHStreamer(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {} | ||||
40 | |||||
41 | EHStreamer::~EHStreamer() = default; | ||||
42 | |||||
43 | /// How many leading type ids two landing pads have in common. | ||||
44 | unsigned EHStreamer::sharedTypeIDs(const LandingPadInfo *L, | ||||
45 | const LandingPadInfo *R) { | ||||
46 | const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds; | ||||
47 | return std::mismatch(LIds.begin(), LIds.end(), RIds.begin(), RIds.end()) | ||||
48 | .first - | ||||
49 | LIds.begin(); | ||||
50 | } | ||||
51 | |||||
52 | /// Compute the actions table and gather the first action index for each landing | ||||
53 | /// pad site. | ||||
54 | void EHStreamer::computeActionsTable( | ||||
55 | const SmallVectorImpl<const LandingPadInfo *> &LandingPads, | ||||
56 | SmallVectorImpl<ActionEntry> &Actions, | ||||
57 | SmallVectorImpl<unsigned> &FirstActions) { | ||||
58 | // The action table follows the call-site table in the LSDA. The individual | ||||
59 | // records are of two types: | ||||
60 | // | ||||
61 | // * Catch clause | ||||
62 | // * Exception specification | ||||
63 | // | ||||
64 | // The two record kinds have the same format, with only small differences. | ||||
65 | // They are distinguished by the "switch value" field: Catch clauses | ||||
66 | // (TypeInfos) have strictly positive switch values, and exception | ||||
67 | // specifications (FilterIds) have strictly negative switch values. Value 0 | ||||
68 | // indicates a catch-all clause. | ||||
69 | // | ||||
70 | // Negative type IDs index into FilterIds. Positive type IDs index into | ||||
71 | // TypeInfos. The value written for a positive type ID is just the type ID | ||||
72 | // itself. For a negative type ID, however, the value written is the | ||||
73 | // (negative) byte offset of the corresponding FilterIds entry. The byte | ||||
74 | // offset is usually equal to the type ID (because the FilterIds entries are | ||||
75 | // written using a variable width encoding, which outputs one byte per entry | ||||
76 | // as long as the value written is not too large) but can differ. This kind | ||||
77 | // of complication does not occur for positive type IDs because type infos are | ||||
78 | // output using a fixed width encoding. FilterOffsets[i] holds the byte | ||||
79 | // offset corresponding to FilterIds[i]. | ||||
80 | |||||
81 | const std::vector<unsigned> &FilterIds = Asm->MF->getFilterIds(); | ||||
82 | SmallVector<int, 16> FilterOffsets; | ||||
83 | FilterOffsets.reserve(FilterIds.size()); | ||||
84 | int Offset = -1; | ||||
85 | |||||
86 | for (std::vector<unsigned>::const_iterator | ||||
87 | I = FilterIds.begin(), E = FilterIds.end(); I != E; ++I) { | ||||
88 | FilterOffsets.push_back(Offset); | ||||
89 | Offset -= getULEB128Size(*I); | ||||
90 | } | ||||
91 | |||||
92 | FirstActions.reserve(LandingPads.size()); | ||||
93 | |||||
94 | int FirstAction = 0; | ||||
95 | unsigned SizeActions = 0; // Total size of all action entries for a function | ||||
96 | const LandingPadInfo *PrevLPI = nullptr; | ||||
97 | |||||
98 | for (SmallVectorImpl<const LandingPadInfo *>::const_iterator | ||||
99 | I = LandingPads.begin(), E = LandingPads.end(); I != E; ++I) { | ||||
100 | const LandingPadInfo *LPI = *I; | ||||
101 | const std::vector<int> &TypeIds = LPI->TypeIds; | ||||
102 | unsigned NumShared = PrevLPI ? sharedTypeIDs(LPI, PrevLPI) : 0; | ||||
103 | unsigned SizeSiteActions = 0; // Total size of all entries for a landingpad | ||||
104 | |||||
105 | if (NumShared < TypeIds.size()) { | ||||
106 | // Size of one action entry (typeid + next action) | ||||
107 | unsigned SizeActionEntry = 0; | ||||
108 | unsigned PrevAction = (unsigned)-1; | ||||
109 | |||||
110 | if (NumShared) { | ||||
111 | unsigned SizePrevIds = PrevLPI->TypeIds.size(); | ||||
112 | assert(Actions.size())((Actions.size()) ? static_cast<void> (0) : __assert_fail ("Actions.size()", "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 112, __PRETTY_FUNCTION__)); | ||||
113 | PrevAction = Actions.size() - 1; | ||||
114 | SizeActionEntry = getSLEB128Size(Actions[PrevAction].NextAction) + | ||||
115 | getSLEB128Size(Actions[PrevAction].ValueForTypeID); | ||||
116 | |||||
117 | for (unsigned j = NumShared; j != SizePrevIds; ++j) { | ||||
118 | assert(PrevAction != (unsigned)-1 && "PrevAction is invalid!")((PrevAction != (unsigned)-1 && "PrevAction is invalid!" ) ? static_cast<void> (0) : __assert_fail ("PrevAction != (unsigned)-1 && \"PrevAction is invalid!\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 118, __PRETTY_FUNCTION__)); | ||||
119 | SizeActionEntry -= getSLEB128Size(Actions[PrevAction].ValueForTypeID); | ||||
120 | SizeActionEntry += -Actions[PrevAction].NextAction; | ||||
121 | PrevAction = Actions[PrevAction].Previous; | ||||
122 | } | ||||
123 | } | ||||
124 | |||||
125 | // Compute the actions. | ||||
126 | for (unsigned J = NumShared, M = TypeIds.size(); J != M; ++J) { | ||||
127 | int TypeID = TypeIds[J]; | ||||
128 | assert(-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!")((-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!" ) ? static_cast<void> (0) : __assert_fail ("-1 - TypeID < (int)FilterOffsets.size() && \"Unknown filter id!\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 128, __PRETTY_FUNCTION__)); | ||||
129 | int ValueForTypeID = | ||||
130 | isFilterEHSelector(TypeID) ? FilterOffsets[-1 - TypeID] : TypeID; | ||||
131 | unsigned SizeTypeID = getSLEB128Size(ValueForTypeID); | ||||
132 | |||||
133 | int NextAction = SizeActionEntry ? -(SizeActionEntry + SizeTypeID) : 0; | ||||
134 | SizeActionEntry = SizeTypeID + getSLEB128Size(NextAction); | ||||
135 | SizeSiteActions += SizeActionEntry; | ||||
136 | |||||
137 | ActionEntry Action = { ValueForTypeID, NextAction, PrevAction }; | ||||
138 | Actions.push_back(Action); | ||||
139 | PrevAction = Actions.size() - 1; | ||||
140 | } | ||||
141 | |||||
142 | // Record the first action of the landing pad site. | ||||
143 | FirstAction = SizeActions + SizeSiteActions - SizeActionEntry + 1; | ||||
144 | } // else identical - re-use previous FirstAction | ||||
145 | |||||
146 | // Information used when creating the call-site table. The action record | ||||
147 | // field of the call site record is the offset of the first associated | ||||
148 | // action record, relative to the start of the actions table. This value is | ||||
149 | // biased by 1 (1 indicating the start of the actions table), and 0 | ||||
150 | // indicates that there are no actions. | ||||
151 | FirstActions.push_back(FirstAction); | ||||
152 | |||||
153 | // Compute this sites contribution to size. | ||||
154 | SizeActions += SizeSiteActions; | ||||
155 | |||||
156 | PrevLPI = LPI; | ||||
157 | } | ||||
158 | } | ||||
159 | |||||
160 | /// Return `true' if this is a call to a function marked `nounwind'. Return | ||||
161 | /// `false' otherwise. | ||||
162 | bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) { | ||||
163 | assert(MI->isCall() && "This should be a call instruction!")((MI->isCall() && "This should be a call instruction!" ) ? static_cast<void> (0) : __assert_fail ("MI->isCall() && \"This should be a call instruction!\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 163, __PRETTY_FUNCTION__)); | ||||
164 | |||||
165 | bool MarkedNoUnwind = false; | ||||
166 | bool SawFunc = false; | ||||
167 | |||||
168 | for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) { | ||||
169 | const MachineOperand &MO = MI->getOperand(I); | ||||
170 | |||||
171 | if (!MO.isGlobal()) continue; | ||||
172 | |||||
173 | const Function *F = dyn_cast<Function>(MO.getGlobal()); | ||||
174 | if (!F) continue; | ||||
175 | |||||
176 | if (SawFunc) { | ||||
177 | // Be conservative. If we have more than one function operand for this | ||||
178 | // call, then we can't make the assumption that it's the callee and | ||||
179 | // not a parameter to the call. | ||||
180 | // | ||||
181 | // FIXME: Determine if there's a way to say that `F' is the callee or | ||||
182 | // parameter. | ||||
183 | MarkedNoUnwind = false; | ||||
184 | break; | ||||
185 | } | ||||
186 | |||||
187 | MarkedNoUnwind = F->doesNotThrow(); | ||||
188 | SawFunc = true; | ||||
189 | } | ||||
190 | |||||
191 | return MarkedNoUnwind; | ||||
192 | } | ||||
193 | |||||
194 | void EHStreamer::computePadMap( | ||||
195 | const SmallVectorImpl<const LandingPadInfo *> &LandingPads, | ||||
196 | RangeMapType &PadMap) { | ||||
197 | // Invokes and nounwind calls have entries in PadMap (due to being bracketed | ||||
198 | // by try-range labels when lowered). Ordinary calls do not, so appropriate | ||||
199 | // try-ranges for them need be deduced so we can put them in the LSDA. | ||||
200 | for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { | ||||
201 | const LandingPadInfo *LandingPad = LandingPads[i]; | ||||
202 | for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) { | ||||
203 | MCSymbol *BeginLabel = LandingPad->BeginLabels[j]; | ||||
204 | assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!")((!PadMap.count(BeginLabel) && "Duplicate landing pad labels!" ) ? static_cast<void> (0) : __assert_fail ("!PadMap.count(BeginLabel) && \"Duplicate landing pad labels!\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 204, __PRETTY_FUNCTION__)); | ||||
205 | PadRange P = { i, j }; | ||||
206 | PadMap[BeginLabel] = P; | ||||
207 | } | ||||
208 | } | ||||
209 | } | ||||
210 | |||||
211 | /// Compute the call-site table. The entry for an invoke has a try-range | ||||
212 | /// containing the call, a non-zero landing pad, and an appropriate action. The | ||||
213 | /// entry for an ordinary call has a try-range containing the call and zero for | ||||
214 | /// the landing pad and the action. Calls marked 'nounwind' have no entry and | ||||
215 | /// must not be contained in the try-range of any entry - they form gaps in the | ||||
216 | /// table. Entries must be ordered by try-range address. | ||||
217 | /// | ||||
218 | /// Call-sites are split into one or more call-site ranges associated with | ||||
219 | /// different sections of the function. | ||||
220 | /// | ||||
221 | /// - Without -basic-block-sections, all call-sites are grouped into one | ||||
222 | /// call-site-range corresponding to the function section. | ||||
223 | /// | ||||
224 | /// - With -basic-block-sections, one call-site range is created for each | ||||
225 | /// section, with its FragmentBeginLabel and FragmentEndLabel respectively | ||||
226 | // set to the beginning and ending of the corresponding section and its | ||||
227 | // ExceptionLabel set to the exception symbol dedicated for this section. | ||||
228 | // Later, one LSDA header will be emitted for each call-site range with its | ||||
229 | // call-sites following. The action table and type info table will be | ||||
230 | // shared across all ranges. | ||||
231 | void EHStreamer::computeCallSiteTable( | ||||
232 | SmallVectorImpl<CallSiteEntry> &CallSites, | ||||
233 | SmallVectorImpl<CallSiteRange> &CallSiteRanges, | ||||
234 | const SmallVectorImpl<const LandingPadInfo *> &LandingPads, | ||||
235 | const SmallVectorImpl<unsigned> &FirstActions) { | ||||
236 | RangeMapType PadMap; | ||||
237 | computePadMap(LandingPads, PadMap); | ||||
238 | |||||
239 | // The end label of the previous invoke or nounwind try-range. | ||||
240 | MCSymbol *LastLabel = Asm->getFunctionBegin(); | ||||
241 | |||||
242 | // Whether there is a potentially throwing instruction (currently this means | ||||
243 | // an ordinary call) between the end of the previous try-range and now. | ||||
244 | bool SawPotentiallyThrowing = false; | ||||
245 | |||||
246 | // Whether the last CallSite entry was for an invoke. | ||||
247 | bool PreviousIsInvoke = false; | ||||
248 | |||||
249 | bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; | ||||
250 | |||||
251 | // Visit all instructions in order of address. | ||||
252 | for (const auto &MBB : *Asm->MF) { | ||||
253 | if (&MBB == &Asm->MF->front() || MBB.isBeginSection()) { | ||||
254 | // We start a call-site range upon function entry and at the beginning of | ||||
255 | // every basic block section. | ||||
256 | CallSiteRanges.push_back( | ||||
257 | {Asm->MBBSectionRanges[MBB.getSectionIDNum()].BeginLabel, | ||||
258 | Asm->MBBSectionRanges[MBB.getSectionIDNum()].EndLabel, | ||||
259 | Asm->getMBBExceptionSym(MBB), CallSites.size()}); | ||||
260 | PreviousIsInvoke = false; | ||||
261 | SawPotentiallyThrowing = false; | ||||
262 | LastLabel = nullptr; | ||||
263 | } | ||||
264 | |||||
265 | if (MBB.isEHPad()) | ||||
266 | CallSiteRanges.back().IsLPRange = true; | ||||
267 | |||||
268 | for (const auto &MI : MBB) { | ||||
269 | if (!MI.isEHLabel()) { | ||||
270 | if (MI.isCall()) | ||||
271 | SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI); | ||||
272 | continue; | ||||
273 | } | ||||
274 | |||||
275 | // End of the previous try-range? | ||||
276 | MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol(); | ||||
277 | if (BeginLabel == LastLabel) | ||||
278 | SawPotentiallyThrowing = false; | ||||
279 | |||||
280 | // Beginning of a new try-range? | ||||
281 | RangeMapType::const_iterator L = PadMap.find(BeginLabel); | ||||
282 | if (L == PadMap.end()) | ||||
283 | // Nope, it was just some random label. | ||||
284 | continue; | ||||
285 | |||||
286 | const PadRange &P = L->second; | ||||
287 | const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; | ||||
288 | assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&((BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && "Inconsistent landing pad map!") ? static_cast<void> ( 0) : __assert_fail ("BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && \"Inconsistent landing pad map!\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 289, __PRETTY_FUNCTION__)) | ||||
289 | "Inconsistent landing pad map!")((BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && "Inconsistent landing pad map!") ? static_cast<void> ( 0) : __assert_fail ("BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && \"Inconsistent landing pad map!\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 289, __PRETTY_FUNCTION__)); | ||||
290 | |||||
291 | // For Dwarf exception handling (SjLj handling doesn't use this). If some | ||||
292 | // instruction between the previous try-range and this one may throw, | ||||
293 | // create a call-site entry with no landing pad for the region between the | ||||
294 | // try-ranges. | ||||
295 | if (SawPotentiallyThrowing && Asm->MAI->usesCFIForEH()) { | ||||
296 | CallSites.push_back({LastLabel, BeginLabel, nullptr, 0}); | ||||
297 | PreviousIsInvoke = false; | ||||
298 | } | ||||
299 | |||||
300 | LastLabel = LandingPad->EndLabels[P.RangeIndex]; | ||||
301 | assert(BeginLabel && LastLabel && "Invalid landing pad!")((BeginLabel && LastLabel && "Invalid landing pad!" ) ? static_cast<void> (0) : __assert_fail ("BeginLabel && LastLabel && \"Invalid landing pad!\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 301, __PRETTY_FUNCTION__)); | ||||
302 | |||||
303 | if (!LandingPad->LandingPadLabel) { | ||||
304 | // Create a gap. | ||||
305 | PreviousIsInvoke = false; | ||||
306 | } else { | ||||
307 | // This try-range is for an invoke. | ||||
308 | CallSiteEntry Site = { | ||||
309 | BeginLabel, | ||||
310 | LastLabel, | ||||
311 | LandingPad, | ||||
312 | FirstActions[P.PadIndex] | ||||
313 | }; | ||||
314 | |||||
315 | // Try to merge with the previous call-site. SJLJ doesn't do this | ||||
316 | if (PreviousIsInvoke && !IsSJLJ) { | ||||
317 | CallSiteEntry &Prev = CallSites.back(); | ||||
318 | if (Site.LPad == Prev.LPad && Site.Action == Prev.Action) { | ||||
319 | // Extend the range of the previous entry. | ||||
320 | Prev.EndLabel = Site.EndLabel; | ||||
321 | continue; | ||||
322 | } | ||||
323 | } | ||||
324 | |||||
325 | // Otherwise, create a new call-site. | ||||
326 | if (!IsSJLJ) | ||||
327 | CallSites.push_back(Site); | ||||
328 | else { | ||||
329 | // SjLj EH must maintain the call sites in the order assigned | ||||
330 | // to them by the SjLjPrepare pass. | ||||
331 | unsigned SiteNo = Asm->MF->getCallSiteBeginLabel(BeginLabel); | ||||
332 | if (CallSites.size() < SiteNo) | ||||
333 | CallSites.resize(SiteNo); | ||||
334 | CallSites[SiteNo - 1] = Site; | ||||
335 | } | ||||
336 | PreviousIsInvoke = true; | ||||
337 | } | ||||
338 | } | ||||
339 | |||||
340 | // We end the call-site range upon function exit and at the end of every | ||||
341 | // basic block section. | ||||
342 | if (&MBB == &Asm->MF->back() || MBB.isEndSection()) { | ||||
343 | // If some instruction between the previous try-range and the end of the | ||||
344 | // function may throw, create a call-site entry with no landing pad for | ||||
345 | // the region following the try-range. | ||||
346 | if (SawPotentiallyThrowing && !IsSJLJ) { | ||||
347 | CallSiteEntry Site = {LastLabel, CallSiteRanges.back().FragmentEndLabel, | ||||
348 | nullptr, 0}; | ||||
349 | CallSites.push_back(Site); | ||||
350 | SawPotentiallyThrowing = false; | ||||
351 | } | ||||
352 | CallSiteRanges.back().CallSiteEndIdx = CallSites.size(); | ||||
353 | } | ||||
354 | } | ||||
355 | } | ||||
356 | |||||
357 | /// Emit landing pads and actions. | ||||
358 | /// | ||||
359 | /// The general organization of the table is complex, but the basic concepts are | ||||
360 | /// easy. First there is a header which describes the location and organization | ||||
361 | /// of the three components that follow. | ||||
362 | /// | ||||
363 | /// 1. The landing pad site information describes the range of code covered by | ||||
364 | /// the try. In our case it's an accumulation of the ranges covered by the | ||||
365 | /// invokes in the try. There is also a reference to the landing pad that | ||||
366 | /// handles the exception once processed. Finally an index into the actions | ||||
367 | /// table. | ||||
368 | /// 2. The action table, in our case, is composed of pairs of type IDs and next | ||||
369 | /// action offset. Starting with the action index from the landing pad | ||||
370 | /// site, each type ID is checked for a match to the current exception. If | ||||
371 | /// it matches then the exception and type id are passed on to the landing | ||||
372 | /// pad. Otherwise the next action is looked up. This chain is terminated | ||||
373 | /// with a next action of zero. If no type id is found then the frame is | ||||
374 | /// unwound and handling continues. | ||||
375 | /// 3. Type ID table contains references to all the C++ typeinfo for all | ||||
376 | /// catches in the function. This tables is reverse indexed base 1. | ||||
377 | /// | ||||
378 | /// Returns the starting symbol of an exception table. | ||||
379 | MCSymbol *EHStreamer::emitExceptionTable() { | ||||
380 | const MachineFunction *MF = Asm->MF; | ||||
381 | const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos(); | ||||
382 | const std::vector<unsigned> &FilterIds = MF->getFilterIds(); | ||||
383 | const std::vector<LandingPadInfo> &PadInfos = MF->getLandingPads(); | ||||
384 | |||||
385 | // Sort the landing pads in order of their type ids. This is used to fold | ||||
386 | // duplicate actions. | ||||
387 | SmallVector<const LandingPadInfo *, 64> LandingPads; | ||||
388 | LandingPads.reserve(PadInfos.size()); | ||||
389 | |||||
390 | for (unsigned i = 0, N = PadInfos.size(); i != N; ++i) | ||||
| |||||
391 | LandingPads.push_back(&PadInfos[i]); | ||||
392 | |||||
393 | // Order landing pads lexicographically by type id. | ||||
394 | llvm::sort(LandingPads, [](const LandingPadInfo *L, const LandingPadInfo *R) { | ||||
395 | return L->TypeIds < R->TypeIds; | ||||
396 | }); | ||||
397 | |||||
398 | // Compute the actions table and gather the first action index for each | ||||
399 | // landing pad site. | ||||
400 | SmallVector<ActionEntry, 32> Actions; | ||||
401 | SmallVector<unsigned, 64> FirstActions; | ||||
402 | computeActionsTable(LandingPads, Actions, FirstActions); | ||||
403 | |||||
404 | // Compute the call-site table and call-site ranges. Normally, there is only | ||||
405 | // one call-site-range which covers the whole funciton. With | ||||
406 | // -basic-block-sections, there is one call-site-range per basic block | ||||
407 | // section. | ||||
408 | SmallVector<CallSiteEntry, 64> CallSites; | ||||
409 | SmallVector<CallSiteRange, 4> CallSiteRanges; | ||||
410 | computeCallSiteTable(CallSites, CallSiteRanges, LandingPads, FirstActions); | ||||
411 | |||||
412 | bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; | ||||
413 | bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm; | ||||
414 | unsigned CallSiteEncoding = | ||||
415 | IsSJLJ
| ||||
416 | Asm->getObjFileLowering().getCallSiteEncoding(); | ||||
417 | bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty(); | ||||
418 | |||||
419 | // Type infos. | ||||
420 | MCSection *LSDASection = Asm->getObjFileLowering().getLSDASection(); | ||||
421 | unsigned TTypeEncoding; | ||||
422 | |||||
423 | if (!HaveTTData
| ||||
424 | // If there is no TypeInfo, then we just explicitly say that we're omitting | ||||
425 | // that bit. | ||||
426 | TTypeEncoding = dwarf::DW_EH_PE_omit; | ||||
427 | } else { | ||||
428 | // Okay, we have actual filters or typeinfos to emit. As such, we need to | ||||
429 | // pick a type encoding for them. We're about to emit a list of pointers to | ||||
430 | // typeinfo objects at the end of the LSDA. However, unless we're in static | ||||
431 | // mode, this reference will require a relocation by the dynamic linker. | ||||
432 | // | ||||
433 | // Because of this, we have a couple of options: | ||||
434 | // | ||||
435 | // 1) If we are in -static mode, we can always use an absolute reference | ||||
436 | // from the LSDA, because the static linker will resolve it. | ||||
437 | // | ||||
438 | // 2) Otherwise, if the LSDA section is writable, we can output the direct | ||||
439 | // reference to the typeinfo and allow the dynamic linker to relocate | ||||
440 | // it. Since it is in a writable section, the dynamic linker won't | ||||
441 | // have a problem. | ||||
442 | // | ||||
443 | // 3) Finally, if we're in PIC mode and the LDSA section isn't writable, | ||||
444 | // we need to use some form of indirection. For example, on Darwin, | ||||
445 | // we can output a statically-relocatable reference to a dyld stub. The | ||||
446 | // offset to the stub is constant, but the contents are in a section | ||||
447 | // that is updated by the dynamic linker. This is easy enough, but we | ||||
448 | // need to tell the personality function of the unwinder to indirect | ||||
449 | // through the dyld stub. | ||||
450 | // | ||||
451 | // FIXME: When (3) is actually implemented, we'll have to emit the stubs | ||||
452 | // somewhere. This predicate should be moved to a shared location that is | ||||
453 | // in target-independent code. | ||||
454 | // | ||||
455 | TTypeEncoding = Asm->getObjFileLowering().getTTypeEncoding(); | ||||
456 | } | ||||
457 | |||||
458 | // Begin the exception table. | ||||
459 | // Sometimes we want not to emit the data into separate section (e.g. ARM | ||||
460 | // EHABI). In this case LSDASection will be NULL. | ||||
461 | if (LSDASection) | ||||
462 | Asm->OutStreamer->SwitchSection(LSDASection); | ||||
463 | Asm->emitAlignment(Align(4)); | ||||
464 | |||||
465 | // Emit the LSDA. | ||||
466 | MCSymbol *GCCETSym = | ||||
467 | Asm->OutContext.getOrCreateSymbol(Twine("GCC_except_table")+ | ||||
468 | Twine(Asm->getFunctionNumber())); | ||||
469 | Asm->OutStreamer->emitLabel(GCCETSym); | ||||
470 | MCSymbol *CstEndLabel = Asm->createTempSymbol( | ||||
471 | CallSiteRanges.size() > 1 ? "action_table_base" : "cst_end"); | ||||
472 | |||||
473 | MCSymbol *TTBaseLabel = nullptr; | ||||
474 | if (HaveTTData
| ||||
475 | TTBaseLabel = Asm->createTempSymbol("ttbase"); | ||||
476 | |||||
477 | const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); | ||||
478 | |||||
479 | // Helper for emitting references (offsets) for type table and the end of the | ||||
480 | // call-site table (which marks the beginning of the action table). | ||||
481 | // * For Itanium, these references will be emitted for every callsite range. | ||||
482 | // * For SJLJ and Wasm, they will be emitted only once in the LSDA header. | ||||
483 | auto EmitTypeTableRefAndCallSiteTableEndRef = [&]() { | ||||
484 | Asm->emitEncodingByte(TTypeEncoding, "@TType"); | ||||
485 | if (HaveTTData) { | ||||
486 | // N.B.: There is a dependency loop between the size of the TTBase uleb128 | ||||
487 | // here and the amount of padding before the aligned type table. The | ||||
488 | // assembler must sometimes pad this uleb128 or insert extra padding | ||||
489 | // before the type table. See PR35809 or GNU as bug 4029. | ||||
490 | MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); | ||||
491 | Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); | ||||
492 | Asm->OutStreamer->emitLabel(TTBaseRefLabel); | ||||
493 | } | ||||
494 | |||||
495 | // The Action table follows the call-site table. So we emit the | ||||
496 | // label difference from here (start of the call-site table for SJLJ and | ||||
497 | // Wasm, and start of a call-site range for Itanium) to the end of the | ||||
498 | // whole call-site table (end of the last call-site range for Itanium). | ||||
499 | MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); | ||||
500 | Asm->emitEncodingByte(CallSiteEncoding, "Call site"); | ||||
501 | Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); | ||||
502 | Asm->OutStreamer->emitLabel(CstBeginLabel); | ||||
503 | }; | ||||
504 | |||||
505 | // SjLj / Wasm Exception handling | ||||
506 | if (IsSJLJ
| ||||
507 | Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front())); | ||||
508 | |||||
509 | // emit the LSDA header. | ||||
510 | Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); | ||||
511 | EmitTypeTableRefAndCallSiteTableEndRef(); | ||||
512 | |||||
513 | unsigned idx = 0; | ||||
514 | for (SmallVectorImpl<CallSiteEntry>::const_iterator | ||||
515 | I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) { | ||||
516 | const CallSiteEntry &S = *I; | ||||
517 | |||||
518 | // Index of the call site entry. | ||||
519 | if (VerboseAsm) { | ||||
520 | Asm->OutStreamer->AddComment(">> Call Site " + Twine(idx) + " <<"); | ||||
521 | Asm->OutStreamer->AddComment(" On exception at call site "+Twine(idx)); | ||||
522 | } | ||||
523 | Asm->emitULEB128(idx); | ||||
524 | |||||
525 | // Offset of the first associated action record, relative to the start of | ||||
526 | // the action table. This value is biased by 1 (1 indicates the start of | ||||
527 | // the action table), and 0 indicates that there are no actions. | ||||
528 | if (VerboseAsm) { | ||||
529 | if (S.Action == 0) | ||||
530 | Asm->OutStreamer->AddComment(" Action: cleanup"); | ||||
531 | else | ||||
532 | Asm->OutStreamer->AddComment(" Action: " + | ||||
533 | Twine((S.Action - 1) / 2 + 1)); | ||||
534 | } | ||||
535 | Asm->emitULEB128(S.Action); | ||||
536 | } | ||||
537 | Asm->OutStreamer->emitLabel(CstEndLabel); | ||||
538 | } else { | ||||
539 | // Itanium LSDA exception handling | ||||
540 | |||||
541 | // The call-site table is a list of all call sites that may throw an | ||||
542 | // exception (including C++ 'throw' statements) in the procedure | ||||
543 | // fragment. It immediately follows the LSDA header. Each entry indicates, | ||||
544 | // for a given call, the first corresponding action record and corresponding | ||||
545 | // landing pad. | ||||
546 | // | ||||
547 | // The table begins with the number of bytes, stored as an LEB128 | ||||
548 | // compressed, unsigned integer. The records immediately follow the record | ||||
549 | // count. They are sorted in increasing call-site address. Each record | ||||
550 | // indicates: | ||||
551 | // | ||||
552 | // * The position of the call-site. | ||||
553 | // * The position of the landing pad. | ||||
554 | // * The first action record for that call site. | ||||
555 | // | ||||
556 | // A missing entry in the call-site table indicates that a call is not | ||||
557 | // supposed to throw. | ||||
558 | |||||
559 | assert(CallSiteRanges.size() != 0 && "No call-site ranges!")((CallSiteRanges.size() != 0 && "No call-site ranges!" ) ? static_cast<void> (0) : __assert_fail ("CallSiteRanges.size() != 0 && \"No call-site ranges!\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 559, __PRETTY_FUNCTION__)); | ||||
560 | |||||
561 | // There should be only one call-site range which includes all the landing | ||||
562 | // pads. Find that call-site range here. | ||||
563 | const CallSiteRange *LandingPadRange = nullptr; | ||||
564 | for (const CallSiteRange &CSRange : CallSiteRanges) { | ||||
565 | if (CSRange.IsLPRange) { | ||||
566 | assert(LandingPadRange == nullptr &&((LandingPadRange == nullptr && "All landing pads must be in a single callsite range." ) ? static_cast<void> (0) : __assert_fail ("LandingPadRange == nullptr && \"All landing pads must be in a single callsite range.\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 567, __PRETTY_FUNCTION__)) | ||||
567 | "All landing pads must be in a single callsite range.")((LandingPadRange == nullptr && "All landing pads must be in a single callsite range." ) ? static_cast<void> (0) : __assert_fail ("LandingPadRange == nullptr && \"All landing pads must be in a single callsite range.\"" , "/build/llvm-toolchain-snapshot-12.0.0~++20201102111116+1ed2ca68191/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp" , 567, __PRETTY_FUNCTION__)); | ||||
568 | LandingPadRange = &CSRange; | ||||
569 | } | ||||
570 | } | ||||
571 | |||||
572 | // The call-site table is split into its call-site ranges, each being | ||||
573 | // emitted as: | ||||
574 | // [ LPStartEncoding | LPStart ] | ||||
575 | // [ TypeTableEncoding | TypeTableOffset ] | ||||
576 | // [ CallSiteEncoding | CallSiteTableEndOffset ] | ||||
577 | // cst_begin -> { call-site entries contained in this range } | ||||
578 | // | ||||
579 | // and is followed by the next call-site range. | ||||
580 | // | ||||
581 | // For each call-site range, CallSiteTableEndOffset is computed as the | ||||
582 | // difference between cst_begin of that range and the last call-site-table's | ||||
583 | // end label. This offset is used to find the action table. | ||||
584 | |||||
585 | unsigned Entry = 0; | ||||
586 | for (const CallSiteRange &CSRange : CallSiteRanges) { | ||||
587 | if (CSRange.CallSiteBeginIdx != 0) { | ||||
588 | // Align the call-site range for all ranges except the first. The | ||||
589 | // first range is already aligned due to the exception table alignment. | ||||
590 | Asm->emitAlignment(Align(4)); | ||||
591 | } | ||||
592 | Asm->OutStreamer->emitLabel(CSRange.ExceptionLabel); | ||||
593 | |||||
594 | // Emit the LSDA header. | ||||
595 | // If only one call-site range exists, LPStart is omitted as it is the | ||||
596 | // same as the function entry. | ||||
597 | if (CallSiteRanges.size() == 1) { | ||||
598 | Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); | ||||
599 | } else if (!Asm->isPositionIndependent()) { | ||||
600 | // For more than one call-site ranges, LPStart must be explicitly | ||||
601 | // specified. | ||||
602 | // For non-PIC we can simply use the absolute value. | ||||
603 | Asm->emitEncodingByte(dwarf::DW_EH_PE_absptr, "@LPStart"); | ||||
604 | Asm->OutStreamer->emitSymbolValue(LandingPadRange->FragmentBeginLabel, | ||||
605 | Asm->MAI->getCodePointerSize()); | ||||
606 | } else { | ||||
607 | // For PIC mode, we Emit a PC-relative address for LPStart. | ||||
608 | Asm->emitEncodingByte(dwarf::DW_EH_PE_pcrel, "@LPStart"); | ||||
609 | MCContext &Context = Asm->OutStreamer->getContext(); | ||||
610 | MCSymbol *Dot = Context.createTempSymbol(); | ||||
611 | Asm->OutStreamer->emitLabel(Dot); | ||||
612 | Asm->OutStreamer->emitValue( | ||||
613 | MCBinaryExpr::createSub( | ||||
614 | MCSymbolRefExpr::create(LandingPadRange->FragmentBeginLabel, | ||||
615 | Context), | ||||
616 | MCSymbolRefExpr::create(Dot, Context), Context), | ||||
617 | Asm->MAI->getCodePointerSize()); | ||||
618 | } | ||||
619 | |||||
620 | EmitTypeTableRefAndCallSiteTableEndRef(); | ||||
621 | |||||
622 | for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx; | ||||
623 | CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) { | ||||
624 | const CallSiteEntry &S = CallSites[CallSiteIdx]; | ||||
625 | |||||
626 | MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel; | ||||
627 | MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel; | ||||
628 | |||||
629 | MCSymbol *BeginLabel = S.BeginLabel; | ||||
630 | if (!BeginLabel) | ||||
631 | BeginLabel = EHFuncBeginSym; | ||||
632 | MCSymbol *EndLabel = S.EndLabel; | ||||
633 | if (!EndLabel) | ||||
634 | EndLabel = EHFuncEndSym; | ||||
635 | |||||
636 | // Offset of the call site relative to the start of the procedure. | ||||
637 | if (VerboseAsm) | ||||
638 | Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + | ||||
639 | " <<"); | ||||
640 | Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding); | ||||
641 | if (VerboseAsm
| ||||
642 | Asm->OutStreamer->AddComment(Twine(" Call between ") + | ||||
643 | BeginLabel->getName() + " and " + | ||||
644 | EndLabel->getName()); | ||||
645 | Asm->emitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding); | ||||
646 | |||||
647 | // Offset of the landing pad relative to the start of the landing pad | ||||
648 | // fragment. | ||||
649 | if (!S.LPad) { | ||||
650 | if (VerboseAsm) | ||||
651 | Asm->OutStreamer->AddComment(" has no landing pad"); | ||||
652 | Asm->emitCallSiteValue(0, CallSiteEncoding); | ||||
653 | } else { | ||||
654 | if (VerboseAsm
| ||||
655 | Asm->OutStreamer->AddComment(Twine(" jumps to ") + | ||||
656 | S.LPad->LandingPadLabel->getName()); | ||||
657 | Asm->emitCallSiteOffset(S.LPad->LandingPadLabel, | ||||
658 | LandingPadRange->FragmentBeginLabel, | ||||
| |||||
659 | CallSiteEncoding); | ||||
660 | } | ||||
661 | |||||
662 | // Offset of the first associated action record, relative to the start | ||||
663 | // of the action table. This value is biased by 1 (1 indicates the start | ||||
664 | // of the action table), and 0 indicates that there are no actions. | ||||
665 | if (VerboseAsm) { | ||||
666 | if (S.Action == 0) | ||||
667 | Asm->OutStreamer->AddComment(" On action: cleanup"); | ||||
668 | else | ||||
669 | Asm->OutStreamer->AddComment(" On action: " + | ||||
670 | Twine((S.Action - 1) / 2 + 1)); | ||||
671 | } | ||||
672 | Asm->emitULEB128(S.Action); | ||||
673 | } | ||||
674 | } | ||||
675 | Asm->OutStreamer->emitLabel(CstEndLabel); | ||||
676 | } | ||||
677 | |||||
678 | // Emit the Action Table. | ||||
679 | int Entry = 0; | ||||
680 | for (SmallVectorImpl<ActionEntry>::const_iterator | ||||
681 | I = Actions.begin(), E = Actions.end(); I != E; ++I) { | ||||
682 | const ActionEntry &Action = *I; | ||||
683 | |||||
684 | if (VerboseAsm) { | ||||
685 | // Emit comments that decode the action table. | ||||
686 | Asm->OutStreamer->AddComment(">> Action Record " + Twine(++Entry) + " <<"); | ||||
687 | } | ||||
688 | |||||
689 | // Type Filter | ||||
690 | // | ||||
691 | // Used by the runtime to match the type of the thrown exception to the | ||||
692 | // type of the catch clauses or the types in the exception specification. | ||||
693 | if (VerboseAsm) { | ||||
694 | if (Action.ValueForTypeID > 0) | ||||
695 | Asm->OutStreamer->AddComment(" Catch TypeInfo " + | ||||
696 | Twine(Action.ValueForTypeID)); | ||||
697 | else if (Action.ValueForTypeID < 0) | ||||
698 | Asm->OutStreamer->AddComment(" Filter TypeInfo " + | ||||
699 | Twine(Action.ValueForTypeID)); | ||||
700 | else | ||||
701 | Asm->OutStreamer->AddComment(" Cleanup"); | ||||
702 | } | ||||
703 | Asm->emitSLEB128(Action.ValueForTypeID); | ||||
704 | |||||
705 | // Action Record | ||||
706 | if (VerboseAsm) { | ||||
707 | if (Action.Previous == unsigned(-1)) { | ||||
708 | Asm->OutStreamer->AddComment(" No further actions"); | ||||
709 | } else { | ||||
710 | Asm->OutStreamer->AddComment(" Continue to action " + | ||||
711 | Twine(Action.Previous + 1)); | ||||
712 | } | ||||
713 | } | ||||
714 | Asm->emitSLEB128(Action.NextAction); | ||||
715 | } | ||||
716 | |||||
717 | if (HaveTTData) { | ||||
718 | Asm->emitAlignment(Align(4)); | ||||
719 | emitTypeInfos(TTypeEncoding, TTBaseLabel); | ||||
720 | } | ||||
721 | |||||
722 | Asm->emitAlignment(Align(4)); | ||||
723 | return GCCETSym; | ||||
724 | } | ||||
725 | |||||
726 | void EHStreamer::emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) { | ||||
727 | const MachineFunction *MF = Asm->MF; | ||||
728 | const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos(); | ||||
729 | const std::vector<unsigned> &FilterIds = MF->getFilterIds(); | ||||
730 | |||||
731 | const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); | ||||
732 | |||||
733 | int Entry = 0; | ||||
734 | // Emit the Catch TypeInfos. | ||||
735 | if (VerboseAsm && !TypeInfos.empty()) { | ||||
736 | Asm->OutStreamer->AddComment(">> Catch TypeInfos <<"); | ||||
737 | Asm->OutStreamer->AddBlankLine(); | ||||
738 | Entry = TypeInfos.size(); | ||||
739 | } | ||||
740 | |||||
741 | for (const GlobalValue *GV : make_range(TypeInfos.rbegin(), | ||||
742 | TypeInfos.rend())) { | ||||
743 | if (VerboseAsm) | ||||
744 | Asm->OutStreamer->AddComment("TypeInfo " + Twine(Entry--)); | ||||
745 | Asm->emitTTypeReference(GV, TTypeEncoding); | ||||
746 | } | ||||
747 | |||||
748 | Asm->OutStreamer->emitLabel(TTBaseLabel); | ||||
749 | |||||
750 | // Emit the Exception Specifications. | ||||
751 | if (VerboseAsm && !FilterIds.empty()) { | ||||
752 | Asm->OutStreamer->AddComment(">> Filter TypeInfos <<"); | ||||
753 | Asm->OutStreamer->AddBlankLine(); | ||||
754 | Entry = 0; | ||||
755 | } | ||||
756 | for (std::vector<unsigned>::const_iterator | ||||
757 | I = FilterIds.begin(), E = FilterIds.end(); I < E; ++I) { | ||||
758 | unsigned TypeID = *I; | ||||
759 | if (VerboseAsm) { | ||||
760 | --Entry; | ||||
761 | if (isFilterEHSelector(TypeID)) | ||||
762 | Asm->OutStreamer->AddComment("FilterInfo " + Twine(Entry)); | ||||
763 | } | ||||
764 | |||||
765 | Asm->emitULEB128(TypeID); | ||||
766 | } | ||||
767 | } |