Bug Summary

File:tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
Warning:line 351, column 5
Forming reference to null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name CompactUnwindPass.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-8/lib/clang/8.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lld/lib/ReaderWriter/MachO -I /build/llvm-toolchain-snapshot-8~svn345461/tools/lld/lib/ReaderWriter/MachO -I /build/llvm-toolchain-snapshot-8~svn345461/tools/lld/include -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lld/include -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/include -I /build/llvm-toolchain-snapshot-8~svn345461/include -I /build/llvm-toolchain-snapshot-8~svn345461/tools/lld/lib/ReaderWriter/MachO/. -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/include/clang/8.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-8/lib/clang/8.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lld/lib/ReaderWriter/MachO -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-10-27-211344-32123-1 -x c++ /build/llvm-toolchain-snapshot-8~svn345461/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp -faddrsig
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
31namespace lld {
32namespace mach_o {
33
34namespace {
35struct 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
61struct UnwindInfoPage {
62 ArrayRef<CompactUnwindEntry> entries;
63};
64}
65
66class UnwindInfoAtom : public SimpleDefinedAtom {
67public:
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
261private:
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///
274class CompactUnwindPass : public Pass {
275public:
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
283private:
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())
1
Assuming the condition is false
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 {
3
Loop condition is false. Exiting loop
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());
2
Assuming the condition is false
347
348 auto *unwind = new (_file.allocator())
4
'unwind' initialized to a null pointer value
349 UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
350 commonEncodings, pages, numLSDAs);
351 mergedFile.addAtom(*unwind);
5
Forming reference to null pointer
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
579void 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