1 //===- SymbolTable.cpp ----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "SymbolTable.h"
10 #include "ConcatOutputSection.h"
11 #include "Config.h"
12 #include "InputFiles.h"
13 #include "InputSection.h"
14 #include "Symbols.h"
15 #include "SyntheticSections.h"
16 #include "lld/Common/ErrorHandler.h"
17 #include "lld/Common/Memory.h"
18 #include "llvm/Demangle/Demangle.h"
19
20 using namespace llvm;
21 using namespace lld;
22 using namespace lld::macho;
23
find(CachedHashStringRef cachedName)24 Symbol *SymbolTable::find(CachedHashStringRef cachedName) {
25 auto it = symMap.find(cachedName);
26 if (it == symMap.end())
27 return nullptr;
28 return symVector[it->second];
29 }
30
insert(StringRef name,const InputFile * file)31 std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
32 const InputFile *file) {
33 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
34
35 Symbol *sym;
36 if (!p.second) {
37 // Name already present in the symbol table.
38 sym = symVector[p.first->second];
39 } else {
40 // Name is a new symbol.
41 sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
42 symVector.push_back(sym);
43 }
44
45 sym->isUsedInRegularObj |= !file || isa<ObjFile>(file);
46 return {sym, p.second};
47 }
48
49 namespace {
50 struct DuplicateSymbolDiag {
51 // Pair containing source location and source file
52 const std::pair<std::string, std::string> src1;
53 const std::pair<std::string, std::string> src2;
54 const Symbol *sym;
55
DuplicateSymbolDiag__anonc612aba00111::DuplicateSymbolDiag56 DuplicateSymbolDiag(const std::pair<std::string, std::string> src1,
57 const std::pair<std::string, std::string> src2,
58 const Symbol *sym)
59 : src1(src1), src2(src2), sym(sym) {}
60 };
61 SmallVector<DuplicateSymbolDiag> dupSymDiags;
62 } // namespace
63
64 // Move symbols at \p fromOff in \p fromIsec into \p toIsec, unless that symbol
65 // is \p skip.
transplantSymbolsAtOffset(InputSection * fromIsec,InputSection * toIsec,Defined * skip,uint64_t fromOff,uint64_t toOff)66 static void transplantSymbolsAtOffset(InputSection *fromIsec,
67 InputSection *toIsec, Defined *skip,
68 uint64_t fromOff, uint64_t toOff) {
69 // Ensure the symbols will still be in address order after our insertions.
70 auto symSucceedsOff = [](uint64_t off, const Symbol *s) {
71 return cast<Defined>(s)->value > off;
72 };
73 assert(std::is_partitioned(toIsec->symbols.begin(), toIsec->symbols.end(),
74 [symSucceedsOff, toOff](const Symbol *s) {
75 return !symSucceedsOff(toOff, s);
76 }) &&
77 "Symbols in toIsec must be partitioned by toOff.");
78 auto insertIt = llvm::upper_bound(toIsec->symbols, toOff, symSucceedsOff);
79 llvm::erase_if(fromIsec->symbols, [&](Symbol *s) {
80 auto *d = cast<Defined>(s);
81 if (d->value != fromOff)
82 return false;
83 if (d != skip) {
84 // This repeated insertion will be quadratic unless insertIt is the end
85 // iterator. However, that is typically the case for files that have
86 // .subsections_via_symbols set.
87 insertIt = toIsec->symbols.insert(insertIt, d);
88 d->originalIsec = toIsec;
89 d->value = toOff;
90 // We don't want to have more than one unwindEntry at a given address, so
91 // drop the redundant ones. We We can safely drop the unwindEntries of
92 // the symbols in fromIsec since we will be adding another unwindEntry as
93 // we finish parsing toIsec's file. (We can assume that toIsec has its
94 // own unwindEntry because of the ODR.)
95 d->originalUnwindEntry = nullptr;
96 }
97 return true;
98 });
99 }
100
addDefined(StringRef name,InputFile * file,InputSection * isec,uint64_t value,uint64_t size,bool isWeakDef,bool isPrivateExtern,bool isReferencedDynamically,bool noDeadStrip,bool isWeakDefCanBeHidden)101 Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
102 InputSection *isec, uint64_t value,
103 uint64_t size, bool isWeakDef,
104 bool isPrivateExtern,
105 bool isReferencedDynamically, bool noDeadStrip,
106 bool isWeakDefCanBeHidden) {
107 bool overridesWeakDef = false;
108 auto [s, wasInserted] = insert(name, file);
109
110 assert(!file || !isa<BitcodeFile>(file) || !isec);
111
112 if (!wasInserted) {
113 if (auto *defined = dyn_cast<Defined>(s)) {
114 if (isWeakDef) {
115 // See further comment in createDefined() in InputFiles.cpp
116 if (defined->isWeakDef()) {
117 defined->privateExtern &= isPrivateExtern;
118 defined->weakDefCanBeHidden &= isWeakDefCanBeHidden;
119 defined->referencedDynamically |= isReferencedDynamically;
120 defined->noDeadStrip |= noDeadStrip;
121 }
122 if (auto concatIsec = dyn_cast_or_null<ConcatInputSection>(isec)) {
123 concatIsec->wasCoalesced = true;
124 // Any local symbols that alias the coalesced symbol should be moved
125 // into the prevailing section. Note that we have sorted the symbols
126 // in ObjFile::parseSymbols() such that extern weak symbols appear
127 // last, so we don't need to worry about subsequent symbols being
128 // added to an already-coalesced section.
129 if (defined->isec())
130 transplantSymbolsAtOffset(concatIsec, defined->isec(),
131 /*skip=*/nullptr, value, defined->value);
132 }
133 return defined;
134 }
135
136 if (defined->isWeakDef()) {
137 if (auto concatIsec =
138 dyn_cast_or_null<ConcatInputSection>(defined->isec())) {
139 concatIsec->wasCoalesced = true;
140 if (isec)
141 transplantSymbolsAtOffset(concatIsec, isec, defined, defined->value,
142 value);
143 }
144 } else {
145 std::string srcLoc1 = defined->getSourceLocation();
146 std::string srcLoc2 = isec ? isec->getSourceLocation(value) : "";
147 std::string srcFile1 = toString(defined->getFile());
148 std::string srcFile2 = toString(file);
149
150 dupSymDiags.push_back({make_pair(srcLoc1, srcFile1),
151 make_pair(srcLoc2, srcFile2), defined});
152 }
153
154 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
155 overridesWeakDef = !isWeakDef && dysym->isWeakDef();
156 dysym->unreference();
157 } else if (auto *undef = dyn_cast<Undefined>(s)) {
158 if (undef->wasBitcodeSymbol) {
159 auto objFile = dyn_cast<ObjFile>(file);
160 if (!objFile) {
161 // The file must be a native object file, as opposed to potentially
162 // being another bitcode file. A situation arises when some symbols
163 // are defined thru `module asm` and thus they are not present in the
164 // bitcode's symbol table. Consider bitcode modules `A`, `B`, and `C`.
165 // LTO compiles only `A` and `C`, since there's no explicit symbol
166 // reference to `B` other than a symbol from `A` via `module asm`.
167 // After LTO is finished, the missing symbol now appears in the
168 // resulting object file for `A`, which prematurely resolves another
169 // prevailing symbol with `B` that hasn't been compiled, instead of
170 // the resulting object for `C`. Consequently, an incorrect
171 // relocation is generated for the prevailing symbol.
172 assert(isa<BitcodeFile>(file) && "Bitcode file is expected.");
173 std::string message =
174 "The pending prevailing symbol(" + name.str() +
175 ") in the bitcode file(" + toString(undef->getFile()) +
176 ") is overridden by a non-native object (from bitcode): " +
177 toString(file);
178 error(message);
179 } else if (!objFile->builtFromBitcode) {
180 // Ideally, this should be an object file compiled from a bitcode
181 // file. However, this might not hold true if a LC linker option is
182 // used. In case LTO internalizes a prevailing hidden weak symbol,
183 // there's a situation where an unresolved prevailing symbol might be
184 // linked with the corresponding one from a native library, which is
185 // loaded later after LTO. Although this could potentially result in
186 // an ODR violation, we choose to permit this scenario as a warning.
187 std::string message = "The pending prevailing symbol(" + name.str() +
188 ") in the bitcode file(" +
189 toString(undef->getFile()) +
190 ") is overridden by a post-processed native "
191 "object (from native archive): " +
192 toString(file);
193 warn(message);
194 } else {
195 // Preserve the original bitcode file name (instead of using the
196 // object file name).
197 file = undef->getFile();
198 }
199 }
200 }
201 // Defined symbols take priority over other types of symbols, so in case
202 // of a name conflict, we fall through to the replaceSymbol() call below.
203 }
204
205 // With -flat_namespace, all extern symbols in dylibs are interposable.
206 bool interposable = ((config->namespaceKind == NamespaceKind::flat &&
207 config->outputType != MachO::MH_EXECUTE) ||
208 config->interposable) &&
209 !isPrivateExtern;
210 Defined *defined = replaceSymbol<Defined>(
211 s, name, file, isec, value, size, isWeakDef, /*isExternal=*/true,
212 isPrivateExtern, /*includeInSymtab=*/true, isReferencedDynamically,
213 noDeadStrip, overridesWeakDef, isWeakDefCanBeHidden, interposable);
214 return defined;
215 }
216
aliasDefined(Defined * src,StringRef target,InputFile * newFile,bool makePrivateExtern)217 Defined *SymbolTable::aliasDefined(Defined *src, StringRef target,
218 InputFile *newFile, bool makePrivateExtern) {
219 bool isPrivateExtern = makePrivateExtern || src->privateExtern;
220 return addDefined(target, newFile, src->isec(), src->value, src->size,
221 src->isWeakDef(), isPrivateExtern,
222 src->referencedDynamically, src->noDeadStrip,
223 src->weakDefCanBeHidden);
224 }
225
addUndefined(StringRef name,InputFile * file,bool isWeakRef)226 Symbol *SymbolTable::addUndefined(StringRef name, InputFile *file,
227 bool isWeakRef) {
228 auto [s, wasInserted] = insert(name, file);
229
230 RefState refState = isWeakRef ? RefState::Weak : RefState::Strong;
231
232 if (wasInserted)
233 replaceSymbol<Undefined>(s, name, file, refState,
234 /*wasBitcodeSymbol=*/false);
235 else if (auto *lazy = dyn_cast<LazyArchive>(s))
236 lazy->fetchArchiveMember();
237 else if (isa<LazyObject>(s))
238 extract(*s->getFile(), s->getName());
239 else if (auto *dynsym = dyn_cast<DylibSymbol>(s))
240 dynsym->reference(refState);
241 else if (auto *undefined = dyn_cast<Undefined>(s))
242 undefined->refState = std::max(undefined->refState, refState);
243 return s;
244 }
245
addCommon(StringRef name,InputFile * file,uint64_t size,uint32_t align,bool isPrivateExtern)246 Symbol *SymbolTable::addCommon(StringRef name, InputFile *file, uint64_t size,
247 uint32_t align, bool isPrivateExtern) {
248 auto [s, wasInserted] = insert(name, file);
249
250 if (!wasInserted) {
251 if (auto *common = dyn_cast<CommonSymbol>(s)) {
252 if (size < common->size)
253 return s;
254 } else if (isa<Defined>(s)) {
255 return s;
256 }
257 // Common symbols take priority over all non-Defined symbols, so in case of
258 // a name conflict, we fall through to the replaceSymbol() call below.
259 }
260
261 replaceSymbol<CommonSymbol>(s, name, file, size, align, isPrivateExtern);
262 return s;
263 }
264
addDylib(StringRef name,DylibFile * file,bool isWeakDef,bool isTlv)265 Symbol *SymbolTable::addDylib(StringRef name, DylibFile *file, bool isWeakDef,
266 bool isTlv) {
267 auto [s, wasInserted] = insert(name, file);
268
269 RefState refState = RefState::Unreferenced;
270 if (!wasInserted) {
271 if (auto *defined = dyn_cast<Defined>(s)) {
272 if (isWeakDef && !defined->isWeakDef())
273 defined->overridesWeakDef = true;
274 } else if (auto *undefined = dyn_cast<Undefined>(s)) {
275 refState = undefined->refState;
276 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
277 refState = dysym->getRefState();
278 }
279 }
280
281 bool isDynamicLookup = file == nullptr;
282 if (wasInserted || isa<Undefined>(s) ||
283 (isa<DylibSymbol>(s) &&
284 ((!isWeakDef && s->isWeakDef()) ||
285 (!isDynamicLookup && cast<DylibSymbol>(s)->isDynamicLookup())))) {
286 if (auto *dynsym = dyn_cast<DylibSymbol>(s))
287 dynsym->unreference();
288 replaceSymbol<DylibSymbol>(s, file, name, isWeakDef, refState, isTlv);
289 }
290
291 return s;
292 }
293
addDynamicLookup(StringRef name)294 Symbol *SymbolTable::addDynamicLookup(StringRef name) {
295 return addDylib(name, /*file=*/nullptr, /*isWeakDef=*/false, /*isTlv=*/false);
296 }
297
addLazyArchive(StringRef name,ArchiveFile * file,const object::Archive::Symbol & sym)298 Symbol *SymbolTable::addLazyArchive(StringRef name, ArchiveFile *file,
299 const object::Archive::Symbol &sym) {
300 auto [s, wasInserted] = insert(name, file);
301
302 if (wasInserted) {
303 replaceSymbol<LazyArchive>(s, file, sym);
304 } else if (isa<Undefined>(s)) {
305 file->fetch(sym);
306 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
307 if (dysym->isWeakDef()) {
308 if (dysym->getRefState() != RefState::Unreferenced)
309 file->fetch(sym);
310 else
311 replaceSymbol<LazyArchive>(s, file, sym);
312 }
313 }
314 return s;
315 }
316
addLazyObject(StringRef name,InputFile & file)317 Symbol *SymbolTable::addLazyObject(StringRef name, InputFile &file) {
318 auto [s, wasInserted] = insert(name, &file);
319
320 if (wasInserted) {
321 replaceSymbol<LazyObject>(s, file, name);
322 } else if (isa<Undefined>(s)) {
323 extract(file, name);
324 } else if (auto *dysym = dyn_cast<DylibSymbol>(s)) {
325 if (dysym->isWeakDef()) {
326 if (dysym->getRefState() != RefState::Unreferenced)
327 extract(file, name);
328 else
329 replaceSymbol<LazyObject>(s, file, name);
330 }
331 }
332 return s;
333 }
334
addSynthetic(StringRef name,InputSection * isec,uint64_t value,bool isPrivateExtern,bool includeInSymtab,bool referencedDynamically)335 Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
336 uint64_t value, bool isPrivateExtern,
337 bool includeInSymtab,
338 bool referencedDynamically) {
339 assert(!isec || !isec->getFile()); // See makeSyntheticInputSection().
340 Defined *s = addDefined(name, /*file=*/nullptr, isec, value, /*size=*/0,
341 /*isWeakDef=*/false, isPrivateExtern,
342 referencedDynamically, /*noDeadStrip=*/false,
343 /*isWeakDefCanBeHidden=*/false);
344 s->includeInSymtab = includeInSymtab;
345 return s;
346 }
347
348 enum class Boundary {
349 Start,
350 End,
351 };
352
createBoundarySymbol(const Undefined & sym)353 static Defined *createBoundarySymbol(const Undefined &sym) {
354 return symtab->addSynthetic(
355 sym.getName(), /*isec=*/nullptr, /*value=*/-1, /*isPrivateExtern=*/true,
356 /*includeInSymtab=*/false, /*referencedDynamically=*/false);
357 }
358
handleSectionBoundarySymbol(const Undefined & sym,StringRef segSect,Boundary which)359 static void handleSectionBoundarySymbol(const Undefined &sym, StringRef segSect,
360 Boundary which) {
361 auto [segName, sectName] = segSect.split('$');
362
363 // Attach the symbol to any InputSection that will end up in the right
364 // OutputSection -- it doesn't matter which one we pick.
365 // Don't bother looking through inputSections for a matching
366 // ConcatInputSection -- we need to create ConcatInputSection for
367 // non-existing sections anyways, and that codepath works even if we should
368 // already have a ConcatInputSection with the right name.
369
370 OutputSection *osec = nullptr;
371 // This looks for __TEXT,__cstring etc.
372 for (SyntheticSection *ssec : syntheticSections)
373 if (ssec->segname == segName && ssec->name == sectName) {
374 osec = ssec->isec->parent;
375 break;
376 }
377
378 if (!osec) {
379 ConcatInputSection *isec = makeSyntheticInputSection(segName, sectName);
380
381 // This runs after markLive() and is only called for Undefineds that are
382 // live. Marking the isec live ensures an OutputSection is created that the
383 // start/end symbol can refer to.
384 assert(sym.isLive());
385 assert(isec->live);
386
387 // This runs after gatherInputSections(), so need to explicitly set parent
388 // and add to inputSections.
389 osec = isec->parent = ConcatOutputSection::getOrCreateForInput(isec);
390 inputSections.push_back(isec);
391 }
392
393 if (which == Boundary::Start)
394 osec->sectionStartSymbols.push_back(createBoundarySymbol(sym));
395 else
396 osec->sectionEndSymbols.push_back(createBoundarySymbol(sym));
397 }
398
handleSegmentBoundarySymbol(const Undefined & sym,StringRef segName,Boundary which)399 static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName,
400 Boundary which) {
401 OutputSegment *seg = getOrCreateOutputSegment(segName);
402 if (which == Boundary::Start)
403 seg->segmentStartSymbols.push_back(createBoundarySymbol(sym));
404 else
405 seg->segmentEndSymbols.push_back(createBoundarySymbol(sym));
406 }
407
408 // Try to find a definition for an undefined symbol.
409 // Returns true if a definition was found and no diagnostics are needed.
recoverFromUndefinedSymbol(const Undefined & sym)410 static bool recoverFromUndefinedSymbol(const Undefined &sym) {
411 // Handle start/end symbols.
412 StringRef name = sym.getName();
413 if (name.consume_front("section$start$")) {
414 handleSectionBoundarySymbol(sym, name, Boundary::Start);
415 return true;
416 }
417 if (name.consume_front("section$end$")) {
418 handleSectionBoundarySymbol(sym, name, Boundary::End);
419 return true;
420 }
421 if (name.consume_front("segment$start$")) {
422 handleSegmentBoundarySymbol(sym, name, Boundary::Start);
423 return true;
424 }
425 if (name.consume_front("segment$end$")) {
426 handleSegmentBoundarySymbol(sym, name, Boundary::End);
427 return true;
428 }
429
430 // Leave dtrace symbols, since we will handle them when we do the relocation
431 if (name.starts_with("___dtrace_"))
432 return true;
433
434 // Handle -U.
435 if (config->explicitDynamicLookups.count(sym.getName())) {
436 symtab->addDynamicLookup(sym.getName());
437 return true;
438 }
439
440 // Handle -undefined.
441 if (config->undefinedSymbolTreatment ==
442 UndefinedSymbolTreatment::dynamic_lookup ||
443 config->undefinedSymbolTreatment == UndefinedSymbolTreatment::suppress) {
444 symtab->addDynamicLookup(sym.getName());
445 return true;
446 }
447
448 // We do not return true here, as we still need to print diagnostics.
449 if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::warning)
450 symtab->addDynamicLookup(sym.getName());
451
452 return false;
453 }
454
455 namespace {
456 struct UndefinedDiag {
457 struct SectionAndOffset {
458 const InputSection *isec;
459 uint64_t offset;
460 };
461
462 std::vector<SectionAndOffset> codeReferences;
463 std::vector<std::string> otherReferences;
464 };
465
466 MapVector<const Undefined *, UndefinedDiag> undefs;
467 } // namespace
468
reportPendingDuplicateSymbols()469 void macho::reportPendingDuplicateSymbols() {
470 for (const auto &duplicate : dupSymDiags) {
471 if (!config->deadStripDuplicates || duplicate.sym->isLive()) {
472 std::string message =
473 "duplicate symbol: " + toString(*duplicate.sym) + "\n>>> defined in ";
474 if (!duplicate.src1.first.empty())
475 message += duplicate.src1.first + "\n>>> ";
476 message += duplicate.src1.second + "\n>>> defined in ";
477 if (!duplicate.src2.first.empty())
478 message += duplicate.src2.first + "\n>>> ";
479 error(message + duplicate.src2.second);
480 }
481 }
482 }
483
484 // Check whether the definition name def is a mangled function name that matches
485 // the reference name ref.
canSuggestExternCForCXX(StringRef ref,StringRef def)486 static bool canSuggestExternCForCXX(StringRef ref, StringRef def) {
487 llvm::ItaniumPartialDemangler d;
488 std::string name = def.str();
489 if (d.partialDemangle(name.c_str()))
490 return false;
491 char *buf = d.getFunctionName(nullptr, nullptr);
492 if (!buf)
493 return false;
494 bool ret = ref == buf;
495 free(buf);
496 return ret;
497 }
498
499 // Suggest an alternative spelling of an "undefined symbol" diagnostic. Returns
500 // the suggested symbol, which is either in the symbol table, or in the same
501 // file of sym.
getAlternativeSpelling(const Undefined & sym,std::string & preHint,std::string & postHint)502 static const Symbol *getAlternativeSpelling(const Undefined &sym,
503 std::string &preHint,
504 std::string &postHint) {
505 DenseMap<StringRef, const Symbol *> map;
506 if (sym.getFile() && sym.getFile()->kind() == InputFile::ObjKind) {
507 // Build a map of local defined symbols.
508 for (const Symbol *s : sym.getFile()->symbols)
509 if (auto *defined = dyn_cast_or_null<Defined>(s))
510 if (!defined->isExternal())
511 map.try_emplace(s->getName(), s);
512 }
513
514 auto suggest = [&](StringRef newName) -> const Symbol * {
515 // If defined locally.
516 if (const Symbol *s = map.lookup(newName))
517 return s;
518
519 // If in the symbol table and not undefined.
520 if (const Symbol *s = symtab->find(newName))
521 if (!isa<Undefined>(s))
522 return s;
523
524 return nullptr;
525 };
526
527 // This loop enumerates all strings of Levenshtein distance 1 as typo
528 // correction candidates and suggests the one that exists as a non-undefined
529 // symbol.
530 StringRef name = sym.getName();
531 for (size_t i = 0, e = name.size(); i != e + 1; ++i) {
532 // Insert a character before name[i].
533 std::string newName = (name.substr(0, i) + "0" + name.substr(i)).str();
534 for (char c = '0'; c <= 'z'; ++c) {
535 newName[i] = c;
536 if (const Symbol *s = suggest(newName))
537 return s;
538 }
539 if (i == e)
540 break;
541
542 // Substitute name[i].
543 newName = std::string(name);
544 for (char c = '0'; c <= 'z'; ++c) {
545 newName[i] = c;
546 if (const Symbol *s = suggest(newName))
547 return s;
548 }
549
550 // Transpose name[i] and name[i+1]. This is of edit distance 2 but it is
551 // common.
552 if (i + 1 < e) {
553 newName[i] = name[i + 1];
554 newName[i + 1] = name[i];
555 if (const Symbol *s = suggest(newName))
556 return s;
557 }
558
559 // Delete name[i].
560 newName = (name.substr(0, i) + name.substr(i + 1)).str();
561 if (const Symbol *s = suggest(newName))
562 return s;
563 }
564
565 // Case mismatch, e.g. Foo vs FOO.
566 for (auto &it : map)
567 if (name.equals_insensitive(it.first))
568 return it.second;
569 for (Symbol *sym : symtab->getSymbols())
570 if (!isa<Undefined>(sym) && name.equals_insensitive(sym->getName()))
571 return sym;
572
573 // The reference may be a mangled name while the definition is not. Suggest a
574 // missing extern "C".
575 if (name.starts_with("__Z")) {
576 std::string buf = name.str();
577 llvm::ItaniumPartialDemangler d;
578 if (!d.partialDemangle(buf.c_str()))
579 if (char *buf = d.getFunctionName(nullptr, nullptr)) {
580 const Symbol *s = suggest((Twine("_") + buf).str());
581 free(buf);
582 if (s) {
583 preHint = ": extern \"C\" ";
584 return s;
585 }
586 }
587 } else {
588 StringRef nameWithoutUnderscore = name;
589 nameWithoutUnderscore.consume_front("_");
590 const Symbol *s = nullptr;
591 for (auto &it : map)
592 if (canSuggestExternCForCXX(nameWithoutUnderscore, it.first)) {
593 s = it.second;
594 break;
595 }
596 if (!s)
597 for (Symbol *sym : symtab->getSymbols())
598 if (canSuggestExternCForCXX(nameWithoutUnderscore, sym->getName())) {
599 s = sym;
600 break;
601 }
602 if (s) {
603 preHint = " to declare ";
604 postHint = " as extern \"C\"?";
605 return s;
606 }
607 }
608
609 return nullptr;
610 }
611
reportUndefinedSymbol(const Undefined & sym,const UndefinedDiag & locations,bool correctSpelling)612 static void reportUndefinedSymbol(const Undefined &sym,
613 const UndefinedDiag &locations,
614 bool correctSpelling) {
615 std::string message = "undefined symbol";
616 if (config->archMultiple)
617 message += (" for arch " + getArchitectureName(config->arch())).str();
618 message += ": " + toString(sym);
619
620 const size_t maxUndefinedReferences = 3;
621 size_t i = 0;
622 for (const std::string &loc : locations.otherReferences) {
623 if (i >= maxUndefinedReferences)
624 break;
625 message += "\n>>> referenced by " + loc;
626 ++i;
627 }
628
629 for (const UndefinedDiag::SectionAndOffset &loc : locations.codeReferences) {
630 if (i >= maxUndefinedReferences)
631 break;
632 message += "\n>>> referenced by ";
633 std::string src = loc.isec->getSourceLocation(loc.offset);
634 if (!src.empty())
635 message += src + "\n>>> ";
636 message += loc.isec->getLocation(loc.offset);
637 ++i;
638 }
639
640 size_t totalReferences =
641 locations.otherReferences.size() + locations.codeReferences.size();
642 if (totalReferences > i)
643 message +=
644 ("\n>>> referenced " + Twine(totalReferences - i) + " more times")
645 .str();
646
647 if (correctSpelling) {
648 std::string preHint = ": ", postHint;
649 if (const Symbol *corrected =
650 getAlternativeSpelling(sym, preHint, postHint)) {
651 message +=
652 "\n>>> did you mean" + preHint + toString(*corrected) + postHint;
653 if (corrected->getFile())
654 message += "\n>>> defined in: " + toString(corrected->getFile());
655 }
656 }
657
658 if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::error)
659 error(message);
660 else if (config->undefinedSymbolTreatment ==
661 UndefinedSymbolTreatment::warning)
662 warn(message);
663 else
664 assert(false && "diagnostics make sense for -undefined error|warning only");
665 }
666
reportPendingUndefinedSymbols()667 void macho::reportPendingUndefinedSymbols() {
668 // Enable spell corrector for the first 2 diagnostics.
669 for (const auto &[i, undef] : llvm::enumerate(undefs))
670 reportUndefinedSymbol(*undef.first, undef.second, i < 2);
671
672 // This function is called multiple times during execution. Clear the printed
673 // diagnostics to avoid printing the same things again the next time.
674 undefs.clear();
675 }
676
treatUndefinedSymbol(const Undefined & sym,StringRef source)677 void macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
678 if (recoverFromUndefinedSymbol(sym))
679 return;
680
681 undefs[&sym].otherReferences.push_back(source.str());
682 }
683
treatUndefinedSymbol(const Undefined & sym,const InputSection * isec,uint64_t offset)684 void macho::treatUndefinedSymbol(const Undefined &sym, const InputSection *isec,
685 uint64_t offset) {
686 if (recoverFromUndefinedSymbol(sym))
687 return;
688
689 undefs[&sym].codeReferences.push_back({isec, offset});
690 }
691
692 std::unique_ptr<SymbolTable> macho::symtab;
693