109467b48Spatrick //===- tools/dsymutil/DwarfLinkerForBinary.cpp ----------------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick
909467b48Spatrick #include "DwarfLinkerForBinary.h"
1009467b48Spatrick #include "BinaryHolder.h"
1109467b48Spatrick #include "DebugMap.h"
1209467b48Spatrick #include "MachOUtils.h"
1309467b48Spatrick #include "dsymutil.h"
1409467b48Spatrick #include "llvm/ADT/ArrayRef.h"
1509467b48Spatrick #include "llvm/ADT/BitVector.h"
1609467b48Spatrick #include "llvm/ADT/DenseMap.h"
1709467b48Spatrick #include "llvm/ADT/DenseMapInfo.h"
1809467b48Spatrick #include "llvm/ADT/DenseSet.h"
1909467b48Spatrick #include "llvm/ADT/FoldingSet.h"
2009467b48Spatrick #include "llvm/ADT/Hashing.h"
2109467b48Spatrick #include "llvm/ADT/PointerIntPair.h"
2209467b48Spatrick #include "llvm/ADT/STLExtras.h"
2309467b48Spatrick #include "llvm/ADT/SmallString.h"
2409467b48Spatrick #include "llvm/ADT/StringMap.h"
2509467b48Spatrick #include "llvm/ADT/StringRef.h"
2609467b48Spatrick #include "llvm/ADT/Triple.h"
2709467b48Spatrick #include "llvm/ADT/Twine.h"
2809467b48Spatrick #include "llvm/BinaryFormat/Dwarf.h"
2909467b48Spatrick #include "llvm/BinaryFormat/MachO.h"
30*d415bd75Srobert #include "llvm/BinaryFormat/Swift.h"
3109467b48Spatrick #include "llvm/CodeGen/AccelTable.h"
3209467b48Spatrick #include "llvm/CodeGen/AsmPrinter.h"
3309467b48Spatrick #include "llvm/CodeGen/DIE.h"
3409467b48Spatrick #include "llvm/CodeGen/NonRelocatableStringpool.h"
3509467b48Spatrick #include "llvm/Config/config.h"
3609467b48Spatrick #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
3709467b48Spatrick #include "llvm/DebugInfo/DIContext.h"
3809467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
3909467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFContext.h"
4009467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
4109467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
4209467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
4309467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFDie.h"
4409467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
4509467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFSection.h"
4609467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
4709467b48Spatrick #include "llvm/MC/MCAsmBackend.h"
4809467b48Spatrick #include "llvm/MC/MCAsmInfo.h"
4909467b48Spatrick #include "llvm/MC/MCCodeEmitter.h"
5009467b48Spatrick #include "llvm/MC/MCContext.h"
5109467b48Spatrick #include "llvm/MC/MCDwarf.h"
5209467b48Spatrick #include "llvm/MC/MCInstrInfo.h"
5309467b48Spatrick #include "llvm/MC/MCObjectFileInfo.h"
5409467b48Spatrick #include "llvm/MC/MCObjectWriter.h"
5509467b48Spatrick #include "llvm/MC/MCRegisterInfo.h"
5609467b48Spatrick #include "llvm/MC/MCSection.h"
5709467b48Spatrick #include "llvm/MC/MCStreamer.h"
5809467b48Spatrick #include "llvm/MC/MCSubtargetInfo.h"
5909467b48Spatrick #include "llvm/MC/MCTargetOptions.h"
60*d415bd75Srobert #include "llvm/MC/MCTargetOptionsCommandFlags.h"
61*d415bd75Srobert #include "llvm/MC/TargetRegistry.h"
6209467b48Spatrick #include "llvm/Object/MachO.h"
6309467b48Spatrick #include "llvm/Object/ObjectFile.h"
6409467b48Spatrick #include "llvm/Object/SymbolicFile.h"
6509467b48Spatrick #include "llvm/Support/Allocator.h"
6609467b48Spatrick #include "llvm/Support/Casting.h"
6709467b48Spatrick #include "llvm/Support/Compiler.h"
6809467b48Spatrick #include "llvm/Support/DJB.h"
6909467b48Spatrick #include "llvm/Support/DataExtractor.h"
7009467b48Spatrick #include "llvm/Support/Error.h"
7109467b48Spatrick #include "llvm/Support/ErrorHandling.h"
7209467b48Spatrick #include "llvm/Support/ErrorOr.h"
7309467b48Spatrick #include "llvm/Support/FileSystem.h"
7409467b48Spatrick #include "llvm/Support/Format.h"
7509467b48Spatrick #include "llvm/Support/LEB128.h"
7609467b48Spatrick #include "llvm/Support/MathExtras.h"
7709467b48Spatrick #include "llvm/Support/MemoryBuffer.h"
7809467b48Spatrick #include "llvm/Support/Path.h"
7909467b48Spatrick #include "llvm/Support/ThreadPool.h"
8009467b48Spatrick #include "llvm/Support/ToolOutputFile.h"
8109467b48Spatrick #include "llvm/Support/WithColor.h"
8209467b48Spatrick #include "llvm/Support/raw_ostream.h"
8309467b48Spatrick #include "llvm/Target/TargetMachine.h"
8409467b48Spatrick #include "llvm/Target/TargetOptions.h"
8509467b48Spatrick #include <algorithm>
8609467b48Spatrick #include <cassert>
8709467b48Spatrick #include <cinttypes>
8809467b48Spatrick #include <climits>
8909467b48Spatrick #include <cstdint>
9009467b48Spatrick #include <cstdlib>
9109467b48Spatrick #include <cstring>
9209467b48Spatrick #include <limits>
9309467b48Spatrick #include <map>
9409467b48Spatrick #include <memory>
95*d415bd75Srobert #include <optional>
9609467b48Spatrick #include <string>
9709467b48Spatrick #include <system_error>
9809467b48Spatrick #include <tuple>
9909467b48Spatrick #include <utility>
10009467b48Spatrick #include <vector>
10109467b48Spatrick
10209467b48Spatrick namespace llvm {
103097a140dSpatrick
104097a140dSpatrick static mc::RegisterMCTargetOptionsFlags MOF;
105097a140dSpatrick
10609467b48Spatrick namespace dsymutil {
10709467b48Spatrick
copySwiftInterfaces(const std::map<std::string,std::string> & ParseableSwiftInterfaces,StringRef Architecture,const LinkOptions & Options)10809467b48Spatrick static Error copySwiftInterfaces(
10909467b48Spatrick const std::map<std::string, std::string> &ParseableSwiftInterfaces,
11009467b48Spatrick StringRef Architecture, const LinkOptions &Options) {
11109467b48Spatrick std::error_code EC;
11209467b48Spatrick SmallString<128> InputPath;
11309467b48Spatrick SmallString<128> Path;
11409467b48Spatrick sys::path::append(Path, *Options.ResourceDir, "Swift", Architecture);
11509467b48Spatrick if ((EC = sys::fs::create_directories(Path.str(), true,
11609467b48Spatrick sys::fs::perms::all_all)))
11709467b48Spatrick return make_error<StringError>(
11809467b48Spatrick "cannot create directory: " + toString(errorCodeToError(EC)), EC);
11909467b48Spatrick unsigned BaseLength = Path.size();
12009467b48Spatrick
12109467b48Spatrick for (auto &I : ParseableSwiftInterfaces) {
12209467b48Spatrick StringRef ModuleName = I.first;
12309467b48Spatrick StringRef InterfaceFile = I.second;
12409467b48Spatrick if (!Options.PrependPath.empty()) {
12509467b48Spatrick InputPath.clear();
12609467b48Spatrick sys::path::append(InputPath, Options.PrependPath, InterfaceFile);
12709467b48Spatrick InterfaceFile = InputPath;
12809467b48Spatrick }
12909467b48Spatrick sys::path::append(Path, ModuleName);
13009467b48Spatrick Path.append(".swiftinterface");
13109467b48Spatrick if (Options.Verbose)
13209467b48Spatrick outs() << "copy parseable Swift interface " << InterfaceFile << " -> "
13309467b48Spatrick << Path.str() << '\n';
13409467b48Spatrick
13509467b48Spatrick // copy_file attempts an APFS clone first, so this should be cheap.
13609467b48Spatrick if ((EC = sys::fs::copy_file(InterfaceFile, Path.str())))
13709467b48Spatrick warn(Twine("cannot copy parseable Swift interface ") + InterfaceFile +
13809467b48Spatrick ": " + toString(errorCodeToError(EC)));
13909467b48Spatrick Path.resize(BaseLength);
14009467b48Spatrick }
14109467b48Spatrick return Error::success();
14209467b48Spatrick }
14309467b48Spatrick
144097a140dSpatrick /// Report a warning to the user, optionally including information about a
145097a140dSpatrick /// specific \p DIE related to the warning.
reportWarning(const Twine & Warning,StringRef Context,const DWARFDie * DIE) const146097a140dSpatrick void DwarfLinkerForBinary::reportWarning(const Twine &Warning,
147097a140dSpatrick StringRef Context,
148097a140dSpatrick const DWARFDie *DIE) const {
149097a140dSpatrick
150097a140dSpatrick warn(Warning, Context);
151097a140dSpatrick
152097a140dSpatrick if (!Options.Verbose || !DIE)
153097a140dSpatrick return;
154097a140dSpatrick
155097a140dSpatrick DIDumpOptions DumpOpts;
156097a140dSpatrick DumpOpts.ChildRecurseDepth = 0;
157097a140dSpatrick DumpOpts.Verbose = Options.Verbose;
158097a140dSpatrick
159097a140dSpatrick WithColor::note() << " in DIE:\n";
160097a140dSpatrick DIE->dump(errs(), 6 /* Indent */, DumpOpts);
161097a140dSpatrick }
162097a140dSpatrick
createStreamer(const Triple & TheTriple,raw_fd_ostream & OutFile)163097a140dSpatrick bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple,
164097a140dSpatrick raw_fd_ostream &OutFile) {
165097a140dSpatrick if (Options.NoOutput)
166097a140dSpatrick return true;
167097a140dSpatrick
168097a140dSpatrick Streamer = std::make_unique<DwarfStreamer>(
16973471bf0Spatrick Options.FileType, OutFile, Options.Translator,
170097a140dSpatrick [&](const Twine &Error, StringRef Context, const DWARFDie *) {
171097a140dSpatrick error(Error, Context);
172097a140dSpatrick },
173097a140dSpatrick [&](const Twine &Warning, StringRef Context, const DWARFDie *) {
174097a140dSpatrick warn(Warning, Context);
175097a140dSpatrick });
176*d415bd75Srobert return Streamer->init(TheTriple, "__DWARF");
177097a140dSpatrick }
178097a140dSpatrick
179097a140dSpatrick ErrorOr<const object::ObjectFile &>
loadObject(const DebugMapObject & Obj,const Triple & Triple)180097a140dSpatrick DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
181097a140dSpatrick const Triple &Triple) {
182097a140dSpatrick auto ObjectEntry =
183097a140dSpatrick BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp());
184097a140dSpatrick if (!ObjectEntry) {
185097a140dSpatrick auto Err = ObjectEntry.takeError();
186097a140dSpatrick reportWarning(Twine(Obj.getObjectFilename()) + ": " +
187097a140dSpatrick toString(std::move(Err)),
188097a140dSpatrick Obj.getObjectFilename());
189097a140dSpatrick return errorToErrorCode(std::move(Err));
190097a140dSpatrick }
191097a140dSpatrick
192097a140dSpatrick auto Object = ObjectEntry->getObject(Triple);
193097a140dSpatrick if (!Object) {
194097a140dSpatrick auto Err = Object.takeError();
195097a140dSpatrick reportWarning(Twine(Obj.getObjectFilename()) + ": " +
196097a140dSpatrick toString(std::move(Err)),
197097a140dSpatrick Obj.getObjectFilename());
198097a140dSpatrick return errorToErrorCode(std::move(Err));
199097a140dSpatrick }
200097a140dSpatrick
201097a140dSpatrick return *Object;
202097a140dSpatrick }
203097a140dSpatrick
remarksErrorHandler(const DebugMapObject & DMO,DwarfLinkerForBinary & Linker,std::unique_ptr<FileError> FE)204097a140dSpatrick static Error remarksErrorHandler(const DebugMapObject &DMO,
205097a140dSpatrick DwarfLinkerForBinary &Linker,
206097a140dSpatrick std::unique_ptr<FileError> FE) {
207097a140dSpatrick bool IsArchive = DMO.getObjectFilename().endswith(")");
208097a140dSpatrick // Don't report errors for missing remark files from static
209097a140dSpatrick // archives.
210097a140dSpatrick if (!IsArchive)
211097a140dSpatrick return Error(std::move(FE));
212097a140dSpatrick
213097a140dSpatrick std::string Message = FE->message();
214097a140dSpatrick Error E = FE->takeError();
215097a140dSpatrick Error NewE = handleErrors(std::move(E), [&](std::unique_ptr<ECError> EC) {
216097a140dSpatrick if (EC->convertToErrorCode() != std::errc::no_such_file_or_directory)
217097a140dSpatrick return Error(std::move(EC));
218097a140dSpatrick
219097a140dSpatrick Linker.reportWarning(Message, DMO.getObjectFilename());
220097a140dSpatrick return Error(Error::success());
221097a140dSpatrick });
222097a140dSpatrick
223097a140dSpatrick if (!NewE)
224097a140dSpatrick return Error::success();
225097a140dSpatrick
226097a140dSpatrick return createFileError(FE->getFileName(), std::move(NewE));
227097a140dSpatrick }
228097a140dSpatrick
emitRemarks(const LinkOptions & Options,StringRef BinaryPath,StringRef ArchName,const remarks::RemarkLinker & RL)22909467b48Spatrick static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath,
23009467b48Spatrick StringRef ArchName, const remarks::RemarkLinker &RL) {
23109467b48Spatrick // Make sure we don't create the directories and the file if there is nothing
23209467b48Spatrick // to serialize.
23309467b48Spatrick if (RL.empty())
23409467b48Spatrick return Error::success();
23509467b48Spatrick
23609467b48Spatrick SmallString<128> InputPath;
23709467b48Spatrick SmallString<128> Path;
23809467b48Spatrick // Create the "Remarks" directory in the "Resources" directory.
23909467b48Spatrick sys::path::append(Path, *Options.ResourceDir, "Remarks");
24009467b48Spatrick if (std::error_code EC = sys::fs::create_directories(Path.str(), true,
24109467b48Spatrick sys::fs::perms::all_all))
24209467b48Spatrick return errorCodeToError(EC);
24309467b48Spatrick
24409467b48Spatrick // Append the file name.
24509467b48Spatrick // For fat binaries, also append a dash and the architecture name.
24609467b48Spatrick sys::path::append(Path, sys::path::filename(BinaryPath));
24709467b48Spatrick if (Options.NumDebugMaps > 1) {
24809467b48Spatrick // More than one debug map means we have a fat binary.
24909467b48Spatrick Path += '-';
25009467b48Spatrick Path += ArchName;
25109467b48Spatrick }
25209467b48Spatrick
25309467b48Spatrick std::error_code EC;
25473471bf0Spatrick raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC,
25573471bf0Spatrick Options.RemarksFormat == remarks::Format::Bitstream
25673471bf0Spatrick ? sys::fs::OF_None
25773471bf0Spatrick : sys::fs::OF_Text);
25809467b48Spatrick if (EC)
25909467b48Spatrick return errorCodeToError(EC);
26009467b48Spatrick
26109467b48Spatrick if (Error E = RL.serialize(OS, Options.RemarksFormat))
26209467b48Spatrick return E;
26309467b48Spatrick
26409467b48Spatrick return Error::success();
26509467b48Spatrick }
26609467b48Spatrick
26773471bf0Spatrick ErrorOr<DWARFFile &>
loadObject(const DebugMapObject & Obj,const DebugMap & DebugMap,remarks::RemarkLinker & RL)268097a140dSpatrick DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
269097a140dSpatrick const DebugMap &DebugMap,
270097a140dSpatrick remarks::RemarkLinker &RL) {
271097a140dSpatrick auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());
272097a140dSpatrick
273097a140dSpatrick if (ErrorOrObj) {
274097a140dSpatrick ContextForLinking.push_back(
275097a140dSpatrick std::unique_ptr<DWARFContext>(DWARFContext::create(*ErrorOrObj)));
276097a140dSpatrick AddressMapForLinking.push_back(
277097a140dSpatrick std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj));
278097a140dSpatrick
27973471bf0Spatrick ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
280097a140dSpatrick Obj.getObjectFilename(), ContextForLinking.back().get(),
281097a140dSpatrick AddressMapForLinking.back().get(),
282097a140dSpatrick Obj.empty() ? Obj.getWarnings() : EmptyWarnings));
283097a140dSpatrick
284097a140dSpatrick Error E = RL.link(*ErrorOrObj);
285097a140dSpatrick if (Error NewE = handleErrors(
286097a140dSpatrick std::move(E), [&](std::unique_ptr<FileError> EC) -> Error {
287097a140dSpatrick return remarksErrorHandler(Obj, *this, std::move(EC));
288097a140dSpatrick }))
289097a140dSpatrick return errorToErrorCode(std::move(NewE));
290097a140dSpatrick
291097a140dSpatrick return *ObjectsForLinking.back();
292097a140dSpatrick }
293097a140dSpatrick
294097a140dSpatrick return ErrorOrObj.getError();
295097a140dSpatrick }
296097a140dSpatrick
binaryHasStrippableSwiftReflectionSections(const DebugMap & Map,const LinkOptions & Options,BinaryHolder & BinHolder)297*d415bd75Srobert static bool binaryHasStrippableSwiftReflectionSections(
298*d415bd75Srobert const DebugMap &Map, const LinkOptions &Options, BinaryHolder &BinHolder) {
299*d415bd75Srobert // If the input binary has strippable swift5 reflection sections, there is no
300*d415bd75Srobert // need to copy them to the .dSYM. Only copy them for binaries where the
301*d415bd75Srobert // linker omitted the reflection metadata.
302*d415bd75Srobert if (!Map.getBinaryPath().empty() &&
303*d415bd75Srobert Options.FileType == OutputFileType::Object) {
304*d415bd75Srobert
305*d415bd75Srobert auto ObjectEntry = BinHolder.getObjectEntry(Map.getBinaryPath());
306*d415bd75Srobert // If ObjectEntry or Object has an error, no binary exists, therefore no
307*d415bd75Srobert // reflection sections exist.
308*d415bd75Srobert if (!ObjectEntry) {
309*d415bd75Srobert // Any errors will be diagnosed later in the main loop, ignore them here.
310*d415bd75Srobert llvm::consumeError(ObjectEntry.takeError());
311*d415bd75Srobert return false;
312*d415bd75Srobert }
313*d415bd75Srobert
314*d415bd75Srobert auto Object =
315*d415bd75Srobert ObjectEntry->getObjectAs<object::MachOObjectFile>(Map.getTriple());
316*d415bd75Srobert if (!Object) {
317*d415bd75Srobert // Any errors will be diagnosed later in the main loop, ignore them here.
318*d415bd75Srobert llvm::consumeError(Object.takeError());
319*d415bd75Srobert return false;
320*d415bd75Srobert }
321*d415bd75Srobert
322*d415bd75Srobert for (auto &Section : Object->sections()) {
323*d415bd75Srobert llvm::Expected<llvm::StringRef> NameOrErr =
324*d415bd75Srobert Object->getSectionName(Section.getRawDataRefImpl());
325*d415bd75Srobert if (!NameOrErr) {
326*d415bd75Srobert llvm::consumeError(NameOrErr.takeError());
327*d415bd75Srobert continue;
328*d415bd75Srobert }
329*d415bd75Srobert NameOrErr->consume_back("__TEXT");
330*d415bd75Srobert auto ReflectionSectionKind =
331*d415bd75Srobert Object->mapReflectionSectionNameToEnumValue(*NameOrErr);
332*d415bd75Srobert if (Object->isReflectionSectionStrippable(ReflectionSectionKind)) {
333*d415bd75Srobert return true;
334*d415bd75Srobert }
335*d415bd75Srobert }
336*d415bd75Srobert }
337*d415bd75Srobert return false;
338*d415bd75Srobert }
339*d415bd75Srobert
340*d415bd75Srobert /// Calculate the start of the strippable swift reflection sections in Dwarf.
341*d415bd75Srobert /// Note that there's an assumption that the reflection sections will appear
342*d415bd75Srobert /// in alphabetic order.
343*d415bd75Srobert static std::vector<uint64_t>
calculateStartOfStrippableReflectionSections(const DebugMap & Map)344*d415bd75Srobert calculateStartOfStrippableReflectionSections(const DebugMap &Map) {
345*d415bd75Srobert using llvm::binaryformat::Swift5ReflectionSectionKind;
346*d415bd75Srobert uint64_t AssocTySize = 0;
347*d415bd75Srobert uint64_t FieldMdSize = 0;
348*d415bd75Srobert for (const auto &Obj : Map.objects()) {
349*d415bd75Srobert auto OF =
350*d415bd75Srobert llvm::object::ObjectFile::createObjectFile(Obj->getObjectFilename());
351*d415bd75Srobert if (!OF) {
352*d415bd75Srobert llvm::consumeError(OF.takeError());
353*d415bd75Srobert continue;
354*d415bd75Srobert }
355*d415bd75Srobert if (auto *MO = dyn_cast<llvm::object::MachOObjectFile>(OF->getBinary())) {
356*d415bd75Srobert for (auto &Section : MO->sections()) {
357*d415bd75Srobert llvm::Expected<llvm::StringRef> NameOrErr =
358*d415bd75Srobert MO->getSectionName(Section.getRawDataRefImpl());
359*d415bd75Srobert if (!NameOrErr) {
360*d415bd75Srobert llvm::consumeError(NameOrErr.takeError());
361*d415bd75Srobert continue;
362*d415bd75Srobert }
363*d415bd75Srobert NameOrErr->consume_back("__TEXT");
364*d415bd75Srobert auto ReflSectionKind =
365*d415bd75Srobert MO->mapReflectionSectionNameToEnumValue(*NameOrErr);
366*d415bd75Srobert switch (ReflSectionKind) {
367*d415bd75Srobert case Swift5ReflectionSectionKind::assocty:
368*d415bd75Srobert AssocTySize += Section.getSize();
369*d415bd75Srobert break;
370*d415bd75Srobert case Swift5ReflectionSectionKind::fieldmd:
371*d415bd75Srobert FieldMdSize += Section.getSize();
372*d415bd75Srobert break;
373*d415bd75Srobert default:
374*d415bd75Srobert break;
375*d415bd75Srobert }
376*d415bd75Srobert }
377*d415bd75Srobert }
378*d415bd75Srobert }
379*d415bd75Srobert // Initialize the vector with enough space to fit every reflection section
380*d415bd75Srobert // kind.
381*d415bd75Srobert std::vector<uint64_t> SectionToOffset(Swift5ReflectionSectionKind::last, 0);
382*d415bd75Srobert SectionToOffset[Swift5ReflectionSectionKind::assocty] = 0;
383*d415bd75Srobert SectionToOffset[Swift5ReflectionSectionKind::fieldmd] =
384*d415bd75Srobert llvm::alignTo(AssocTySize, 4);
385*d415bd75Srobert SectionToOffset[Swift5ReflectionSectionKind::reflstr] = llvm::alignTo(
386*d415bd75Srobert SectionToOffset[Swift5ReflectionSectionKind::fieldmd] + FieldMdSize, 4);
387*d415bd75Srobert
388*d415bd75Srobert return SectionToOffset;
389*d415bd75Srobert }
390*d415bd75Srobert
collectRelocationsToApplyToSwiftReflectionSections(const object::SectionRef & Section,StringRef & Contents,const llvm::object::MachOObjectFile * MO,const std::vector<uint64_t> & SectionToOffsetInDwarf,const llvm::dsymutil::DebugMapObject * Obj,std::vector<MachOUtils::DwarfRelocationApplicationInfo> & RelocationsToApply) const391*d415bd75Srobert void DwarfLinkerForBinary::collectRelocationsToApplyToSwiftReflectionSections(
392*d415bd75Srobert const object::SectionRef &Section, StringRef &Contents,
393*d415bd75Srobert const llvm::object::MachOObjectFile *MO,
394*d415bd75Srobert const std::vector<uint64_t> &SectionToOffsetInDwarf,
395*d415bd75Srobert const llvm::dsymutil::DebugMapObject *Obj,
396*d415bd75Srobert std::vector<MachOUtils::DwarfRelocationApplicationInfo> &RelocationsToApply)
397*d415bd75Srobert const {
398*d415bd75Srobert for (auto It = Section.relocation_begin(); It != Section.relocation_end();
399*d415bd75Srobert ++It) {
400*d415bd75Srobert object::DataRefImpl RelocDataRef = It->getRawDataRefImpl();
401*d415bd75Srobert MachO::any_relocation_info MachOReloc = MO->getRelocation(RelocDataRef);
402*d415bd75Srobert
403*d415bd75Srobert if (!object::MachOObjectFile::isMachOPairedReloc(
404*d415bd75Srobert MO->getAnyRelocationType(MachOReloc), MO->getArch())) {
405*d415bd75Srobert reportWarning(
406*d415bd75Srobert "Unimplemented relocation type in strippable reflection section ",
407*d415bd75Srobert Obj->getObjectFilename());
408*d415bd75Srobert continue;
409*d415bd75Srobert }
410*d415bd75Srobert
411*d415bd75Srobert auto CalculateAddressOfSymbolInDwarfSegment =
412*d415bd75Srobert [&]() -> std::optional<int64_t> {
413*d415bd75Srobert auto Symbol = It->getSymbol();
414*d415bd75Srobert auto SymbolAbsoluteAddress = Symbol->getAddress();
415*d415bd75Srobert if (!SymbolAbsoluteAddress)
416*d415bd75Srobert return {};
417*d415bd75Srobert auto Section = Symbol->getSection();
418*d415bd75Srobert if (!Section) {
419*d415bd75Srobert llvm::consumeError(Section.takeError());
420*d415bd75Srobert return {};
421*d415bd75Srobert }
422*d415bd75Srobert
423*d415bd75Srobert if ((*Section)->getObject()->section_end() == *Section)
424*d415bd75Srobert return {};
425*d415bd75Srobert
426*d415bd75Srobert auto SectionStart = (*Section)->getAddress();
427*d415bd75Srobert auto SymbolAddressInSection = *SymbolAbsoluteAddress - SectionStart;
428*d415bd75Srobert auto SectionName = (*Section)->getName();
429*d415bd75Srobert if (!SectionName)
430*d415bd75Srobert return {};
431*d415bd75Srobert auto ReflSectionKind =
432*d415bd75Srobert MO->mapReflectionSectionNameToEnumValue(*SectionName);
433*d415bd75Srobert
434*d415bd75Srobert int64_t SectionStartInLinkedBinary =
435*d415bd75Srobert SectionToOffsetInDwarf[ReflSectionKind];
436*d415bd75Srobert
437*d415bd75Srobert auto Addr = SectionStartInLinkedBinary + SymbolAddressInSection;
438*d415bd75Srobert return Addr;
439*d415bd75Srobert };
440*d415bd75Srobert
441*d415bd75Srobert // The first symbol should always be in the section we're currently
442*d415bd75Srobert // iterating over.
443*d415bd75Srobert auto FirstSymbolAddress = CalculateAddressOfSymbolInDwarfSegment();
444*d415bd75Srobert ++It;
445*d415bd75Srobert
446*d415bd75Srobert bool ShouldSubtractDwarfVM = false;
447*d415bd75Srobert // For the second symbol there are two possibilities.
448*d415bd75Srobert std::optional<int64_t> SecondSymbolAddress;
449*d415bd75Srobert auto Sym = It->getSymbol();
450*d415bd75Srobert if (Sym != MO->symbol_end()) {
451*d415bd75Srobert Expected<StringRef> SymbolName = Sym->getName();
452*d415bd75Srobert if (SymbolName) {
453*d415bd75Srobert if (const auto *Mapping = Obj->lookupSymbol(*SymbolName)) {
454*d415bd75Srobert // First possibility: the symbol exists in the binary, and exists in a
455*d415bd75Srobert // non-strippable section (for example, typeref, or __TEXT,__const),
456*d415bd75Srobert // in which case we look up its address in the binary, which dsymutil
457*d415bd75Srobert // will copy verbatim.
458*d415bd75Srobert SecondSymbolAddress = Mapping->getValue().BinaryAddress;
459*d415bd75Srobert // Since the symbols live in different segments, we have to substract
460*d415bd75Srobert // the start of the Dwarf's vmaddr so the value calculated points to
461*d415bd75Srobert // the correct place.
462*d415bd75Srobert ShouldSubtractDwarfVM = true;
463*d415bd75Srobert }
464*d415bd75Srobert }
465*d415bd75Srobert }
466*d415bd75Srobert
467*d415bd75Srobert if (!SecondSymbolAddress) {
468*d415bd75Srobert // Second possibility, this symbol is not present in the main binary, and
469*d415bd75Srobert // must be in one of the strippable sections (for example, reflstr).
470*d415bd75Srobert // Calculate its address in the same way as we did the first one.
471*d415bd75Srobert SecondSymbolAddress = CalculateAddressOfSymbolInDwarfSegment();
472*d415bd75Srobert }
473*d415bd75Srobert
474*d415bd75Srobert if (!FirstSymbolAddress || !SecondSymbolAddress)
475*d415bd75Srobert continue;
476*d415bd75Srobert
477*d415bd75Srobert auto SectionName = Section.getName();
478*d415bd75Srobert if (!SectionName)
479*d415bd75Srobert continue;
480*d415bd75Srobert
481*d415bd75Srobert int32_t Addend;
482*d415bd75Srobert memcpy(&Addend, Contents.data() + It->getOffset(), sizeof(int32_t));
483*d415bd75Srobert int32_t Value = (*SecondSymbolAddress + Addend) - *FirstSymbolAddress;
484*d415bd75Srobert auto ReflSectionKind =
485*d415bd75Srobert MO->mapReflectionSectionNameToEnumValue(*SectionName);
486*d415bd75Srobert uint64_t AddressFromDwarfVM =
487*d415bd75Srobert SectionToOffsetInDwarf[ReflSectionKind] + It->getOffset();
488*d415bd75Srobert RelocationsToApply.emplace_back(AddressFromDwarfVM, Value,
489*d415bd75Srobert ShouldSubtractDwarfVM);
490*d415bd75Srobert }
491*d415bd75Srobert }
492*d415bd75Srobert
copySwiftReflectionMetadata(const llvm::dsymutil::DebugMapObject * Obj,DwarfStreamer * Streamer,std::vector<uint64_t> & SectionToOffsetInDwarf,std::vector<MachOUtils::DwarfRelocationApplicationInfo> & RelocationsToApply)493*d415bd75Srobert void DwarfLinkerForBinary::copySwiftReflectionMetadata(
494*d415bd75Srobert const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer,
495*d415bd75Srobert std::vector<uint64_t> &SectionToOffsetInDwarf,
496*d415bd75Srobert std::vector<MachOUtils::DwarfRelocationApplicationInfo>
497*d415bd75Srobert &RelocationsToApply) {
498*d415bd75Srobert using binaryformat::Swift5ReflectionSectionKind;
499*d415bd75Srobert auto OF =
500*d415bd75Srobert llvm::object::ObjectFile::createObjectFile(Obj->getObjectFilename());
501*d415bd75Srobert if (!OF) {
502*d415bd75Srobert llvm::consumeError(OF.takeError());
503*d415bd75Srobert return;
504*d415bd75Srobert }
505*d415bd75Srobert if (auto *MO = dyn_cast<llvm::object::MachOObjectFile>(OF->getBinary())) {
506*d415bd75Srobert // Collect the swift reflection sections before emitting them. This is
507*d415bd75Srobert // done so we control the order they're emitted.
508*d415bd75Srobert std::array<std::optional<object::SectionRef>,
509*d415bd75Srobert Swift5ReflectionSectionKind::last + 1>
510*d415bd75Srobert SwiftSections;
511*d415bd75Srobert for (auto &Section : MO->sections()) {
512*d415bd75Srobert llvm::Expected<llvm::StringRef> NameOrErr =
513*d415bd75Srobert MO->getSectionName(Section.getRawDataRefImpl());
514*d415bd75Srobert if (!NameOrErr) {
515*d415bd75Srobert llvm::consumeError(NameOrErr.takeError());
516*d415bd75Srobert continue;
517*d415bd75Srobert }
518*d415bd75Srobert NameOrErr->consume_back("__TEXT");
519*d415bd75Srobert auto ReflSectionKind =
520*d415bd75Srobert MO->mapReflectionSectionNameToEnumValue(*NameOrErr);
521*d415bd75Srobert if (MO->isReflectionSectionStrippable(ReflSectionKind))
522*d415bd75Srobert SwiftSections[ReflSectionKind] = Section;
523*d415bd75Srobert }
524*d415bd75Srobert // Make sure we copy the sections in alphabetic order.
525*d415bd75Srobert auto SectionKindsToEmit = {Swift5ReflectionSectionKind::assocty,
526*d415bd75Srobert Swift5ReflectionSectionKind::fieldmd,
527*d415bd75Srobert Swift5ReflectionSectionKind::reflstr};
528*d415bd75Srobert for (auto SectionKind : SectionKindsToEmit) {
529*d415bd75Srobert if (!SwiftSections[SectionKind])
530*d415bd75Srobert continue;
531*d415bd75Srobert auto &Section = *SwiftSections[SectionKind];
532*d415bd75Srobert llvm::Expected<llvm::StringRef> SectionContents = Section.getContents();
533*d415bd75Srobert if (!SectionContents)
534*d415bd75Srobert continue;
535*d415bd75Srobert const auto *MO =
536*d415bd75Srobert llvm::cast<llvm::object::MachOObjectFile>(Section.getObject());
537*d415bd75Srobert collectRelocationsToApplyToSwiftReflectionSections(
538*d415bd75Srobert Section, *SectionContents, MO, SectionToOffsetInDwarf, Obj,
539*d415bd75Srobert RelocationsToApply);
540*d415bd75Srobert // Update the section start with the current section's contribution, so
541*d415bd75Srobert // the next section we copy from a different .o file points to the correct
542*d415bd75Srobert // place.
543*d415bd75Srobert SectionToOffsetInDwarf[SectionKind] += Section.getSize();
544*d415bd75Srobert Streamer->emitSwiftReflectionSection(SectionKind, *SectionContents,
545*d415bd75Srobert Section.getAlignment().value(),
546*d415bd75Srobert Section.getSize());
547*d415bd75Srobert }
548*d415bd75Srobert }
549*d415bd75Srobert }
550*d415bd75Srobert
link(const DebugMap & Map)55109467b48Spatrick bool DwarfLinkerForBinary::link(const DebugMap &Map) {
55209467b48Spatrick if (!createStreamer(Map.getTriple(), OutFile))
55309467b48Spatrick return false;
55409467b48Spatrick
555097a140dSpatrick ObjectsForLinking.clear();
556097a140dSpatrick ContextForLinking.clear();
557097a140dSpatrick AddressMapForLinking.clear();
55809467b48Spatrick
559097a140dSpatrick DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
560097a140dSpatrick
561097a140dSpatrick DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil);
562097a140dSpatrick
563097a140dSpatrick remarks::RemarkLinker RL;
564097a140dSpatrick if (!Options.RemarksPrependPath.empty())
565097a140dSpatrick RL.setExternalFilePrependPath(Options.RemarksPrependPath);
566097a140dSpatrick GeneralLinker.setObjectPrefixMap(&Options.ObjectPrefixMap);
567097a140dSpatrick
568097a140dSpatrick std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) {
569097a140dSpatrick assert(Options.Translator);
570097a140dSpatrick return Options.Translator(Input);
571097a140dSpatrick };
572097a140dSpatrick
573097a140dSpatrick GeneralLinker.setVerbosity(Options.Verbose);
574097a140dSpatrick GeneralLinker.setStatistics(Options.Statistics);
575*d415bd75Srobert GeneralLinker.setVerifyInputDWARF(Options.VerifyInputDWARF);
576097a140dSpatrick GeneralLinker.setNoOutput(Options.NoOutput);
577097a140dSpatrick GeneralLinker.setNoODR(Options.NoODR);
578097a140dSpatrick GeneralLinker.setUpdate(Options.Update);
579097a140dSpatrick GeneralLinker.setNumThreads(Options.Threads);
580097a140dSpatrick GeneralLinker.setPrependPath(Options.PrependPath);
58173471bf0Spatrick GeneralLinker.setKeepFunctionForStatic(Options.KeepFunctionForStatic);
582097a140dSpatrick if (Options.Translator)
583097a140dSpatrick GeneralLinker.setStringsTranslator(TranslationLambda);
584097a140dSpatrick GeneralLinker.setWarningHandler(
585097a140dSpatrick [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) {
586097a140dSpatrick reportWarning(Warning, Context, DIE);
587097a140dSpatrick });
588097a140dSpatrick GeneralLinker.setErrorHandler(
589097a140dSpatrick [&](const Twine &Error, StringRef Context, const DWARFDie *) {
590097a140dSpatrick error(Error, Context);
591097a140dSpatrick });
592*d415bd75Srobert objFileLoader Loader = [&DebugMap, &RL,
593*d415bd75Srobert this](StringRef ContainerName,
59473471bf0Spatrick StringRef Path) -> ErrorOr<DWARFFile &> {
595097a140dSpatrick auto &Obj = DebugMap.addDebugMapObject(
596097a140dSpatrick Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
597097a140dSpatrick
598097a140dSpatrick if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) {
599097a140dSpatrick return *ErrorOrObj;
600097a140dSpatrick } else {
601097a140dSpatrick // Try and emit more helpful warnings by applying some heuristics.
602097a140dSpatrick StringRef ObjFile = ContainerName;
603097a140dSpatrick bool IsClangModule = sys::path::extension(Path).equals(".pcm");
604097a140dSpatrick bool IsArchive = ObjFile.endswith(")");
605097a140dSpatrick
606097a140dSpatrick if (IsClangModule) {
607097a140dSpatrick StringRef ModuleCacheDir = sys::path::parent_path(Path);
608097a140dSpatrick if (sys::fs::exists(ModuleCacheDir)) {
609097a140dSpatrick // If the module's parent directory exists, we assume that the
610097a140dSpatrick // module cache has expired and was pruned by clang. A more
611097a140dSpatrick // adventurous dsymutil would invoke clang to rebuild the module
612097a140dSpatrick // now.
613097a140dSpatrick if (!ModuleCacheHintDisplayed) {
614097a140dSpatrick WithColor::note()
615097a140dSpatrick << "The clang module cache may have expired since "
616097a140dSpatrick "this object file was built. Rebuilding the "
617097a140dSpatrick "object file will rebuild the module cache.\n";
618097a140dSpatrick ModuleCacheHintDisplayed = true;
619097a140dSpatrick }
620097a140dSpatrick } else if (IsArchive) {
621097a140dSpatrick // If the module cache directory doesn't exist at all and the
622097a140dSpatrick // object file is inside a static library, we assume that the
623097a140dSpatrick // static library was built on a different machine. We don't want
624097a140dSpatrick // to discourage module debugging for convenience libraries within
625097a140dSpatrick // a project though.
626097a140dSpatrick if (!ArchiveHintDisplayed) {
627097a140dSpatrick WithColor::note()
628097a140dSpatrick << "Linking a static library that was built with "
629097a140dSpatrick "-gmodules, but the module cache was not found. "
630097a140dSpatrick "Redistributable static libraries should never be "
631097a140dSpatrick "built with module debugging enabled. The debug "
632097a140dSpatrick "experience will be degraded due to incomplete "
633097a140dSpatrick "debug information.\n";
634097a140dSpatrick ArchiveHintDisplayed = true;
635097a140dSpatrick }
636097a140dSpatrick }
637097a140dSpatrick }
638097a140dSpatrick
639097a140dSpatrick return ErrorOrObj.getError();
640097a140dSpatrick }
641097a140dSpatrick
642097a140dSpatrick llvm_unreachable("Unhandled DebugMap object");
643*d415bd75Srobert };
644097a140dSpatrick GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces);
645*d415bd75Srobert bool ReflectionSectionsPresentInBinary = false;
646*d415bd75Srobert // If there is no output specified, no point in checking the binary for swift5
647*d415bd75Srobert // reflection sections.
648*d415bd75Srobert if (!Options.NoOutput) {
649*d415bd75Srobert ReflectionSectionsPresentInBinary =
650*d415bd75Srobert binaryHasStrippableSwiftReflectionSections(Map, Options, BinHolder);
651*d415bd75Srobert }
652*d415bd75Srobert
653*d415bd75Srobert std::vector<MachOUtils::DwarfRelocationApplicationInfo> RelocationsToApply;
654*d415bd75Srobert if (!Options.NoOutput && !ReflectionSectionsPresentInBinary) {
655*d415bd75Srobert auto SectionToOffsetInDwarf =
656*d415bd75Srobert calculateStartOfStrippableReflectionSections(Map);
657*d415bd75Srobert for (const auto &Obj : Map.objects())
658*d415bd75Srobert copySwiftReflectionMetadata(Obj.get(), Streamer.get(),
659*d415bd75Srobert SectionToOffsetInDwarf, RelocationsToApply);
660*d415bd75Srobert }
661*d415bd75Srobert
662*d415bd75Srobert uint16_t MaxDWARFVersion = 0;
663*d415bd75Srobert std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
664*d415bd75Srobert [&MaxDWARFVersion](const DWARFUnit &Unit) {
665*d415bd75Srobert MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);
666*d415bd75Srobert };
667097a140dSpatrick
66809467b48Spatrick for (const auto &Obj : Map.objects()) {
66909467b48Spatrick // N_AST objects (swiftmodule files) should get dumped directly into the
67009467b48Spatrick // appropriate DWARF section.
671097a140dSpatrick if (Obj->getType() == MachO::N_AST) {
672097a140dSpatrick if (Options.Verbose)
673097a140dSpatrick outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
674097a140dSpatrick
675097a140dSpatrick StringRef File = Obj->getObjectFilename();
67609467b48Spatrick auto ErrorOrMem = MemoryBuffer::getFile(File);
67709467b48Spatrick if (!ErrorOrMem) {
67809467b48Spatrick warn("Could not open '" + File + "'\n");
67909467b48Spatrick continue;
68009467b48Spatrick }
68109467b48Spatrick sys::fs::file_status Stat;
68209467b48Spatrick if (auto Err = sys::fs::status(File, Stat)) {
68309467b48Spatrick warn(Err.message());
68409467b48Spatrick continue;
68509467b48Spatrick }
68609467b48Spatrick if (!Options.NoTimestamp) {
68709467b48Spatrick // The modification can have sub-second precision so we need to cast
68809467b48Spatrick // away the extra precision that's not present in the debug map.
68909467b48Spatrick auto ModificationTime =
69009467b48Spatrick std::chrono::time_point_cast<std::chrono::seconds>(
69109467b48Spatrick Stat.getLastModificationTime());
692*d415bd75Srobert if (Obj->getTimestamp() != sys::TimePoint<>() &&
693*d415bd75Srobert ModificationTime != Obj->getTimestamp()) {
69409467b48Spatrick // Not using the helper here as we can easily stream TimePoint<>.
69573471bf0Spatrick WithColor::warning()
69673471bf0Spatrick << File << ": timestamp mismatch between swift interface file ("
697*d415bd75Srobert << sys::TimePoint<>(ModificationTime) << ") and debug map ("
69873471bf0Spatrick << sys::TimePoint<>(Obj->getTimestamp()) << ")\n";
69909467b48Spatrick continue;
70009467b48Spatrick }
70109467b48Spatrick }
70209467b48Spatrick
70309467b48Spatrick // Copy the module into the .swift_ast section.
70409467b48Spatrick if (!Options.NoOutput)
70509467b48Spatrick Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
706097a140dSpatrick
70709467b48Spatrick continue;
70809467b48Spatrick }
70909467b48Spatrick
710097a140dSpatrick if (auto ErrorOrObj = loadObject(*Obj, Map, RL))
711*d415bd75Srobert GeneralLinker.addObjectFile(*ErrorOrObj, Loader, OnCUDieLoaded);
712097a140dSpatrick else {
71373471bf0Spatrick ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
714097a140dSpatrick Obj->getObjectFilename(), nullptr, nullptr,
715097a140dSpatrick Obj->empty() ? Obj->getWarnings() : EmptyWarnings));
716097a140dSpatrick GeneralLinker.addObjectFile(*ObjectsForLinking.back());
71709467b48Spatrick }
71809467b48Spatrick }
71909467b48Spatrick
720*d415bd75Srobert // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
721*d415bd75Srobert if (MaxDWARFVersion == 0)
722*d415bd75Srobert MaxDWARFVersion = 3;
723*d415bd75Srobert
724*d415bd75Srobert if (Error E = GeneralLinker.setTargetDWARFVersion(MaxDWARFVersion))
725*d415bd75Srobert return error(toString(std::move(E)));
726*d415bd75Srobert
727*d415bd75Srobert switch (Options.TheAccelTableKind) {
728*d415bd75Srobert case DsymutilAccelTableKind::Apple:
729*d415bd75Srobert GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Apple);
730*d415bd75Srobert break;
731*d415bd75Srobert case DsymutilAccelTableKind::Dwarf:
732*d415bd75Srobert GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::DebugNames);
733*d415bd75Srobert break;
734*d415bd75Srobert case DsymutilAccelTableKind::Pub:
735*d415bd75Srobert GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Pub);
736*d415bd75Srobert break;
737*d415bd75Srobert case DsymutilAccelTableKind::Default:
738*d415bd75Srobert if (MaxDWARFVersion >= 5)
739*d415bd75Srobert GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::DebugNames);
740*d415bd75Srobert else
741*d415bd75Srobert GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Apple);
742*d415bd75Srobert break;
743*d415bd75Srobert case DsymutilAccelTableKind::None:
744*d415bd75Srobert // Nothing to do.
745*d415bd75Srobert break;
746*d415bd75Srobert }
747*d415bd75Srobert
748097a140dSpatrick // link debug info for loaded object files.
749*d415bd75Srobert if (Error E = GeneralLinker.link())
750*d415bd75Srobert return error(toString(std::move(E)));
75109467b48Spatrick
75209467b48Spatrick StringRef ArchName = Map.getTriple().getArchName();
753097a140dSpatrick if (Error E = emitRemarks(Options, Map.getBinaryPath(), ArchName, RL))
75409467b48Spatrick return error(toString(std::move(E)));
75509467b48Spatrick
75609467b48Spatrick if (Options.NoOutput)
75709467b48Spatrick return true;
75809467b48Spatrick
75909467b48Spatrick if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) {
76009467b48Spatrick StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch());
76109467b48Spatrick if (auto E =
76209467b48Spatrick copySwiftInterfaces(ParseableSwiftInterfaces, ArchName, Options))
76309467b48Spatrick return error(toString(std::move(E)));
76409467b48Spatrick }
76509467b48Spatrick
766097a140dSpatrick if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() &&
767097a140dSpatrick Options.FileType == OutputFileType::Object)
768097a140dSpatrick return MachOUtils::generateDsymCompanion(
769097a140dSpatrick Options.VFS, Map, Options.Translator,
770*d415bd75Srobert *Streamer->getAsmPrinter().OutStreamer, OutFile, RelocationsToApply);
771097a140dSpatrick
772097a140dSpatrick Streamer->finish();
773097a140dSpatrick return true;
774097a140dSpatrick }
775097a140dSpatrick
776097a140dSpatrick /// Iterate over the relocations of the given \p Section and
777097a140dSpatrick /// store the ones that correspond to debug map entries into the
778097a140dSpatrick /// ValidRelocs array.
findValidRelocsMachO(const object::SectionRef & Section,const object::MachOObjectFile & Obj,const DebugMapObject & DMO,std::vector<ValidReloc> & ValidRelocs)779097a140dSpatrick void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
780097a140dSpatrick const object::SectionRef &Section, const object::MachOObjectFile &Obj,
78173471bf0Spatrick const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) {
782097a140dSpatrick Expected<StringRef> ContentsOrErr = Section.getContents();
783097a140dSpatrick if (!ContentsOrErr) {
784097a140dSpatrick consumeError(ContentsOrErr.takeError());
785097a140dSpatrick Linker.reportWarning("error reading section", DMO.getObjectFilename());
786097a140dSpatrick return;
787097a140dSpatrick }
788097a140dSpatrick DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0);
789097a140dSpatrick bool SkipNext = false;
790097a140dSpatrick
791097a140dSpatrick for (const object::RelocationRef &Reloc : Section.relocations()) {
792097a140dSpatrick if (SkipNext) {
793097a140dSpatrick SkipNext = false;
794097a140dSpatrick continue;
795097a140dSpatrick }
796097a140dSpatrick
797097a140dSpatrick object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
798097a140dSpatrick MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
799097a140dSpatrick
800*d415bd75Srobert if (object::MachOObjectFile::isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),
801097a140dSpatrick Obj.getArch())) {
802097a140dSpatrick SkipNext = true;
80373471bf0Spatrick Linker.reportWarning("unsupported relocation in " + *Section.getName() +
80473471bf0Spatrick " section.",
805097a140dSpatrick DMO.getObjectFilename());
806097a140dSpatrick continue;
807097a140dSpatrick }
808097a140dSpatrick
809097a140dSpatrick unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
810097a140dSpatrick uint64_t Offset64 = Reloc.getOffset();
811097a140dSpatrick if ((RelocSize != 4 && RelocSize != 8)) {
81273471bf0Spatrick Linker.reportWarning("unsupported relocation in " + *Section.getName() +
81373471bf0Spatrick " section.",
814097a140dSpatrick DMO.getObjectFilename());
815097a140dSpatrick continue;
816097a140dSpatrick }
817097a140dSpatrick uint64_t OffsetCopy = Offset64;
818097a140dSpatrick // Mach-o uses REL relocations, the addend is at the relocation offset.
819097a140dSpatrick uint64_t Addend = Data.getUnsigned(&OffsetCopy, RelocSize);
820097a140dSpatrick uint64_t SymAddress;
821097a140dSpatrick int64_t SymOffset;
822097a140dSpatrick
823097a140dSpatrick if (Obj.isRelocationScattered(MachOReloc)) {
824097a140dSpatrick // The address of the base symbol for scattered relocations is
825097a140dSpatrick // stored in the reloc itself. The actual addend will store the
826097a140dSpatrick // base address plus the offset.
827097a140dSpatrick SymAddress = Obj.getScatteredRelocationValue(MachOReloc);
828097a140dSpatrick SymOffset = int64_t(Addend) - SymAddress;
829097a140dSpatrick } else {
830097a140dSpatrick SymAddress = Addend;
831097a140dSpatrick SymOffset = 0;
832097a140dSpatrick }
833097a140dSpatrick
834097a140dSpatrick auto Sym = Reloc.getSymbol();
835097a140dSpatrick if (Sym != Obj.symbol_end()) {
836097a140dSpatrick Expected<StringRef> SymbolName = Sym->getName();
837097a140dSpatrick if (!SymbolName) {
838097a140dSpatrick consumeError(SymbolName.takeError());
839097a140dSpatrick Linker.reportWarning("error getting relocation symbol name.",
840097a140dSpatrick DMO.getObjectFilename());
841097a140dSpatrick continue;
842097a140dSpatrick }
843097a140dSpatrick if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
844097a140dSpatrick ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
845097a140dSpatrick } else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) {
846097a140dSpatrick // Do not store the addend. The addend was the address of the symbol in
847097a140dSpatrick // the object file, the address in the binary that is stored in the debug
848097a140dSpatrick // map doesn't need to be offset.
849097a140dSpatrick ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping);
850097a140dSpatrick }
851097a140dSpatrick }
852097a140dSpatrick }
853097a140dSpatrick
854097a140dSpatrick /// Dispatch the valid relocation finding logic to the
855097a140dSpatrick /// appropriate handler depending on the object file format.
findValidRelocs(const object::SectionRef & Section,const object::ObjectFile & Obj,const DebugMapObject & DMO,std::vector<ValidReloc> & Relocs)856097a140dSpatrick bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
857097a140dSpatrick const object::SectionRef &Section, const object::ObjectFile &Obj,
85873471bf0Spatrick const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
859097a140dSpatrick // Dispatch to the right handler depending on the file type.
860097a140dSpatrick if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
86173471bf0Spatrick findValidRelocsMachO(Section, *MachOObj, DMO, Relocs);
862097a140dSpatrick else
863097a140dSpatrick Linker.reportWarning(Twine("unsupported object file type: ") +
864097a140dSpatrick Obj.getFileName(),
865097a140dSpatrick DMO.getObjectFilename());
86673471bf0Spatrick if (Relocs.empty())
867097a140dSpatrick return false;
868097a140dSpatrick
869097a140dSpatrick // Sort the relocations by offset. We will walk the DIEs linearly in
870097a140dSpatrick // the file, this allows us to just keep an index in the relocation
871097a140dSpatrick // array that we advance during our walk, rather than resorting to
872097a140dSpatrick // some associative container. See DwarfLinkerForBinary::NextValidReloc.
87373471bf0Spatrick llvm::sort(Relocs);
874097a140dSpatrick return true;
875097a140dSpatrick }
876097a140dSpatrick
87773471bf0Spatrick /// Look for relocations in the debug_info and debug_addr section that match
87873471bf0Spatrick /// entries in the debug map. These relocations will drive the Dwarf link by
87973471bf0Spatrick /// indicating which DIEs refer to symbols present in the linked binary.
880097a140dSpatrick /// \returns whether there are any valid relocations in the debug info.
findValidRelocsInDebugSections(const object::ObjectFile & Obj,const DebugMapObject & DMO)88173471bf0Spatrick bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
882097a140dSpatrick const object::ObjectFile &Obj, const DebugMapObject &DMO) {
883097a140dSpatrick // Find the debug_info section.
88473471bf0Spatrick bool FoundValidRelocs = false;
885097a140dSpatrick for (const object::SectionRef &Section : Obj.sections()) {
886097a140dSpatrick StringRef SectionName;
887097a140dSpatrick if (Expected<StringRef> NameOrErr = Section.getName())
888097a140dSpatrick SectionName = *NameOrErr;
889097a140dSpatrick else
890097a140dSpatrick consumeError(NameOrErr.takeError());
891097a140dSpatrick
892097a140dSpatrick SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
89373471bf0Spatrick if (SectionName == "debug_info")
89473471bf0Spatrick FoundValidRelocs |=
89573471bf0Spatrick findValidRelocs(Section, Obj, DMO, ValidDebugInfoRelocs);
89673471bf0Spatrick if (SectionName == "debug_addr")
89773471bf0Spatrick FoundValidRelocs |=
89873471bf0Spatrick findValidRelocs(Section, Obj, DMO, ValidDebugAddrRelocs);
899097a140dSpatrick }
90073471bf0Spatrick return FoundValidRelocs;
901097a140dSpatrick }
902097a140dSpatrick
90373471bf0Spatrick std::vector<DwarfLinkerForBinary::AddressManager::ValidReloc>
getRelocations(const std::vector<ValidReloc> & Relocs,uint64_t StartPos,uint64_t EndPos)90473471bf0Spatrick DwarfLinkerForBinary::AddressManager::getRelocations(
90573471bf0Spatrick const std::vector<ValidReloc> &Relocs, uint64_t StartPos, uint64_t EndPos) {
90673471bf0Spatrick std::vector<DwarfLinkerForBinary::AddressManager::ValidReloc> Res;
907097a140dSpatrick
90873471bf0Spatrick auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) {
90973471bf0Spatrick return Reloc.Offset < StartPos;
91073471bf0Spatrick });
911097a140dSpatrick
91273471bf0Spatrick while (CurReloc != Relocs.end() && CurReloc->Offset >= StartPos &&
91373471bf0Spatrick CurReloc->Offset < EndPos) {
91473471bf0Spatrick Res.push_back(*CurReloc);
91573471bf0Spatrick CurReloc++;
91673471bf0Spatrick }
917097a140dSpatrick
91873471bf0Spatrick return Res;
91973471bf0Spatrick }
920097a140dSpatrick
printReloc(const ValidReloc & Reloc)92173471bf0Spatrick void DwarfLinkerForBinary::AddressManager::printReloc(const ValidReloc &Reloc) {
92273471bf0Spatrick const auto &Mapping = Reloc.Mapping->getValue();
923097a140dSpatrick const uint64_t ObjectAddress = Mapping.ObjectAddress
924097a140dSpatrick ? uint64_t(*Mapping.ObjectAddress)
925097a140dSpatrick : std::numeric_limits<uint64_t>::max();
926097a140dSpatrick
92773471bf0Spatrick outs() << "Found valid debug map entry: " << Reloc.Mapping->getKey() << "\t"
92873471bf0Spatrick << format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress,
92973471bf0Spatrick uint64_t(Mapping.BinaryAddress));
93073471bf0Spatrick }
93173471bf0Spatrick
fillDieInfo(const ValidReloc & Reloc,CompileUnit::DIEInfo & Info)93273471bf0Spatrick void DwarfLinkerForBinary::AddressManager::fillDieInfo(
93373471bf0Spatrick const ValidReloc &Reloc, CompileUnit::DIEInfo &Info) {
93473471bf0Spatrick Info.AddrAdjust = relocate(Reloc);
93573471bf0Spatrick if (Reloc.Mapping->getValue().ObjectAddress)
93673471bf0Spatrick Info.AddrAdjust -= uint64_t(*Reloc.Mapping->getValue().ObjectAddress);
937097a140dSpatrick Info.InDebugMap = true;
93873471bf0Spatrick }
93973471bf0Spatrick
hasValidRelocationAt(const std::vector<ValidReloc> & AllRelocs,uint64_t StartOffset,uint64_t EndOffset,CompileUnit::DIEInfo & Info)94073471bf0Spatrick bool DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
94173471bf0Spatrick const std::vector<ValidReloc> &AllRelocs, uint64_t StartOffset,
94273471bf0Spatrick uint64_t EndOffset, CompileUnit::DIEInfo &Info) {
94373471bf0Spatrick std::vector<ValidReloc> Relocs =
94473471bf0Spatrick getRelocations(AllRelocs, StartOffset, EndOffset);
94573471bf0Spatrick
94673471bf0Spatrick if (Relocs.size() == 0)
94773471bf0Spatrick return false;
94873471bf0Spatrick
94973471bf0Spatrick if (Linker.Options.Verbose)
95073471bf0Spatrick printReloc(Relocs[0]);
95173471bf0Spatrick fillDieInfo(Relocs[0], Info);
95273471bf0Spatrick
953097a140dSpatrick return true;
954097a140dSpatrick }
955097a140dSpatrick
95673471bf0Spatrick /// Get the starting and ending (exclusive) offset for the
95773471bf0Spatrick /// attribute with index \p Idx descibed by \p Abbrev. \p Offset is
95873471bf0Spatrick /// supposed to point to the position of the first attribute described
95973471bf0Spatrick /// by \p Abbrev.
96073471bf0Spatrick /// \return [StartOffset, EndOffset) as a pair.
96173471bf0Spatrick static std::pair<uint64_t, uint64_t>
getAttributeOffsets(const DWARFAbbreviationDeclaration * Abbrev,unsigned Idx,uint64_t Offset,const DWARFUnit & Unit)96273471bf0Spatrick getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
96373471bf0Spatrick uint64_t Offset, const DWARFUnit &Unit) {
96473471bf0Spatrick DataExtractor Data = Unit.getDebugInfoExtractor();
96573471bf0Spatrick
96673471bf0Spatrick for (unsigned I = 0; I < Idx; ++I)
96773471bf0Spatrick DWARFFormValue::skipValue(Abbrev->getFormByIndex(I), Data, &Offset,
96873471bf0Spatrick Unit.getFormParams());
96973471bf0Spatrick
97073471bf0Spatrick uint64_t End = Offset;
97173471bf0Spatrick DWARFFormValue::skipValue(Abbrev->getFormByIndex(Idx), Data, &End,
97273471bf0Spatrick Unit.getFormParams());
97373471bf0Spatrick
97473471bf0Spatrick return std::make_pair(Offset, End);
97573471bf0Spatrick }
97673471bf0Spatrick
isLiveVariable(const DWARFDie & DIE,CompileUnit::DIEInfo & MyInfo)977*d415bd75Srobert bool DwarfLinkerForBinary::AddressManager::isLiveVariable(
97873471bf0Spatrick const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo) {
97973471bf0Spatrick const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
98073471bf0Spatrick
981*d415bd75Srobert std::optional<uint32_t> LocationIdx =
98273471bf0Spatrick Abbrev->findAttributeIndex(dwarf::DW_AT_location);
98373471bf0Spatrick if (!LocationIdx)
98473471bf0Spatrick return false;
98573471bf0Spatrick
98673471bf0Spatrick uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
98773471bf0Spatrick uint64_t LocationOffset, LocationEndOffset;
98873471bf0Spatrick std::tie(LocationOffset, LocationEndOffset) =
98973471bf0Spatrick getAttributeOffsets(Abbrev, *LocationIdx, Offset, *DIE.getDwarfUnit());
99073471bf0Spatrick
99173471bf0Spatrick // FIXME: Support relocations debug_addr.
99273471bf0Spatrick return hasValidRelocationAt(ValidDebugInfoRelocs, LocationOffset,
99373471bf0Spatrick LocationEndOffset, MyInfo);
99473471bf0Spatrick }
99573471bf0Spatrick
isLiveSubprogram(const DWARFDie & DIE,CompileUnit::DIEInfo & MyInfo)996*d415bd75Srobert bool DwarfLinkerForBinary::AddressManager::isLiveSubprogram(
99773471bf0Spatrick const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo) {
99873471bf0Spatrick const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
99973471bf0Spatrick
1000*d415bd75Srobert std::optional<uint32_t> LowPcIdx =
1001*d415bd75Srobert Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc);
100273471bf0Spatrick if (!LowPcIdx)
100373471bf0Spatrick return false;
100473471bf0Spatrick
100573471bf0Spatrick dwarf::Form Form = Abbrev->getFormByIndex(*LowPcIdx);
100673471bf0Spatrick
100773471bf0Spatrick if (Form == dwarf::DW_FORM_addr) {
100873471bf0Spatrick uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
100973471bf0Spatrick uint64_t LowPcOffset, LowPcEndOffset;
101073471bf0Spatrick std::tie(LowPcOffset, LowPcEndOffset) =
101173471bf0Spatrick getAttributeOffsets(Abbrev, *LowPcIdx, Offset, *DIE.getDwarfUnit());
101273471bf0Spatrick return hasValidRelocationAt(ValidDebugInfoRelocs, LowPcOffset,
101373471bf0Spatrick LowPcEndOffset, MyInfo);
101473471bf0Spatrick }
101573471bf0Spatrick
101673471bf0Spatrick if (Form == dwarf::DW_FORM_addrx) {
1017*d415bd75Srobert std::optional<DWARFFormValue> AddrValue = DIE.find(dwarf::DW_AT_low_pc);
1018*d415bd75Srobert if (std::optional<uint64_t> AddrOffsetSectionBase =
101973471bf0Spatrick DIE.getDwarfUnit()->getAddrOffsetSectionBase()) {
102073471bf0Spatrick uint64_t StartOffset = *AddrOffsetSectionBase + AddrValue->getRawUValue();
102173471bf0Spatrick uint64_t EndOffset =
102273471bf0Spatrick StartOffset + DIE.getDwarfUnit()->getAddressByteSize();
102373471bf0Spatrick return hasValidRelocationAt(ValidDebugAddrRelocs, StartOffset, EndOffset,
102473471bf0Spatrick MyInfo);
102573471bf0Spatrick } else
102673471bf0Spatrick Linker.reportWarning("no base offset for address table", SrcFileName);
102773471bf0Spatrick }
102873471bf0Spatrick
102973471bf0Spatrick return false;
103073471bf0Spatrick }
103173471bf0Spatrick
103273471bf0Spatrick uint64_t
relocate(const ValidReloc & Reloc) const103373471bf0Spatrick DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const {
103473471bf0Spatrick return Reloc.Mapping->getValue().BinaryAddress + Reloc.Addend;
103573471bf0Spatrick }
103673471bf0Spatrick
1037097a140dSpatrick /// Apply the valid relocations found by findValidRelocs() to
1038097a140dSpatrick /// the buffer \p Data, taking into account that Data is at \p BaseOffset
1039097a140dSpatrick /// in the debug_info section.
1040097a140dSpatrick ///
1041097a140dSpatrick /// Like for findValidRelocs(), this function must be called with
1042097a140dSpatrick /// monotonic \p BaseOffset values.
1043097a140dSpatrick ///
1044097a140dSpatrick /// \returns whether any reloc has been applied.
applyValidRelocs(MutableArrayRef<char> Data,uint64_t BaseOffset,bool IsLittleEndian)1045097a140dSpatrick bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
1046097a140dSpatrick MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
104773471bf0Spatrick std::vector<ValidReloc> Relocs = getRelocations(
104873471bf0Spatrick ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size());
1049097a140dSpatrick
105073471bf0Spatrick for (const ValidReloc &CurReloc : Relocs) {
105173471bf0Spatrick assert(CurReloc.Offset - BaseOffset < Data.size());
105273471bf0Spatrick assert(CurReloc.Offset - BaseOffset + CurReloc.Size <= Data.size());
1053097a140dSpatrick char Buf[8];
105473471bf0Spatrick uint64_t Value = relocate(CurReloc);
105573471bf0Spatrick for (unsigned I = 0; I != CurReloc.Size; ++I) {
105673471bf0Spatrick unsigned Index = IsLittleEndian ? I : (CurReloc.Size - I - 1);
1057097a140dSpatrick Buf[I] = uint8_t(Value >> (Index * 8));
1058097a140dSpatrick }
105973471bf0Spatrick assert(CurReloc.Size <= sizeof(Buf));
106073471bf0Spatrick memcpy(&Data[CurReloc.Offset - BaseOffset], Buf, CurReloc.Size);
1061097a140dSpatrick }
1062097a140dSpatrick
106373471bf0Spatrick return Relocs.size() > 0;
106473471bf0Spatrick }
106573471bf0Spatrick
106673471bf0Spatrick llvm::Expected<uint64_t>
relocateIndexedAddr(uint64_t StartOffset,uint64_t EndOffset)106773471bf0Spatrick DwarfLinkerForBinary::AddressManager::relocateIndexedAddr(uint64_t StartOffset,
106873471bf0Spatrick uint64_t EndOffset) {
106973471bf0Spatrick std::vector<ValidReloc> Relocs =
107073471bf0Spatrick getRelocations(ValidDebugAddrRelocs, StartOffset, EndOffset);
107173471bf0Spatrick if (Relocs.size() == 0)
107273471bf0Spatrick return createStringError(
107373471bf0Spatrick std::make_error_code(std::errc::invalid_argument),
107473471bf0Spatrick "no relocation for offset %llu in debug_addr section", StartOffset);
107573471bf0Spatrick
107673471bf0Spatrick return relocate(Relocs[0]);
1077097a140dSpatrick }
107809467b48Spatrick
linkDwarf(raw_fd_ostream & OutFile,BinaryHolder & BinHolder,const DebugMap & DM,LinkOptions Options)107909467b48Spatrick bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
108009467b48Spatrick const DebugMap &DM, LinkOptions Options) {
108109467b48Spatrick DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options));
108209467b48Spatrick return Linker.link(DM);
108309467b48Spatrick }
108409467b48Spatrick
108509467b48Spatrick } // namespace dsymutil
108609467b48Spatrick } // namespace llvm
1087