File: | tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp |
Warning: | line 351, column 5 Forming reference to null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -------------*- C++ -*-===// | |||
2 | // | |||
3 | // The LLVM Linker | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | /// | |||
10 | /// \file A pass to convert MachO's __compact_unwind sections into the final | |||
11 | /// __unwind_info format used during runtime. See | |||
12 | /// mach-o/compact_unwind_encoding.h for more details on the formats involved. | |||
13 | /// | |||
14 | //===----------------------------------------------------------------------===// | |||
15 | ||||
16 | #include "ArchHandler.h" | |||
17 | #include "File.h" | |||
18 | #include "MachONormalizedFileBinaryUtils.h" | |||
19 | #include "MachOPasses.h" | |||
20 | #include "lld/Common/LLVM.h" | |||
21 | #include "lld/Core/DefinedAtom.h" | |||
22 | #include "lld/Core/File.h" | |||
23 | #include "lld/Core/Reference.h" | |||
24 | #include "lld/Core/Simple.h" | |||
25 | #include "llvm/ADT/DenseMap.h" | |||
26 | #include "llvm/Support/Debug.h" | |||
27 | #include "llvm/Support/Format.h" | |||
28 | ||||
29 | #define DEBUG_TYPE"macho-compact-unwind" "macho-compact-unwind" | |||
30 | ||||
31 | namespace lld { | |||
32 | namespace mach_o { | |||
33 | ||||
34 | namespace { | |||
35 | struct CompactUnwindEntry { | |||
36 | const Atom *rangeStart; | |||
37 | const Atom *personalityFunction; | |||
38 | const Atom *lsdaLocation; | |||
39 | const Atom *ehFrame; | |||
40 | ||||
41 | uint32_t rangeLength; | |||
42 | ||||
43 | // There are 3 types of compact unwind entry, distinguished by the encoding | |||
44 | // value: 0 indicates a function with no unwind info; | |||
45 | // _archHandler.dwarfCompactUnwindType() indicates that the entry defers to | |||
46 | // __eh_frame, and that the ehFrame entry will be valid; any other value is a | |||
47 | // real compact unwind entry -- personalityFunction will be set and | |||
48 | // lsdaLocation may be. | |||
49 | uint32_t encoding; | |||
50 | ||||
51 | CompactUnwindEntry(const DefinedAtom *function) | |||
52 | : rangeStart(function), personalityFunction(nullptr), | |||
53 | lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(function->size()), | |||
54 | encoding(0) {} | |||
55 | ||||
56 | CompactUnwindEntry() | |||
57 | : rangeStart(nullptr), personalityFunction(nullptr), | |||
58 | lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(0), encoding(0) {} | |||
59 | }; | |||
60 | ||||
61 | struct UnwindInfoPage { | |||
62 | ArrayRef<CompactUnwindEntry> entries; | |||
63 | }; | |||
64 | } | |||
65 | ||||
66 | class UnwindInfoAtom : public SimpleDefinedAtom { | |||
67 | public: | |||
68 | UnwindInfoAtom(ArchHandler &archHandler, const File &file, bool isBig, | |||
69 | std::vector<const Atom *> &personalities, | |||
70 | std::vector<uint32_t> &commonEncodings, | |||
71 | std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs) | |||
72 | : SimpleDefinedAtom(file), _archHandler(archHandler), | |||
73 | _commonEncodingsOffset(7 * sizeof(uint32_t)), | |||
74 | _personalityArrayOffset(_commonEncodingsOffset + | |||
75 | commonEncodings.size() * sizeof(uint32_t)), | |||
76 | _topLevelIndexOffset(_personalityArrayOffset + | |||
77 | personalities.size() * sizeof(uint32_t)), | |||
78 | _lsdaIndexOffset(_topLevelIndexOffset + | |||
79 | 3 * (pages.size() + 1) * sizeof(uint32_t)), | |||
80 | _firstPageOffset(_lsdaIndexOffset + 2 * numLSDAs * sizeof(uint32_t)), | |||
81 | _isBig(isBig) { | |||
82 | ||||
83 | addHeader(commonEncodings.size(), personalities.size(), pages.size()); | |||
84 | addCommonEncodings(commonEncodings); | |||
85 | addPersonalityFunctions(personalities); | |||
86 | addTopLevelIndexes(pages); | |||
87 | addLSDAIndexes(pages, numLSDAs); | |||
88 | addSecondLevelPages(pages); | |||
89 | } | |||
90 | ||||
91 | ~UnwindInfoAtom() override = default; | |||
92 | ||||
93 | ContentType contentType() const override { | |||
94 | return DefinedAtom::typeProcessedUnwindInfo; | |||
95 | } | |||
96 | ||||
97 | Alignment alignment() const override { return 4; } | |||
98 | ||||
99 | uint64_t size() const override { return _contents.size(); } | |||
100 | ||||
101 | ContentPermissions permissions() const override { | |||
102 | return DefinedAtom::permR__; | |||
103 | } | |||
104 | ||||
105 | ArrayRef<uint8_t> rawContent() const override { return _contents; } | |||
106 | ||||
107 | void addHeader(uint32_t numCommon, uint32_t numPersonalities, | |||
108 | uint32_t numPages) { | |||
109 | using normalized::write32; | |||
110 | ||||
111 | uint32_t headerSize = 7 * sizeof(uint32_t); | |||
112 | _contents.resize(headerSize); | |||
113 | ||||
114 | uint8_t *headerEntries = _contents.data(); | |||
115 | // version | |||
116 | write32(headerEntries, 1, _isBig); | |||
117 | // commonEncodingsArraySectionOffset | |||
118 | write32(headerEntries + sizeof(uint32_t), _commonEncodingsOffset, _isBig); | |||
119 | // commonEncodingsArrayCount | |||
120 | write32(headerEntries + 2 * sizeof(uint32_t), numCommon, _isBig); | |||
121 | // personalityArraySectionOffset | |||
122 | write32(headerEntries + 3 * sizeof(uint32_t), _personalityArrayOffset, | |||
123 | _isBig); | |||
124 | // personalityArrayCount | |||
125 | write32(headerEntries + 4 * sizeof(uint32_t), numPersonalities, _isBig); | |||
126 | // indexSectionOffset | |||
127 | write32(headerEntries + 5 * sizeof(uint32_t), _topLevelIndexOffset, _isBig); | |||
128 | // indexCount | |||
129 | write32(headerEntries + 6 * sizeof(uint32_t), numPages + 1, _isBig); | |||
130 | } | |||
131 | ||||
132 | /// Add the list of common encodings to the section; this is simply an array | |||
133 | /// of uint32_t compact values. Size has already been specified in the header. | |||
134 | void addCommonEncodings(std::vector<uint32_t> &commonEncodings) { | |||
135 | using normalized::write32; | |||
136 | ||||
137 | _contents.resize(_commonEncodingsOffset + | |||
138 | commonEncodings.size() * sizeof(uint32_t)); | |||
139 | uint8_t *commonEncodingsArea = | |||
140 | reinterpret_cast<uint8_t *>(_contents.data() + _commonEncodingsOffset); | |||
141 | ||||
142 | for (uint32_t encoding : commonEncodings) { | |||
143 | write32(commonEncodingsArea, encoding, _isBig); | |||
144 | commonEncodingsArea += sizeof(uint32_t); | |||
145 | } | |||
146 | } | |||
147 | ||||
148 | void addPersonalityFunctions(std::vector<const Atom *> personalities) { | |||
149 | _contents.resize(_personalityArrayOffset + | |||
150 | personalities.size() * sizeof(uint32_t)); | |||
151 | ||||
152 | for (unsigned i = 0; i < personalities.size(); ++i) | |||
153 | addImageReferenceIndirect(_personalityArrayOffset + i * sizeof(uint32_t), | |||
154 | personalities[i]); | |||
155 | } | |||
156 | ||||
157 | void addTopLevelIndexes(std::vector<UnwindInfoPage> &pages) { | |||
158 | using normalized::write32; | |||
159 | ||||
160 | uint32_t numIndexes = pages.size() + 1; | |||
161 | _contents.resize(_topLevelIndexOffset + numIndexes * 3 * sizeof(uint32_t)); | |||
162 | ||||
163 | uint32_t pageLoc = _firstPageOffset; | |||
164 | ||||
165 | // The most difficult job here is calculating the LSDAs; everything else | |||
166 | // follows fairly naturally, but we can't state where the first | |||
167 | uint8_t *indexData = &_contents[_topLevelIndexOffset]; | |||
168 | uint32_t numLSDAs = 0; | |||
169 | for (unsigned i = 0; i < pages.size(); ++i) { | |||
170 | // functionOffset | |||
171 | addImageReference(_topLevelIndexOffset + 3 * i * sizeof(uint32_t), | |||
172 | pages[i].entries[0].rangeStart); | |||
173 | // secondLevelPagesSectionOffset | |||
174 | write32(indexData + (3 * i + 1) * sizeof(uint32_t), pageLoc, _isBig); | |||
175 | write32(indexData + (3 * i + 2) * sizeof(uint32_t), | |||
176 | _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig); | |||
177 | ||||
178 | for (auto &entry : pages[i].entries) | |||
179 | if (entry.lsdaLocation) | |||
180 | ++numLSDAs; | |||
181 | } | |||
182 | ||||
183 | // Finally, write out the final sentinel index | |||
184 | auto &finalEntry = pages[pages.size() - 1].entries.back(); | |||
185 | addImageReference(_topLevelIndexOffset + | |||
186 | 3 * pages.size() * sizeof(uint32_t), | |||
187 | finalEntry.rangeStart, finalEntry.rangeLength); | |||
188 | // secondLevelPagesSectionOffset => 0 | |||
189 | write32(indexData + (3 * pages.size() + 2) * sizeof(uint32_t), | |||
190 | _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig); | |||
191 | } | |||
192 | ||||
193 | void addLSDAIndexes(std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs) { | |||
194 | _contents.resize(_lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t)); | |||
195 | ||||
196 | uint32_t curOffset = _lsdaIndexOffset; | |||
197 | for (auto &page : pages) { | |||
198 | for (auto &entry : page.entries) { | |||
199 | if (!entry.lsdaLocation) | |||
200 | continue; | |||
201 | ||||
202 | addImageReference(curOffset, entry.rangeStart); | |||
203 | addImageReference(curOffset + sizeof(uint32_t), entry.lsdaLocation); | |||
204 | curOffset += 2 * sizeof(uint32_t); | |||
205 | } | |||
206 | } | |||
207 | } | |||
208 | ||||
209 | void addSecondLevelPages(std::vector<UnwindInfoPage> &pages) { | |||
210 | for (auto &page : pages) { | |||
211 | addRegularSecondLevelPage(page); | |||
212 | } | |||
213 | } | |||
214 | ||||
215 | void addRegularSecondLevelPage(const UnwindInfoPage &page) { | |||
216 | uint32_t curPageOffset = _contents.size(); | |||
217 | const int16_t headerSize = sizeof(uint32_t) + 2 * sizeof(uint16_t); | |||
218 | uint32_t curPageSize = | |||
219 | headerSize + 2 * page.entries.size() * sizeof(uint32_t); | |||
220 | _contents.resize(curPageOffset + curPageSize); | |||
221 | ||||
222 | using normalized::write32; | |||
223 | using normalized::write16; | |||
224 | // 2 => regular page | |||
225 | write32(&_contents[curPageOffset], 2, _isBig); | |||
226 | // offset of 1st entry | |||
227 | write16(&_contents[curPageOffset + 4], headerSize, _isBig); | |||
228 | write16(&_contents[curPageOffset + 6], page.entries.size(), _isBig); | |||
229 | ||||
230 | uint32_t pagePos = curPageOffset + headerSize; | |||
231 | for (auto &entry : page.entries) { | |||
232 | addImageReference(pagePos, entry.rangeStart); | |||
233 | ||||
234 | write32(_contents.data() + pagePos + sizeof(uint32_t), entry.encoding, | |||
235 | _isBig); | |||
236 | if ((entry.encoding & 0x0f000000U) == | |||
237 | _archHandler.dwarfCompactUnwindType()) | |||
238 | addEhFrameReference(pagePos + sizeof(uint32_t), entry.ehFrame); | |||
239 | ||||
240 | pagePos += 2 * sizeof(uint32_t); | |||
241 | } | |||
242 | } | |||
243 | ||||
244 | void addEhFrameReference(uint32_t offset, const Atom *dest, | |||
245 | Reference::Addend addend = 0) { | |||
246 | addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(), | |||
247 | _archHandler.unwindRefToEhFrameKind(), offset, dest, addend); | |||
248 | } | |||
249 | ||||
250 | void addImageReference(uint32_t offset, const Atom *dest, | |||
251 | Reference::Addend addend = 0) { | |||
252 | addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(), | |||
253 | _archHandler.imageOffsetKind(), offset, dest, addend); | |||
254 | } | |||
255 | ||||
256 | void addImageReferenceIndirect(uint32_t offset, const Atom *dest) { | |||
257 | addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(), | |||
258 | _archHandler.imageOffsetKindIndirect(), offset, dest, 0); | |||
259 | } | |||
260 | ||||
261 | private: | |||
262 | mach_o::ArchHandler &_archHandler; | |||
263 | std::vector<uint8_t> _contents; | |||
264 | uint32_t _commonEncodingsOffset; | |||
265 | uint32_t _personalityArrayOffset; | |||
266 | uint32_t _topLevelIndexOffset; | |||
267 | uint32_t _lsdaIndexOffset; | |||
268 | uint32_t _firstPageOffset; | |||
269 | bool _isBig; | |||
270 | }; | |||
271 | ||||
272 | /// Pass for instantiating and optimizing GOT slots. | |||
273 | /// | |||
274 | class CompactUnwindPass : public Pass { | |||
275 | public: | |||
276 | CompactUnwindPass(const MachOLinkingContext &context) | |||
277 | : _ctx(context), _archHandler(_ctx.archHandler()), | |||
278 | _file(*_ctx.make_file<MachOFile>("<mach-o Compact Unwind Pass>")), | |||
279 | _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) { | |||
280 | _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); | |||
281 | } | |||
282 | ||||
283 | private: | |||
284 | llvm::Error perform(SimpleFile &mergedFile) override { | |||
285 | LLVM_DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << "MachO Compact Unwind pass\n" ; } } while (false); | |||
286 | ||||
287 | std::map<const Atom *, CompactUnwindEntry> unwindLocs; | |||
288 | std::map<const Atom *, const Atom *> dwarfFrames; | |||
289 | std::vector<const Atom *> personalities; | |||
290 | uint32_t numLSDAs = 0; | |||
291 | ||||
292 | // First collect all __compact_unwind and __eh_frame entries, addressable by | |||
293 | // the function referred to. | |||
294 | collectCompactUnwindEntries(mergedFile, unwindLocs, personalities, | |||
295 | numLSDAs); | |||
296 | ||||
297 | collectDwarfFrameEntries(mergedFile, dwarfFrames); | |||
298 | ||||
299 | // Skip rest of pass if no unwind info. | |||
300 | if (unwindLocs.empty() && dwarfFrames.empty()) | |||
| ||||
301 | return llvm::Error::success(); | |||
302 | ||||
303 | // FIXME: if there are more than 4 personality functions then we need to | |||
304 | // defer to DWARF info for the ones we don't put in the list. They should | |||
305 | // also probably be sorted by frequency. | |||
306 | assert(personalities.size() <= 4)((personalities.size() <= 4) ? static_cast<void> (0) : __assert_fail ("personalities.size() <= 4", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp" , 306, __PRETTY_FUNCTION__)); | |||
307 | ||||
308 | // TODO: Find commmon encodings for use by compressed pages. | |||
309 | std::vector<uint32_t> commonEncodings; | |||
310 | ||||
311 | // Now sort the entries by final address and fixup the compact encoding to | |||
312 | // its final form (i.e. set personality function bits & create DWARF | |||
313 | // references where needed). | |||
314 | std::vector<CompactUnwindEntry> unwindInfos = createUnwindInfoEntries( | |||
315 | mergedFile, unwindLocs, personalities, dwarfFrames); | |||
316 | ||||
317 | // Remove any unused eh-frame atoms. | |||
318 | pruneUnusedEHFrames(mergedFile, unwindInfos, unwindLocs, dwarfFrames); | |||
319 | ||||
320 | // Finally, we can start creating pages based on these entries. | |||
321 | ||||
322 | LLVM_DEBUG(llvm::dbgs() << " Splitting entries into pages\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Splitting entries into pages\n" ; } } while (false); | |||
323 | // FIXME: we split the entries into pages naively: lots of 4k pages followed | |||
324 | // by a small one. ld64 tried to minimize space and align them to real 4k | |||
325 | // boundaries. That might be worth doing, or perhaps we could perform some | |||
326 | // minor balancing for expected number of lookups. | |||
327 | std::vector<UnwindInfoPage> pages; | |||
328 | auto remainingInfos = llvm::makeArrayRef(unwindInfos); | |||
329 | do { | |||
330 | pages.push_back(UnwindInfoPage()); | |||
331 | ||||
332 | // FIXME: we only create regular pages at the moment. These can hold up to | |||
333 | // 1021 entries according to the documentation. | |||
334 | unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size()); | |||
335 | ||||
336 | pages.back().entries = remainingInfos.slice(0, entriesInPage); | |||
337 | remainingInfos = remainingInfos.slice(entriesInPage); | |||
338 | ||||
339 | LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Page from " << pages.back().entries[0].rangeStart->name() << " to " << pages.back().entries.back().rangeStart->name () << " + " << llvm::format("0x%x", pages.back(). entries.back().rangeLength) << " has " << entriesInPage << " entries\n"; } } while (false) | |||
340 | << " Page from "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Page from " << pages.back().entries[0].rangeStart->name() << " to " << pages.back().entries.back().rangeStart->name () << " + " << llvm::format("0x%x", pages.back(). entries.back().rangeLength) << " has " << entriesInPage << " entries\n"; } } while (false) | |||
341 | << pages.back().entries[0].rangeStart->name() << " to "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Page from " << pages.back().entries[0].rangeStart->name() << " to " << pages.back().entries.back().rangeStart->name () << " + " << llvm::format("0x%x", pages.back(). entries.back().rangeLength) << " has " << entriesInPage << " entries\n"; } } while (false) | |||
342 | << pages.back().entries.back().rangeStart->name() << " + "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Page from " << pages.back().entries[0].rangeStart->name() << " to " << pages.back().entries.back().rangeStart->name () << " + " << llvm::format("0x%x", pages.back(). entries.back().rangeLength) << " has " << entriesInPage << " entries\n"; } } while (false) | |||
343 | << llvm::format("0x%x",do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Page from " << pages.back().entries[0].rangeStart->name() << " to " << pages.back().entries.back().rangeStart->name () << " + " << llvm::format("0x%x", pages.back(). entries.back().rangeLength) << " has " << entriesInPage << " entries\n"; } } while (false) | |||
344 | pages.back().entries.back().rangeLength)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Page from " << pages.back().entries[0].rangeStart->name() << " to " << pages.back().entries.back().rangeStart->name () << " + " << llvm::format("0x%x", pages.back(). entries.back().rangeLength) << " has " << entriesInPage << " entries\n"; } } while (false) | |||
345 | << " has " << entriesInPage << " entries\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Page from " << pages.back().entries[0].rangeStart->name() << " to " << pages.back().entries.back().rangeStart->name () << " + " << llvm::format("0x%x", pages.back(). entries.back().rangeLength) << " has " << entriesInPage << " entries\n"; } } while (false); | |||
346 | } while (!remainingInfos.empty()); | |||
347 | ||||
348 | auto *unwind = new (_file.allocator()) | |||
349 | UnwindInfoAtom(_archHandler, _file, _isBig, personalities, | |||
350 | commonEncodings, pages, numLSDAs); | |||
351 | mergedFile.addAtom(*unwind); | |||
| ||||
352 | ||||
353 | // Finally, remove all __compact_unwind atoms now that we've processed them. | |||
354 | mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) { | |||
355 | return atom->contentType() == DefinedAtom::typeCompactUnwindInfo; | |||
356 | }); | |||
357 | ||||
358 | return llvm::Error::success(); | |||
359 | } | |||
360 | ||||
361 | void collectCompactUnwindEntries( | |||
362 | const SimpleFile &mergedFile, | |||
363 | std::map<const Atom *, CompactUnwindEntry> &unwindLocs, | |||
364 | std::vector<const Atom *> &personalities, uint32_t &numLSDAs) { | |||
365 | LLVM_DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Collecting __compact_unwind entries\n" ; } } while (false); | |||
366 | ||||
367 | for (const DefinedAtom *atom : mergedFile.defined()) { | |||
368 | if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo) | |||
369 | continue; | |||
370 | ||||
371 | auto unwindEntry = extractCompactUnwindEntry(atom); | |||
372 | unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry)); | |||
373 | ||||
374 | LLVM_DEBUG(llvm::dbgs() << " Entry for "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name() << ", encoding=" << llvm::format("0x%08x", unwindEntry.encoding); } } while (false) | |||
375 | << unwindEntry.rangeStart->name() << ", encoding="do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name() << ", encoding=" << llvm::format("0x%08x", unwindEntry.encoding); } } while (false) | |||
376 | << llvm::format("0x%08x", unwindEntry.encoding))do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name() << ", encoding=" << llvm::format("0x%08x", unwindEntry.encoding); } } while (false); | |||
377 | if (unwindEntry.personalityFunction) | |||
378 | LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << ", personality=" << unwindEntry.personalityFunction->name() << ", lsdaLoc=" << unwindEntry.lsdaLocation->name(); } } while (false) | |||
379 | << ", personality="do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << ", personality=" << unwindEntry.personalityFunction->name() << ", lsdaLoc=" << unwindEntry.lsdaLocation->name(); } } while (false) | |||
380 | << unwindEntry.personalityFunction->name()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << ", personality=" << unwindEntry.personalityFunction->name() << ", lsdaLoc=" << unwindEntry.lsdaLocation->name(); } } while (false) | |||
381 | << ", lsdaLoc=" << unwindEntry.lsdaLocation->name())do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << ", personality=" << unwindEntry.personalityFunction->name() << ", lsdaLoc=" << unwindEntry.lsdaLocation->name(); } } while (false); | |||
382 | LLVM_DEBUG(llvm::dbgs() << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << '\n'; } } while (false); | |||
383 | ||||
384 | // Count number of LSDAs we see, since we need to know how big the index | |||
385 | // will be while laying out the section. | |||
386 | if (unwindEntry.lsdaLocation) | |||
387 | ++numLSDAs; | |||
388 | ||||
389 | // Gather the personality functions now, so that they're in deterministic | |||
390 | // order (derived from the DefinedAtom order). | |||
391 | if (unwindEntry.personalityFunction) { | |||
392 | auto pFunc = std::find(personalities.begin(), personalities.end(), | |||
393 | unwindEntry.personalityFunction); | |||
394 | if (pFunc == personalities.end()) | |||
395 | personalities.push_back(unwindEntry.personalityFunction); | |||
396 | } | |||
397 | } | |||
398 | } | |||
399 | ||||
400 | CompactUnwindEntry extractCompactUnwindEntry(const DefinedAtom *atom) { | |||
401 | CompactUnwindEntry entry; | |||
402 | ||||
403 | for (const Reference *ref : *atom) { | |||
404 | switch (ref->offsetInAtom()) { | |||
405 | case 0: | |||
406 | // FIXME: there could legitimately be functions with multiple encoding | |||
407 | // entries. However, nothing produces them at the moment. | |||
408 | assert(ref->addend() == 0 && "unexpected offset into function")((ref->addend() == 0 && "unexpected offset into function" ) ? static_cast<void> (0) : __assert_fail ("ref->addend() == 0 && \"unexpected offset into function\"" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp" , 408, __PRETTY_FUNCTION__)); | |||
409 | entry.rangeStart = ref->target(); | |||
410 | break; | |||
411 | case 0x10: | |||
412 | assert(ref->addend() == 0 && "unexpected offset into personality fn")((ref->addend() == 0 && "unexpected offset into personality fn" ) ? static_cast<void> (0) : __assert_fail ("ref->addend() == 0 && \"unexpected offset into personality fn\"" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp" , 412, __PRETTY_FUNCTION__)); | |||
413 | entry.personalityFunction = ref->target(); | |||
414 | break; | |||
415 | case 0x18: | |||
416 | assert(ref->addend() == 0 && "unexpected offset into LSDA atom")((ref->addend() == 0 && "unexpected offset into LSDA atom" ) ? static_cast<void> (0) : __assert_fail ("ref->addend() == 0 && \"unexpected offset into LSDA atom\"" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp" , 416, __PRETTY_FUNCTION__)); | |||
417 | entry.lsdaLocation = ref->target(); | |||
418 | break; | |||
419 | } | |||
420 | } | |||
421 | ||||
422 | if (atom->rawContent().size() < 4 * sizeof(uint32_t)) | |||
423 | return entry; | |||
424 | ||||
425 | using normalized::read32; | |||
426 | entry.rangeLength = | |||
427 | read32(atom->rawContent().data() + 2 * sizeof(uint32_t), _isBig); | |||
428 | entry.encoding = | |||
429 | read32(atom->rawContent().data() + 3 * sizeof(uint32_t), _isBig); | |||
430 | return entry; | |||
431 | } | |||
432 | ||||
433 | void | |||
434 | collectDwarfFrameEntries(const SimpleFile &mergedFile, | |||
435 | std::map<const Atom *, const Atom *> &dwarfFrames) { | |||
436 | for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) { | |||
437 | if (ehFrameAtom->contentType() != DefinedAtom::typeCFI) | |||
438 | continue; | |||
439 | if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom)) | |||
440 | continue; | |||
441 | ||||
442 | if (const Atom *function = _archHandler.fdeTargetFunction(ehFrameAtom)) | |||
443 | dwarfFrames[function] = ehFrameAtom; | |||
444 | } | |||
445 | } | |||
446 | ||||
447 | /// Every atom defined in __TEXT,__text needs an entry in the final | |||
448 | /// __unwind_info section (in order). These comes from two sources: | |||
449 | /// + Input __compact_unwind sections where possible (after adding the | |||
450 | /// personality function offset which is only known now). | |||
451 | /// + A synthesised reference to __eh_frame if there's no __compact_unwind | |||
452 | /// or too many personality functions to be accommodated. | |||
453 | std::vector<CompactUnwindEntry> createUnwindInfoEntries( | |||
454 | const SimpleFile &mergedFile, | |||
455 | const std::map<const Atom *, CompactUnwindEntry> &unwindLocs, | |||
456 | const std::vector<const Atom *> &personalities, | |||
457 | const std::map<const Atom *, const Atom *> &dwarfFrames) { | |||
458 | std::vector<CompactUnwindEntry> unwindInfos; | |||
459 | ||||
460 | LLVM_DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Creating __unwind_info entries\n" ; } } while (false); | |||
461 | // The final order in the __unwind_info section must be derived from the | |||
462 | // order of typeCode atoms, since that's how they'll be put into the object | |||
463 | // file eventually (yuck!). | |||
464 | for (const DefinedAtom *atom : mergedFile.defined()) { | |||
465 | if (atom->contentType() != DefinedAtom::typeCode) | |||
466 | continue; | |||
467 | ||||
468 | unwindInfos.push_back(finalizeUnwindInfoEntryForAtom( | |||
469 | atom, unwindLocs, personalities, dwarfFrames)); | |||
470 | ||||
471 | LLVM_DEBUG(llvm::dbgs()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Entry for " << atom->name() << ", final encoding=" << llvm::format("0x%08x", unwindInfos.back().encoding) << '\n'; } } while (false) | |||
472 | << " Entry for " << atom->name() << ", final encoding="do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Entry for " << atom->name() << ", final encoding=" << llvm::format("0x%08x", unwindInfos.back().encoding) << '\n'; } } while (false) | |||
473 | << llvm::format("0x%08x", unwindInfos.back().encoding)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Entry for " << atom->name() << ", final encoding=" << llvm::format("0x%08x", unwindInfos.back().encoding) << '\n'; } } while (false) | |||
474 | << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("macho-compact-unwind")) { llvm::dbgs() << " Entry for " << atom->name() << ", final encoding=" << llvm::format("0x%08x", unwindInfos.back().encoding) << '\n'; } } while (false); | |||
475 | } | |||
476 | ||||
477 | return unwindInfos; | |||
478 | } | |||
479 | ||||
480 | /// Remove unused EH frames. | |||
481 | /// | |||
482 | /// An EH frame is considered unused if there is a corresponding compact | |||
483 | /// unwind atom that doesn't require the EH frame. | |||
484 | void pruneUnusedEHFrames( | |||
485 | SimpleFile &mergedFile, | |||
486 | const std::vector<CompactUnwindEntry> &unwindInfos, | |||
487 | const std::map<const Atom *, CompactUnwindEntry> &unwindLocs, | |||
488 | const std::map<const Atom *, const Atom *> &dwarfFrames) { | |||
489 | ||||
490 | // Worklist of all 'used' FDEs. | |||
491 | std::vector<const DefinedAtom *> usedDwarfWorklist; | |||
492 | ||||
493 | // We have to check two conditions when building the worklist: | |||
494 | // (1) EH frames used by compact unwind entries. | |||
495 | for (auto &entry : unwindInfos) | |||
496 | if (entry.ehFrame) | |||
497 | usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.ehFrame)); | |||
498 | ||||
499 | // (2) EH frames that reference functions with no corresponding compact | |||
500 | // unwind info. | |||
501 | for (auto &entry : dwarfFrames) | |||
502 | if (!unwindLocs.count(entry.first)) | |||
503 | usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.second)); | |||
504 | ||||
505 | // Add all transitively referenced CFI atoms by processing the worklist. | |||
506 | std::set<const Atom *> usedDwarfFrames; | |||
507 | while (!usedDwarfWorklist.empty()) { | |||
508 | const DefinedAtom *cfiAtom = usedDwarfWorklist.back(); | |||
509 | usedDwarfWorklist.pop_back(); | |||
510 | usedDwarfFrames.insert(cfiAtom); | |||
511 | for (const auto *ref : *cfiAtom) { | |||
512 | const DefinedAtom *cfiTarget = dyn_cast<DefinedAtom>(ref->target()); | |||
513 | if (cfiTarget->contentType() == DefinedAtom::typeCFI) | |||
514 | usedDwarfWorklist.push_back(cfiTarget); | |||
515 | } | |||
516 | } | |||
517 | ||||
518 | // Finally, delete all unreferenced CFI atoms. | |||
519 | mergedFile.removeDefinedAtomsIf([&](const DefinedAtom *atom) { | |||
520 | if ((atom->contentType() == DefinedAtom::typeCFI) && | |||
521 | !usedDwarfFrames.count(atom)) | |||
522 | return true; | |||
523 | return false; | |||
524 | }); | |||
525 | } | |||
526 | ||||
527 | CompactUnwindEntry finalizeUnwindInfoEntryForAtom( | |||
528 | const DefinedAtom *function, | |||
529 | const std::map<const Atom *, CompactUnwindEntry> &unwindLocs, | |||
530 | const std::vector<const Atom *> &personalities, | |||
531 | const std::map<const Atom *, const Atom *> &dwarfFrames) { | |||
532 | auto unwindLoc = unwindLocs.find(function); | |||
533 | ||||
534 | CompactUnwindEntry entry; | |||
535 | if (unwindLoc == unwindLocs.end()) { | |||
536 | // Default entry has correct encoding (0 => no unwind), but we need to | |||
537 | // synthesise the function. | |||
538 | entry.rangeStart = function; | |||
539 | entry.rangeLength = function->size(); | |||
540 | } else | |||
541 | entry = unwindLoc->second; | |||
542 | ||||
543 | ||||
544 | // If there's no __compact_unwind entry, or it explicitly says to use | |||
545 | // __eh_frame, we need to try and fill in the correct DWARF atom. | |||
546 | if (entry.encoding == _archHandler.dwarfCompactUnwindType() || | |||
547 | entry.encoding == 0) { | |||
548 | auto dwarfFrame = dwarfFrames.find(function); | |||
549 | if (dwarfFrame != dwarfFrames.end()) { | |||
550 | entry.encoding = _archHandler.dwarfCompactUnwindType(); | |||
551 | entry.ehFrame = dwarfFrame->second; | |||
552 | } | |||
553 | } | |||
554 | ||||
555 | auto personality = std::find(personalities.begin(), personalities.end(), | |||
556 | entry.personalityFunction); | |||
557 | uint32_t personalityIdx = personality == personalities.end() | |||
558 | ? 0 | |||
559 | : personality - personalities.begin() + 1; | |||
560 | ||||
561 | // FIXME: We should also use DWARF when there isn't enough room for the | |||
562 | // personality function in the compact encoding. | |||
563 | assert(personalityIdx < 4 && "too many personality functions")((personalityIdx < 4 && "too many personality functions" ) ? static_cast<void> (0) : __assert_fail ("personalityIdx < 4 && \"too many personality functions\"" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp" , 563, __PRETTY_FUNCTION__)); | |||
564 | ||||
565 | entry.encoding |= personalityIdx << 28; | |||
566 | ||||
567 | if (entry.lsdaLocation) | |||
568 | entry.encoding |= 1U << 30; | |||
569 | ||||
570 | return entry; | |||
571 | } | |||
572 | ||||
573 | const MachOLinkingContext &_ctx; | |||
574 | mach_o::ArchHandler &_archHandler; | |||
575 | MachOFile &_file; | |||
576 | bool _isBig; | |||
577 | }; | |||
578 | ||||
579 | void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx) { | |||
580 | assert(ctx.needsCompactUnwindPass())((ctx.needsCompactUnwindPass()) ? static_cast<void> (0) : __assert_fail ("ctx.needsCompactUnwindPass()", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp" , 580, __PRETTY_FUNCTION__)); | |||
581 | pm.add(llvm::make_unique<CompactUnwindPass>(ctx)); | |||
582 | } | |||
583 | ||||
584 | } // end namesapce mach_o | |||
585 | } // end namesapce lld |