diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/libs/llvm12/tools/dsymutil | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/llvm12/tools/dsymutil')
20 files changed, 4722 insertions, 4722 deletions
diff --git a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp index f83521346c..6a90549be5 100644 --- a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp +++ b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp @@ -1,101 +1,101 @@ -//===-- BinaryHolder.cpp --------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This program is a utility that aims to be a dropin replacement for -// Darwin's dsymutil. -// -//===----------------------------------------------------------------------===// - -#include "BinaryHolder.h" -#include "llvm/Object/MachO.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" - -namespace llvm { -namespace dsymutil { - -static std::pair<StringRef, StringRef> -getArchiveAndObjectName(StringRef Filename) { - StringRef Archive = Filename.substr(0, Filename.rfind('(')); - StringRef Object = Filename.substr(Archive.size() + 1).drop_back(); - return {Archive, Object}; -} - -static bool isArchive(StringRef Filename) { return Filename.endswith(")"); } - -static std::vector<MemoryBufferRef> -getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem, - object::MachOUniversalBinary &Fat) { - std::vector<MemoryBufferRef> Buffers; - StringRef FatData = Fat.getData(); - for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End; - ++It) { - StringRef ObjData = FatData.substr(It->getOffset(), It->getSize()); - Buffers.emplace_back(ObjData, Filename); - } - return Buffers; -} - -Error BinaryHolder::ArchiveEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, - StringRef Filename, - TimestampTy Timestamp, bool Verbose) { - StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first; - - // Try to load archive and force it to be memory mapped. - auto ErrOrBuff = (ArchiveFilename == "-") - ? MemoryBuffer::getSTDIN() - : VFS->getBufferForFile(ArchiveFilename, -1, false); - if (auto Err = ErrOrBuff.getError()) - return errorCodeToError(Err); - - MemBuffer = std::move(*ErrOrBuff); - - if (Verbose) - WithColor::note() << "loaded archive '" << ArchiveFilename << "'\n"; - - // Load one or more archive buffers, depending on whether we're dealing with - // a fat binary. - std::vector<MemoryBufferRef> ArchiveBuffers; - - auto ErrOrFat = - object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef()); - if (!ErrOrFat) { - consumeError(ErrOrFat.takeError()); - ArchiveBuffers.push_back(MemBuffer->getMemBufferRef()); - } else { - FatBinary = std::move(*ErrOrFat); - FatBinaryName = std::string(ArchiveFilename); - ArchiveBuffers = - getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary); - } - - // Finally, try to load the archives. - Archives.reserve(ArchiveBuffers.size()); - for (auto MemRef : ArchiveBuffers) { - auto ErrOrArchive = object::Archive::create(MemRef); - if (!ErrOrArchive) - return ErrOrArchive.takeError(); - Archives.push_back(std::move(*ErrOrArchive)); - } - - return Error::success(); -} - -Error BinaryHolder::ObjectEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, +//===-- BinaryHolder.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that aims to be a dropin replacement for +// Darwin's dsymutil. +// +//===----------------------------------------------------------------------===// + +#include "BinaryHolder.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace dsymutil { + +static std::pair<StringRef, StringRef> +getArchiveAndObjectName(StringRef Filename) { + StringRef Archive = Filename.substr(0, Filename.rfind('(')); + StringRef Object = Filename.substr(Archive.size() + 1).drop_back(); + return {Archive, Object}; +} + +static bool isArchive(StringRef Filename) { return Filename.endswith(")"); } + +static std::vector<MemoryBufferRef> +getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem, + object::MachOUniversalBinary &Fat) { + std::vector<MemoryBufferRef> Buffers; + StringRef FatData = Fat.getData(); + for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End; + ++It) { + StringRef ObjData = FatData.substr(It->getOffset(), It->getSize()); + Buffers.emplace_back(ObjData, Filename); + } + return Buffers; +} + +Error BinaryHolder::ArchiveEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, + StringRef Filename, + TimestampTy Timestamp, bool Verbose) { + StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first; + + // Try to load archive and force it to be memory mapped. + auto ErrOrBuff = (ArchiveFilename == "-") + ? MemoryBuffer::getSTDIN() + : VFS->getBufferForFile(ArchiveFilename, -1, false); + if (auto Err = ErrOrBuff.getError()) + return errorCodeToError(Err); + + MemBuffer = std::move(*ErrOrBuff); + + if (Verbose) + WithColor::note() << "loaded archive '" << ArchiveFilename << "'\n"; + + // Load one or more archive buffers, depending on whether we're dealing with + // a fat binary. + std::vector<MemoryBufferRef> ArchiveBuffers; + + auto ErrOrFat = + object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef()); + if (!ErrOrFat) { + consumeError(ErrOrFat.takeError()); + ArchiveBuffers.push_back(MemBuffer->getMemBufferRef()); + } else { + FatBinary = std::move(*ErrOrFat); + FatBinaryName = std::string(ArchiveFilename); + ArchiveBuffers = + getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary); + } + + // Finally, try to load the archives. + Archives.reserve(ArchiveBuffers.size()); + for (auto MemRef : ArchiveBuffers) { + auto ErrOrArchive = object::Archive::create(MemRef); + if (!ErrOrArchive) + return ErrOrArchive.takeError(); + Archives.push_back(std::move(*ErrOrArchive)); + } + + return Error::success(); +} + +Error BinaryHolder::ObjectEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename, TimestampTy Timestamp, bool Verbose) { - // Try to load regular binary and force it to be memory mapped. - auto ErrOrBuff = (Filename == "-") - ? MemoryBuffer::getSTDIN() - : VFS->getBufferForFile(Filename, -1, false); - if (auto Err = ErrOrBuff.getError()) - return errorCodeToError(Err); - + // Try to load regular binary and force it to be memory mapped. + auto ErrOrBuff = (Filename == "-") + ? MemoryBuffer::getSTDIN() + : VFS->getBufferForFile(Filename, -1, false); + if (auto Err = ErrOrBuff.getError()) + return errorCodeToError(Err); + if (Filename != "-" && Timestamp != sys::TimePoint<>()) { llvm::ErrorOr<vfs::Status> Stat = VFS->status(Filename); if (!Stat) @@ -108,178 +108,178 @@ Error BinaryHolder::ObjectEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, << ") and debug map (" << Timestamp << ")\n"; } - MemBuffer = std::move(*ErrOrBuff); - - if (Verbose) - WithColor::note() << "loaded object.\n"; - - // Load one or more object buffers, depending on whether we're dealing with a - // fat binary. - std::vector<MemoryBufferRef> ObjectBuffers; - - auto ErrOrFat = - object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef()); - if (!ErrOrFat) { - consumeError(ErrOrFat.takeError()); - ObjectBuffers.push_back(MemBuffer->getMemBufferRef()); - } else { - FatBinary = std::move(*ErrOrFat); - FatBinaryName = std::string(Filename); - ObjectBuffers = - getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary); - } - - Objects.reserve(ObjectBuffers.size()); - for (auto MemRef : ObjectBuffers) { - auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemRef); - if (!ErrOrObjectFile) - return ErrOrObjectFile.takeError(); - Objects.push_back(std::move(*ErrOrObjectFile)); - } - - return Error::success(); -} - -std::vector<const object::ObjectFile *> -BinaryHolder::ObjectEntry::getObjects() const { - std::vector<const object::ObjectFile *> Result; - Result.reserve(Objects.size()); - for (auto &Object : Objects) { - Result.push_back(Object.get()); - } - return Result; -} -Expected<const object::ObjectFile &> -BinaryHolder::ObjectEntry::getObject(const Triple &T) const { - for (const auto &Obj : Objects) { - if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) { - if (MachO->getArchTriple().str() == T.str()) - return *MachO; - } else if (Obj->getArch() == T.getArch()) - return *Obj; - } - return errorCodeToError(object::object_error::arch_not_found); -} - -Expected<const BinaryHolder::ObjectEntry &> -BinaryHolder::ArchiveEntry::getObjectEntry(StringRef Filename, - TimestampTy Timestamp, - bool Verbose) { - StringRef ArchiveFilename; - StringRef ObjectFilename; - std::tie(ArchiveFilename, ObjectFilename) = getArchiveAndObjectName(Filename); - - // Try the cache first. - KeyTy Key = {ObjectFilename, Timestamp}; - - { - std::lock_guard<std::mutex> Lock(MemberCacheMutex); - if (MemberCache.count(Key)) - return MemberCache[Key]; - } - - // Create a new ObjectEntry, but don't add it to the cache yet. Loading of - // the archive members might fail and we don't want to lock the whole archive - // during this operation. - ObjectEntry OE; - - for (const auto &Archive : Archives) { - Error Err = Error::success(); - for (auto Child : Archive->children(Err)) { - if (auto NameOrErr = Child.getName()) { - if (*NameOrErr == ObjectFilename) { - auto ModTimeOrErr = Child.getLastModified(); - if (!ModTimeOrErr) - return ModTimeOrErr.takeError(); - - if (Timestamp != sys::TimePoint<>() && + MemBuffer = std::move(*ErrOrBuff); + + if (Verbose) + WithColor::note() << "loaded object.\n"; + + // Load one or more object buffers, depending on whether we're dealing with a + // fat binary. + std::vector<MemoryBufferRef> ObjectBuffers; + + auto ErrOrFat = + object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef()); + if (!ErrOrFat) { + consumeError(ErrOrFat.takeError()); + ObjectBuffers.push_back(MemBuffer->getMemBufferRef()); + } else { + FatBinary = std::move(*ErrOrFat); + FatBinaryName = std::string(Filename); + ObjectBuffers = + getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary); + } + + Objects.reserve(ObjectBuffers.size()); + for (auto MemRef : ObjectBuffers) { + auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemRef); + if (!ErrOrObjectFile) + return ErrOrObjectFile.takeError(); + Objects.push_back(std::move(*ErrOrObjectFile)); + } + + return Error::success(); +} + +std::vector<const object::ObjectFile *> +BinaryHolder::ObjectEntry::getObjects() const { + std::vector<const object::ObjectFile *> Result; + Result.reserve(Objects.size()); + for (auto &Object : Objects) { + Result.push_back(Object.get()); + } + return Result; +} +Expected<const object::ObjectFile &> +BinaryHolder::ObjectEntry::getObject(const Triple &T) const { + for (const auto &Obj : Objects) { + if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) { + if (MachO->getArchTriple().str() == T.str()) + return *MachO; + } else if (Obj->getArch() == T.getArch()) + return *Obj; + } + return errorCodeToError(object::object_error::arch_not_found); +} + +Expected<const BinaryHolder::ObjectEntry &> +BinaryHolder::ArchiveEntry::getObjectEntry(StringRef Filename, + TimestampTy Timestamp, + bool Verbose) { + StringRef ArchiveFilename; + StringRef ObjectFilename; + std::tie(ArchiveFilename, ObjectFilename) = getArchiveAndObjectName(Filename); + + // Try the cache first. + KeyTy Key = {ObjectFilename, Timestamp}; + + { + std::lock_guard<std::mutex> Lock(MemberCacheMutex); + if (MemberCache.count(Key)) + return MemberCache[Key]; + } + + // Create a new ObjectEntry, but don't add it to the cache yet. Loading of + // the archive members might fail and we don't want to lock the whole archive + // during this operation. + ObjectEntry OE; + + for (const auto &Archive : Archives) { + Error Err = Error::success(); + for (auto Child : Archive->children(Err)) { + if (auto NameOrErr = Child.getName()) { + if (*NameOrErr == ObjectFilename) { + auto ModTimeOrErr = Child.getLastModified(); + if (!ModTimeOrErr) + return ModTimeOrErr.takeError(); + + if (Timestamp != sys::TimePoint<>() && Timestamp != std::chrono::time_point_cast<std::chrono::seconds>( ModTimeOrErr.get())) { - if (Verbose) + if (Verbose) WithColor::warning() << *NameOrErr << ": timestamp mismatch between archive member (" << ModTimeOrErr.get() << ") and debug map (" << Timestamp << ")\n"; - continue; - } - - if (Verbose) - WithColor::note() << "found member in archive.\n"; - - auto ErrOrMem = Child.getMemoryBufferRef(); - if (!ErrOrMem) - return ErrOrMem.takeError(); - - auto ErrOrObjectFile = - object::ObjectFile::createObjectFile(*ErrOrMem); - if (!ErrOrObjectFile) - return ErrOrObjectFile.takeError(); - - OE.Objects.push_back(std::move(*ErrOrObjectFile)); - } - } - } - if (Err) - return std::move(Err); - } - - if (OE.Objects.empty()) - return errorCodeToError(errc::no_such_file_or_directory); - - std::lock_guard<std::mutex> Lock(MemberCacheMutex); - MemberCache.try_emplace(Key, std::move(OE)); - return MemberCache[Key]; -} - -Expected<const BinaryHolder::ObjectEntry &> -BinaryHolder::getObjectEntry(StringRef Filename, TimestampTy Timestamp) { - if (Verbose) - WithColor::note() << "trying to open '" << Filename << "'\n"; - - // If this is an archive, we might have either the object or the archive - // cached. In this case we can load it without accessing the file system. - if (isArchive(Filename)) { - StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first; - std::lock_guard<std::mutex> Lock(ArchiveCacheMutex); - if (ArchiveCache.count(ArchiveFilename)) { - return ArchiveCache[ArchiveFilename].getObjectEntry(Filename, Timestamp, - Verbose); - } else { - ArchiveEntry &AE = ArchiveCache[ArchiveFilename]; - auto Err = AE.load(VFS, Filename, Timestamp, Verbose); - if (Err) { - ArchiveCache.erase(ArchiveFilename); - // Don't return the error here: maybe the file wasn't an archive. - llvm::consumeError(std::move(Err)); - } else { - return ArchiveCache[ArchiveFilename].getObjectEntry(Filename, Timestamp, - Verbose); - } - } - } - - // If this is an object, we might have it cached. If not we'll have to load - // it from the file system and cache it now. - std::lock_guard<std::mutex> Lock(ObjectCacheMutex); - if (!ObjectCache.count(Filename)) { - ObjectEntry &OE = ObjectCache[Filename]; + continue; + } + + if (Verbose) + WithColor::note() << "found member in archive.\n"; + + auto ErrOrMem = Child.getMemoryBufferRef(); + if (!ErrOrMem) + return ErrOrMem.takeError(); + + auto ErrOrObjectFile = + object::ObjectFile::createObjectFile(*ErrOrMem); + if (!ErrOrObjectFile) + return ErrOrObjectFile.takeError(); + + OE.Objects.push_back(std::move(*ErrOrObjectFile)); + } + } + } + if (Err) + return std::move(Err); + } + + if (OE.Objects.empty()) + return errorCodeToError(errc::no_such_file_or_directory); + + std::lock_guard<std::mutex> Lock(MemberCacheMutex); + MemberCache.try_emplace(Key, std::move(OE)); + return MemberCache[Key]; +} + +Expected<const BinaryHolder::ObjectEntry &> +BinaryHolder::getObjectEntry(StringRef Filename, TimestampTy Timestamp) { + if (Verbose) + WithColor::note() << "trying to open '" << Filename << "'\n"; + + // If this is an archive, we might have either the object or the archive + // cached. In this case we can load it without accessing the file system. + if (isArchive(Filename)) { + StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first; + std::lock_guard<std::mutex> Lock(ArchiveCacheMutex); + if (ArchiveCache.count(ArchiveFilename)) { + return ArchiveCache[ArchiveFilename].getObjectEntry(Filename, Timestamp, + Verbose); + } else { + ArchiveEntry &AE = ArchiveCache[ArchiveFilename]; + auto Err = AE.load(VFS, Filename, Timestamp, Verbose); + if (Err) { + ArchiveCache.erase(ArchiveFilename); + // Don't return the error here: maybe the file wasn't an archive. + llvm::consumeError(std::move(Err)); + } else { + return ArchiveCache[ArchiveFilename].getObjectEntry(Filename, Timestamp, + Verbose); + } + } + } + + // If this is an object, we might have it cached. If not we'll have to load + // it from the file system and cache it now. + std::lock_guard<std::mutex> Lock(ObjectCacheMutex); + if (!ObjectCache.count(Filename)) { + ObjectEntry &OE = ObjectCache[Filename]; auto Err = OE.load(VFS, Filename, Timestamp, Verbose); - if (Err) { - ObjectCache.erase(Filename); - return std::move(Err); - } - } - - return ObjectCache[Filename]; -} - -void BinaryHolder::clear() { - std::lock_guard<std::mutex> ArchiveLock(ArchiveCacheMutex); - std::lock_guard<std::mutex> ObjectLock(ObjectCacheMutex); - ArchiveCache.clear(); - ObjectCache.clear(); -} - -} // namespace dsymutil -} // namespace llvm + if (Err) { + ObjectCache.erase(Filename); + return std::move(Err); + } + } + + return ObjectCache[Filename]; +} + +void BinaryHolder::clear() { + std::lock_guard<std::mutex> ArchiveLock(ArchiveCacheMutex); + std::lock_guard<std::mutex> ObjectLock(ObjectCacheMutex); + ArchiveCache.clear(); + ObjectCache.clear(); +} + +} // namespace dsymutil +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h index 5e81fe4b93..bf4bcb63b6 100644 --- a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h +++ b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h @@ -1,172 +1,172 @@ -//===-- BinaryHolder.h - Utility class for accessing binaries -------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This program is a utility that aims to be a dropin replacement for -// Darwin's dsymutil. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H -#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/Error.h" -#include "llvm/Object/MachOUniversal.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Chrono.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/VirtualFileSystem.h" - -#include <mutex> - -namespace llvm { -namespace dsymutil { - -/// The BinaryHolder class is responsible for creating and owning -/// ObjectFiles and their underlying MemoryBuffers. It differs from a simple -/// OwningBinary in that it handles accessing and caching of archives and its -/// members. -class BinaryHolder { -public: - using TimestampTy = sys::TimePoint<std::chrono::seconds>; - - BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool Verbose = false) - : VFS(VFS), Verbose(Verbose) {} - - // Forward declarations for friend declaration. - class ObjectEntry; - class ArchiveEntry; - - /// Base class shared by cached entries, representing objects and archives. - class EntryBase { - protected: - std::unique_ptr<MemoryBuffer> MemBuffer; - std::unique_ptr<object::MachOUniversalBinary> FatBinary; - std::string FatBinaryName; - }; - - /// Cached entry holding one or more (in case of a fat binary) object files. - class ObjectEntry : public EntryBase { - public: - /// Load the given object binary in memory. - Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename, +//===-- BinaryHolder.h - Utility class for accessing binaries -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that aims to be a dropin replacement for +// Darwin's dsymutil. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H +#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/Error.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/VirtualFileSystem.h" + +#include <mutex> + +namespace llvm { +namespace dsymutil { + +/// The BinaryHolder class is responsible for creating and owning +/// ObjectFiles and their underlying MemoryBuffers. It differs from a simple +/// OwningBinary in that it handles accessing and caching of archives and its +/// members. +class BinaryHolder { +public: + using TimestampTy = sys::TimePoint<std::chrono::seconds>; + + BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool Verbose = false) + : VFS(VFS), Verbose(Verbose) {} + + // Forward declarations for friend declaration. + class ObjectEntry; + class ArchiveEntry; + + /// Base class shared by cached entries, representing objects and archives. + class EntryBase { + protected: + std::unique_ptr<MemoryBuffer> MemBuffer; + std::unique_ptr<object::MachOUniversalBinary> FatBinary; + std::string FatBinaryName; + }; + + /// Cached entry holding one or more (in case of a fat binary) object files. + class ObjectEntry : public EntryBase { + public: + /// Load the given object binary in memory. + Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename, TimestampTy Timestamp, bool Verbose = false); - - /// Access all owned ObjectFiles. - std::vector<const object::ObjectFile *> getObjects() const; - - /// Access to a derived version of all the currently owned ObjectFiles. The - /// conversion might be invalid, in which case an Error is returned. - template <typename ObjectFileType> - Expected<std::vector<const ObjectFileType *>> getObjectsAs() const { - std::vector<const ObjectFileType *> Result; - Result.reserve(Objects.size()); - for (auto &Object : Objects) { - const auto *Derived = dyn_cast<ObjectFileType>(Object.get()); - if (!Derived) - return errorCodeToError(object::object_error::invalid_file_type); - Result.push_back(Derived); - } - return Result; - } - - /// Access the owned ObjectFile with architecture \p T. - Expected<const object::ObjectFile &> getObject(const Triple &T) const; - - /// Access to a derived version of the currently owned ObjectFile with - /// architecture \p T. The conversion must be known to be valid. - template <typename ObjectFileType> - Expected<const ObjectFileType &> getObjectAs(const Triple &T) const { - auto Object = getObject(T); - if (!Object) - return Object.takeError(); - return cast<ObjectFileType>(*Object); - } - - private: - std::vector<std::unique_ptr<object::ObjectFile>> Objects; - friend ArchiveEntry; - }; - - /// Cached entry holding one or more (in the of a fat binary) archive files. - class ArchiveEntry : public EntryBase { - public: - struct KeyTy { - std::string Filename; - TimestampTy Timestamp; - - KeyTy() : Filename(), Timestamp() {} - KeyTy(StringRef Filename, TimestampTy Timestamp) - : Filename(Filename.str()), Timestamp(Timestamp) {} - }; - - /// Load the given object binary in memory. - Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename, - TimestampTy Timestamp, bool Verbose = false); - - Expected<const ObjectEntry &> getObjectEntry(StringRef Filename, - TimestampTy Timestamp, - bool Verbose = false); - - private: - std::vector<std::unique_ptr<object::Archive>> Archives; - DenseMap<KeyTy, ObjectEntry> MemberCache; - std::mutex MemberCacheMutex; - }; - - Expected<const ObjectEntry &> - getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy()); - - void clear(); - -private: - /// Cache of static archives. Objects that are part of a static archive are - /// stored under this object, rather than in the map below. - StringMap<ArchiveEntry> ArchiveCache; - std::mutex ArchiveCacheMutex; - - /// Object entries for objects that are not in a static archive. - StringMap<ObjectEntry> ObjectCache; - std::mutex ObjectCacheMutex; - - /// Virtual File System instance. - IntrusiveRefCntPtr<vfs::FileSystem> VFS; - - bool Verbose; -}; - -} // namespace dsymutil - -template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> { - - static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() { - return dsymutil::BinaryHolder::ArchiveEntry::KeyTy(); - } - - static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() { - return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {}); - } - - static unsigned - getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) { - return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename), - DenseMapInfo<unsigned>::getHashValue( - K.Timestamp.time_since_epoch().count())); - } - - static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS, - const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) { - return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp; - } -}; - -} // namespace llvm -#endif + + /// Access all owned ObjectFiles. + std::vector<const object::ObjectFile *> getObjects() const; + + /// Access to a derived version of all the currently owned ObjectFiles. The + /// conversion might be invalid, in which case an Error is returned. + template <typename ObjectFileType> + Expected<std::vector<const ObjectFileType *>> getObjectsAs() const { + std::vector<const ObjectFileType *> Result; + Result.reserve(Objects.size()); + for (auto &Object : Objects) { + const auto *Derived = dyn_cast<ObjectFileType>(Object.get()); + if (!Derived) + return errorCodeToError(object::object_error::invalid_file_type); + Result.push_back(Derived); + } + return Result; + } + + /// Access the owned ObjectFile with architecture \p T. + Expected<const object::ObjectFile &> getObject(const Triple &T) const; + + /// Access to a derived version of the currently owned ObjectFile with + /// architecture \p T. The conversion must be known to be valid. + template <typename ObjectFileType> + Expected<const ObjectFileType &> getObjectAs(const Triple &T) const { + auto Object = getObject(T); + if (!Object) + return Object.takeError(); + return cast<ObjectFileType>(*Object); + } + + private: + std::vector<std::unique_ptr<object::ObjectFile>> Objects; + friend ArchiveEntry; + }; + + /// Cached entry holding one or more (in the of a fat binary) archive files. + class ArchiveEntry : public EntryBase { + public: + struct KeyTy { + std::string Filename; + TimestampTy Timestamp; + + KeyTy() : Filename(), Timestamp() {} + KeyTy(StringRef Filename, TimestampTy Timestamp) + : Filename(Filename.str()), Timestamp(Timestamp) {} + }; + + /// Load the given object binary in memory. + Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename, + TimestampTy Timestamp, bool Verbose = false); + + Expected<const ObjectEntry &> getObjectEntry(StringRef Filename, + TimestampTy Timestamp, + bool Verbose = false); + + private: + std::vector<std::unique_ptr<object::Archive>> Archives; + DenseMap<KeyTy, ObjectEntry> MemberCache; + std::mutex MemberCacheMutex; + }; + + Expected<const ObjectEntry &> + getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy()); + + void clear(); + +private: + /// Cache of static archives. Objects that are part of a static archive are + /// stored under this object, rather than in the map below. + StringMap<ArchiveEntry> ArchiveCache; + std::mutex ArchiveCacheMutex; + + /// Object entries for objects that are not in a static archive. + StringMap<ObjectEntry> ObjectCache; + std::mutex ObjectCacheMutex; + + /// Virtual File System instance. + IntrusiveRefCntPtr<vfs::FileSystem> VFS; + + bool Verbose; +}; + +} // namespace dsymutil + +template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> { + + static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() { + return dsymutil::BinaryHolder::ArchiveEntry::KeyTy(); + } + + static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() { + return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {}); + } + + static unsigned + getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) { + return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename), + DenseMapInfo<unsigned>::getHashValue( + K.Timestamp.time_since_epoch().count())); + } + + static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS, + const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) { + return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp; + } +}; + +} // namespace llvm +#endif diff --git a/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp b/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp index 0625afb18a..406c35cc59 100644 --- a/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp +++ b/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp @@ -1,185 +1,185 @@ -//===- tools/dsymutil/CFBundle.cpp - CFBundle helper ------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "CFBundle.h" - -#ifdef __APPLE__ -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <CoreFoundation/CoreFoundation.h> -#include <assert.h> -#include <glob.h> -#include <memory> -#endif - -namespace llvm { -namespace dsymutil { - -#ifdef __APPLE__ -/// Deleter that calls CFRelease rather than deleting the pointer. -template <typename T> struct CFDeleter { - void operator()(T *P) { - if (P) - ::CFRelease(P); - } -}; - -/// This helper owns any CoreFoundation pointer and will call CFRelease() on -/// any valid pointer it owns unless that pointer is explicitly released using -/// the release() member function. -template <typename T> -using CFReleaser = std::unique_ptr<std::remove_pointer_t<T>, - CFDeleter<std::remove_pointer_t<T>>>; - -/// RAII wrapper around CFBundleRef. -class CFString : public CFReleaser<CFStringRef> { -public: - CFString(CFStringRef CFStr = nullptr) : CFReleaser<CFStringRef>(CFStr) {} - - const char *UTF8(std::string &Str) const { - return CFString::UTF8(get(), Str); - } - - CFIndex GetLength() const { - if (CFStringRef Str = get()) - return CFStringGetLength(Str); - return 0; - } - - static const char *UTF8(CFStringRef CFStr, std::string &Str); -}; - -/// Static function that puts a copy of the UTF-8 contents of CFStringRef into -/// std::string and returns the C string pointer that is contained in the -/// std::string when successful, nullptr otherwise. -/// -/// This allows the std::string parameter to own the extracted string, and also -/// allows that string to be returned as a C string pointer that can be used. -const char *CFString::UTF8(CFStringRef CFStr, std::string &Str) { - if (!CFStr) - return nullptr; - - const CFStringEncoding Encoding = kCFStringEncodingUTF8; - CFIndex MaxUTF8StrLength = CFStringGetLength(CFStr); - MaxUTF8StrLength = - CFStringGetMaximumSizeForEncoding(MaxUTF8StrLength, Encoding); - if (MaxUTF8StrLength > 0) { - Str.resize(MaxUTF8StrLength); - if (!Str.empty() && - CFStringGetCString(CFStr, &Str[0], Str.size(), Encoding)) { - Str.resize(strlen(Str.c_str())); - return Str.c_str(); - } - } - - return nullptr; -} - -/// RAII wrapper around CFBundleRef. -class CFBundle : public CFReleaser<CFBundleRef> { -public: - CFBundle(StringRef Path) : CFReleaser<CFBundleRef>() { SetFromPath(Path); } - - CFBundle(CFURLRef Url) - : CFReleaser<CFBundleRef>(Url ? ::CFBundleCreate(nullptr, Url) - : nullptr) {} - - /// Return the bundle identifier. - CFStringRef GetIdentifier() const { - if (CFBundleRef bundle = get()) - return ::CFBundleGetIdentifier(bundle); - return nullptr; - } - - /// Return value for key. - CFTypeRef GetValueForInfoDictionaryKey(CFStringRef key) const { - if (CFBundleRef bundle = get()) - return ::CFBundleGetValueForInfoDictionaryKey(bundle, key); - return nullptr; - } - -private: - /// Helper to initialize this instance with a new bundle created from the - /// given path. This function will recursively remove components from the - /// path in its search for the nearest Info.plist. - void SetFromPath(StringRef Path); -}; - -void CFBundle::SetFromPath(StringRef Path) { - // Start from an empty/invalid CFBundle. - reset(); - - if (Path.empty() || !sys::fs::exists(Path)) - return; - - SmallString<256> RealPath; - sys::fs::real_path(Path, RealPath, /*expand_tilde*/ true); - - do { - // Create a CFURL from the current path and use it to create a CFBundle. - CFReleaser<CFURLRef> BundleURL(::CFURLCreateFromFileSystemRepresentation( - kCFAllocatorDefault, (const UInt8 *)RealPath.data(), RealPath.size(), - false)); - reset(::CFBundleCreate(kCFAllocatorDefault, BundleURL.get())); - - // If we have a valid bundle and find its identifier we are done. - if (get() != nullptr) { - if (GetIdentifier() != nullptr) - return; - reset(); - } - - // Remove the last component of the path and try again until there's - // nothing left but the root. - sys::path::remove_filename(RealPath); - } while (RealPath != sys::path::root_name(RealPath)); -} -#endif - -/// On Darwin, try and find the original executable's Info.plist to extract -/// information about the bundle. Return default values on other platforms. -CFBundleInfo getBundleInfo(StringRef ExePath) { - CFBundleInfo BundleInfo; - -#ifdef __APPLE__ - auto PrintError = [&](CFTypeID TypeID) { - CFString TypeIDCFStr(::CFCopyTypeIDDescription(TypeID)); - std::string TypeIDStr; - errs() << "The Info.plist key \"CFBundleShortVersionString\" is" - << "a " << TypeIDCFStr.UTF8(TypeIDStr) - << ", but it should be a string in: " << ExePath << ".\n"; - }; - - CFBundle Bundle(ExePath); - if (CFStringRef BundleID = Bundle.GetIdentifier()) { - CFString::UTF8(BundleID, BundleInfo.IDStr); - if (CFTypeRef TypeRef = - Bundle.GetValueForInfoDictionaryKey(CFSTR("CFBundleVersion"))) { - CFTypeID TypeID = ::CFGetTypeID(TypeRef); - if (TypeID == ::CFStringGetTypeID()) - CFString::UTF8((CFStringRef)TypeRef, BundleInfo.VersionStr); - else - PrintError(TypeID); - } - if (CFTypeRef TypeRef = Bundle.GetValueForInfoDictionaryKey( - CFSTR("CFBundleShortVersionString"))) { - CFTypeID TypeID = ::CFGetTypeID(TypeRef); - if (TypeID == ::CFStringGetTypeID()) - CFString::UTF8((CFStringRef)TypeRef, BundleInfo.ShortVersionStr); - else - PrintError(TypeID); - } - } -#endif - - return BundleInfo; -} - -} // end namespace dsymutil -} // end namespace llvm +//===- tools/dsymutil/CFBundle.cpp - CFBundle helper ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CFBundle.h" + +#ifdef __APPLE__ +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include <CoreFoundation/CoreFoundation.h> +#include <assert.h> +#include <glob.h> +#include <memory> +#endif + +namespace llvm { +namespace dsymutil { + +#ifdef __APPLE__ +/// Deleter that calls CFRelease rather than deleting the pointer. +template <typename T> struct CFDeleter { + void operator()(T *P) { + if (P) + ::CFRelease(P); + } +}; + +/// This helper owns any CoreFoundation pointer and will call CFRelease() on +/// any valid pointer it owns unless that pointer is explicitly released using +/// the release() member function. +template <typename T> +using CFReleaser = std::unique_ptr<std::remove_pointer_t<T>, + CFDeleter<std::remove_pointer_t<T>>>; + +/// RAII wrapper around CFBundleRef. +class CFString : public CFReleaser<CFStringRef> { +public: + CFString(CFStringRef CFStr = nullptr) : CFReleaser<CFStringRef>(CFStr) {} + + const char *UTF8(std::string &Str) const { + return CFString::UTF8(get(), Str); + } + + CFIndex GetLength() const { + if (CFStringRef Str = get()) + return CFStringGetLength(Str); + return 0; + } + + static const char *UTF8(CFStringRef CFStr, std::string &Str); +}; + +/// Static function that puts a copy of the UTF-8 contents of CFStringRef into +/// std::string and returns the C string pointer that is contained in the +/// std::string when successful, nullptr otherwise. +/// +/// This allows the std::string parameter to own the extracted string, and also +/// allows that string to be returned as a C string pointer that can be used. +const char *CFString::UTF8(CFStringRef CFStr, std::string &Str) { + if (!CFStr) + return nullptr; + + const CFStringEncoding Encoding = kCFStringEncodingUTF8; + CFIndex MaxUTF8StrLength = CFStringGetLength(CFStr); + MaxUTF8StrLength = + CFStringGetMaximumSizeForEncoding(MaxUTF8StrLength, Encoding); + if (MaxUTF8StrLength > 0) { + Str.resize(MaxUTF8StrLength); + if (!Str.empty() && + CFStringGetCString(CFStr, &Str[0], Str.size(), Encoding)) { + Str.resize(strlen(Str.c_str())); + return Str.c_str(); + } + } + + return nullptr; +} + +/// RAII wrapper around CFBundleRef. +class CFBundle : public CFReleaser<CFBundleRef> { +public: + CFBundle(StringRef Path) : CFReleaser<CFBundleRef>() { SetFromPath(Path); } + + CFBundle(CFURLRef Url) + : CFReleaser<CFBundleRef>(Url ? ::CFBundleCreate(nullptr, Url) + : nullptr) {} + + /// Return the bundle identifier. + CFStringRef GetIdentifier() const { + if (CFBundleRef bundle = get()) + return ::CFBundleGetIdentifier(bundle); + return nullptr; + } + + /// Return value for key. + CFTypeRef GetValueForInfoDictionaryKey(CFStringRef key) const { + if (CFBundleRef bundle = get()) + return ::CFBundleGetValueForInfoDictionaryKey(bundle, key); + return nullptr; + } + +private: + /// Helper to initialize this instance with a new bundle created from the + /// given path. This function will recursively remove components from the + /// path in its search for the nearest Info.plist. + void SetFromPath(StringRef Path); +}; + +void CFBundle::SetFromPath(StringRef Path) { + // Start from an empty/invalid CFBundle. + reset(); + + if (Path.empty() || !sys::fs::exists(Path)) + return; + + SmallString<256> RealPath; + sys::fs::real_path(Path, RealPath, /*expand_tilde*/ true); + + do { + // Create a CFURL from the current path and use it to create a CFBundle. + CFReleaser<CFURLRef> BundleURL(::CFURLCreateFromFileSystemRepresentation( + kCFAllocatorDefault, (const UInt8 *)RealPath.data(), RealPath.size(), + false)); + reset(::CFBundleCreate(kCFAllocatorDefault, BundleURL.get())); + + // If we have a valid bundle and find its identifier we are done. + if (get() != nullptr) { + if (GetIdentifier() != nullptr) + return; + reset(); + } + + // Remove the last component of the path and try again until there's + // nothing left but the root. + sys::path::remove_filename(RealPath); + } while (RealPath != sys::path::root_name(RealPath)); +} +#endif + +/// On Darwin, try and find the original executable's Info.plist to extract +/// information about the bundle. Return default values on other platforms. +CFBundleInfo getBundleInfo(StringRef ExePath) { + CFBundleInfo BundleInfo; + +#ifdef __APPLE__ + auto PrintError = [&](CFTypeID TypeID) { + CFString TypeIDCFStr(::CFCopyTypeIDDescription(TypeID)); + std::string TypeIDStr; + errs() << "The Info.plist key \"CFBundleShortVersionString\" is" + << "a " << TypeIDCFStr.UTF8(TypeIDStr) + << ", but it should be a string in: " << ExePath << ".\n"; + }; + + CFBundle Bundle(ExePath); + if (CFStringRef BundleID = Bundle.GetIdentifier()) { + CFString::UTF8(BundleID, BundleInfo.IDStr); + if (CFTypeRef TypeRef = + Bundle.GetValueForInfoDictionaryKey(CFSTR("CFBundleVersion"))) { + CFTypeID TypeID = ::CFGetTypeID(TypeRef); + if (TypeID == ::CFStringGetTypeID()) + CFString::UTF8((CFStringRef)TypeRef, BundleInfo.VersionStr); + else + PrintError(TypeID); + } + if (CFTypeRef TypeRef = Bundle.GetValueForInfoDictionaryKey( + CFSTR("CFBundleShortVersionString"))) { + CFTypeID TypeID = ::CFGetTypeID(TypeRef); + if (TypeID == ::CFStringGetTypeID()) + CFString::UTF8((CFStringRef)TypeRef, BundleInfo.ShortVersionStr); + else + PrintError(TypeID); + } + } +#endif + + return BundleInfo; +} + +} // end namespace dsymutil +} // end namespace llvm diff --git a/contrib/libs/llvm12/tools/dsymutil/CFBundle.h b/contrib/libs/llvm12/tools/dsymutil/CFBundle.h index 103db03516..12eb64ac0b 100644 --- a/contrib/libs/llvm12/tools/dsymutil/CFBundle.h +++ b/contrib/libs/llvm12/tools/dsymutil/CFBundle.h @@ -1,30 +1,30 @@ -//===- tools/dsymutil/CFBundle.h - CFBundle helper --------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_DSYMUTIL_CFBUNDLE_H -#define LLVM_TOOLS_DSYMUTIL_CFBUNDLE_H - -#include "llvm/ADT/StringRef.h" -#include <string> - -namespace llvm { -namespace dsymutil { - -struct CFBundleInfo { - std::string VersionStr = "1"; - std::string ShortVersionStr = "1.0"; - std::string IDStr; - bool OmitShortVersion() const { return ShortVersionStr.empty(); } -}; - -CFBundleInfo getBundleInfo(llvm::StringRef ExePath); - -} // end namespace dsymutil -} // end namespace llvm - -#endif +//===- tools/dsymutil/CFBundle.h - CFBundle helper --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_DSYMUTIL_CFBUNDLE_H +#define LLVM_TOOLS_DSYMUTIL_CFBUNDLE_H + +#include "llvm/ADT/StringRef.h" +#include <string> + +namespace llvm { +namespace dsymutil { + +struct CFBundleInfo { + std::string VersionStr = "1"; + std::string ShortVersionStr = "1.0"; + std::string IDStr; + bool OmitShortVersion() const { return ShortVersionStr.empty(); } +}; + +CFBundleInfo getBundleInfo(llvm::StringRef ExePath); + +} // end namespace dsymutil +} // end namespace llvm + +#endif diff --git a/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp b/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp index 605c1317b9..ba763e65c5 100644 --- a/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp +++ b/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp @@ -1,294 +1,294 @@ -//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DebugMap.h" -#include "BinaryHolder.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/BinaryFormat/MachO.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Chrono.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/YAMLTraits.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cinttypes> -#include <cstdint> -#include <memory> -#include <string> -#include <utility> -#include <vector> - -namespace llvm { - -namespace dsymutil { - -using namespace llvm::object; - -DebugMapObject::DebugMapObject(StringRef ObjectFilename, - sys::TimePoint<std::chrono::seconds> Timestamp, - uint8_t Type) - : Filename(std::string(ObjectFilename)), Timestamp(Timestamp), Type(Type) {} - -bool DebugMapObject::addSymbol(StringRef Name, Optional<uint64_t> ObjectAddress, - uint64_t LinkedAddress, uint32_t Size) { - auto InsertResult = Symbols.insert( - std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size))); - - if (ObjectAddress && InsertResult.second) - AddressToMapping[*ObjectAddress] = &*InsertResult.first; - return InsertResult.second; -} - -void DebugMapObject::print(raw_ostream &OS) const { - OS << getObjectFilename() << ":\n"; - // Sort the symbols in alphabetical order, like llvm-nm (and to get - // deterministic output for testing). - using Entry = std::pair<StringRef, SymbolMapping>; - std::vector<Entry> Entries; - Entries.reserve(Symbols.getNumItems()); +//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DebugMap.h" +#include "BinaryHolder.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cinttypes> +#include <cstdint> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + +namespace dsymutil { + +using namespace llvm::object; + +DebugMapObject::DebugMapObject(StringRef ObjectFilename, + sys::TimePoint<std::chrono::seconds> Timestamp, + uint8_t Type) + : Filename(std::string(ObjectFilename)), Timestamp(Timestamp), Type(Type) {} + +bool DebugMapObject::addSymbol(StringRef Name, Optional<uint64_t> ObjectAddress, + uint64_t LinkedAddress, uint32_t Size) { + auto InsertResult = Symbols.insert( + std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size))); + + if (ObjectAddress && InsertResult.second) + AddressToMapping[*ObjectAddress] = &*InsertResult.first; + return InsertResult.second; +} + +void DebugMapObject::print(raw_ostream &OS) const { + OS << getObjectFilename() << ":\n"; + // Sort the symbols in alphabetical order, like llvm-nm (and to get + // deterministic output for testing). + using Entry = std::pair<StringRef, SymbolMapping>; + std::vector<Entry> Entries; + Entries.reserve(Symbols.getNumItems()); for (const auto &Sym : Symbols) - Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue())); - llvm::sort(Entries, [](const Entry &LHS, const Entry &RHS) { - return LHS.first < RHS.first; - }); - for (const auto &Sym : Entries) { - if (Sym.second.ObjectAddress) - OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress)); - else - OS << "\t????????????????"; - OS << format(" => %016" PRIx64 "+0x%x\t%s\n", - uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size), - Sym.first.data()); - } - OS << '\n'; -} - -#ifndef NDEBUG -void DebugMapObject::dump() const { print(errs()); } -#endif - -DebugMapObject & -DebugMap::addDebugMapObject(StringRef ObjectFilePath, - sys::TimePoint<std::chrono::seconds> Timestamp, - uint8_t Type) { - Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type)); - return *Objects.back(); -} - -const DebugMapObject::DebugMapEntry * -DebugMapObject::lookupSymbol(StringRef SymbolName) const { - StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName); - if (Sym == Symbols.end()) - return nullptr; - return &*Sym; -} - -const DebugMapObject::DebugMapEntry * -DebugMapObject::lookupObjectAddress(uint64_t Address) const { - auto Mapping = AddressToMapping.find(Address); - if (Mapping == AddressToMapping.end()) - return nullptr; - return Mapping->getSecond(); -} - -void DebugMap::print(raw_ostream &OS) const { - yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0); - yout << const_cast<DebugMap &>(*this); -} - -#ifndef NDEBUG -void DebugMap::dump() const { print(errs()); } -#endif - -namespace { - -struct YAMLContext { - StringRef PrependPath; - Triple BinaryTriple; -}; - -} // end anonymous namespace - -ErrorOr<std::vector<std::unique_ptr<DebugMap>>> -DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, - bool Verbose) { - auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile); - if (auto Err = ErrOrFile.getError()) - return Err; - - YAMLContext Ctxt; - - Ctxt.PrependPath = PrependPath; - - std::unique_ptr<DebugMap> Res; - yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt); - yin >> Res; - - if (auto EC = yin.error()) - return EC; - std::vector<std::unique_ptr<DebugMap>> Result; - Result.push_back(std::move(Res)); - return std::move(Result); -} - -} // end namespace dsymutil - -namespace yaml { - -// Normalize/Denormalize between YAML and a DebugMapObject. -struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO { - YamlDMO(IO &io) { Timestamp = 0; } - YamlDMO(IO &io, dsymutil::DebugMapObject &Obj); - dsymutil::DebugMapObject denormalize(IO &IO); - - std::string Filename; - int64_t Timestamp; - std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries; -}; - -void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>:: - mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) { - io.mapRequired("sym", s.first); - io.mapOptional("objAddr", s.second.ObjectAddress); - io.mapRequired("binAddr", s.second.BinaryAddress); - io.mapOptional("size", s.second.Size); -} - -void MappingTraits<dsymutil::DebugMapObject>::mapping( - IO &io, dsymutil::DebugMapObject &DMO) { - MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO); - io.mapRequired("filename", Norm->Filename); - io.mapOptional("timestamp", Norm->Timestamp); - io.mapRequired("symbols", Norm->Entries); -} - -void ScalarTraits<Triple>::output(const Triple &val, void *, raw_ostream &out) { - out << val.str(); -} - -StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) { - value = Triple(scalar); - return StringRef(); -} - -size_t -SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size( - IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) { - return seq.size(); -} - -dsymutil::DebugMapObject & -SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element( - IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq, - size_t index) { - if (index >= seq.size()) { - seq.resize(index + 1); - seq[index].reset(new dsymutil::DebugMapObject); - } - return *seq[index]; -} - -void MappingTraits<dsymutil::DebugMap>::mapping(IO &io, - dsymutil::DebugMap &DM) { - io.mapRequired("triple", DM.BinaryTriple); - io.mapOptional("binary-path", DM.BinaryPath); - if (void *Ctxt = io.getContext()) - reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple; - io.mapOptional("objects", DM.Objects); -} - -void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping( - IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) { - if (!DM) - DM.reset(new DebugMap()); - io.mapRequired("triple", DM->BinaryTriple); - io.mapOptional("binary-path", DM->BinaryPath); - if (void *Ctxt = io.getContext()) - reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple; - io.mapOptional("objects", DM->Objects); -} - -MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO( - IO &io, dsymutil::DebugMapObject &Obj) { - Filename = Obj.Filename; - Timestamp = sys::toTimeT(Obj.getTimestamp()); - Entries.reserve(Obj.Symbols.size()); - for (auto &Entry : Obj.Symbols) - Entries.push_back( - std::make_pair(std::string(Entry.getKey()), Entry.getValue())); -} - -dsymutil::DebugMapObject -MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) { - BinaryHolder BinHolder(vfs::getRealFileSystem(), /* Verbose =*/false); - const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext()); - SmallString<80> Path(Ctxt.PrependPath); - StringMap<uint64_t> SymbolAddresses; - - sys::path::append(Path, Filename); - - auto ObjectEntry = BinHolder.getObjectEntry(Path); - if (!ObjectEntry) { - auto Err = ObjectEntry.takeError(); - WithColor::warning() << "Unable to open " << Path << " " - << toString(std::move(Err)) << '\n'; - } else { - auto Object = ObjectEntry->getObject(Ctxt.BinaryTriple); - if (!Object) { - auto Err = Object.takeError(); - WithColor::warning() << "Unable to open " << Path << " " - << toString(std::move(Err)) << '\n'; - } else { - for (const auto &Sym : Object->symbols()) { - Expected<uint64_t> AddressOrErr = Sym.getValue(); - if (!AddressOrErr) { - // TODO: Actually report errors helpfully. - consumeError(AddressOrErr.takeError()); - continue; - } - Expected<StringRef> Name = Sym.getName(); - Expected<uint32_t> FlagsOrErr = Sym.getFlags(); - if (!Name || !FlagsOrErr || - (*FlagsOrErr & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) { - // TODO: Actually report errors helpfully. - if (!FlagsOrErr) - consumeError(FlagsOrErr.takeError()); - if (!Name) - consumeError(Name.takeError()); - continue; - } - SymbolAddresses[*Name] = *AddressOrErr; - } - } - } - - dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO); - for (auto &Entry : Entries) { - auto &Mapping = Entry.second; - Optional<uint64_t> ObjAddress; - if (Mapping.ObjectAddress) - ObjAddress = *Mapping.ObjectAddress; - auto AddressIt = SymbolAddresses.find(Entry.first); - if (AddressIt != SymbolAddresses.end()) - ObjAddress = AddressIt->getValue(); - Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size); - } - return Res; -} - -} // end namespace yaml -} // end namespace llvm + Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue())); + llvm::sort(Entries, [](const Entry &LHS, const Entry &RHS) { + return LHS.first < RHS.first; + }); + for (const auto &Sym : Entries) { + if (Sym.second.ObjectAddress) + OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress)); + else + OS << "\t????????????????"; + OS << format(" => %016" PRIx64 "+0x%x\t%s\n", + uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size), + Sym.first.data()); + } + OS << '\n'; +} + +#ifndef NDEBUG +void DebugMapObject::dump() const { print(errs()); } +#endif + +DebugMapObject & +DebugMap::addDebugMapObject(StringRef ObjectFilePath, + sys::TimePoint<std::chrono::seconds> Timestamp, + uint8_t Type) { + Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type)); + return *Objects.back(); +} + +const DebugMapObject::DebugMapEntry * +DebugMapObject::lookupSymbol(StringRef SymbolName) const { + StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName); + if (Sym == Symbols.end()) + return nullptr; + return &*Sym; +} + +const DebugMapObject::DebugMapEntry * +DebugMapObject::lookupObjectAddress(uint64_t Address) const { + auto Mapping = AddressToMapping.find(Address); + if (Mapping == AddressToMapping.end()) + return nullptr; + return Mapping->getSecond(); +} + +void DebugMap::print(raw_ostream &OS) const { + yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0); + yout << const_cast<DebugMap &>(*this); +} + +#ifndef NDEBUG +void DebugMap::dump() const { print(errs()); } +#endif + +namespace { + +struct YAMLContext { + StringRef PrependPath; + Triple BinaryTriple; +}; + +} // end anonymous namespace + +ErrorOr<std::vector<std::unique_ptr<DebugMap>>> +DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, + bool Verbose) { + auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile); + if (auto Err = ErrOrFile.getError()) + return Err; + + YAMLContext Ctxt; + + Ctxt.PrependPath = PrependPath; + + std::unique_ptr<DebugMap> Res; + yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt); + yin >> Res; + + if (auto EC = yin.error()) + return EC; + std::vector<std::unique_ptr<DebugMap>> Result; + Result.push_back(std::move(Res)); + return std::move(Result); +} + +} // end namespace dsymutil + +namespace yaml { + +// Normalize/Denormalize between YAML and a DebugMapObject. +struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO { + YamlDMO(IO &io) { Timestamp = 0; } + YamlDMO(IO &io, dsymutil::DebugMapObject &Obj); + dsymutil::DebugMapObject denormalize(IO &IO); + + std::string Filename; + int64_t Timestamp; + std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries; +}; + +void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>:: + mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) { + io.mapRequired("sym", s.first); + io.mapOptional("objAddr", s.second.ObjectAddress); + io.mapRequired("binAddr", s.second.BinaryAddress); + io.mapOptional("size", s.second.Size); +} + +void MappingTraits<dsymutil::DebugMapObject>::mapping( + IO &io, dsymutil::DebugMapObject &DMO) { + MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO); + io.mapRequired("filename", Norm->Filename); + io.mapOptional("timestamp", Norm->Timestamp); + io.mapRequired("symbols", Norm->Entries); +} + +void ScalarTraits<Triple>::output(const Triple &val, void *, raw_ostream &out) { + out << val.str(); +} + +StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) { + value = Triple(scalar); + return StringRef(); +} + +size_t +SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size( + IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) { + return seq.size(); +} + +dsymutil::DebugMapObject & +SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element( + IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq, + size_t index) { + if (index >= seq.size()) { + seq.resize(index + 1); + seq[index].reset(new dsymutil::DebugMapObject); + } + return *seq[index]; +} + +void MappingTraits<dsymutil::DebugMap>::mapping(IO &io, + dsymutil::DebugMap &DM) { + io.mapRequired("triple", DM.BinaryTriple); + io.mapOptional("binary-path", DM.BinaryPath); + if (void *Ctxt = io.getContext()) + reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple; + io.mapOptional("objects", DM.Objects); +} + +void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping( + IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) { + if (!DM) + DM.reset(new DebugMap()); + io.mapRequired("triple", DM->BinaryTriple); + io.mapOptional("binary-path", DM->BinaryPath); + if (void *Ctxt = io.getContext()) + reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple; + io.mapOptional("objects", DM->Objects); +} + +MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO( + IO &io, dsymutil::DebugMapObject &Obj) { + Filename = Obj.Filename; + Timestamp = sys::toTimeT(Obj.getTimestamp()); + Entries.reserve(Obj.Symbols.size()); + for (auto &Entry : Obj.Symbols) + Entries.push_back( + std::make_pair(std::string(Entry.getKey()), Entry.getValue())); +} + +dsymutil::DebugMapObject +MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) { + BinaryHolder BinHolder(vfs::getRealFileSystem(), /* Verbose =*/false); + const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext()); + SmallString<80> Path(Ctxt.PrependPath); + StringMap<uint64_t> SymbolAddresses; + + sys::path::append(Path, Filename); + + auto ObjectEntry = BinHolder.getObjectEntry(Path); + if (!ObjectEntry) { + auto Err = ObjectEntry.takeError(); + WithColor::warning() << "Unable to open " << Path << " " + << toString(std::move(Err)) << '\n'; + } else { + auto Object = ObjectEntry->getObject(Ctxt.BinaryTriple); + if (!Object) { + auto Err = Object.takeError(); + WithColor::warning() << "Unable to open " << Path << " " + << toString(std::move(Err)) << '\n'; + } else { + for (const auto &Sym : Object->symbols()) { + Expected<uint64_t> AddressOrErr = Sym.getValue(); + if (!AddressOrErr) { + // TODO: Actually report errors helpfully. + consumeError(AddressOrErr.takeError()); + continue; + } + Expected<StringRef> Name = Sym.getName(); + Expected<uint32_t> FlagsOrErr = Sym.getFlags(); + if (!Name || !FlagsOrErr || + (*FlagsOrErr & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) { + // TODO: Actually report errors helpfully. + if (!FlagsOrErr) + consumeError(FlagsOrErr.takeError()); + if (!Name) + consumeError(Name.takeError()); + continue; + } + SymbolAddresses[*Name] = *AddressOrErr; + } + } + } + + dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO); + for (auto &Entry : Entries) { + auto &Mapping = Entry.second; + Optional<uint64_t> ObjAddress; + if (Mapping.ObjectAddress) + ObjAddress = *Mapping.ObjectAddress; + auto AddressIt = SymbolAddresses.find(Entry.first); + if (AddressIt != SymbolAddresses.end()) + ObjAddress = AddressIt->getValue(); + Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size); + } + return Res; +} + +} // end namespace yaml +} // end namespace llvm diff --git a/contrib/libs/llvm12/tools/dsymutil/DebugMap.h b/contrib/libs/llvm12/tools/dsymutil/DebugMap.h index ee552ed983..3ce8a33a0a 100644 --- a/contrib/libs/llvm12/tools/dsymutil/DebugMap.h +++ b/contrib/libs/llvm12/tools/dsymutil/DebugMap.h @@ -1,272 +1,272 @@ -//=- tools/dsymutil/DebugMap.h - Generic debug map representation -*- C++ -*-=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -/// \file -/// -/// This file contains the class declaration of the DebugMap -/// entity. A DebugMap lists all the object files linked together to -/// produce an executable along with the linked address of all the -/// atoms used in these object files. -/// The DebugMap is an input to the DwarfLinker class that will -/// extract the Dwarf debug information from the referenced object -/// files and link their usefull debug info together. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H -#define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/Object/MachO.h" -#include "llvm/Support/Chrono.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/YAMLTraits.h" -#include <chrono> -#include <cstddef> -#include <cstdint> -#include <memory> -#include <string> -#include <utility> -#include <vector> - -namespace llvm { - -class raw_ostream; - -namespace dsymutil { - -class DebugMapObject; - -/// The DebugMap object stores the list of object files to query for debug -/// information along with the mapping between the symbols' addresses in the -/// object file to their linked address in the linked binary. -/// -/// A DebugMap producer could look like this: -/// DebugMap *DM = new DebugMap(); -/// for (const auto &Obj: LinkedObjects) { -/// DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath()); -/// for (const auto &Sym: Obj.getLinkedSymbols()) -/// DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(), -/// Sym.getBinaryAddress()); -/// } -/// -/// A DebugMap consumer can then use the map to link the debug -/// information. For example something along the lines of: -/// for (const auto &DMO: DM->objects()) { -/// auto Obj = createBinary(DMO.getObjectFilename()); -/// for (auto &DIE: Obj.getDwarfDIEs()) { -/// if (SymbolMapping *Sym = DMO.lookup(DIE.getName())) -/// DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress); -/// else -/// DIE.discardSubtree(); -/// } -/// } -class DebugMap { - Triple BinaryTriple; - std::string BinaryPath; - std::vector<uint8_t> BinaryUUID; - using ObjectContainer = std::vector<std::unique_ptr<DebugMapObject>>; - - ObjectContainer Objects; - - /// For YAML IO support. - ///@{ - friend yaml::MappingTraits<std::unique_ptr<DebugMap>>; - friend yaml::MappingTraits<DebugMap>; - - DebugMap() = default; - ///@} - -public: - DebugMap(const Triple &BinaryTriple, StringRef BinaryPath, - ArrayRef<uint8_t> BinaryUUID = ArrayRef<uint8_t>()) - : BinaryTriple(BinaryTriple), BinaryPath(std::string(BinaryPath)), - BinaryUUID(BinaryUUID.begin(), BinaryUUID.end()) {} - - using const_iterator = ObjectContainer::const_iterator; - - iterator_range<const_iterator> objects() const { - return make_range(begin(), end()); - } - - const_iterator begin() const { return Objects.begin(); } - - const_iterator end() const { return Objects.end(); } - - unsigned getNumberOfObjects() const { return Objects.size(); } - - /// This function adds an DebugMapObject to the list owned by this - /// debug map. - DebugMapObject & - addDebugMapObject(StringRef ObjectFilePath, - sys::TimePoint<std::chrono::seconds> Timestamp, - uint8_t Type = llvm::MachO::N_OSO); - - const Triple &getTriple() const { return BinaryTriple; } - - const ArrayRef<uint8_t> getUUID() const { - return ArrayRef<uint8_t>(BinaryUUID); - } - - StringRef getBinaryPath() const { return BinaryPath; } - - void print(raw_ostream &OS) const; - -#ifndef NDEBUG - void dump() const; -#endif - - /// Read a debug map for \a InputFile. - static ErrorOr<std::vector<std::unique_ptr<DebugMap>>> - parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose); -}; - -/// The DebugMapObject represents one object file described by the DebugMap. It -/// contains a list of mappings between addresses in the object file and in the -/// linked binary for all the linked atoms in this object file. -class DebugMapObject { -public: - struct SymbolMapping { - Optional<yaml::Hex64> ObjectAddress; - yaml::Hex64 BinaryAddress; - yaml::Hex32 Size; - - SymbolMapping(Optional<uint64_t> ObjectAddr, uint64_t BinaryAddress, - uint32_t Size) - : BinaryAddress(BinaryAddress), Size(Size) { - if (ObjectAddr) - ObjectAddress = *ObjectAddr; - } - - /// For YAML IO support - SymbolMapping() = default; - }; - - using YAMLSymbolMapping = std::pair<std::string, SymbolMapping>; - using DebugMapEntry = StringMapEntry<SymbolMapping>; - - /// Adds a symbol mapping to this DebugMapObject. - /// \returns false if the symbol was already registered. The request - /// is discarded in this case. - bool addSymbol(StringRef SymName, Optional<uint64_t> ObjectAddress, - uint64_t LinkedAddress, uint32_t Size); - - /// Lookup a symbol mapping. - /// \returns null if the symbol isn't found. - const DebugMapEntry *lookupSymbol(StringRef SymbolName) const; - - /// Lookup an object file address. - /// \returns null if the address isn't found. - const DebugMapEntry *lookupObjectAddress(uint64_t Address) const; - - StringRef getObjectFilename() const { return Filename; } - - sys::TimePoint<std::chrono::seconds> getTimestamp() const { - return Timestamp; - } - - uint8_t getType() const { return Type; } - - iterator_range<StringMap<SymbolMapping>::const_iterator> symbols() const { - return make_range(Symbols.begin(), Symbols.end()); - } - - bool empty() const { return Symbols.empty(); } - - void addWarning(StringRef Warning) { - Warnings.push_back(std::string(Warning)); - } - const std::vector<std::string> &getWarnings() const { return Warnings; } - - void print(raw_ostream &OS) const; -#ifndef NDEBUG - void dump() const; -#endif - -private: - friend class DebugMap; - - /// DebugMapObjects can only be constructed by the owning DebugMap. - DebugMapObject(StringRef ObjectFilename, - sys::TimePoint<std::chrono::seconds> Timestamp, uint8_t Type); - - std::string Filename; - sys::TimePoint<std::chrono::seconds> Timestamp; - StringMap<SymbolMapping> Symbols; - DenseMap<uint64_t, DebugMapEntry *> AddressToMapping; - uint8_t Type; - - std::vector<std::string> Warnings; - - /// For YAMLIO support. - ///@{ - friend yaml::MappingTraits<dsymutil::DebugMapObject>; - friend yaml::SequenceTraits<std::vector<std::unique_ptr<DebugMapObject>>>; - - DebugMapObject() = default; - -public: - DebugMapObject(DebugMapObject &&) = default; - DebugMapObject &operator=(DebugMapObject &&) = default; - ///@} -}; - -} // end namespace dsymutil -} // end namespace llvm - -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::dsymutil::DebugMapObject::YAMLSymbolMapping) - -namespace llvm { -namespace yaml { - -using namespace llvm::dsymutil; - -template <> -struct MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>> { - static void mapping(IO &io, - std::pair<std::string, DebugMapObject::SymbolMapping> &s); - static const bool flow = true; -}; - -template <> struct MappingTraits<dsymutil::DebugMapObject> { - struct YamlDMO; - static void mapping(IO &io, dsymutil::DebugMapObject &DMO); -}; - -template <> struct ScalarTraits<Triple> { - static void output(const Triple &val, void *, raw_ostream &out); - static StringRef input(StringRef scalar, void *, Triple &value); - static QuotingType mustQuote(StringRef) { return QuotingType::Single; } -}; - -template <> -struct SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>> { - static size_t - size(IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq); - static dsymutil::DebugMapObject & - element(IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq, - size_t index); -}; - -template <> struct MappingTraits<dsymutil::DebugMap> { - static void mapping(IO &io, dsymutil::DebugMap &DM); -}; - -template <> struct MappingTraits<std::unique_ptr<dsymutil::DebugMap>> { - static void mapping(IO &io, std::unique_ptr<dsymutil::DebugMap> &DM); -}; - -} // end namespace yaml -} // end namespace llvm - -#endif // LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H +//=- tools/dsymutil/DebugMap.h - Generic debug map representation -*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// +/// This file contains the class declaration of the DebugMap +/// entity. A DebugMap lists all the object files linked together to +/// produce an executable along with the linked address of all the +/// atoms used in these object files. +/// The DebugMap is an input to the DwarfLinker class that will +/// extract the Dwarf debug information from the referenced object +/// files and link their usefull debug info together. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H +#define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/YAMLTraits.h" +#include <chrono> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + +class raw_ostream; + +namespace dsymutil { + +class DebugMapObject; + +/// The DebugMap object stores the list of object files to query for debug +/// information along with the mapping between the symbols' addresses in the +/// object file to their linked address in the linked binary. +/// +/// A DebugMap producer could look like this: +/// DebugMap *DM = new DebugMap(); +/// for (const auto &Obj: LinkedObjects) { +/// DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath()); +/// for (const auto &Sym: Obj.getLinkedSymbols()) +/// DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(), +/// Sym.getBinaryAddress()); +/// } +/// +/// A DebugMap consumer can then use the map to link the debug +/// information. For example something along the lines of: +/// for (const auto &DMO: DM->objects()) { +/// auto Obj = createBinary(DMO.getObjectFilename()); +/// for (auto &DIE: Obj.getDwarfDIEs()) { +/// if (SymbolMapping *Sym = DMO.lookup(DIE.getName())) +/// DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress); +/// else +/// DIE.discardSubtree(); +/// } +/// } +class DebugMap { + Triple BinaryTriple; + std::string BinaryPath; + std::vector<uint8_t> BinaryUUID; + using ObjectContainer = std::vector<std::unique_ptr<DebugMapObject>>; + + ObjectContainer Objects; + + /// For YAML IO support. + ///@{ + friend yaml::MappingTraits<std::unique_ptr<DebugMap>>; + friend yaml::MappingTraits<DebugMap>; + + DebugMap() = default; + ///@} + +public: + DebugMap(const Triple &BinaryTriple, StringRef BinaryPath, + ArrayRef<uint8_t> BinaryUUID = ArrayRef<uint8_t>()) + : BinaryTriple(BinaryTriple), BinaryPath(std::string(BinaryPath)), + BinaryUUID(BinaryUUID.begin(), BinaryUUID.end()) {} + + using const_iterator = ObjectContainer::const_iterator; + + iterator_range<const_iterator> objects() const { + return make_range(begin(), end()); + } + + const_iterator begin() const { return Objects.begin(); } + + const_iterator end() const { return Objects.end(); } + + unsigned getNumberOfObjects() const { return Objects.size(); } + + /// This function adds an DebugMapObject to the list owned by this + /// debug map. + DebugMapObject & + addDebugMapObject(StringRef ObjectFilePath, + sys::TimePoint<std::chrono::seconds> Timestamp, + uint8_t Type = llvm::MachO::N_OSO); + + const Triple &getTriple() const { return BinaryTriple; } + + const ArrayRef<uint8_t> getUUID() const { + return ArrayRef<uint8_t>(BinaryUUID); + } + + StringRef getBinaryPath() const { return BinaryPath; } + + void print(raw_ostream &OS) const; + +#ifndef NDEBUG + void dump() const; +#endif + + /// Read a debug map for \a InputFile. + static ErrorOr<std::vector<std::unique_ptr<DebugMap>>> + parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose); +}; + +/// The DebugMapObject represents one object file described by the DebugMap. It +/// contains a list of mappings between addresses in the object file and in the +/// linked binary for all the linked atoms in this object file. +class DebugMapObject { +public: + struct SymbolMapping { + Optional<yaml::Hex64> ObjectAddress; + yaml::Hex64 BinaryAddress; + yaml::Hex32 Size; + + SymbolMapping(Optional<uint64_t> ObjectAddr, uint64_t BinaryAddress, + uint32_t Size) + : BinaryAddress(BinaryAddress), Size(Size) { + if (ObjectAddr) + ObjectAddress = *ObjectAddr; + } + + /// For YAML IO support + SymbolMapping() = default; + }; + + using YAMLSymbolMapping = std::pair<std::string, SymbolMapping>; + using DebugMapEntry = StringMapEntry<SymbolMapping>; + + /// Adds a symbol mapping to this DebugMapObject. + /// \returns false if the symbol was already registered. The request + /// is discarded in this case. + bool addSymbol(StringRef SymName, Optional<uint64_t> ObjectAddress, + uint64_t LinkedAddress, uint32_t Size); + + /// Lookup a symbol mapping. + /// \returns null if the symbol isn't found. + const DebugMapEntry *lookupSymbol(StringRef SymbolName) const; + + /// Lookup an object file address. + /// \returns null if the address isn't found. + const DebugMapEntry *lookupObjectAddress(uint64_t Address) const; + + StringRef getObjectFilename() const { return Filename; } + + sys::TimePoint<std::chrono::seconds> getTimestamp() const { + return Timestamp; + } + + uint8_t getType() const { return Type; } + + iterator_range<StringMap<SymbolMapping>::const_iterator> symbols() const { + return make_range(Symbols.begin(), Symbols.end()); + } + + bool empty() const { return Symbols.empty(); } + + void addWarning(StringRef Warning) { + Warnings.push_back(std::string(Warning)); + } + const std::vector<std::string> &getWarnings() const { return Warnings; } + + void print(raw_ostream &OS) const; +#ifndef NDEBUG + void dump() const; +#endif + +private: + friend class DebugMap; + + /// DebugMapObjects can only be constructed by the owning DebugMap. + DebugMapObject(StringRef ObjectFilename, + sys::TimePoint<std::chrono::seconds> Timestamp, uint8_t Type); + + std::string Filename; + sys::TimePoint<std::chrono::seconds> Timestamp; + StringMap<SymbolMapping> Symbols; + DenseMap<uint64_t, DebugMapEntry *> AddressToMapping; + uint8_t Type; + + std::vector<std::string> Warnings; + + /// For YAMLIO support. + ///@{ + friend yaml::MappingTraits<dsymutil::DebugMapObject>; + friend yaml::SequenceTraits<std::vector<std::unique_ptr<DebugMapObject>>>; + + DebugMapObject() = default; + +public: + DebugMapObject(DebugMapObject &&) = default; + DebugMapObject &operator=(DebugMapObject &&) = default; + ///@} +}; + +} // end namespace dsymutil +} // end namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::dsymutil::DebugMapObject::YAMLSymbolMapping) + +namespace llvm { +namespace yaml { + +using namespace llvm::dsymutil; + +template <> +struct MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>> { + static void mapping(IO &io, + std::pair<std::string, DebugMapObject::SymbolMapping> &s); + static const bool flow = true; +}; + +template <> struct MappingTraits<dsymutil::DebugMapObject> { + struct YamlDMO; + static void mapping(IO &io, dsymutil::DebugMapObject &DMO); +}; + +template <> struct ScalarTraits<Triple> { + static void output(const Triple &val, void *, raw_ostream &out); + static StringRef input(StringRef scalar, void *, Triple &value); + static QuotingType mustQuote(StringRef) { return QuotingType::Single; } +}; + +template <> +struct SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>> { + static size_t + size(IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq); + static dsymutil::DebugMapObject & + element(IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq, + size_t index); +}; + +template <> struct MappingTraits<dsymutil::DebugMap> { + static void mapping(IO &io, dsymutil::DebugMap &DM); +}; + +template <> struct MappingTraits<std::unique_ptr<dsymutil::DebugMap>> { + static void mapping(IO &io, std::unique_ptr<dsymutil::DebugMap> &DM); +}; + +} // end namespace yaml +} // end namespace llvm + +#endif // LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H diff --git a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp index 29408e7c49..1cb561dbac 100644 --- a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp +++ b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp @@ -1,616 +1,616 @@ -//===- tools/dsymutil/DwarfLinkerForBinary.cpp ----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DwarfLinkerForBinary.h" -#include "BinaryHolder.h" -#include "DebugMap.h" -#include "MachOUtils.h" -#include "dsymutil.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseMapInfo.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/Hashing.h" -#include "llvm/ADT/IntervalMap.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/BinaryFormat/MachO.h" -#include "llvm/CodeGen/AccelTable.h" -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/DIE.h" -#include "llvm/CodeGen/NonRelocatableStringpool.h" -#include "llvm/Config/config.h" -#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" -#include "llvm/DebugInfo/DIContext.h" -#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/DebugInfo/DWARF/DWARFSection.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/MC/MCAsmBackend.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCCodeEmitter.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDwarf.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCObjectFileInfo.h" -#include "llvm/MC/MCObjectWriter.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCSection.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/MCTargetOptions.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Object/SymbolicFile.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DJB.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/LEB128.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/ThreadPool.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/MC/MCTargetOptionsCommandFlags.h" -#include <algorithm> -#include <cassert> -#include <cinttypes> -#include <climits> -#include <cstdint> -#include <cstdlib> -#include <cstring> -#include <limits> -#include <map> -#include <memory> -#include <string> -#include <system_error> -#include <tuple> -#include <utility> -#include <vector> - -namespace llvm { - -static mc::RegisterMCTargetOptionsFlags MOF; - -namespace dsymutil { - -static Error copySwiftInterfaces( - const std::map<std::string, std::string> &ParseableSwiftInterfaces, - StringRef Architecture, const LinkOptions &Options) { - std::error_code EC; - SmallString<128> InputPath; - SmallString<128> Path; - sys::path::append(Path, *Options.ResourceDir, "Swift", Architecture); - if ((EC = sys::fs::create_directories(Path.str(), true, - sys::fs::perms::all_all))) - return make_error<StringError>( - "cannot create directory: " + toString(errorCodeToError(EC)), EC); - unsigned BaseLength = Path.size(); - - for (auto &I : ParseableSwiftInterfaces) { - StringRef ModuleName = I.first; - StringRef InterfaceFile = I.second; - if (!Options.PrependPath.empty()) { - InputPath.clear(); - sys::path::append(InputPath, Options.PrependPath, InterfaceFile); - InterfaceFile = InputPath; - } - sys::path::append(Path, ModuleName); - Path.append(".swiftinterface"); - if (Options.Verbose) - outs() << "copy parseable Swift interface " << InterfaceFile << " -> " - << Path.str() << '\n'; - - // copy_file attempts an APFS clone first, so this should be cheap. - if ((EC = sys::fs::copy_file(InterfaceFile, Path.str()))) - warn(Twine("cannot copy parseable Swift interface ") + InterfaceFile + - ": " + toString(errorCodeToError(EC))); - Path.resize(BaseLength); - } - return Error::success(); -} - -/// Report a warning to the user, optionally including information about a -/// specific \p DIE related to the warning. -void DwarfLinkerForBinary::reportWarning(const Twine &Warning, - StringRef Context, - const DWARFDie *DIE) const { - - warn(Warning, Context); - - if (!Options.Verbose || !DIE) - return; - - DIDumpOptions DumpOpts; - DumpOpts.ChildRecurseDepth = 0; - DumpOpts.Verbose = Options.Verbose; - - WithColor::note() << " in DIE:\n"; - DIE->dump(errs(), 6 /* Indent */, DumpOpts); -} - -bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple, - raw_fd_ostream &OutFile) { - if (Options.NoOutput) - return true; - - Streamer = std::make_unique<DwarfStreamer>( - Options.FileType, OutFile, Options.Translator, Options.Minimize, - [&](const Twine &Error, StringRef Context, const DWARFDie *) { - error(Error, Context); - }, - [&](const Twine &Warning, StringRef Context, const DWARFDie *) { - warn(Warning, Context); - }); - return Streamer->init(TheTriple); -} - -ErrorOr<const object::ObjectFile &> -DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj, - const Triple &Triple) { - auto ObjectEntry = - BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp()); - if (!ObjectEntry) { - auto Err = ObjectEntry.takeError(); - reportWarning(Twine(Obj.getObjectFilename()) + ": " + - toString(std::move(Err)), - Obj.getObjectFilename()); - return errorToErrorCode(std::move(Err)); - } - - auto Object = ObjectEntry->getObject(Triple); - if (!Object) { - auto Err = Object.takeError(); - reportWarning(Twine(Obj.getObjectFilename()) + ": " + - toString(std::move(Err)), - Obj.getObjectFilename()); - return errorToErrorCode(std::move(Err)); - } - - return *Object; -} - -static Error remarksErrorHandler(const DebugMapObject &DMO, - DwarfLinkerForBinary &Linker, - std::unique_ptr<FileError> FE) { - bool IsArchive = DMO.getObjectFilename().endswith(")"); - // Don't report errors for missing remark files from static - // archives. - if (!IsArchive) - return Error(std::move(FE)); - - std::string Message = FE->message(); - Error E = FE->takeError(); - Error NewE = handleErrors(std::move(E), [&](std::unique_ptr<ECError> EC) { - if (EC->convertToErrorCode() != std::errc::no_such_file_or_directory) - return Error(std::move(EC)); - - Linker.reportWarning(Message, DMO.getObjectFilename()); - return Error(Error::success()); - }); - - if (!NewE) - return Error::success(); - - return createFileError(FE->getFileName(), std::move(NewE)); -} - -static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath, - StringRef ArchName, const remarks::RemarkLinker &RL) { - // Make sure we don't create the directories and the file if there is nothing - // to serialize. - if (RL.empty()) - return Error::success(); - - SmallString<128> InputPath; - SmallString<128> Path; - // Create the "Remarks" directory in the "Resources" directory. - sys::path::append(Path, *Options.ResourceDir, "Remarks"); - if (std::error_code EC = sys::fs::create_directories(Path.str(), true, - sys::fs::perms::all_all)) - return errorCodeToError(EC); - - // Append the file name. - // For fat binaries, also append a dash and the architecture name. - sys::path::append(Path, sys::path::filename(BinaryPath)); - if (Options.NumDebugMaps > 1) { - // More than one debug map means we have a fat binary. - Path += '-'; - Path += ArchName; - } - - std::error_code EC; - raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC, sys::fs::OF_None); - if (EC) - return errorCodeToError(EC); - - if (Error E = RL.serialize(OS, Options.RemarksFormat)) - return E; - - return Error::success(); -} - +//===- tools/dsymutil/DwarfLinkerForBinary.cpp ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DwarfLinkerForBinary.h" +#include "BinaryHolder.h" +#include "DebugMap.h" +#include "MachOUtils.h" +#include "dsymutil.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/CodeGen/AccelTable.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DIE.h" +#include "llvm/CodeGen/NonRelocatableStringpool.h" +#include "llvm/Config/config.h" +#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/ThreadPool.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/MC/MCTargetOptionsCommandFlags.h" +#include <algorithm> +#include <cassert> +#include <cinttypes> +#include <climits> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <limits> +#include <map> +#include <memory> +#include <string> +#include <system_error> +#include <tuple> +#include <utility> +#include <vector> + +namespace llvm { + +static mc::RegisterMCTargetOptionsFlags MOF; + +namespace dsymutil { + +static Error copySwiftInterfaces( + const std::map<std::string, std::string> &ParseableSwiftInterfaces, + StringRef Architecture, const LinkOptions &Options) { + std::error_code EC; + SmallString<128> InputPath; + SmallString<128> Path; + sys::path::append(Path, *Options.ResourceDir, "Swift", Architecture); + if ((EC = sys::fs::create_directories(Path.str(), true, + sys::fs::perms::all_all))) + return make_error<StringError>( + "cannot create directory: " + toString(errorCodeToError(EC)), EC); + unsigned BaseLength = Path.size(); + + for (auto &I : ParseableSwiftInterfaces) { + StringRef ModuleName = I.first; + StringRef InterfaceFile = I.second; + if (!Options.PrependPath.empty()) { + InputPath.clear(); + sys::path::append(InputPath, Options.PrependPath, InterfaceFile); + InterfaceFile = InputPath; + } + sys::path::append(Path, ModuleName); + Path.append(".swiftinterface"); + if (Options.Verbose) + outs() << "copy parseable Swift interface " << InterfaceFile << " -> " + << Path.str() << '\n'; + + // copy_file attempts an APFS clone first, so this should be cheap. + if ((EC = sys::fs::copy_file(InterfaceFile, Path.str()))) + warn(Twine("cannot copy parseable Swift interface ") + InterfaceFile + + ": " + toString(errorCodeToError(EC))); + Path.resize(BaseLength); + } + return Error::success(); +} + +/// Report a warning to the user, optionally including information about a +/// specific \p DIE related to the warning. +void DwarfLinkerForBinary::reportWarning(const Twine &Warning, + StringRef Context, + const DWARFDie *DIE) const { + + warn(Warning, Context); + + if (!Options.Verbose || !DIE) + return; + + DIDumpOptions DumpOpts; + DumpOpts.ChildRecurseDepth = 0; + DumpOpts.Verbose = Options.Verbose; + + WithColor::note() << " in DIE:\n"; + DIE->dump(errs(), 6 /* Indent */, DumpOpts); +} + +bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple, + raw_fd_ostream &OutFile) { + if (Options.NoOutput) + return true; + + Streamer = std::make_unique<DwarfStreamer>( + Options.FileType, OutFile, Options.Translator, Options.Minimize, + [&](const Twine &Error, StringRef Context, const DWARFDie *) { + error(Error, Context); + }, + [&](const Twine &Warning, StringRef Context, const DWARFDie *) { + warn(Warning, Context); + }); + return Streamer->init(TheTriple); +} + +ErrorOr<const object::ObjectFile &> +DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj, + const Triple &Triple) { + auto ObjectEntry = + BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp()); + if (!ObjectEntry) { + auto Err = ObjectEntry.takeError(); + reportWarning(Twine(Obj.getObjectFilename()) + ": " + + toString(std::move(Err)), + Obj.getObjectFilename()); + return errorToErrorCode(std::move(Err)); + } + + auto Object = ObjectEntry->getObject(Triple); + if (!Object) { + auto Err = Object.takeError(); + reportWarning(Twine(Obj.getObjectFilename()) + ": " + + toString(std::move(Err)), + Obj.getObjectFilename()); + return errorToErrorCode(std::move(Err)); + } + + return *Object; +} + +static Error remarksErrorHandler(const DebugMapObject &DMO, + DwarfLinkerForBinary &Linker, + std::unique_ptr<FileError> FE) { + bool IsArchive = DMO.getObjectFilename().endswith(")"); + // Don't report errors for missing remark files from static + // archives. + if (!IsArchive) + return Error(std::move(FE)); + + std::string Message = FE->message(); + Error E = FE->takeError(); + Error NewE = handleErrors(std::move(E), [&](std::unique_ptr<ECError> EC) { + if (EC->convertToErrorCode() != std::errc::no_such_file_or_directory) + return Error(std::move(EC)); + + Linker.reportWarning(Message, DMO.getObjectFilename()); + return Error(Error::success()); + }); + + if (!NewE) + return Error::success(); + + return createFileError(FE->getFileName(), std::move(NewE)); +} + +static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath, + StringRef ArchName, const remarks::RemarkLinker &RL) { + // Make sure we don't create the directories and the file if there is nothing + // to serialize. + if (RL.empty()) + return Error::success(); + + SmallString<128> InputPath; + SmallString<128> Path; + // Create the "Remarks" directory in the "Resources" directory. + sys::path::append(Path, *Options.ResourceDir, "Remarks"); + if (std::error_code EC = sys::fs::create_directories(Path.str(), true, + sys::fs::perms::all_all)) + return errorCodeToError(EC); + + // Append the file name. + // For fat binaries, also append a dash and the architecture name. + sys::path::append(Path, sys::path::filename(BinaryPath)); + if (Options.NumDebugMaps > 1) { + // More than one debug map means we have a fat binary. + Path += '-'; + Path += ArchName; + } + + std::error_code EC; + raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC, sys::fs::OF_None); + if (EC) + return errorCodeToError(EC); + + if (Error E = RL.serialize(OS, Options.RemarksFormat)) + return E; + + return Error::success(); +} + ErrorOr<DWARFFile &> -DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj, - const DebugMap &DebugMap, - remarks::RemarkLinker &RL) { - auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple()); - - if (ErrorOrObj) { - ContextForLinking.push_back( - std::unique_ptr<DWARFContext>(DWARFContext::create(*ErrorOrObj))); - AddressMapForLinking.push_back( - std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj)); - +DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj, + const DebugMap &DebugMap, + remarks::RemarkLinker &RL) { + auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple()); + + if (ErrorOrObj) { + ContextForLinking.push_back( + std::unique_ptr<DWARFContext>(DWARFContext::create(*ErrorOrObj))); + AddressMapForLinking.push_back( + std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj)); + ObjectsForLinking.push_back(std::make_unique<DWARFFile>( - Obj.getObjectFilename(), ContextForLinking.back().get(), - AddressMapForLinking.back().get(), - Obj.empty() ? Obj.getWarnings() : EmptyWarnings)); - - Error E = RL.link(*ErrorOrObj); - if (Error NewE = handleErrors( - std::move(E), [&](std::unique_ptr<FileError> EC) -> Error { - return remarksErrorHandler(Obj, *this, std::move(EC)); - })) - return errorToErrorCode(std::move(NewE)); - - return *ObjectsForLinking.back(); - } - - return ErrorOrObj.getError(); -} - -bool DwarfLinkerForBinary::link(const DebugMap &Map) { - if (!createStreamer(Map.getTriple(), OutFile)) - return false; - - ObjectsForLinking.clear(); - ContextForLinking.clear(); - AddressMapForLinking.clear(); - - DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath()); - - DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil); - - remarks::RemarkLinker RL; - if (!Options.RemarksPrependPath.empty()) - RL.setExternalFilePrependPath(Options.RemarksPrependPath); - GeneralLinker.setObjectPrefixMap(&Options.ObjectPrefixMap); - - std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) { - assert(Options.Translator); - return Options.Translator(Input); - }; - - GeneralLinker.setVerbosity(Options.Verbose); - GeneralLinker.setStatistics(Options.Statistics); - GeneralLinker.setNoOutput(Options.NoOutput); - GeneralLinker.setNoODR(Options.NoODR); - GeneralLinker.setUpdate(Options.Update); - GeneralLinker.setNumThreads(Options.Threads); - GeneralLinker.setAccelTableKind(Options.TheAccelTableKind); - GeneralLinker.setPrependPath(Options.PrependPath); - if (Options.Translator) - GeneralLinker.setStringsTranslator(TranslationLambda); - GeneralLinker.setWarningHandler( - [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) { - reportWarning(Warning, Context, DIE); - }); - GeneralLinker.setErrorHandler( - [&](const Twine &Error, StringRef Context, const DWARFDie *) { - error(Error, Context); - }); - GeneralLinker.setObjFileLoader( - [&DebugMap, &RL, this](StringRef ContainerName, + Obj.getObjectFilename(), ContextForLinking.back().get(), + AddressMapForLinking.back().get(), + Obj.empty() ? Obj.getWarnings() : EmptyWarnings)); + + Error E = RL.link(*ErrorOrObj); + if (Error NewE = handleErrors( + std::move(E), [&](std::unique_ptr<FileError> EC) -> Error { + return remarksErrorHandler(Obj, *this, std::move(EC)); + })) + return errorToErrorCode(std::move(NewE)); + + return *ObjectsForLinking.back(); + } + + return ErrorOrObj.getError(); +} + +bool DwarfLinkerForBinary::link(const DebugMap &Map) { + if (!createStreamer(Map.getTriple(), OutFile)) + return false; + + ObjectsForLinking.clear(); + ContextForLinking.clear(); + AddressMapForLinking.clear(); + + DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath()); + + DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil); + + remarks::RemarkLinker RL; + if (!Options.RemarksPrependPath.empty()) + RL.setExternalFilePrependPath(Options.RemarksPrependPath); + GeneralLinker.setObjectPrefixMap(&Options.ObjectPrefixMap); + + std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) { + assert(Options.Translator); + return Options.Translator(Input); + }; + + GeneralLinker.setVerbosity(Options.Verbose); + GeneralLinker.setStatistics(Options.Statistics); + GeneralLinker.setNoOutput(Options.NoOutput); + GeneralLinker.setNoODR(Options.NoODR); + GeneralLinker.setUpdate(Options.Update); + GeneralLinker.setNumThreads(Options.Threads); + GeneralLinker.setAccelTableKind(Options.TheAccelTableKind); + GeneralLinker.setPrependPath(Options.PrependPath); + if (Options.Translator) + GeneralLinker.setStringsTranslator(TranslationLambda); + GeneralLinker.setWarningHandler( + [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) { + reportWarning(Warning, Context, DIE); + }); + GeneralLinker.setErrorHandler( + [&](const Twine &Error, StringRef Context, const DWARFDie *) { + error(Error, Context); + }); + GeneralLinker.setObjFileLoader( + [&DebugMap, &RL, this](StringRef ContainerName, StringRef Path) -> ErrorOr<DWARFFile &> { - auto &Obj = DebugMap.addDebugMapObject( - Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO); - - if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) { - return *ErrorOrObj; - } else { - // Try and emit more helpful warnings by applying some heuristics. - StringRef ObjFile = ContainerName; - bool IsClangModule = sys::path::extension(Path).equals(".pcm"); - bool IsArchive = ObjFile.endswith(")"); - - if (IsClangModule) { - StringRef ModuleCacheDir = sys::path::parent_path(Path); - if (sys::fs::exists(ModuleCacheDir)) { - // If the module's parent directory exists, we assume that the - // module cache has expired and was pruned by clang. A more - // adventurous dsymutil would invoke clang to rebuild the module - // now. - if (!ModuleCacheHintDisplayed) { - WithColor::note() - << "The clang module cache may have expired since " - "this object file was built. Rebuilding the " - "object file will rebuild the module cache.\n"; - ModuleCacheHintDisplayed = true; - } - } else if (IsArchive) { - // If the module cache directory doesn't exist at all and the - // object file is inside a static library, we assume that the - // static library was built on a different machine. We don't want - // to discourage module debugging for convenience libraries within - // a project though. - if (!ArchiveHintDisplayed) { - WithColor::note() - << "Linking a static library that was built with " - "-gmodules, but the module cache was not found. " - "Redistributable static libraries should never be " - "built with module debugging enabled. The debug " - "experience will be degraded due to incomplete " - "debug information.\n"; - ArchiveHintDisplayed = true; - } - } - } - - return ErrorOrObj.getError(); - } - - llvm_unreachable("Unhandled DebugMap object"); - }); - GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces); - - for (const auto &Obj : Map.objects()) { - // N_AST objects (swiftmodule files) should get dumped directly into the - // appropriate DWARF section. - if (Obj->getType() == MachO::N_AST) { - if (Options.Verbose) - outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n"; - - StringRef File = Obj->getObjectFilename(); - auto ErrorOrMem = MemoryBuffer::getFile(File); - if (!ErrorOrMem) { - warn("Could not open '" + File + "'\n"); - continue; - } - sys::fs::file_status Stat; - if (auto Err = sys::fs::status(File, Stat)) { - warn(Err.message()); - continue; - } - if (!Options.NoTimestamp) { - // The modification can have sub-second precision so we need to cast - // away the extra precision that's not present in the debug map. - auto ModificationTime = - std::chrono::time_point_cast<std::chrono::seconds>( - Stat.getLastModificationTime()); - if (ModificationTime != Obj->getTimestamp()) { - // Not using the helper here as we can easily stream TimePoint<>. + auto &Obj = DebugMap.addDebugMapObject( + Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO); + + if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) { + return *ErrorOrObj; + } else { + // Try and emit more helpful warnings by applying some heuristics. + StringRef ObjFile = ContainerName; + bool IsClangModule = sys::path::extension(Path).equals(".pcm"); + bool IsArchive = ObjFile.endswith(")"); + + if (IsClangModule) { + StringRef ModuleCacheDir = sys::path::parent_path(Path); + if (sys::fs::exists(ModuleCacheDir)) { + // If the module's parent directory exists, we assume that the + // module cache has expired and was pruned by clang. A more + // adventurous dsymutil would invoke clang to rebuild the module + // now. + if (!ModuleCacheHintDisplayed) { + WithColor::note() + << "The clang module cache may have expired since " + "this object file was built. Rebuilding the " + "object file will rebuild the module cache.\n"; + ModuleCacheHintDisplayed = true; + } + } else if (IsArchive) { + // If the module cache directory doesn't exist at all and the + // object file is inside a static library, we assume that the + // static library was built on a different machine. We don't want + // to discourage module debugging for convenience libraries within + // a project though. + if (!ArchiveHintDisplayed) { + WithColor::note() + << "Linking a static library that was built with " + "-gmodules, but the module cache was not found. " + "Redistributable static libraries should never be " + "built with module debugging enabled. The debug " + "experience will be degraded due to incomplete " + "debug information.\n"; + ArchiveHintDisplayed = true; + } + } + } + + return ErrorOrObj.getError(); + } + + llvm_unreachable("Unhandled DebugMap object"); + }); + GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces); + + for (const auto &Obj : Map.objects()) { + // N_AST objects (swiftmodule files) should get dumped directly into the + // appropriate DWARF section. + if (Obj->getType() == MachO::N_AST) { + if (Options.Verbose) + outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n"; + + StringRef File = Obj->getObjectFilename(); + auto ErrorOrMem = MemoryBuffer::getFile(File); + if (!ErrorOrMem) { + warn("Could not open '" + File + "'\n"); + continue; + } + sys::fs::file_status Stat; + if (auto Err = sys::fs::status(File, Stat)) { + warn(Err.message()); + continue; + } + if (!Options.NoTimestamp) { + // The modification can have sub-second precision so we need to cast + // away the extra precision that's not present in the debug map. + auto ModificationTime = + std::chrono::time_point_cast<std::chrono::seconds>( + Stat.getLastModificationTime()); + if (ModificationTime != Obj->getTimestamp()) { + // Not using the helper here as we can easily stream TimePoint<>. WithColor::warning() << File << ": timestamp mismatch between swift interface file (" << sys::TimePoint<>(Obj->getTimestamp()) << ") and debug map (" << sys::TimePoint<>(Obj->getTimestamp()) << ")\n"; - continue; - } - } - - // Copy the module into the .swift_ast section. - if (!Options.NoOutput) - Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer()); - - continue; - } - - if (auto ErrorOrObj = loadObject(*Obj, Map, RL)) - GeneralLinker.addObjectFile(*ErrorOrObj); - else { + continue; + } + } + + // Copy the module into the .swift_ast section. + if (!Options.NoOutput) + Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer()); + + continue; + } + + if (auto ErrorOrObj = loadObject(*Obj, Map, RL)) + GeneralLinker.addObjectFile(*ErrorOrObj); + else { ObjectsForLinking.push_back(std::make_unique<DWARFFile>( - Obj->getObjectFilename(), nullptr, nullptr, - Obj->empty() ? Obj->getWarnings() : EmptyWarnings)); - GeneralLinker.addObjectFile(*ObjectsForLinking.back()); - } - } - - // link debug info for loaded object files. - GeneralLinker.link(); - - StringRef ArchName = Map.getTriple().getArchName(); - if (Error E = emitRemarks(Options, Map.getBinaryPath(), ArchName, RL)) - return error(toString(std::move(E))); - - if (Options.NoOutput) - return true; - - if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) { - StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch()); - if (auto E = - copySwiftInterfaces(ParseableSwiftInterfaces, ArchName, Options)) - return error(toString(std::move(E))); - } - - if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() && - Options.FileType == OutputFileType::Object) - return MachOUtils::generateDsymCompanion( - Options.VFS, Map, Options.Translator, - *Streamer->getAsmPrinter().OutStreamer, OutFile); - - Streamer->finish(); - return true; -} - -static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) { - switch (Arch) { - case Triple::x86: - return RelocType == MachO::GENERIC_RELOC_SECTDIFF || - RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF; - case Triple::x86_64: - return RelocType == MachO::X86_64_RELOC_SUBTRACTOR; - case Triple::arm: - case Triple::thumb: - return RelocType == MachO::ARM_RELOC_SECTDIFF || - RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF || - RelocType == MachO::ARM_RELOC_HALF || - RelocType == MachO::ARM_RELOC_HALF_SECTDIFF; - case Triple::aarch64: - return RelocType == MachO::ARM64_RELOC_SUBTRACTOR; - default: - return false; - } -} - -/// Iterate over the relocations of the given \p Section and -/// store the ones that correspond to debug map entries into the -/// ValidRelocs array. -void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO( - const object::SectionRef &Section, const object::MachOObjectFile &Obj, + Obj->getObjectFilename(), nullptr, nullptr, + Obj->empty() ? Obj->getWarnings() : EmptyWarnings)); + GeneralLinker.addObjectFile(*ObjectsForLinking.back()); + } + } + + // link debug info for loaded object files. + GeneralLinker.link(); + + StringRef ArchName = Map.getTriple().getArchName(); + if (Error E = emitRemarks(Options, Map.getBinaryPath(), ArchName, RL)) + return error(toString(std::move(E))); + + if (Options.NoOutput) + return true; + + if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) { + StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch()); + if (auto E = + copySwiftInterfaces(ParseableSwiftInterfaces, ArchName, Options)) + return error(toString(std::move(E))); + } + + if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() && + Options.FileType == OutputFileType::Object) + return MachOUtils::generateDsymCompanion( + Options.VFS, Map, Options.Translator, + *Streamer->getAsmPrinter().OutStreamer, OutFile); + + Streamer->finish(); + return true; +} + +static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) { + switch (Arch) { + case Triple::x86: + return RelocType == MachO::GENERIC_RELOC_SECTDIFF || + RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF; + case Triple::x86_64: + return RelocType == MachO::X86_64_RELOC_SUBTRACTOR; + case Triple::arm: + case Triple::thumb: + return RelocType == MachO::ARM_RELOC_SECTDIFF || + RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF || + RelocType == MachO::ARM_RELOC_HALF || + RelocType == MachO::ARM_RELOC_HALF_SECTDIFF; + case Triple::aarch64: + return RelocType == MachO::ARM64_RELOC_SUBTRACTOR; + default: + return false; + } +} + +/// Iterate over the relocations of the given \p Section and +/// store the ones that correspond to debug map entries into the +/// ValidRelocs array. +void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO( + const object::SectionRef &Section, const object::MachOObjectFile &Obj, const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) { - Expected<StringRef> ContentsOrErr = Section.getContents(); - if (!ContentsOrErr) { - consumeError(ContentsOrErr.takeError()); - Linker.reportWarning("error reading section", DMO.getObjectFilename()); - return; - } - DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0); - bool SkipNext = false; - - for (const object::RelocationRef &Reloc : Section.relocations()) { - if (SkipNext) { - SkipNext = false; - continue; - } - - object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl(); - MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef); - - if (isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc), - Obj.getArch())) { - SkipNext = true; + Expected<StringRef> ContentsOrErr = Section.getContents(); + if (!ContentsOrErr) { + consumeError(ContentsOrErr.takeError()); + Linker.reportWarning("error reading section", DMO.getObjectFilename()); + return; + } + DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0); + bool SkipNext = false; + + for (const object::RelocationRef &Reloc : Section.relocations()) { + if (SkipNext) { + SkipNext = false; + continue; + } + + object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl(); + MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef); + + if (isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc), + Obj.getArch())) { + SkipNext = true; Linker.reportWarning("unsupported relocation in " + *Section.getName() + " section.", - DMO.getObjectFilename()); - continue; - } - - unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc); - uint64_t Offset64 = Reloc.getOffset(); - if ((RelocSize != 4 && RelocSize != 8)) { + DMO.getObjectFilename()); + continue; + } + + unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc); + uint64_t Offset64 = Reloc.getOffset(); + if ((RelocSize != 4 && RelocSize != 8)) { Linker.reportWarning("unsupported relocation in " + *Section.getName() + " section.", - DMO.getObjectFilename()); - continue; - } - uint64_t OffsetCopy = Offset64; - // Mach-o uses REL relocations, the addend is at the relocation offset. - uint64_t Addend = Data.getUnsigned(&OffsetCopy, RelocSize); - uint64_t SymAddress; - int64_t SymOffset; - - if (Obj.isRelocationScattered(MachOReloc)) { - // The address of the base symbol for scattered relocations is - // stored in the reloc itself. The actual addend will store the - // base address plus the offset. - SymAddress = Obj.getScatteredRelocationValue(MachOReloc); - SymOffset = int64_t(Addend) - SymAddress; - } else { - SymAddress = Addend; - SymOffset = 0; - } - - auto Sym = Reloc.getSymbol(); - if (Sym != Obj.symbol_end()) { - Expected<StringRef> SymbolName = Sym->getName(); - if (!SymbolName) { - consumeError(SymbolName.takeError()); - Linker.reportWarning("error getting relocation symbol name.", - DMO.getObjectFilename()); - continue; - } - if (const auto *Mapping = DMO.lookupSymbol(*SymbolName)) - ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping); - } else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) { - // Do not store the addend. The addend was the address of the symbol in - // the object file, the address in the binary that is stored in the debug - // map doesn't need to be offset. - ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping); - } - } -} - -/// Dispatch the valid relocation finding logic to the -/// appropriate handler depending on the object file format. -bool DwarfLinkerForBinary::AddressManager::findValidRelocs( - const object::SectionRef &Section, const object::ObjectFile &Obj, + DMO.getObjectFilename()); + continue; + } + uint64_t OffsetCopy = Offset64; + // Mach-o uses REL relocations, the addend is at the relocation offset. + uint64_t Addend = Data.getUnsigned(&OffsetCopy, RelocSize); + uint64_t SymAddress; + int64_t SymOffset; + + if (Obj.isRelocationScattered(MachOReloc)) { + // The address of the base symbol for scattered relocations is + // stored in the reloc itself. The actual addend will store the + // base address plus the offset. + SymAddress = Obj.getScatteredRelocationValue(MachOReloc); + SymOffset = int64_t(Addend) - SymAddress; + } else { + SymAddress = Addend; + SymOffset = 0; + } + + auto Sym = Reloc.getSymbol(); + if (Sym != Obj.symbol_end()) { + Expected<StringRef> SymbolName = Sym->getName(); + if (!SymbolName) { + consumeError(SymbolName.takeError()); + Linker.reportWarning("error getting relocation symbol name.", + DMO.getObjectFilename()); + continue; + } + if (const auto *Mapping = DMO.lookupSymbol(*SymbolName)) + ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping); + } else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) { + // Do not store the addend. The addend was the address of the symbol in + // the object file, the address in the binary that is stored in the debug + // map doesn't need to be offset. + ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping); + } + } +} + +/// Dispatch the valid relocation finding logic to the +/// appropriate handler depending on the object file format. +bool DwarfLinkerForBinary::AddressManager::findValidRelocs( + const object::SectionRef &Section, const object::ObjectFile &Obj, const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) { - // Dispatch to the right handler depending on the file type. - if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj)) + // Dispatch to the right handler depending on the file type. + if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj)) findValidRelocsMachO(Section, *MachOObj, DMO, Relocs); - else - Linker.reportWarning(Twine("unsupported object file type: ") + - Obj.getFileName(), - DMO.getObjectFilename()); + else + Linker.reportWarning(Twine("unsupported object file type: ") + + Obj.getFileName(), + DMO.getObjectFilename()); if (Relocs.empty()) - return false; - - // Sort the relocations by offset. We will walk the DIEs linearly in - // the file, this allows us to just keep an index in the relocation - // array that we advance during our walk, rather than resorting to - // some associative container. See DwarfLinkerForBinary::NextValidReloc. + return false; + + // Sort the relocations by offset. We will walk the DIEs linearly in + // the file, this allows us to just keep an index in the relocation + // array that we advance during our walk, rather than resorting to + // some associative container. See DwarfLinkerForBinary::NextValidReloc. llvm::sort(Relocs); - return true; -} - + return true; +} + /// Look for relocations in the debug_info and debug_addr section that match /// entries in the debug map. These relocations will drive the Dwarf link by /// indicating which DIEs refer to symbols present in the linked binary. -/// \returns whether there are any valid relocations in the debug info. +/// \returns whether there are any valid relocations in the debug info. bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections( - const object::ObjectFile &Obj, const DebugMapObject &DMO) { - // Find the debug_info section. + const object::ObjectFile &Obj, const DebugMapObject &DMO) { + // Find the debug_info section. bool FoundValidRelocs = false; - for (const object::SectionRef &Section : Obj.sections()) { - StringRef SectionName; - if (Expected<StringRef> NameOrErr = Section.getName()) - SectionName = *NameOrErr; - else - consumeError(NameOrErr.takeError()); - - SectionName = SectionName.substr(SectionName.find_first_not_of("._")); + for (const object::SectionRef &Section : Obj.sections()) { + StringRef SectionName; + if (Expected<StringRef> NameOrErr = Section.getName()) + SectionName = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + SectionName = SectionName.substr(SectionName.find_first_not_of("._")); if (SectionName == "debug_info") FoundValidRelocs |= findValidRelocs(Section, Obj, DMO, ValidDebugInfoRelocs); if (SectionName == "debug_addr") FoundValidRelocs |= findValidRelocs(Section, Obj, DMO, ValidDebugAddrRelocs); - } + } return FoundValidRelocs; -} - +} + bool DwarfLinkerForBinary::AddressManager::hasValidDebugAddrRelocationAt( uint64_t Offset) { auto It = std::lower_bound(ValidDebugAddrRelocs.begin(), @@ -619,44 +619,44 @@ bool DwarfLinkerForBinary::AddressManager::hasValidDebugAddrRelocationAt( } bool DwarfLinkerForBinary::AddressManager::hasValidDebugInfoRelocationAt( - uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) { - assert(NextValidReloc == 0 || + uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) { + assert(NextValidReloc == 0 || StartOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset); if (NextValidReloc >= ValidDebugInfoRelocs.size()) - return false; - + return false; + uint64_t RelocOffset = ValidDebugInfoRelocs[NextValidReloc].Offset; - - // We might need to skip some relocs that we didn't consider. For - // example the high_pc of a discarded DIE might contain a reloc that - // is in the list because it actually corresponds to the start of a - // function that is in the debug map. + + // We might need to skip some relocs that we didn't consider. For + // example the high_pc of a discarded DIE might contain a reloc that + // is in the list because it actually corresponds to the start of a + // function that is in the debug map. while (RelocOffset < StartOffset && NextValidReloc < ValidDebugInfoRelocs.size() - 1) RelocOffset = ValidDebugInfoRelocs[++NextValidReloc].Offset; - - if (RelocOffset < StartOffset || RelocOffset >= EndOffset) - return false; - + + if (RelocOffset < StartOffset || RelocOffset >= EndOffset) + return false; + const auto &ValidReloc = ValidDebugInfoRelocs[NextValidReloc++]; - const auto &Mapping = ValidReloc.Mapping->getValue(); - const uint64_t BinaryAddress = Mapping.BinaryAddress; - const uint64_t ObjectAddress = Mapping.ObjectAddress - ? uint64_t(*Mapping.ObjectAddress) - : std::numeric_limits<uint64_t>::max(); - if (Linker.Options.Verbose) - outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey() - << "\t" - << format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress, - BinaryAddress); - - Info.AddrAdjust = BinaryAddress + ValidReloc.Addend; - if (Mapping.ObjectAddress) - Info.AddrAdjust -= ObjectAddress; - Info.InDebugMap = true; - return true; -} - + const auto &Mapping = ValidReloc.Mapping->getValue(); + const uint64_t BinaryAddress = Mapping.BinaryAddress; + const uint64_t ObjectAddress = Mapping.ObjectAddress + ? uint64_t(*Mapping.ObjectAddress) + : std::numeric_limits<uint64_t>::max(); + if (Linker.Options.Verbose) + outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey() + << "\t" + << format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress, + BinaryAddress); + + Info.AddrAdjust = BinaryAddress + ValidReloc.Addend; + if (Mapping.ObjectAddress) + Info.AddrAdjust -= ObjectAddress; + Info.InDebugMap = true; + return true; +} + /// Get the starting and ending (exclusive) offset for the /// attribute with index \p Idx descibed by \p Abbrev. \p Offset is /// supposed to point to the position of the first attribute described @@ -722,51 +722,51 @@ bool DwarfLinkerForBinary::AddressManager::hasLiveAddressRange( return false; } -/// Apply the valid relocations found by findValidRelocs() to -/// the buffer \p Data, taking into account that Data is at \p BaseOffset -/// in the debug_info section. -/// -/// Like for findValidRelocs(), this function must be called with -/// monotonic \p BaseOffset values. -/// -/// \returns whether any reloc has been applied. -bool DwarfLinkerForBinary::AddressManager::applyValidRelocs( - MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) { - assert(areRelocationsResolved()); - assert((NextValidReloc == 0 || +/// Apply the valid relocations found by findValidRelocs() to +/// the buffer \p Data, taking into account that Data is at \p BaseOffset +/// in the debug_info section. +/// +/// Like for findValidRelocs(), this function must be called with +/// monotonic \p BaseOffset values. +/// +/// \returns whether any reloc has been applied. +bool DwarfLinkerForBinary::AddressManager::applyValidRelocs( + MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) { + assert(areRelocationsResolved()); + assert((NextValidReloc == 0 || BaseOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset) && - "BaseOffset should only be increasing."); + "BaseOffset should only be increasing."); if (NextValidReloc >= ValidDebugInfoRelocs.size()) - return false; - - // Skip relocs that haven't been applied. + return false; + + // Skip relocs that haven't been applied. while (NextValidReloc < ValidDebugInfoRelocs.size() && ValidDebugInfoRelocs[NextValidReloc].Offset < BaseOffset) - ++NextValidReloc; - - bool Applied = false; - uint64_t EndOffset = BaseOffset + Data.size(); + ++NextValidReloc; + + bool Applied = false; + uint64_t EndOffset = BaseOffset + Data.size(); while (NextValidReloc < ValidDebugInfoRelocs.size() && ValidDebugInfoRelocs[NextValidReloc].Offset >= BaseOffset && ValidDebugInfoRelocs[NextValidReloc].Offset < EndOffset) { const auto &ValidReloc = ValidDebugInfoRelocs[NextValidReloc++]; - assert(ValidReloc.Offset - BaseOffset < Data.size()); - assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size()); - char Buf[8]; - uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress; - Value += ValidReloc.Addend; - for (unsigned I = 0; I != ValidReloc.Size; ++I) { - unsigned Index = IsLittleEndian ? I : (ValidReloc.Size - I - 1); - Buf[I] = uint8_t(Value >> (Index * 8)); - } - assert(ValidReloc.Size <= sizeof(Buf)); - memcpy(&Data[ValidReloc.Offset - BaseOffset], Buf, ValidReloc.Size); - Applied = true; - } - - return Applied; -} - + assert(ValidReloc.Offset - BaseOffset < Data.size()); + assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size()); + char Buf[8]; + uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress; + Value += ValidReloc.Addend; + for (unsigned I = 0; I != ValidReloc.Size; ++I) { + unsigned Index = IsLittleEndian ? I : (ValidReloc.Size - I - 1); + Buf[I] = uint8_t(Value >> (Index * 8)); + } + assert(ValidReloc.Size <= sizeof(Buf)); + memcpy(&Data[ValidReloc.Offset - BaseOffset], Buf, ValidReloc.Size); + Applied = true; + } + + return Applied; +} + llvm::Expected<uint64_t> DwarfLinkerForBinary::AddressManager::relocateIndexedAddr(uint64_t Offset) { auto It = std::lower_bound(ValidDebugAddrRelocs.begin(), @@ -778,11 +778,11 @@ DwarfLinkerForBinary::AddressManager::relocateIndexedAddr(uint64_t Offset) { return It->Mapping->getValue().BinaryAddress + It->Addend; } -bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, - const DebugMap &DM, LinkOptions Options) { - DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options)); - return Linker.link(DM); -} - -} // namespace dsymutil -} // namespace llvm +bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, + const DebugMap &DM, LinkOptions Options) { + DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options)); + return Linker.link(DM); +} + +} // namespace dsymutil +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h index c6c07d689f..849d2c7fa5 100644 --- a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h +++ b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h @@ -1,154 +1,154 @@ -//===- tools/dsymutil/DwarfLinkerForBinary.h --------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H -#define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H - -#include "BinaryHolder.h" -#include "DebugMap.h" -#include "LinkUtils.h" -#include "llvm/DWARFLinker/DWARFLinker.h" -#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" -#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" -#include "llvm/DWARFLinker/DWARFStreamer.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/Remarks/RemarkFormat.h" -#include "llvm/Remarks/RemarkLinker.h" - -namespace llvm { -namespace dsymutil { - -/// The core of the Dsymutil Dwarf linking logic. -/// -/// The link of the dwarf information from the object files will be -/// driven by DWARFLinker. DwarfLinkerForBinary reads DebugMap objects -/// and pass information to the DWARFLinker. DWARFLinker -/// optimizes DWARF taking into account valid relocations. -/// Finally, optimized DWARF is passed to DwarfLinkerForBinary through -/// DWARFEmitter interface. -class DwarfLinkerForBinary { -public: - DwarfLinkerForBinary(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, - LinkOptions Options) - : OutFile(OutFile), BinHolder(BinHolder), Options(std::move(Options)) {} - - /// Link the contents of the DebugMap. - bool link(const DebugMap &); - - void reportWarning(const Twine &Warning, StringRef Context, - const DWARFDie *DIE = nullptr) const; - - /// Flags passed to DwarfLinker::lookForDIEsToKeep - enum TraversalFlags { - TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept. - TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope. - TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE. - TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE. - TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents. - TF_SkipPC = 1 << 5, ///< Skip all location attributes. - }; - -private: - - /// Keeps track of relocations. - class AddressManager : public AddressesMap { - struct ValidReloc { - uint64_t Offset; - uint32_t Size; - uint64_t Addend; - const DebugMapObject::DebugMapEntry *Mapping; - - ValidReloc(uint64_t Offset, uint32_t Size, uint64_t Addend, - const DebugMapObject::DebugMapEntry *Mapping) - : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {} - - bool operator<(const ValidReloc &RHS) const { - return Offset < RHS.Offset; - } +//===- tools/dsymutil/DwarfLinkerForBinary.h --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H +#define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H + +#include "BinaryHolder.h" +#include "DebugMap.h" +#include "LinkUtils.h" +#include "llvm/DWARFLinker/DWARFLinker.h" +#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" +#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" +#include "llvm/DWARFLinker/DWARFStreamer.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Remarks/RemarkFormat.h" +#include "llvm/Remarks/RemarkLinker.h" + +namespace llvm { +namespace dsymutil { + +/// The core of the Dsymutil Dwarf linking logic. +/// +/// The link of the dwarf information from the object files will be +/// driven by DWARFLinker. DwarfLinkerForBinary reads DebugMap objects +/// and pass information to the DWARFLinker. DWARFLinker +/// optimizes DWARF taking into account valid relocations. +/// Finally, optimized DWARF is passed to DwarfLinkerForBinary through +/// DWARFEmitter interface. +class DwarfLinkerForBinary { +public: + DwarfLinkerForBinary(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, + LinkOptions Options) + : OutFile(OutFile), BinHolder(BinHolder), Options(std::move(Options)) {} + + /// Link the contents of the DebugMap. + bool link(const DebugMap &); + + void reportWarning(const Twine &Warning, StringRef Context, + const DWARFDie *DIE = nullptr) const; + + /// Flags passed to DwarfLinker::lookForDIEsToKeep + enum TraversalFlags { + TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept. + TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope. + TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE. + TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE. + TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents. + TF_SkipPC = 1 << 5, ///< Skip all location attributes. + }; + +private: + + /// Keeps track of relocations. + class AddressManager : public AddressesMap { + struct ValidReloc { + uint64_t Offset; + uint32_t Size; + uint64_t Addend; + const DebugMapObject::DebugMapEntry *Mapping; + + ValidReloc(uint64_t Offset, uint32_t Size, uint64_t Addend, + const DebugMapObject::DebugMapEntry *Mapping) + : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {} + + bool operator<(const ValidReloc &RHS) const { + return Offset < RHS.Offset; + } bool operator<(uint64_t RHS) const { return Offset < RHS; } - }; - - const DwarfLinkerForBinary &Linker; - - /// The valid relocations for the current DebugMapObject. - /// This vector is sorted by relocation offset. + }; + + const DwarfLinkerForBinary &Linker; + + /// The valid relocations for the current DebugMapObject. + /// This vector is sorted by relocation offset. /// { std::vector<ValidReloc> ValidDebugInfoRelocs; std::vector<ValidReloc> ValidDebugAddrRelocs; /// } - - /// Index into ValidRelocs of the next relocation to consider. As we walk - /// the DIEs in acsending file offset and as ValidRelocs is sorted by file - /// offset, keeping this index up to date is all we have to do to have a - /// cheap lookup during the root DIE selection and during DIE cloning. - unsigned NextValidReloc = 0; - - RangesTy AddressRanges; - - public: - AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj, - const DebugMapObject &DMO) - : Linker(Linker) { + + /// Index into ValidRelocs of the next relocation to consider. As we walk + /// the DIEs in acsending file offset and as ValidRelocs is sorted by file + /// offset, keeping this index up to date is all we have to do to have a + /// cheap lookup during the root DIE selection and during DIE cloning. + unsigned NextValidReloc = 0; + + RangesTy AddressRanges; + + public: + AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj, + const DebugMapObject &DMO) + : Linker(Linker) { findValidRelocsInDebugSections(Obj, DMO); - - // Iterate over the debug map entries and put all the ones that are - // functions (because they have a size) into the Ranges map. This map is - // very similar to the FunctionRanges that are stored in each unit, with 2 - // notable differences: - // - // 1. Obviously this one is global, while the other ones are per-unit. - // - // 2. This one contains not only the functions described in the DIE - // tree, but also the ones that are only in the debug map. - // - // The latter information is required to reproduce dsymutil's logic while - // linking line tables. The cases where this information matters look like - // bugs that need to be investigated, but for now we need to reproduce - // dsymutil's behavior. - // FIXME: Once we understood exactly if that information is needed, - // maybe totally remove this (or try to use it to do a real - // -gline-tables-only on Darwin. - for (const auto &Entry : DMO.symbols()) { - const auto &Mapping = Entry.getValue(); - if (Mapping.Size && Mapping.ObjectAddress) - AddressRanges[*Mapping.ObjectAddress] = ObjFileAddressRange( - *Mapping.ObjectAddress + Mapping.Size, - int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress); - } - } - virtual ~AddressManager() override { clear(); } - - virtual bool areRelocationsResolved() const override { return true; } - - bool hasValidRelocs(bool ResetRelocsPtr = true) override { - if (ResetRelocsPtr) - NextValidReloc = 0; + + // Iterate over the debug map entries and put all the ones that are + // functions (because they have a size) into the Ranges map. This map is + // very similar to the FunctionRanges that are stored in each unit, with 2 + // notable differences: + // + // 1. Obviously this one is global, while the other ones are per-unit. + // + // 2. This one contains not only the functions described in the DIE + // tree, but also the ones that are only in the debug map. + // + // The latter information is required to reproduce dsymutil's logic while + // linking line tables. The cases where this information matters look like + // bugs that need to be investigated, but for now we need to reproduce + // dsymutil's behavior. + // FIXME: Once we understood exactly if that information is needed, + // maybe totally remove this (or try to use it to do a real + // -gline-tables-only on Darwin. + for (const auto &Entry : DMO.symbols()) { + const auto &Mapping = Entry.getValue(); + if (Mapping.Size && Mapping.ObjectAddress) + AddressRanges[*Mapping.ObjectAddress] = ObjFileAddressRange( + *Mapping.ObjectAddress + Mapping.Size, + int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress); + } + } + virtual ~AddressManager() override { clear(); } + + virtual bool areRelocationsResolved() const override { return true; } + + bool hasValidRelocs(bool ResetRelocsPtr = true) override { + if (ResetRelocsPtr) + NextValidReloc = 0; return !ValidDebugInfoRelocs.empty() || !ValidDebugAddrRelocs.empty(); - } - - /// \defgroup FindValidRelocations Translate debug map into a list - /// of relevant relocations - /// - /// @{ + } + + /// \defgroup FindValidRelocations Translate debug map into a list + /// of relevant relocations + /// + /// @{ bool findValidRelocsInDebugSections(const object::ObjectFile &Obj, const DebugMapObject &DMO); - - bool findValidRelocs(const object::SectionRef &Section, - const object::ObjectFile &Obj, + + bool findValidRelocs(const object::SectionRef &Section, + const object::ObjectFile &Obj, const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs); - - void findValidRelocsMachO(const object::SectionRef &Section, - const object::MachOObjectFile &Obj, + + void findValidRelocsMachO(const object::SectionRef &Section, + const object::MachOObjectFile &Obj, const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs); - /// @} - + /// @} + /// Checks that there is a relocation in the debug_addr section against a /// debug map entry between \p StartOffset and \p NextOffset. /// @@ -157,7 +157,7 @@ private: /// \returns true and sets Info.InDebugMap if it is the case. bool hasValidDebugInfoRelocationAt(uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info); - + /// Checks that there is a relocation in the debug_addr section against a /// debug map entry at the given offset. bool hasValidDebugAddrRelocationAt(uint64_t Offset); @@ -167,54 +167,54 @@ private: bool hasLiveAddressRange(const DWARFDie &DIE, CompileUnit::DIEInfo &Info) override; - bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset, - bool IsLittleEndian) override; - + bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset, + bool IsLittleEndian) override; + llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t Offset) override; - RangesTy &getValidAddressRanges() override { return AddressRanges; } - - void clear() override { - AddressRanges.clear(); + RangesTy &getValidAddressRanges() override { return AddressRanges; } + + void clear() override { + AddressRanges.clear(); ValidDebugInfoRelocs.clear(); ValidDebugAddrRelocs.clear(); - NextValidReloc = 0; - } - }; - -private: - /// \defgroup Helpers Various helper methods. - /// - /// @{ - bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile); - - /// Attempt to load a debug object from disk. - ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj, - const Triple &triple); + NextValidReloc = 0; + } + }; + +private: + /// \defgroup Helpers Various helper methods. + /// + /// @{ + bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile); + + /// Attempt to load a debug object from disk. + ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj, + const Triple &triple); ErrorOr<DWARFFile &> loadObject(const DebugMapObject &Obj, - const DebugMap &DebugMap, - remarks::RemarkLinker &RL); - - raw_fd_ostream &OutFile; - BinaryHolder &BinHolder; - LinkOptions Options; - std::unique_ptr<DwarfStreamer> Streamer; + const DebugMap &DebugMap, + remarks::RemarkLinker &RL); + + raw_fd_ostream &OutFile; + BinaryHolder &BinHolder; + LinkOptions Options; + std::unique_ptr<DwarfStreamer> Streamer; std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking; - std::vector<std::unique_ptr<DWARFContext>> ContextForLinking; - std::vector<std::unique_ptr<AddressManager>> AddressMapForLinking; - std::vector<std::string> EmptyWarnings; - - /// A list of all .swiftinterface files referenced by the debug - /// info, mapping Module name to path on disk. The entries need to - /// be uniqued and sorted and there are only few entries expected - /// per compile unit, which is why this is a std::map. - std::map<std::string, std::string> ParseableSwiftInterfaces; - - bool ModuleCacheHintDisplayed = false; - bool ArchiveHintDisplayed = false; -}; - -} // end namespace dsymutil -} // end namespace llvm - -#endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H + std::vector<std::unique_ptr<DWARFContext>> ContextForLinking; + std::vector<std::unique_ptr<AddressManager>> AddressMapForLinking; + std::vector<std::string> EmptyWarnings; + + /// A list of all .swiftinterface files referenced by the debug + /// info, mapping Module name to path on disk. The entries need to + /// be uniqued and sorted and there are only few entries expected + /// per compile unit, which is why this is a std::map. + std::map<std::string, std::string> ParseableSwiftInterfaces; + + bool ModuleCacheHintDisplayed = false; + bool ArchiveHintDisplayed = false; +}; + +} // end namespace dsymutil +} // end namespace llvm + +#endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H diff --git a/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h b/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h index 52b36353c6..5b2e372547 100644 --- a/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h +++ b/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h @@ -1,107 +1,107 @@ -//===- tools/dsymutil/LinkUtils.h - Dwarf linker utilities ------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H -#define LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H - -#include "SymbolMap.h" - -#include "llvm/ADT/Twine.h" -#include "llvm/Remarks/RemarkFormat.h" -#include "llvm/Support/VirtualFileSystem.h" -#include "llvm/Support/WithColor.h" - -#include "llvm/DWARFLinker/DWARFLinker.h" -#include "llvm/DWARFLinker/DWARFStreamer.h" -#include <string> - -namespace llvm { -namespace dsymutil { - -struct LinkOptions { - /// Verbosity - bool Verbose = false; - - /// Statistics - bool Statistics = false; - - /// Skip emitting output - bool NoOutput = false; - - /// Do not unique types according to ODR - bool NoODR = false; - - /// Update - bool Update = false; - - /// Minimize - bool Minimize = false; - - /// Do not check swiftmodule timestamp - bool NoTimestamp = false; - - /// Number of threads. - unsigned Threads = 1; - - // Output file type. - OutputFileType FileType = OutputFileType::Object; - - /// The accelerator table kind - AccelTableKind TheAccelTableKind; - - /// -oso-prepend-path - std::string PrependPath; - - /// The -object-prefix-map. - std::map<std::string, std::string> ObjectPrefixMap; - - /// The Resources directory in the .dSYM bundle. - Optional<std::string> ResourceDir; - - /// Symbol map translator. - SymbolMapTranslator Translator; - - /// Virtual File System. - llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = - vfs::getRealFileSystem(); - - /// Fields used for linking and placing remarks into the .dSYM bundle. - /// @{ - - /// Number of debug maps processed in total. - unsigned NumDebugMaps = 0; - - /// -remarks-prepend-path: prepend a path to all the external remark file - /// paths found in remark metadata. - std::string RemarksPrependPath; - - /// The output format of the remarks. - remarks::Format RemarksFormat = remarks::Format::Bitstream; - - /// @} - - LinkOptions() = default; -}; - -inline void warn(Twine Warning, Twine Context = {}) { - WithColor::warning() << Warning + "\n"; - if (!Context.isTriviallyEmpty()) - WithColor::note() << Twine("while processing ") + Context + "\n"; -} - -inline bool error(Twine Error, Twine Context = {}) { - WithColor::error() << Error + "\n"; - if (!Context.isTriviallyEmpty()) - WithColor::note() << Twine("while processing ") + Context + "\n"; - return false; -} - -} // end namespace dsymutil -} // end namespace llvm - -#endif // LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H +//===- tools/dsymutil/LinkUtils.h - Dwarf linker utilities ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H +#define LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H + +#include "SymbolMap.h" + +#include "llvm/ADT/Twine.h" +#include "llvm/Remarks/RemarkFormat.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/WithColor.h" + +#include "llvm/DWARFLinker/DWARFLinker.h" +#include "llvm/DWARFLinker/DWARFStreamer.h" +#include <string> + +namespace llvm { +namespace dsymutil { + +struct LinkOptions { + /// Verbosity + bool Verbose = false; + + /// Statistics + bool Statistics = false; + + /// Skip emitting output + bool NoOutput = false; + + /// Do not unique types according to ODR + bool NoODR = false; + + /// Update + bool Update = false; + + /// Minimize + bool Minimize = false; + + /// Do not check swiftmodule timestamp + bool NoTimestamp = false; + + /// Number of threads. + unsigned Threads = 1; + + // Output file type. + OutputFileType FileType = OutputFileType::Object; + + /// The accelerator table kind + AccelTableKind TheAccelTableKind; + + /// -oso-prepend-path + std::string PrependPath; + + /// The -object-prefix-map. + std::map<std::string, std::string> ObjectPrefixMap; + + /// The Resources directory in the .dSYM bundle. + Optional<std::string> ResourceDir; + + /// Symbol map translator. + SymbolMapTranslator Translator; + + /// Virtual File System. + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = + vfs::getRealFileSystem(); + + /// Fields used for linking and placing remarks into the .dSYM bundle. + /// @{ + + /// Number of debug maps processed in total. + unsigned NumDebugMaps = 0; + + /// -remarks-prepend-path: prepend a path to all the external remark file + /// paths found in remark metadata. + std::string RemarksPrependPath; + + /// The output format of the remarks. + remarks::Format RemarksFormat = remarks::Format::Bitstream; + + /// @} + + LinkOptions() = default; +}; + +inline void warn(Twine Warning, Twine Context = {}) { + WithColor::warning() << Warning + "\n"; + if (!Context.isTriviallyEmpty()) + WithColor::note() << Twine("while processing ") + Context + "\n"; +} + +inline bool error(Twine Error, Twine Context = {}) { + WithColor::error() << Error + "\n"; + if (!Context.isTriviallyEmpty()) + WithColor::note() << Twine("while processing ") + Context + "\n"; + return false; +} + +} // end namespace dsymutil +} // end namespace llvm + +#endif // LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H diff --git a/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp b/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp index 37848c561a..4c05326dc2 100644 --- a/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp +++ b/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp @@ -1,609 +1,609 @@ -//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "BinaryHolder.h" -#include "DebugMap.h" -#include "MachOUtils.h" -#include "llvm/ADT/Optional.h" -#include "llvm/Object/MachO.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" -#include <vector> - -namespace { -using namespace llvm; -using namespace llvm::dsymutil; -using namespace llvm::object; - -class MachODebugMapParser { -public: - MachODebugMapParser(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - StringRef BinaryPath, ArrayRef<std::string> Archs, - StringRef PathPrefix = "", - bool PaperTrailWarnings = false, bool Verbose = false) - : BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()), - PathPrefix(std::string(PathPrefix)), - PaperTrailWarnings(PaperTrailWarnings), BinHolder(VFS, Verbose), - CurrentDebugMapObject(nullptr) {} - - /// Parses and returns the DebugMaps of the input binary. The binary contains - /// multiple maps in case it is a universal binary. - /// \returns an error in case the provided BinaryPath doesn't exist - /// or isn't of a supported type. - ErrorOr<std::vector<std::unique_ptr<DebugMap>>> parse(); - - /// Walk the symbol table and dump it. - bool dumpStab(); - -private: - std::string BinaryPath; - SmallVector<StringRef, 1> Archs; - std::string PathPrefix; - bool PaperTrailWarnings; - - /// Owns the MemoryBuffer for the main binary. - BinaryHolder BinHolder; - /// Map of the binary symbol addresses. - StringMap<uint64_t> MainBinarySymbolAddresses; - StringRef MainBinaryStrings; - /// The constructed DebugMap. - std::unique_ptr<DebugMap> Result; - /// List of common symbols that need to be added to the debug map. - std::vector<std::string> CommonSymbols; - - /// Map of the currently processed object file symbol addresses. - StringMap<Optional<uint64_t>> CurrentObjectAddresses; - /// Element of the debug map corresponding to the current object file. - DebugMapObject *CurrentDebugMapObject; - - /// Holds function info while function scope processing. - const char *CurrentFunctionName; - uint64_t CurrentFunctionAddress; - - std::unique_ptr<DebugMap> parseOneBinary(const MachOObjectFile &MainBinary, - StringRef BinaryPath); - - void - switchToNewDebugMapObject(StringRef Filename, - sys::TimePoint<std::chrono::seconds> Timestamp); - void resetParserState(); - uint64_t getMainBinarySymbolAddress(StringRef Name); - std::vector<StringRef> getMainBinarySymbolNames(uint64_t Value); - void loadMainBinarySymbols(const MachOObjectFile &MainBinary); - void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj); - void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type, - uint8_t SectionIndex, uint16_t Flags, - uint64_t Value); - - template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) { - handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc, - STE.n_value); - } - - void addCommonSymbols(); - - /// Dump the symbol table output header. - void dumpSymTabHeader(raw_ostream &OS, StringRef Arch); - - /// Dump the contents of nlist entries. - void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, uint32_t StringIndex, - uint8_t Type, uint8_t SectionIndex, uint16_t Flags, - uint64_t Value); - - template <typename STEType> - void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, const STEType &STE) { - dumpSymTabEntry(OS, Index, STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc, - STE.n_value); - } - void dumpOneBinaryStab(const MachOObjectFile &MainBinary, - StringRef BinaryPath); - - void Warning(const Twine &Msg, StringRef File = StringRef()) { - WithColor::warning() << "(" - << MachOUtils::getArchName( - Result->getTriple().getArchName()) - << ") " << File << " " << Msg << "\n"; - - if (PaperTrailWarnings) { - if (!File.empty()) - Result->addDebugMapObject(File, sys::TimePoint<std::chrono::seconds>()); - if (Result->end() != Result->begin()) { - auto it = Result->end(); - (*--it)->addWarning(Msg.str()); - } - } - } -}; - -} // anonymous namespace - -/// Reset the parser state corresponding to the current object -/// file. This is to be called after an object file is finished -/// processing. -void MachODebugMapParser::resetParserState() { - CommonSymbols.clear(); - CurrentObjectAddresses.clear(); - CurrentDebugMapObject = nullptr; -} - -/// Commons symbols won't show up in the symbol map but might need to be -/// relocated. We can add them to the symbol table ourselves by combining the -/// information in the object file (the symbol name) and the main binary (the -/// address). -void MachODebugMapParser::addCommonSymbols() { - for (auto &CommonSymbol : CommonSymbols) { - uint64_t CommonAddr = getMainBinarySymbolAddress(CommonSymbol); - if (CommonAddr == 0) { - // The main binary doesn't have an address for the given symbol. - continue; - } - if (!CurrentDebugMapObject->addSymbol(CommonSymbol, None /*ObjectAddress*/, - CommonAddr, 0 /*size*/)) { - // The symbol is already present. - continue; - } - } -} - -/// Create a new DebugMapObject. This function resets the state of the -/// parser that was referring to the last object file and sets -/// everything up to add symbols to the new one. -void MachODebugMapParser::switchToNewDebugMapObject( - StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) { - addCommonSymbols(); - resetParserState(); - - SmallString<80> Path(PathPrefix); - sys::path::append(Path, Filename); - - auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp); - if (!ObjectEntry) { - auto Err = ObjectEntry.takeError(); - Warning("unable to open object file: " + toString(std::move(Err)), - Path.str()); - return; - } - - auto Object = ObjectEntry->getObjectAs<MachOObjectFile>(Result->getTriple()); - if (!Object) { - auto Err = Object.takeError(); - Warning("unable to open object file: " + toString(std::move(Err)), - Path.str()); - return; - } - - CurrentDebugMapObject = - &Result->addDebugMapObject(Path, Timestamp, MachO::N_OSO); - loadCurrentObjectFileSymbols(*Object); -} - -static std::string getArchName(const object::MachOObjectFile &Obj) { - Triple T = Obj.getArchTriple(); - return std::string(T.getArchName()); -} - -std::unique_ptr<DebugMap> -MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary, - StringRef BinaryPath) { - loadMainBinarySymbols(MainBinary); - ArrayRef<uint8_t> UUID = MainBinary.getUuid(); - Result = - std::make_unique<DebugMap>(MainBinary.getArchTriple(), BinaryPath, UUID); - MainBinaryStrings = MainBinary.getStringTableData(); - for (const SymbolRef &Symbol : MainBinary.symbols()) { - const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); - if (MainBinary.is64Bit()) - handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI)); - else - handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI)); - } - - resetParserState(); - return std::move(Result); -} - -// Table that maps Darwin's Mach-O stab constants to strings to allow printing. -// llvm-nm has very similar code, the strings used here are however slightly -// different and part of the interface of dsymutil (some project's build-systems -// parse the ouptut of dsymutil -s), thus they shouldn't be changed. -struct DarwinStabName { - uint8_t NType; - const char *Name; -}; - -static const struct DarwinStabName DarwinStabNames[] = { - {MachO::N_GSYM, "N_GSYM"}, {MachO::N_FNAME, "N_FNAME"}, - {MachO::N_FUN, "N_FUN"}, {MachO::N_STSYM, "N_STSYM"}, - {MachO::N_LCSYM, "N_LCSYM"}, {MachO::N_BNSYM, "N_BNSYM"}, - {MachO::N_PC, "N_PC"}, {MachO::N_AST, "N_AST"}, - {MachO::N_OPT, "N_OPT"}, {MachO::N_RSYM, "N_RSYM"}, - {MachO::N_SLINE, "N_SLINE"}, {MachO::N_ENSYM, "N_ENSYM"}, - {MachO::N_SSYM, "N_SSYM"}, {MachO::N_SO, "N_SO"}, - {MachO::N_OSO, "N_OSO"}, {MachO::N_LSYM, "N_LSYM"}, - {MachO::N_BINCL, "N_BINCL"}, {MachO::N_SOL, "N_SOL"}, - {MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"}, - {MachO::N_OLEVEL, "N_OLEV"}, {MachO::N_PSYM, "N_PSYM"}, - {MachO::N_EINCL, "N_EINCL"}, {MachO::N_ENTRY, "N_ENTRY"}, - {MachO::N_LBRAC, "N_LBRAC"}, {MachO::N_EXCL, "N_EXCL"}, - {MachO::N_RBRAC, "N_RBRAC"}, {MachO::N_BCOMM, "N_BCOMM"}, - {MachO::N_ECOMM, "N_ECOMM"}, {MachO::N_ECOML, "N_ECOML"}, - {MachO::N_LENG, "N_LENG"}, {0, nullptr}}; - -static const char *getDarwinStabString(uint8_t NType) { - for (unsigned i = 0; DarwinStabNames[i].Name; i++) { - if (DarwinStabNames[i].NType == NType) - return DarwinStabNames[i].Name; - } - return nullptr; -} - -void MachODebugMapParser::dumpSymTabHeader(raw_ostream &OS, StringRef Arch) { - OS << "-----------------------------------" - "-----------------------------------\n"; - OS << "Symbol table for: '" << BinaryPath << "' (" << Arch.data() << ")\n"; - OS << "-----------------------------------" - "-----------------------------------\n"; - OS << "Index n_strx n_type n_sect n_desc n_value\n"; - OS << "======== -------- ------------------ ------ ------ ----------------\n"; -} - -void MachODebugMapParser::dumpSymTabEntry(raw_ostream &OS, uint64_t Index, - uint32_t StringIndex, uint8_t Type, - uint8_t SectionIndex, uint16_t Flags, - uint64_t Value) { - // Index - OS << '[' << format_decimal(Index, 6) - << "] " - // n_strx - << format_hex_no_prefix(StringIndex, 8) - << ' ' - // n_type... - << format_hex_no_prefix(Type, 2) << " ("; - - if (Type & MachO::N_STAB) - OS << left_justify(getDarwinStabString(Type), 13); - else { - if (Type & MachO::N_PEXT) - OS << "PEXT "; - else - OS << " "; - switch (Type & MachO::N_TYPE) { - case MachO::N_UNDF: // 0x0 undefined, n_sect == NO_SECT - OS << "UNDF"; - break; - case MachO::N_ABS: // 0x2 absolute, n_sect == NO_SECT - OS << "ABS "; - break; - case MachO::N_SECT: // 0xe defined in section number n_sect - OS << "SECT"; - break; - case MachO::N_PBUD: // 0xc prebound undefined (defined in a dylib) - OS << "PBUD"; - break; - case MachO::N_INDR: // 0xa indirect - OS << "INDR"; - break; - default: - OS << format_hex_no_prefix(Type, 2) << " "; - break; - } - if (Type & MachO::N_EXT) - OS << " EXT"; - else - OS << " "; - } - - OS << ") " - // n_sect - << format_hex_no_prefix(SectionIndex, 2) - << " " - // n_desc - << format_hex_no_prefix(Flags, 4) - << " " - // n_value - << format_hex_no_prefix(Value, 16); - - const char *Name = &MainBinaryStrings.data()[StringIndex]; - if (Name && Name[0]) - OS << " '" << Name << "'"; - - OS << "\n"; -} - -void MachODebugMapParser::dumpOneBinaryStab(const MachOObjectFile &MainBinary, - StringRef BinaryPath) { - loadMainBinarySymbols(MainBinary); - MainBinaryStrings = MainBinary.getStringTableData(); - raw_ostream &OS(llvm::outs()); - - dumpSymTabHeader(OS, getArchName(MainBinary)); - uint64_t Idx = 0; - for (const SymbolRef &Symbol : MainBinary.symbols()) { - const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); - if (MainBinary.is64Bit()) - dumpSymTabEntry(OS, Idx, MainBinary.getSymbol64TableEntry(DRI)); - else - dumpSymTabEntry(OS, Idx, MainBinary.getSymbolTableEntry(DRI)); - Idx++; - } - - OS << "\n\n"; - resetParserState(); -} - -static bool shouldLinkArch(SmallVectorImpl<StringRef> &Archs, StringRef Arch) { - if (Archs.empty() || is_contained(Archs, "all") || is_contained(Archs, "*")) - return true; - - if (Arch.startswith("arm") && Arch != "arm64" && is_contained(Archs, "arm")) - return true; - - SmallString<16> ArchName = Arch; - if (Arch.startswith("thumb")) - ArchName = ("arm" + Arch.substr(5)).str(); - - return is_contained(Archs, ArchName); -} - -bool MachODebugMapParser::dumpStab() { - auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath); - if (!ObjectEntry) { - auto Err = ObjectEntry.takeError(); - WithColor::error() << "cannot load '" << BinaryPath - << "': " << toString(std::move(Err)) << '\n'; - return false; - } - - auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>(); - if (!Objects) { - auto Err = Objects.takeError(); - WithColor::error() << "cannot get '" << BinaryPath - << "' as MachO file: " << toString(std::move(Err)) - << "\n"; - return false; - } - - for (const auto *Object : *Objects) - if (shouldLinkArch(Archs, Object->getArchTriple().getArchName())) - dumpOneBinaryStab(*Object, BinaryPath); - - return true; -} - -/// This main parsing routine tries to open the main binary and if -/// successful iterates over the STAB entries. The real parsing is -/// done in handleStabSymbolTableEntry. -ErrorOr<std::vector<std::unique_ptr<DebugMap>>> MachODebugMapParser::parse() { - auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath); - if (!ObjectEntry) { - return errorToErrorCode(ObjectEntry.takeError()); - } - - auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>(); - if (!Objects) { - return errorToErrorCode(Objects.takeError()); - } - - std::vector<std::unique_ptr<DebugMap>> Results; - for (const auto *Object : *Objects) - if (shouldLinkArch(Archs, Object->getArchTriple().getArchName())) - Results.push_back(parseOneBinary(*Object, BinaryPath)); - - return std::move(Results); -} - -/// Interpret the STAB entries to fill the DebugMap. -void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, - uint8_t Type, - uint8_t SectionIndex, - uint16_t Flags, - uint64_t Value) { - if (!(Type & MachO::N_STAB)) - return; - - const char *Name = &MainBinaryStrings.data()[StringIndex]; - - // An N_OSO entry represents the start of a new object file description. - if (Type == MachO::N_OSO) - return switchToNewDebugMapObject(Name, sys::toTimePoint(Value)); - - if (Type == MachO::N_AST) { - SmallString<80> Path(PathPrefix); - sys::path::append(Path, Name); - Result->addDebugMapObject(Path, sys::toTimePoint(Value), Type); - return; - } - - // If the last N_OSO object file wasn't found, CurrentDebugMapObject will be - // null. Do not update anything until we find the next valid N_OSO entry. - if (!CurrentDebugMapObject) - return; - - uint32_t Size = 0; - switch (Type) { - case MachO::N_GSYM: - // This is a global variable. We need to query the main binary - // symbol table to find its address as it might not be in the - // debug map (for common symbols). - Value = getMainBinarySymbolAddress(Name); - break; - case MachO::N_FUN: - // Functions are scopes in STABS. They have an end marker that - // contains the function size. - if (Name[0] == '\0') { - Size = Value; - Value = CurrentFunctionAddress; - Name = CurrentFunctionName; - break; - } else { - CurrentFunctionName = Name; - CurrentFunctionAddress = Value; - return; - } - case MachO::N_STSYM: - break; - default: - return; - } - - auto ObjectSymIt = CurrentObjectAddresses.find(Name); - - // If the name of a (non-static) symbol is not in the current object, we - // check all its aliases from the main binary. - if (ObjectSymIt == CurrentObjectAddresses.end() && Type != MachO::N_STSYM) { - for (const auto &Alias : getMainBinarySymbolNames(Value)) { - ObjectSymIt = CurrentObjectAddresses.find(Alias); - if (ObjectSymIt != CurrentObjectAddresses.end()) - break; - } - } - - if (ObjectSymIt == CurrentObjectAddresses.end()) { - Warning("could not find object file symbol for symbol " + Twine(Name)); - return; - } - - if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value, - Size)) { - Warning(Twine("failed to insert symbol '") + Name + "' in the debug map."); - return; - } -} - -/// Load the current object file symbols into CurrentObjectAddresses. -void MachODebugMapParser::loadCurrentObjectFileSymbols( - const object::MachOObjectFile &Obj) { - CurrentObjectAddresses.clear(); - - for (auto Sym : Obj.symbols()) { - uint64_t Addr = cantFail(Sym.getValue()); - Expected<StringRef> Name = Sym.getName(); - if (!Name) { - // TODO: Actually report errors helpfully. - consumeError(Name.takeError()); - continue; - } - // The value of some categories of symbols isn't meaningful. For - // example common symbols store their size in the value field, not - // their address. Absolute symbols have a fixed address that can - // conflict with standard symbols. These symbols (especially the - // common ones), might still be referenced by relocations. These - // relocations will use the symbol itself, and won't need an - // object file address. The object file address field is optional - // in the DebugMap, leave it unassigned for these symbols. - uint32_t Flags = cantFail(Sym.getFlags()); - if (Flags & SymbolRef::SF_Absolute) { - CurrentObjectAddresses[*Name] = None; - } else if (Flags & SymbolRef::SF_Common) { - CurrentObjectAddresses[*Name] = None; - CommonSymbols.push_back(std::string(*Name)); - } else { - CurrentObjectAddresses[*Name] = Addr; - } - } -} - -/// Lookup a symbol address in the main binary symbol table. The -/// parser only needs to query common symbols, thus not every symbol's -/// address is available through this function. -uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) { - auto Sym = MainBinarySymbolAddresses.find(Name); - if (Sym == MainBinarySymbolAddresses.end()) - return 0; - return Sym->second; -} - -/// Get all symbol names in the main binary for the given value. -std::vector<StringRef> -MachODebugMapParser::getMainBinarySymbolNames(uint64_t Value) { - std::vector<StringRef> Names; - for (const auto &Entry : MainBinarySymbolAddresses) { - if (Entry.second == Value) - Names.push_back(Entry.first()); - } - return Names; -} - -/// Load the interesting main binary symbols' addresses into -/// MainBinarySymbolAddresses. -void MachODebugMapParser::loadMainBinarySymbols( - const MachOObjectFile &MainBinary) { - section_iterator Section = MainBinary.section_end(); - MainBinarySymbolAddresses.clear(); - for (const auto &Sym : MainBinary.symbols()) { - Expected<SymbolRef::Type> TypeOrErr = Sym.getType(); - if (!TypeOrErr) { - // TODO: Actually report errors helpfully. - consumeError(TypeOrErr.takeError()); - continue; - } - SymbolRef::Type Type = *TypeOrErr; - // Skip undefined and STAB entries. - if ((Type == SymbolRef::ST_Debug) || (Type == SymbolRef::ST_Unknown)) - continue; - // In theory, the only symbols of interest are the global variables. These - // are the only ones that need to be queried because the address of common - // data won't be described in the debug map. All other addresses should be - // fetched for the debug map. In reality, by playing with 'ld -r' and - // export lists, you can get symbols described as N_GSYM in the debug map, - // but associated with a local symbol. Gather all the symbols, but prefer - // the global ones. - uint8_t SymType = - MainBinary.getSymbolTableEntry(Sym.getRawDataRefImpl()).n_type; - bool Extern = SymType & (MachO::N_EXT | MachO::N_PEXT); - Expected<section_iterator> SectionOrErr = Sym.getSection(); - if (!SectionOrErr) { - // TODO: Actually report errors helpfully. - consumeError(SectionOrErr.takeError()); - continue; - } - Section = *SectionOrErr; +//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "BinaryHolder.h" +#include "DebugMap.h" +#include "MachOUtils.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> + +namespace { +using namespace llvm; +using namespace llvm::dsymutil; +using namespace llvm::object; + +class MachODebugMapParser { +public: + MachODebugMapParser(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + StringRef BinaryPath, ArrayRef<std::string> Archs, + StringRef PathPrefix = "", + bool PaperTrailWarnings = false, bool Verbose = false) + : BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()), + PathPrefix(std::string(PathPrefix)), + PaperTrailWarnings(PaperTrailWarnings), BinHolder(VFS, Verbose), + CurrentDebugMapObject(nullptr) {} + + /// Parses and returns the DebugMaps of the input binary. The binary contains + /// multiple maps in case it is a universal binary. + /// \returns an error in case the provided BinaryPath doesn't exist + /// or isn't of a supported type. + ErrorOr<std::vector<std::unique_ptr<DebugMap>>> parse(); + + /// Walk the symbol table and dump it. + bool dumpStab(); + +private: + std::string BinaryPath; + SmallVector<StringRef, 1> Archs; + std::string PathPrefix; + bool PaperTrailWarnings; + + /// Owns the MemoryBuffer for the main binary. + BinaryHolder BinHolder; + /// Map of the binary symbol addresses. + StringMap<uint64_t> MainBinarySymbolAddresses; + StringRef MainBinaryStrings; + /// The constructed DebugMap. + std::unique_ptr<DebugMap> Result; + /// List of common symbols that need to be added to the debug map. + std::vector<std::string> CommonSymbols; + + /// Map of the currently processed object file symbol addresses. + StringMap<Optional<uint64_t>> CurrentObjectAddresses; + /// Element of the debug map corresponding to the current object file. + DebugMapObject *CurrentDebugMapObject; + + /// Holds function info while function scope processing. + const char *CurrentFunctionName; + uint64_t CurrentFunctionAddress; + + std::unique_ptr<DebugMap> parseOneBinary(const MachOObjectFile &MainBinary, + StringRef BinaryPath); + + void + switchToNewDebugMapObject(StringRef Filename, + sys::TimePoint<std::chrono::seconds> Timestamp); + void resetParserState(); + uint64_t getMainBinarySymbolAddress(StringRef Name); + std::vector<StringRef> getMainBinarySymbolNames(uint64_t Value); + void loadMainBinarySymbols(const MachOObjectFile &MainBinary); + void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj); + void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type, + uint8_t SectionIndex, uint16_t Flags, + uint64_t Value); + + template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) { + handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc, + STE.n_value); + } + + void addCommonSymbols(); + + /// Dump the symbol table output header. + void dumpSymTabHeader(raw_ostream &OS, StringRef Arch); + + /// Dump the contents of nlist entries. + void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, uint32_t StringIndex, + uint8_t Type, uint8_t SectionIndex, uint16_t Flags, + uint64_t Value); + + template <typename STEType> + void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, const STEType &STE) { + dumpSymTabEntry(OS, Index, STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc, + STE.n_value); + } + void dumpOneBinaryStab(const MachOObjectFile &MainBinary, + StringRef BinaryPath); + + void Warning(const Twine &Msg, StringRef File = StringRef()) { + WithColor::warning() << "(" + << MachOUtils::getArchName( + Result->getTriple().getArchName()) + << ") " << File << " " << Msg << "\n"; + + if (PaperTrailWarnings) { + if (!File.empty()) + Result->addDebugMapObject(File, sys::TimePoint<std::chrono::seconds>()); + if (Result->end() != Result->begin()) { + auto it = Result->end(); + (*--it)->addWarning(Msg.str()); + } + } + } +}; + +} // anonymous namespace + +/// Reset the parser state corresponding to the current object +/// file. This is to be called after an object file is finished +/// processing. +void MachODebugMapParser::resetParserState() { + CommonSymbols.clear(); + CurrentObjectAddresses.clear(); + CurrentDebugMapObject = nullptr; +} + +/// Commons symbols won't show up in the symbol map but might need to be +/// relocated. We can add them to the symbol table ourselves by combining the +/// information in the object file (the symbol name) and the main binary (the +/// address). +void MachODebugMapParser::addCommonSymbols() { + for (auto &CommonSymbol : CommonSymbols) { + uint64_t CommonAddr = getMainBinarySymbolAddress(CommonSymbol); + if (CommonAddr == 0) { + // The main binary doesn't have an address for the given symbol. + continue; + } + if (!CurrentDebugMapObject->addSymbol(CommonSymbol, None /*ObjectAddress*/, + CommonAddr, 0 /*size*/)) { + // The symbol is already present. + continue; + } + } +} + +/// Create a new DebugMapObject. This function resets the state of the +/// parser that was referring to the last object file and sets +/// everything up to add symbols to the new one. +void MachODebugMapParser::switchToNewDebugMapObject( + StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) { + addCommonSymbols(); + resetParserState(); + + SmallString<80> Path(PathPrefix); + sys::path::append(Path, Filename); + + auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp); + if (!ObjectEntry) { + auto Err = ObjectEntry.takeError(); + Warning("unable to open object file: " + toString(std::move(Err)), + Path.str()); + return; + } + + auto Object = ObjectEntry->getObjectAs<MachOObjectFile>(Result->getTriple()); + if (!Object) { + auto Err = Object.takeError(); + Warning("unable to open object file: " + toString(std::move(Err)), + Path.str()); + return; + } + + CurrentDebugMapObject = + &Result->addDebugMapObject(Path, Timestamp, MachO::N_OSO); + loadCurrentObjectFileSymbols(*Object); +} + +static std::string getArchName(const object::MachOObjectFile &Obj) { + Triple T = Obj.getArchTriple(); + return std::string(T.getArchName()); +} + +std::unique_ptr<DebugMap> +MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary, + StringRef BinaryPath) { + loadMainBinarySymbols(MainBinary); + ArrayRef<uint8_t> UUID = MainBinary.getUuid(); + Result = + std::make_unique<DebugMap>(MainBinary.getArchTriple(), BinaryPath, UUID); + MainBinaryStrings = MainBinary.getStringTableData(); + for (const SymbolRef &Symbol : MainBinary.symbols()) { + const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); + if (MainBinary.is64Bit()) + handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI)); + else + handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI)); + } + + resetParserState(); + return std::move(Result); +} + +// Table that maps Darwin's Mach-O stab constants to strings to allow printing. +// llvm-nm has very similar code, the strings used here are however slightly +// different and part of the interface of dsymutil (some project's build-systems +// parse the ouptut of dsymutil -s), thus they shouldn't be changed. +struct DarwinStabName { + uint8_t NType; + const char *Name; +}; + +static const struct DarwinStabName DarwinStabNames[] = { + {MachO::N_GSYM, "N_GSYM"}, {MachO::N_FNAME, "N_FNAME"}, + {MachO::N_FUN, "N_FUN"}, {MachO::N_STSYM, "N_STSYM"}, + {MachO::N_LCSYM, "N_LCSYM"}, {MachO::N_BNSYM, "N_BNSYM"}, + {MachO::N_PC, "N_PC"}, {MachO::N_AST, "N_AST"}, + {MachO::N_OPT, "N_OPT"}, {MachO::N_RSYM, "N_RSYM"}, + {MachO::N_SLINE, "N_SLINE"}, {MachO::N_ENSYM, "N_ENSYM"}, + {MachO::N_SSYM, "N_SSYM"}, {MachO::N_SO, "N_SO"}, + {MachO::N_OSO, "N_OSO"}, {MachO::N_LSYM, "N_LSYM"}, + {MachO::N_BINCL, "N_BINCL"}, {MachO::N_SOL, "N_SOL"}, + {MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"}, + {MachO::N_OLEVEL, "N_OLEV"}, {MachO::N_PSYM, "N_PSYM"}, + {MachO::N_EINCL, "N_EINCL"}, {MachO::N_ENTRY, "N_ENTRY"}, + {MachO::N_LBRAC, "N_LBRAC"}, {MachO::N_EXCL, "N_EXCL"}, + {MachO::N_RBRAC, "N_RBRAC"}, {MachO::N_BCOMM, "N_BCOMM"}, + {MachO::N_ECOMM, "N_ECOMM"}, {MachO::N_ECOML, "N_ECOML"}, + {MachO::N_LENG, "N_LENG"}, {0, nullptr}}; + +static const char *getDarwinStabString(uint8_t NType) { + for (unsigned i = 0; DarwinStabNames[i].Name; i++) { + if (DarwinStabNames[i].NType == NType) + return DarwinStabNames[i].Name; + } + return nullptr; +} + +void MachODebugMapParser::dumpSymTabHeader(raw_ostream &OS, StringRef Arch) { + OS << "-----------------------------------" + "-----------------------------------\n"; + OS << "Symbol table for: '" << BinaryPath << "' (" << Arch.data() << ")\n"; + OS << "-----------------------------------" + "-----------------------------------\n"; + OS << "Index n_strx n_type n_sect n_desc n_value\n"; + OS << "======== -------- ------------------ ------ ------ ----------------\n"; +} + +void MachODebugMapParser::dumpSymTabEntry(raw_ostream &OS, uint64_t Index, + uint32_t StringIndex, uint8_t Type, + uint8_t SectionIndex, uint16_t Flags, + uint64_t Value) { + // Index + OS << '[' << format_decimal(Index, 6) + << "] " + // n_strx + << format_hex_no_prefix(StringIndex, 8) + << ' ' + // n_type... + << format_hex_no_prefix(Type, 2) << " ("; + + if (Type & MachO::N_STAB) + OS << left_justify(getDarwinStabString(Type), 13); + else { + if (Type & MachO::N_PEXT) + OS << "PEXT "; + else + OS << " "; + switch (Type & MachO::N_TYPE) { + case MachO::N_UNDF: // 0x0 undefined, n_sect == NO_SECT + OS << "UNDF"; + break; + case MachO::N_ABS: // 0x2 absolute, n_sect == NO_SECT + OS << "ABS "; + break; + case MachO::N_SECT: // 0xe defined in section number n_sect + OS << "SECT"; + break; + case MachO::N_PBUD: // 0xc prebound undefined (defined in a dylib) + OS << "PBUD"; + break; + case MachO::N_INDR: // 0xa indirect + OS << "INDR"; + break; + default: + OS << format_hex_no_prefix(Type, 2) << " "; + break; + } + if (Type & MachO::N_EXT) + OS << " EXT"; + else + OS << " "; + } + + OS << ") " + // n_sect + << format_hex_no_prefix(SectionIndex, 2) + << " " + // n_desc + << format_hex_no_prefix(Flags, 4) + << " " + // n_value + << format_hex_no_prefix(Value, 16); + + const char *Name = &MainBinaryStrings.data()[StringIndex]; + if (Name && Name[0]) + OS << " '" << Name << "'"; + + OS << "\n"; +} + +void MachODebugMapParser::dumpOneBinaryStab(const MachOObjectFile &MainBinary, + StringRef BinaryPath) { + loadMainBinarySymbols(MainBinary); + MainBinaryStrings = MainBinary.getStringTableData(); + raw_ostream &OS(llvm::outs()); + + dumpSymTabHeader(OS, getArchName(MainBinary)); + uint64_t Idx = 0; + for (const SymbolRef &Symbol : MainBinary.symbols()) { + const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); + if (MainBinary.is64Bit()) + dumpSymTabEntry(OS, Idx, MainBinary.getSymbol64TableEntry(DRI)); + else + dumpSymTabEntry(OS, Idx, MainBinary.getSymbolTableEntry(DRI)); + Idx++; + } + + OS << "\n\n"; + resetParserState(); +} + +static bool shouldLinkArch(SmallVectorImpl<StringRef> &Archs, StringRef Arch) { + if (Archs.empty() || is_contained(Archs, "all") || is_contained(Archs, "*")) + return true; + + if (Arch.startswith("arm") && Arch != "arm64" && is_contained(Archs, "arm")) + return true; + + SmallString<16> ArchName = Arch; + if (Arch.startswith("thumb")) + ArchName = ("arm" + Arch.substr(5)).str(); + + return is_contained(Archs, ArchName); +} + +bool MachODebugMapParser::dumpStab() { + auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath); + if (!ObjectEntry) { + auto Err = ObjectEntry.takeError(); + WithColor::error() << "cannot load '" << BinaryPath + << "': " << toString(std::move(Err)) << '\n'; + return false; + } + + auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>(); + if (!Objects) { + auto Err = Objects.takeError(); + WithColor::error() << "cannot get '" << BinaryPath + << "' as MachO file: " << toString(std::move(Err)) + << "\n"; + return false; + } + + for (const auto *Object : *Objects) + if (shouldLinkArch(Archs, Object->getArchTriple().getArchName())) + dumpOneBinaryStab(*Object, BinaryPath); + + return true; +} + +/// This main parsing routine tries to open the main binary and if +/// successful iterates over the STAB entries. The real parsing is +/// done in handleStabSymbolTableEntry. +ErrorOr<std::vector<std::unique_ptr<DebugMap>>> MachODebugMapParser::parse() { + auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath); + if (!ObjectEntry) { + return errorToErrorCode(ObjectEntry.takeError()); + } + + auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>(); + if (!Objects) { + return errorToErrorCode(Objects.takeError()); + } + + std::vector<std::unique_ptr<DebugMap>> Results; + for (const auto *Object : *Objects) + if (shouldLinkArch(Archs, Object->getArchTriple().getArchName())) + Results.push_back(parseOneBinary(*Object, BinaryPath)); + + return std::move(Results); +} + +/// Interpret the STAB entries to fill the DebugMap. +void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, + uint8_t Type, + uint8_t SectionIndex, + uint16_t Flags, + uint64_t Value) { + if (!(Type & MachO::N_STAB)) + return; + + const char *Name = &MainBinaryStrings.data()[StringIndex]; + + // An N_OSO entry represents the start of a new object file description. + if (Type == MachO::N_OSO) + return switchToNewDebugMapObject(Name, sys::toTimePoint(Value)); + + if (Type == MachO::N_AST) { + SmallString<80> Path(PathPrefix); + sys::path::append(Path, Name); + Result->addDebugMapObject(Path, sys::toTimePoint(Value), Type); + return; + } + + // If the last N_OSO object file wasn't found, CurrentDebugMapObject will be + // null. Do not update anything until we find the next valid N_OSO entry. + if (!CurrentDebugMapObject) + return; + + uint32_t Size = 0; + switch (Type) { + case MachO::N_GSYM: + // This is a global variable. We need to query the main binary + // symbol table to find its address as it might not be in the + // debug map (for common symbols). + Value = getMainBinarySymbolAddress(Name); + break; + case MachO::N_FUN: + // Functions are scopes in STABS. They have an end marker that + // contains the function size. + if (Name[0] == '\0') { + Size = Value; + Value = CurrentFunctionAddress; + Name = CurrentFunctionName; + break; + } else { + CurrentFunctionName = Name; + CurrentFunctionAddress = Value; + return; + } + case MachO::N_STSYM: + break; + default: + return; + } + + auto ObjectSymIt = CurrentObjectAddresses.find(Name); + + // If the name of a (non-static) symbol is not in the current object, we + // check all its aliases from the main binary. + if (ObjectSymIt == CurrentObjectAddresses.end() && Type != MachO::N_STSYM) { + for (const auto &Alias : getMainBinarySymbolNames(Value)) { + ObjectSymIt = CurrentObjectAddresses.find(Alias); + if (ObjectSymIt != CurrentObjectAddresses.end()) + break; + } + } + + if (ObjectSymIt == CurrentObjectAddresses.end()) { + Warning("could not find object file symbol for symbol " + Twine(Name)); + return; + } + + if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value, + Size)) { + Warning(Twine("failed to insert symbol '") + Name + "' in the debug map."); + return; + } +} + +/// Load the current object file symbols into CurrentObjectAddresses. +void MachODebugMapParser::loadCurrentObjectFileSymbols( + const object::MachOObjectFile &Obj) { + CurrentObjectAddresses.clear(); + + for (auto Sym : Obj.symbols()) { + uint64_t Addr = cantFail(Sym.getValue()); + Expected<StringRef> Name = Sym.getName(); + if (!Name) { + // TODO: Actually report errors helpfully. + consumeError(Name.takeError()); + continue; + } + // The value of some categories of symbols isn't meaningful. For + // example common symbols store their size in the value field, not + // their address. Absolute symbols have a fixed address that can + // conflict with standard symbols. These symbols (especially the + // common ones), might still be referenced by relocations. These + // relocations will use the symbol itself, and won't need an + // object file address. The object file address field is optional + // in the DebugMap, leave it unassigned for these symbols. + uint32_t Flags = cantFail(Sym.getFlags()); + if (Flags & SymbolRef::SF_Absolute) { + CurrentObjectAddresses[*Name] = None; + } else if (Flags & SymbolRef::SF_Common) { + CurrentObjectAddresses[*Name] = None; + CommonSymbols.push_back(std::string(*Name)); + } else { + CurrentObjectAddresses[*Name] = Addr; + } + } +} + +/// Lookup a symbol address in the main binary symbol table. The +/// parser only needs to query common symbols, thus not every symbol's +/// address is available through this function. +uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) { + auto Sym = MainBinarySymbolAddresses.find(Name); + if (Sym == MainBinarySymbolAddresses.end()) + return 0; + return Sym->second; +} + +/// Get all symbol names in the main binary for the given value. +std::vector<StringRef> +MachODebugMapParser::getMainBinarySymbolNames(uint64_t Value) { + std::vector<StringRef> Names; + for (const auto &Entry : MainBinarySymbolAddresses) { + if (Entry.second == Value) + Names.push_back(Entry.first()); + } + return Names; +} + +/// Load the interesting main binary symbols' addresses into +/// MainBinarySymbolAddresses. +void MachODebugMapParser::loadMainBinarySymbols( + const MachOObjectFile &MainBinary) { + section_iterator Section = MainBinary.section_end(); + MainBinarySymbolAddresses.clear(); + for (const auto &Sym : MainBinary.symbols()) { + Expected<SymbolRef::Type> TypeOrErr = Sym.getType(); + if (!TypeOrErr) { + // TODO: Actually report errors helpfully. + consumeError(TypeOrErr.takeError()); + continue; + } + SymbolRef::Type Type = *TypeOrErr; + // Skip undefined and STAB entries. + if ((Type == SymbolRef::ST_Debug) || (Type == SymbolRef::ST_Unknown)) + continue; + // In theory, the only symbols of interest are the global variables. These + // are the only ones that need to be queried because the address of common + // data won't be described in the debug map. All other addresses should be + // fetched for the debug map. In reality, by playing with 'ld -r' and + // export lists, you can get symbols described as N_GSYM in the debug map, + // but associated with a local symbol. Gather all the symbols, but prefer + // the global ones. + uint8_t SymType = + MainBinary.getSymbolTableEntry(Sym.getRawDataRefImpl()).n_type; + bool Extern = SymType & (MachO::N_EXT | MachO::N_PEXT); + Expected<section_iterator> SectionOrErr = Sym.getSection(); + if (!SectionOrErr) { + // TODO: Actually report errors helpfully. + consumeError(SectionOrErr.takeError()); + continue; + } + Section = *SectionOrErr; if ((Section == MainBinary.section_end() || Section->isText()) && !Extern) - continue; - uint64_t Addr = cantFail(Sym.getValue()); - Expected<StringRef> NameOrErr = Sym.getName(); - if (!NameOrErr) { - // TODO: Actually report errors helpfully. - consumeError(NameOrErr.takeError()); - continue; - } - StringRef Name = *NameOrErr; - if (Name.size() == 0 || Name[0] == '\0') - continue; - // Override only if the new key is global. - if (Extern) - MainBinarySymbolAddresses[Name] = Addr; - else - MainBinarySymbolAddresses.try_emplace(Name, Addr); - } -} - -namespace llvm { -namespace dsymutil { -llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>> -parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - StringRef InputFile, ArrayRef<std::string> Archs, - StringRef PrependPath, bool PaperTrailWarnings, bool Verbose, - bool InputIsYAML) { - if (InputIsYAML) - return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose); - - MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, - PaperTrailWarnings, Verbose); - return Parser.parse(); -} - -bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - StringRef InputFile, ArrayRef<std::string> Archs, - StringRef PrependPath) { - MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, false); - return Parser.dumpStab(); -} -} // namespace dsymutil -} // namespace llvm + continue; + uint64_t Addr = cantFail(Sym.getValue()); + Expected<StringRef> NameOrErr = Sym.getName(); + if (!NameOrErr) { + // TODO: Actually report errors helpfully. + consumeError(NameOrErr.takeError()); + continue; + } + StringRef Name = *NameOrErr; + if (Name.size() == 0 || Name[0] == '\0') + continue; + // Override only if the new key is global. + if (Extern) + MainBinarySymbolAddresses[Name] = Addr; + else + MainBinarySymbolAddresses.try_emplace(Name, Addr); + } +} + +namespace llvm { +namespace dsymutil { +llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>> +parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + StringRef InputFile, ArrayRef<std::string> Archs, + StringRef PrependPath, bool PaperTrailWarnings, bool Verbose, + bool InputIsYAML) { + if (InputIsYAML) + return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose); + + MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, + PaperTrailWarnings, Verbose); + return Parser.parse(); +} + +bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + StringRef InputFile, ArrayRef<std::string> Archs, + StringRef PrependPath) { + MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, false); + return Parser.dumpStab(); +} +} // namespace dsymutil +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp index 943af43058..c91be23ac6 100644 --- a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp +++ b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp @@ -1,436 +1,436 @@ -//===-- MachOUtils.cpp - Mach-o specific helpers for dsymutil ------------===// +//===-- MachOUtils.cpp - Mach-o specific helpers for dsymutil ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MachOUtils.h" +#include "BinaryHolder.h" +#include "DebugMap.h" +#include "LinkUtils.h" +#include "llvm/CodeGen/NonRelocatableStringpool.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCMachObjectWriter.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace dsymutil { +namespace MachOUtils { + +llvm::Error ArchAndFile::createTempFile() { + llvm::SmallString<128> TmpModel; + llvm::sys::path::system_temp_directory(true, TmpModel); + llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf"); + Expected<sys::fs::TempFile> T = sys::fs::TempFile::create(TmpModel); + + if (!T) + return T.takeError(); + + File = std::make_unique<sys::fs::TempFile>(std::move(*T)); + return Error::success(); +} + +llvm::StringRef ArchAndFile::path() const { return File->TmpName; } + +ArchAndFile::~ArchAndFile() { + if (File) + if (auto E = File->discard()) + llvm::consumeError(std::move(E)); +} + +std::string getArchName(StringRef Arch) { + if (Arch.startswith("thumb")) + return (llvm::Twine("arm") + Arch.drop_front(5)).str(); + return std::string(Arch); +} + +static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) { + auto Path = sys::findProgramByName("lipo", makeArrayRef(SDKPath)); + if (!Path) + Path = sys::findProgramByName("lipo"); + + if (!Path) { + WithColor::error() << "lipo: " << Path.getError().message() << "\n"; + return false; + } + + std::string ErrMsg; + int result = sys::ExecuteAndWait(*Path, Args, None, {}, 0, 0, &ErrMsg); + if (result) { + WithColor::error() << "lipo: " << ErrMsg << "\n"; + return false; + } + + return true; +} + +bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles, + StringRef OutputFileName, + const LinkOptions &Options, StringRef SDKPath) { + // No need to merge one file into a universal fat binary. + if (ArchFiles.size() == 1) { + if (auto E = ArchFiles.front().File->keep(OutputFileName)) { + WithColor::error() << "while keeping " << ArchFiles.front().path() + << " as " << OutputFileName << ": " + << toString(std::move(E)) << "\n"; + return false; + } + return true; + } + + SmallVector<StringRef, 8> Args; + Args.push_back("lipo"); + Args.push_back("-create"); + + for (auto &Thin : ArchFiles) + Args.push_back(Thin.path()); + + // Align segments to match dsymutil-classic alignment + for (auto &Thin : ArchFiles) { + Thin.Arch = getArchName(Thin.Arch); + Args.push_back("-segalign"); + Args.push_back(Thin.Arch); + Args.push_back("20"); + } + + Args.push_back("-output"); + Args.push_back(OutputFileName.data()); + + if (Options.Verbose) { + outs() << "Running lipo\n"; + for (auto Arg : Args) + outs() << ' ' << Arg; + outs() << "\n"; + } + + return Options.NoOutput ? true : runLipo(SDKPath, Args); +} + +// Return a MachO::segment_command_64 that holds the same values as the passed +// MachO::segment_command. We do that to avoid having to duplicate the logic +// for 32bits and 64bits segments. +struct MachO::segment_command_64 adaptFrom32bits(MachO::segment_command Seg) { + MachO::segment_command_64 Seg64; + Seg64.cmd = Seg.cmd; + Seg64.cmdsize = Seg.cmdsize; + memcpy(Seg64.segname, Seg.segname, sizeof(Seg.segname)); + Seg64.vmaddr = Seg.vmaddr; + Seg64.vmsize = Seg.vmsize; + Seg64.fileoff = Seg.fileoff; + Seg64.filesize = Seg.filesize; + Seg64.maxprot = Seg.maxprot; + Seg64.initprot = Seg.initprot; + Seg64.nsects = Seg.nsects; + Seg64.flags = Seg.flags; + return Seg64; +} + +// Iterate on all \a Obj segments, and apply \a Handler to them. +template <typename FunctionTy> +static void iterateOnSegments(const object::MachOObjectFile &Obj, + FunctionTy Handler) { + for (const auto &LCI : Obj.load_commands()) { + MachO::segment_command_64 Segment; + if (LCI.C.cmd == MachO::LC_SEGMENT) + Segment = adaptFrom32bits(Obj.getSegmentLoadCommand(LCI)); + else if (LCI.C.cmd == MachO::LC_SEGMENT_64) + Segment = Obj.getSegment64LoadCommand(LCI); + else + continue; + + Handler(Segment); + } +} + +// Transfer the symbols described by \a NList to \a NewSymtab which is just the +// raw contents of the symbol table for the dSYM companion file. \returns +// whether the symbol was transferred or not. +template <typename NListTy> +static bool transferSymbol(NListTy NList, bool IsLittleEndian, + StringRef Strings, SmallVectorImpl<char> &NewSymtab, + NonRelocatableStringpool &NewStrings, + bool &InDebugNote) { + // Do not transfer undefined symbols, we want real addresses. + if ((NList.n_type & MachO::N_TYPE) == MachO::N_UNDF) + return false; + + // Do not transfer N_AST symbols as their content is copied into a section of + // the Mach-O companion file. + if (NList.n_type == MachO::N_AST) + return false; + + StringRef Name = StringRef(Strings.begin() + NList.n_strx); + + // An N_SO with a filename opens a debugging scope and another one without a + // name closes it. Don't transfer anything in the debugging scope. + if (InDebugNote) { + InDebugNote = + (NList.n_type != MachO::N_SO) || (!Name.empty() && Name[0] != '\0'); + return false; + } else if (NList.n_type == MachO::N_SO) { + InDebugNote = true; + return false; + } + + // FIXME: The + 1 is here to mimic dsymutil-classic that has 2 empty + // strings at the start of the generated string table (There is + // corresponding code in the string table emission). + NList.n_strx = NewStrings.getStringOffset(Name) + 1; + if (IsLittleEndian != sys::IsLittleEndianHost) + MachO::swapStruct(NList); + + NewSymtab.append(reinterpret_cast<char *>(&NList), + reinterpret_cast<char *>(&NList + 1)); + return true; +} + +// Wrapper around transferSymbol to transfer all of \a Obj symbols +// to \a NewSymtab. This function does not write in the output file. +// \returns the number of symbols in \a NewSymtab. +static unsigned transferSymbols(const object::MachOObjectFile &Obj, + SmallVectorImpl<char> &NewSymtab, + NonRelocatableStringpool &NewStrings) { + unsigned Syms = 0; + StringRef Strings = Obj.getStringTableData(); + bool IsLittleEndian = Obj.isLittleEndian(); + bool InDebugNote = false; + + if (Obj.is64Bit()) { + for (const object::SymbolRef &Symbol : Obj.symbols()) { + object::DataRefImpl DRI = Symbol.getRawDataRefImpl(); + if (transferSymbol(Obj.getSymbol64TableEntry(DRI), IsLittleEndian, + Strings, NewSymtab, NewStrings, InDebugNote)) + ++Syms; + } + } else { + for (const object::SymbolRef &Symbol : Obj.symbols()) { + object::DataRefImpl DRI = Symbol.getRawDataRefImpl(); + if (transferSymbol(Obj.getSymbolTableEntry(DRI), IsLittleEndian, Strings, + NewSymtab, NewStrings, InDebugNote)) + ++Syms; + } + } + return Syms; +} + +static MachO::section +getSection(const object::MachOObjectFile &Obj, + const MachO::segment_command &Seg, + const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) { + return Obj.getSection(LCI, Idx); +} + +static MachO::section_64 +getSection(const object::MachOObjectFile &Obj, + const MachO::segment_command_64 &Seg, + const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) { + return Obj.getSection64(LCI, Idx); +} + +// Transfer \a Segment from \a Obj to the output file. This calls into \a Writer +// to write these load commands directly in the output file at the current +// position. // -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// The function also tries to find a hole in the address map to fit the __DWARF +// segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the +// highest segment address. // -//===----------------------------------------------------------------------===// - -#include "MachOUtils.h" -#include "BinaryHolder.h" -#include "DebugMap.h" -#include "LinkUtils.h" -#include "llvm/CodeGen/NonRelocatableStringpool.h" -#include "llvm/MC/MCAsmLayout.h" -#include "llvm/MC/MCMachObjectWriter.h" -#include "llvm/MC/MCObjectStreamer.h" -#include "llvm/MC/MCSectionMachO.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/Object/MachO.h" -#include "llvm/Support/FileUtilities.h" -#include "llvm/Support/Program.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" - -namespace llvm { -namespace dsymutil { -namespace MachOUtils { - -llvm::Error ArchAndFile::createTempFile() { - llvm::SmallString<128> TmpModel; - llvm::sys::path::system_temp_directory(true, TmpModel); - llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf"); - Expected<sys::fs::TempFile> T = sys::fs::TempFile::create(TmpModel); - - if (!T) - return T.takeError(); - - File = std::make_unique<sys::fs::TempFile>(std::move(*T)); - return Error::success(); -} - -llvm::StringRef ArchAndFile::path() const { return File->TmpName; } - -ArchAndFile::~ArchAndFile() { - if (File) - if (auto E = File->discard()) - llvm::consumeError(std::move(E)); -} - -std::string getArchName(StringRef Arch) { - if (Arch.startswith("thumb")) - return (llvm::Twine("arm") + Arch.drop_front(5)).str(); - return std::string(Arch); -} - -static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) { - auto Path = sys::findProgramByName("lipo", makeArrayRef(SDKPath)); - if (!Path) - Path = sys::findProgramByName("lipo"); - - if (!Path) { - WithColor::error() << "lipo: " << Path.getError().message() << "\n"; - return false; - } - - std::string ErrMsg; - int result = sys::ExecuteAndWait(*Path, Args, None, {}, 0, 0, &ErrMsg); - if (result) { - WithColor::error() << "lipo: " << ErrMsg << "\n"; - return false; - } - - return true; -} - -bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles, - StringRef OutputFileName, - const LinkOptions &Options, StringRef SDKPath) { - // No need to merge one file into a universal fat binary. - if (ArchFiles.size() == 1) { - if (auto E = ArchFiles.front().File->keep(OutputFileName)) { - WithColor::error() << "while keeping " << ArchFiles.front().path() - << " as " << OutputFileName << ": " - << toString(std::move(E)) << "\n"; - return false; - } - return true; - } - - SmallVector<StringRef, 8> Args; - Args.push_back("lipo"); - Args.push_back("-create"); - - for (auto &Thin : ArchFiles) - Args.push_back(Thin.path()); - - // Align segments to match dsymutil-classic alignment - for (auto &Thin : ArchFiles) { - Thin.Arch = getArchName(Thin.Arch); - Args.push_back("-segalign"); - Args.push_back(Thin.Arch); - Args.push_back("20"); - } - - Args.push_back("-output"); - Args.push_back(OutputFileName.data()); - - if (Options.Verbose) { - outs() << "Running lipo\n"; - for (auto Arg : Args) - outs() << ' ' << Arg; - outs() << "\n"; - } - - return Options.NoOutput ? true : runLipo(SDKPath, Args); -} - -// Return a MachO::segment_command_64 that holds the same values as the passed -// MachO::segment_command. We do that to avoid having to duplicate the logic -// for 32bits and 64bits segments. -struct MachO::segment_command_64 adaptFrom32bits(MachO::segment_command Seg) { - MachO::segment_command_64 Seg64; - Seg64.cmd = Seg.cmd; - Seg64.cmdsize = Seg.cmdsize; - memcpy(Seg64.segname, Seg.segname, sizeof(Seg.segname)); - Seg64.vmaddr = Seg.vmaddr; - Seg64.vmsize = Seg.vmsize; - Seg64.fileoff = Seg.fileoff; - Seg64.filesize = Seg.filesize; - Seg64.maxprot = Seg.maxprot; - Seg64.initprot = Seg.initprot; - Seg64.nsects = Seg.nsects; - Seg64.flags = Seg.flags; - return Seg64; -} - -// Iterate on all \a Obj segments, and apply \a Handler to them. -template <typename FunctionTy> -static void iterateOnSegments(const object::MachOObjectFile &Obj, - FunctionTy Handler) { - for (const auto &LCI : Obj.load_commands()) { - MachO::segment_command_64 Segment; - if (LCI.C.cmd == MachO::LC_SEGMENT) - Segment = adaptFrom32bits(Obj.getSegmentLoadCommand(LCI)); - else if (LCI.C.cmd == MachO::LC_SEGMENT_64) - Segment = Obj.getSegment64LoadCommand(LCI); - else - continue; - - Handler(Segment); - } -} - -// Transfer the symbols described by \a NList to \a NewSymtab which is just the -// raw contents of the symbol table for the dSYM companion file. \returns -// whether the symbol was transferred or not. -template <typename NListTy> -static bool transferSymbol(NListTy NList, bool IsLittleEndian, - StringRef Strings, SmallVectorImpl<char> &NewSymtab, - NonRelocatableStringpool &NewStrings, - bool &InDebugNote) { - // Do not transfer undefined symbols, we want real addresses. - if ((NList.n_type & MachO::N_TYPE) == MachO::N_UNDF) - return false; - - // Do not transfer N_AST symbols as their content is copied into a section of - // the Mach-O companion file. - if (NList.n_type == MachO::N_AST) - return false; - - StringRef Name = StringRef(Strings.begin() + NList.n_strx); - - // An N_SO with a filename opens a debugging scope and another one without a - // name closes it. Don't transfer anything in the debugging scope. - if (InDebugNote) { - InDebugNote = - (NList.n_type != MachO::N_SO) || (!Name.empty() && Name[0] != '\0'); - return false; - } else if (NList.n_type == MachO::N_SO) { - InDebugNote = true; - return false; - } - - // FIXME: The + 1 is here to mimic dsymutil-classic that has 2 empty - // strings at the start of the generated string table (There is - // corresponding code in the string table emission). - NList.n_strx = NewStrings.getStringOffset(Name) + 1; - if (IsLittleEndian != sys::IsLittleEndianHost) - MachO::swapStruct(NList); - - NewSymtab.append(reinterpret_cast<char *>(&NList), - reinterpret_cast<char *>(&NList + 1)); - return true; -} - -// Wrapper around transferSymbol to transfer all of \a Obj symbols -// to \a NewSymtab. This function does not write in the output file. -// \returns the number of symbols in \a NewSymtab. -static unsigned transferSymbols(const object::MachOObjectFile &Obj, - SmallVectorImpl<char> &NewSymtab, - NonRelocatableStringpool &NewStrings) { - unsigned Syms = 0; - StringRef Strings = Obj.getStringTableData(); - bool IsLittleEndian = Obj.isLittleEndian(); - bool InDebugNote = false; - - if (Obj.is64Bit()) { - for (const object::SymbolRef &Symbol : Obj.symbols()) { - object::DataRefImpl DRI = Symbol.getRawDataRefImpl(); - if (transferSymbol(Obj.getSymbol64TableEntry(DRI), IsLittleEndian, - Strings, NewSymtab, NewStrings, InDebugNote)) - ++Syms; - } - } else { - for (const object::SymbolRef &Symbol : Obj.symbols()) { - object::DataRefImpl DRI = Symbol.getRawDataRefImpl(); - if (transferSymbol(Obj.getSymbolTableEntry(DRI), IsLittleEndian, Strings, - NewSymtab, NewStrings, InDebugNote)) - ++Syms; - } - } - return Syms; -} - -static MachO::section -getSection(const object::MachOObjectFile &Obj, - const MachO::segment_command &Seg, - const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) { - return Obj.getSection(LCI, Idx); -} - -static MachO::section_64 -getSection(const object::MachOObjectFile &Obj, - const MachO::segment_command_64 &Seg, - const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) { - return Obj.getSection64(LCI, Idx); -} - -// Transfer \a Segment from \a Obj to the output file. This calls into \a Writer -// to write these load commands directly in the output file at the current -// position. -// -// The function also tries to find a hole in the address map to fit the __DWARF -// segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the -// highest segment address. -// -// When the __LINKEDIT segment is transferred, its offset and size are set resp. -// to \a LinkeditOffset and \a LinkeditSize. +// When the __LINKEDIT segment is transferred, its offset and size are set resp. +// to \a LinkeditOffset and \a LinkeditSize. // // When the eh_frame section is transferred, its offset and size are set resp. // to \a EHFrameOffset and \a EHFrameSize. -template <typename SegmentTy> -static void transferSegmentAndSections( - const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment, - const object::MachOObjectFile &Obj, MachObjectWriter &Writer, +template <typename SegmentTy> +static void transferSegmentAndSections( + const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment, + const object::MachOObjectFile &Obj, MachObjectWriter &Writer, uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t EHFrameOffset, uint64_t EHFrameSize, uint64_t DwarfSegmentSize, uint64_t &GapForDwarf, uint64_t &EndAddress) { - if (StringRef("__DWARF") == Segment.segname) - return; - + if (StringRef("__DWARF") == Segment.segname) + return; + if (StringRef("__TEXT") == Segment.segname && EHFrameSize > 0) { Segment.fileoff = EHFrameOffset; Segment.filesize = EHFrameSize; } else if (StringRef("__LINKEDIT") == Segment.segname) { - Segment.fileoff = LinkeditOffset; - Segment.filesize = LinkeditSize; - // Resize vmsize by rounding to the page size. - Segment.vmsize = alignTo(LinkeditSize, 0x1000); + Segment.fileoff = LinkeditOffset; + Segment.filesize = LinkeditSize; + // Resize vmsize by rounding to the page size. + Segment.vmsize = alignTo(LinkeditSize, 0x1000); } else { Segment.fileoff = Segment.filesize = 0; - } - - // Check if the end address of the last segment and our current - // start address leave a sufficient gap to store the __DWARF - // segment. - uint64_t PrevEndAddress = EndAddress; - EndAddress = alignTo(EndAddress, 0x1000); - if (GapForDwarf == UINT64_MAX && Segment.vmaddr > EndAddress && - Segment.vmaddr - EndAddress >= DwarfSegmentSize) - GapForDwarf = EndAddress; - - // The segments are not necessarily sorted by their vmaddr. - EndAddress = - std::max<uint64_t>(PrevEndAddress, Segment.vmaddr + Segment.vmsize); - unsigned nsects = Segment.nsects; - if (Obj.isLittleEndian() != sys::IsLittleEndianHost) - MachO::swapStruct(Segment); - Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment)); - for (unsigned i = 0; i < nsects; ++i) { - auto Sect = getSection(Obj, Segment, LCI, i); + } + + // Check if the end address of the last segment and our current + // start address leave a sufficient gap to store the __DWARF + // segment. + uint64_t PrevEndAddress = EndAddress; + EndAddress = alignTo(EndAddress, 0x1000); + if (GapForDwarf == UINT64_MAX && Segment.vmaddr > EndAddress && + Segment.vmaddr - EndAddress >= DwarfSegmentSize) + GapForDwarf = EndAddress; + + // The segments are not necessarily sorted by their vmaddr. + EndAddress = + std::max<uint64_t>(PrevEndAddress, Segment.vmaddr + Segment.vmsize); + unsigned nsects = Segment.nsects; + if (Obj.isLittleEndian() != sys::IsLittleEndianHost) + MachO::swapStruct(Segment); + Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment)); + for (unsigned i = 0; i < nsects; ++i) { + auto Sect = getSection(Obj, Segment, LCI, i); if (StringRef("__eh_frame") == Sect.sectname) { Sect.offset = EHFrameOffset; Sect.reloff = Sect.nreloc = 0; } else { Sect.offset = Sect.reloff = Sect.nreloc = 0; } - if (Obj.isLittleEndian() != sys::IsLittleEndianHost) - MachO::swapStruct(Sect); - Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect)); - } -} - -// Write the __DWARF segment load command to the output file. -static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset, - uint64_t FileSize, unsigned NumSections, - MCAsmLayout &Layout, MachObjectWriter &Writer) { - Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr, - alignTo(FileSize, 0x1000), FileOffset, - FileSize, /* MaxProt */ 7, - /* InitProt =*/3); - - for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { - MCSection *Sec = Layout.getSectionOrder()[i]; - if (Sec->begin() == Sec->end() || !Layout.getSectionFileSize(Sec)) - continue; - - unsigned Align = Sec->getAlignment(); - if (Align > 1) { - VMAddr = alignTo(VMAddr, Align); - FileOffset = alignTo(FileOffset, Align); - } - Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0); - - FileOffset += Layout.getSectionAddressSize(Sec); - VMAddr += Layout.getSectionAddressSize(Sec); - } -} - -static bool isExecutable(const object::MachOObjectFile &Obj) { - if (Obj.is64Bit()) - return Obj.getHeader64().filetype != MachO::MH_OBJECT; - else - return Obj.getHeader().filetype != MachO::MH_OBJECT; -} - -static bool hasLinkEditSegment(const object::MachOObjectFile &Obj) { - bool HasLinkEditSegment = false; - iterateOnSegments(Obj, [&](const MachO::segment_command_64 &Segment) { - if (StringRef("__LINKEDIT") == Segment.segname) - HasLinkEditSegment = true; - }); - return HasLinkEditSegment; -} - -static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) { - if (Is64Bit) - return sizeof(MachO::segment_command_64) + - NumSections * sizeof(MachO::section_64); - - return sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section); -} - -// Stream a dSYM companion binary file corresponding to the binary referenced -// by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to -// \a OutFile and it must be using a MachObjectWriter object to do so. -bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const DebugMap &DM, SymbolMapTranslator &Translator, - MCStreamer &MS, raw_fd_ostream &OutFile) { - auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS); - MCAssembler &MCAsm = ObjectStreamer.getAssembler(); - auto &Writer = static_cast<MachObjectWriter &>(MCAsm.getWriter()); - - // Layout but don't emit. - ObjectStreamer.flushPendingLabels(); - MCAsmLayout Layout(MCAsm); - MCAsm.layout(Layout); - - BinaryHolder InputBinaryHolder(VFS, false); - - auto ObjectEntry = InputBinaryHolder.getObjectEntry(DM.getBinaryPath()); - if (!ObjectEntry) { - auto Err = ObjectEntry.takeError(); - return error(Twine("opening ") + DM.getBinaryPath() + ": " + - toString(std::move(Err)), - "output file streaming"); - } - - auto Object = - ObjectEntry->getObjectAs<object::MachOObjectFile>(DM.getTriple()); - if (!Object) { - auto Err = Object.takeError(); - return error(Twine("opening ") + DM.getBinaryPath() + ": " + - toString(std::move(Err)), - "output file streaming"); - } - - auto &InputBinary = *Object; - - bool Is64Bit = Writer.is64Bit(); - MachO::symtab_command SymtabCmd = InputBinary.getSymtabLoadCommand(); - - // Compute the number of load commands we will need. - unsigned LoadCommandSize = 0; - unsigned NumLoadCommands = 0; - - // Get LC_UUID and LC_BUILD_VERSION. - MachO::uuid_command UUIDCmd; - SmallVector<MachO::build_version_command, 2> BuildVersionCmd; - memset(&UUIDCmd, 0, sizeof(UUIDCmd)); - for (auto &LCI : InputBinary.load_commands()) { - switch (LCI.C.cmd) { - case MachO::LC_UUID: - if (UUIDCmd.cmd) - return error("Binary contains more than one UUID"); - UUIDCmd = InputBinary.getUuidCommand(LCI); - ++NumLoadCommands; - LoadCommandSize += sizeof(UUIDCmd); - break; - case MachO::LC_BUILD_VERSION: { - MachO::build_version_command Cmd; - memset(&Cmd, 0, sizeof(Cmd)); - Cmd = InputBinary.getBuildVersionLoadCommand(LCI); - ++NumLoadCommands; - LoadCommandSize += sizeof(Cmd); - // LLDB doesn't care about the build tools for now. - Cmd.ntools = 0; - BuildVersionCmd.push_back(Cmd); - break; - } - default: - break; - } - } - - // If we have a valid symtab to copy, do it. - bool ShouldEmitSymtab = - isExecutable(InputBinary) && hasLinkEditSegment(InputBinary); - if (ShouldEmitSymtab) { - LoadCommandSize += sizeof(MachO::symtab_command); - ++NumLoadCommands; - } - + if (Obj.isLittleEndian() != sys::IsLittleEndianHost) + MachO::swapStruct(Sect); + Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect)); + } +} + +// Write the __DWARF segment load command to the output file. +static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset, + uint64_t FileSize, unsigned NumSections, + MCAsmLayout &Layout, MachObjectWriter &Writer) { + Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr, + alignTo(FileSize, 0x1000), FileOffset, + FileSize, /* MaxProt */ 7, + /* InitProt =*/3); + + for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { + MCSection *Sec = Layout.getSectionOrder()[i]; + if (Sec->begin() == Sec->end() || !Layout.getSectionFileSize(Sec)) + continue; + + unsigned Align = Sec->getAlignment(); + if (Align > 1) { + VMAddr = alignTo(VMAddr, Align); + FileOffset = alignTo(FileOffset, Align); + } + Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0); + + FileOffset += Layout.getSectionAddressSize(Sec); + VMAddr += Layout.getSectionAddressSize(Sec); + } +} + +static bool isExecutable(const object::MachOObjectFile &Obj) { + if (Obj.is64Bit()) + return Obj.getHeader64().filetype != MachO::MH_OBJECT; + else + return Obj.getHeader().filetype != MachO::MH_OBJECT; +} + +static bool hasLinkEditSegment(const object::MachOObjectFile &Obj) { + bool HasLinkEditSegment = false; + iterateOnSegments(Obj, [&](const MachO::segment_command_64 &Segment) { + if (StringRef("__LINKEDIT") == Segment.segname) + HasLinkEditSegment = true; + }); + return HasLinkEditSegment; +} + +static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) { + if (Is64Bit) + return sizeof(MachO::segment_command_64) + + NumSections * sizeof(MachO::section_64); + + return sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section); +} + +// Stream a dSYM companion binary file corresponding to the binary referenced +// by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to +// \a OutFile and it must be using a MachObjectWriter object to do so. +bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + const DebugMap &DM, SymbolMapTranslator &Translator, + MCStreamer &MS, raw_fd_ostream &OutFile) { + auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS); + MCAssembler &MCAsm = ObjectStreamer.getAssembler(); + auto &Writer = static_cast<MachObjectWriter &>(MCAsm.getWriter()); + + // Layout but don't emit. + ObjectStreamer.flushPendingLabels(); + MCAsmLayout Layout(MCAsm); + MCAsm.layout(Layout); + + BinaryHolder InputBinaryHolder(VFS, false); + + auto ObjectEntry = InputBinaryHolder.getObjectEntry(DM.getBinaryPath()); + if (!ObjectEntry) { + auto Err = ObjectEntry.takeError(); + return error(Twine("opening ") + DM.getBinaryPath() + ": " + + toString(std::move(Err)), + "output file streaming"); + } + + auto Object = + ObjectEntry->getObjectAs<object::MachOObjectFile>(DM.getTriple()); + if (!Object) { + auto Err = Object.takeError(); + return error(Twine("opening ") + DM.getBinaryPath() + ": " + + toString(std::move(Err)), + "output file streaming"); + } + + auto &InputBinary = *Object; + + bool Is64Bit = Writer.is64Bit(); + MachO::symtab_command SymtabCmd = InputBinary.getSymtabLoadCommand(); + + // Compute the number of load commands we will need. + unsigned LoadCommandSize = 0; + unsigned NumLoadCommands = 0; + + // Get LC_UUID and LC_BUILD_VERSION. + MachO::uuid_command UUIDCmd; + SmallVector<MachO::build_version_command, 2> BuildVersionCmd; + memset(&UUIDCmd, 0, sizeof(UUIDCmd)); + for (auto &LCI : InputBinary.load_commands()) { + switch (LCI.C.cmd) { + case MachO::LC_UUID: + if (UUIDCmd.cmd) + return error("Binary contains more than one UUID"); + UUIDCmd = InputBinary.getUuidCommand(LCI); + ++NumLoadCommands; + LoadCommandSize += sizeof(UUIDCmd); + break; + case MachO::LC_BUILD_VERSION: { + MachO::build_version_command Cmd; + memset(&Cmd, 0, sizeof(Cmd)); + Cmd = InputBinary.getBuildVersionLoadCommand(LCI); + ++NumLoadCommands; + LoadCommandSize += sizeof(Cmd); + // LLDB doesn't care about the build tools for now. + Cmd.ntools = 0; + BuildVersionCmd.push_back(Cmd); + break; + } + default: + break; + } + } + + // If we have a valid symtab to copy, do it. + bool ShouldEmitSymtab = + isExecutable(InputBinary) && hasLinkEditSegment(InputBinary); + if (ShouldEmitSymtab) { + LoadCommandSize += sizeof(MachO::symtab_command); + ++NumLoadCommands; + } + // If we have a valid eh_frame to copy, do it. uint64_t EHFrameSize = 0; StringRef EHFrameData; @@ -452,148 +452,148 @@ bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, } } - unsigned HeaderSize = - Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); - // We will copy every segment that isn't __DWARF. - iterateOnSegments(InputBinary, [&](const MachO::segment_command_64 &Segment) { - if (StringRef("__DWARF") == Segment.segname) - return; - - ++NumLoadCommands; - LoadCommandSize += segmentLoadCommandSize(Is64Bit, Segment.nsects); - }); - - // We will add our own brand new __DWARF segment if we have debug - // info. - unsigned NumDwarfSections = 0; - uint64_t DwarfSegmentSize = 0; - - for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { - MCSection *Sec = Layout.getSectionOrder()[i]; - if (Sec->begin() == Sec->end()) - continue; - - if (uint64_t Size = Layout.getSectionFileSize(Sec)) { - DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlignment()); - DwarfSegmentSize += Size; - ++NumDwarfSections; - } - } - - if (NumDwarfSections) { - ++NumLoadCommands; - LoadCommandSize += segmentLoadCommandSize(Is64Bit, NumDwarfSections); - } - - SmallString<0> NewSymtab; - std::function<StringRef(StringRef)> TranslationLambda = - Translator ? [&](StringRef Input) { return Translator(Input); } - : static_cast<std::function<StringRef(StringRef)>>(nullptr); - // Legacy dsymutil puts an empty string at the start of the line table. - // thus we set NonRelocatableStringpool(,PutEmptyString=true) - NonRelocatableStringpool NewStrings(TranslationLambda, true); - unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); - unsigned NumSyms = 0; - uint64_t NewStringsSize = 0; - if (ShouldEmitSymtab) { - NewSymtab.reserve(SymtabCmd.nsyms * NListSize / 2); - NumSyms = transferSymbols(InputBinary, NewSymtab, NewStrings); - NewStringsSize = NewStrings.getSize() + 1; - } - - uint64_t SymtabStart = LoadCommandSize; - SymtabStart += HeaderSize; - SymtabStart = alignTo(SymtabStart, 0x1000); - - // We gathered all the information we need, start emitting the output file. - Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false); - - // Write the load commands. - assert(OutFile.tell() == HeaderSize); - if (UUIDCmd.cmd != 0) { - Writer.W.write<uint32_t>(UUIDCmd.cmd); - Writer.W.write<uint32_t>(sizeof(UUIDCmd)); - OutFile.write(reinterpret_cast<const char *>(UUIDCmd.uuid), 16); - assert(OutFile.tell() == HeaderSize + sizeof(UUIDCmd)); - } - for (auto Cmd : BuildVersionCmd) { - Writer.W.write<uint32_t>(Cmd.cmd); - Writer.W.write<uint32_t>(sizeof(Cmd)); - Writer.W.write<uint32_t>(Cmd.platform); - Writer.W.write<uint32_t>(Cmd.minos); - Writer.W.write<uint32_t>(Cmd.sdk); - Writer.W.write<uint32_t>(Cmd.ntools); - } - - assert(SymtabCmd.cmd && "No symbol table."); - uint64_t StringStart = SymtabStart + NumSyms * NListSize; - if (ShouldEmitSymtab) - Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart, - NewStringsSize); - + unsigned HeaderSize = + Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); + // We will copy every segment that isn't __DWARF. + iterateOnSegments(InputBinary, [&](const MachO::segment_command_64 &Segment) { + if (StringRef("__DWARF") == Segment.segname) + return; + + ++NumLoadCommands; + LoadCommandSize += segmentLoadCommandSize(Is64Bit, Segment.nsects); + }); + + // We will add our own brand new __DWARF segment if we have debug + // info. + unsigned NumDwarfSections = 0; + uint64_t DwarfSegmentSize = 0; + + for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { + MCSection *Sec = Layout.getSectionOrder()[i]; + if (Sec->begin() == Sec->end()) + continue; + + if (uint64_t Size = Layout.getSectionFileSize(Sec)) { + DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlignment()); + DwarfSegmentSize += Size; + ++NumDwarfSections; + } + } + + if (NumDwarfSections) { + ++NumLoadCommands; + LoadCommandSize += segmentLoadCommandSize(Is64Bit, NumDwarfSections); + } + + SmallString<0> NewSymtab; + std::function<StringRef(StringRef)> TranslationLambda = + Translator ? [&](StringRef Input) { return Translator(Input); } + : static_cast<std::function<StringRef(StringRef)>>(nullptr); + // Legacy dsymutil puts an empty string at the start of the line table. + // thus we set NonRelocatableStringpool(,PutEmptyString=true) + NonRelocatableStringpool NewStrings(TranslationLambda, true); + unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); + unsigned NumSyms = 0; + uint64_t NewStringsSize = 0; + if (ShouldEmitSymtab) { + NewSymtab.reserve(SymtabCmd.nsyms * NListSize / 2); + NumSyms = transferSymbols(InputBinary, NewSymtab, NewStrings); + NewStringsSize = NewStrings.getSize() + 1; + } + + uint64_t SymtabStart = LoadCommandSize; + SymtabStart += HeaderSize; + SymtabStart = alignTo(SymtabStart, 0x1000); + + // We gathered all the information we need, start emitting the output file. + Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false); + + // Write the load commands. + assert(OutFile.tell() == HeaderSize); + if (UUIDCmd.cmd != 0) { + Writer.W.write<uint32_t>(UUIDCmd.cmd); + Writer.W.write<uint32_t>(sizeof(UUIDCmd)); + OutFile.write(reinterpret_cast<const char *>(UUIDCmd.uuid), 16); + assert(OutFile.tell() == HeaderSize + sizeof(UUIDCmd)); + } + for (auto Cmd : BuildVersionCmd) { + Writer.W.write<uint32_t>(Cmd.cmd); + Writer.W.write<uint32_t>(sizeof(Cmd)); + Writer.W.write<uint32_t>(Cmd.platform); + Writer.W.write<uint32_t>(Cmd.minos); + Writer.W.write<uint32_t>(Cmd.sdk); + Writer.W.write<uint32_t>(Cmd.ntools); + } + + assert(SymtabCmd.cmd && "No symbol table."); + uint64_t StringStart = SymtabStart + NumSyms * NListSize; + if (ShouldEmitSymtab) + Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart, + NewStringsSize); + uint64_t EHFrameStart = StringStart + NewStringsSize; EHFrameStart = alignTo(EHFrameStart, 0x1000); uint64_t DwarfSegmentStart = EHFrameStart + EHFrameSize; - DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000); - - // Write the load commands for the segments and sections we 'import' from - // the original binary. - uint64_t EndAddress = 0; - uint64_t GapForDwarf = UINT64_MAX; - for (auto &LCI : InputBinary.load_commands()) { - if (LCI.C.cmd == MachO::LC_SEGMENT) + DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000); + + // Write the load commands for the segments and sections we 'import' from + // the original binary. + uint64_t EndAddress = 0; + uint64_t GapForDwarf = UINT64_MAX; + for (auto &LCI : InputBinary.load_commands()) { + if (LCI.C.cmd == MachO::LC_SEGMENT) transferSegmentAndSections( LCI, InputBinary.getSegmentLoadCommand(LCI), InputBinary, Writer, SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart, EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress); - else if (LCI.C.cmd == MachO::LC_SEGMENT_64) + else if (LCI.C.cmd == MachO::LC_SEGMENT_64) transferSegmentAndSections( LCI, InputBinary.getSegment64LoadCommand(LCI), InputBinary, Writer, SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart, EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress); - } - - uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000); - uint64_t DwarfVMMax = Is64Bit ? UINT64_MAX : UINT32_MAX; - if (DwarfVMAddr + DwarfSegmentSize > DwarfVMMax || - DwarfVMAddr + DwarfSegmentSize < DwarfVMAddr /* Overflow */) { - // There is no room for the __DWARF segment at the end of the - // address space. Look through segments to find a gap. - DwarfVMAddr = GapForDwarf; - if (DwarfVMAddr == UINT64_MAX) - warn("not enough VM space for the __DWARF segment.", - "output file streaming"); - } - - // Write the load command for the __DWARF segment. - createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize, - NumDwarfSections, Layout, Writer); - - assert(OutFile.tell() == LoadCommandSize + HeaderSize); - OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize)); - assert(OutFile.tell() == SymtabStart); - - // Transfer symbols. - if (ShouldEmitSymtab) { - OutFile << NewSymtab.str(); - assert(OutFile.tell() == StringStart); - - // Transfer string table. - // FIXME: The NonRelocatableStringpool starts with an empty string, but - // dsymutil-classic starts the reconstructed string table with 2 of these. - // Reproduce that behavior for now (there is corresponding code in - // transferSymbol). - OutFile << '\0'; - std::vector<DwarfStringPoolEntryRef> Strings = - NewStrings.getEntriesForEmission(); - for (auto EntryRef : Strings) { - OutFile.write(EntryRef.getString().data(), - EntryRef.getString().size() + 1); - } - } - assert(OutFile.tell() == StringStart + NewStringsSize); - + } + + uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000); + uint64_t DwarfVMMax = Is64Bit ? UINT64_MAX : UINT32_MAX; + if (DwarfVMAddr + DwarfSegmentSize > DwarfVMMax || + DwarfVMAddr + DwarfSegmentSize < DwarfVMAddr /* Overflow */) { + // There is no room for the __DWARF segment at the end of the + // address space. Look through segments to find a gap. + DwarfVMAddr = GapForDwarf; + if (DwarfVMAddr == UINT64_MAX) + warn("not enough VM space for the __DWARF segment.", + "output file streaming"); + } + + // Write the load command for the __DWARF segment. + createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize, + NumDwarfSections, Layout, Writer); + + assert(OutFile.tell() == LoadCommandSize + HeaderSize); + OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize)); + assert(OutFile.tell() == SymtabStart); + + // Transfer symbols. + if (ShouldEmitSymtab) { + OutFile << NewSymtab.str(); + assert(OutFile.tell() == StringStart); + + // Transfer string table. + // FIXME: The NonRelocatableStringpool starts with an empty string, but + // dsymutil-classic starts the reconstructed string table with 2 of these. + // Reproduce that behavior for now (there is corresponding code in + // transferSymbol). + OutFile << '\0'; + std::vector<DwarfStringPoolEntryRef> Strings = + NewStrings.getEntriesForEmission(); + for (auto EntryRef : Strings) { + OutFile.write(EntryRef.getString().data(), + EntryRef.getString().size() + 1); + } + } + assert(OutFile.tell() == StringStart + NewStringsSize); + // Pad till the EH frame start. OutFile.write_zeros(EHFrameStart - (StringStart + NewStringsSize)); assert(OutFile.tell() == EHFrameStart); @@ -603,22 +603,22 @@ bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, OutFile << EHFrameData; assert(OutFile.tell() == EHFrameStart + EHFrameSize); - // Pad till the Dwarf segment start. + // Pad till the Dwarf segment start. OutFile.write_zeros(DwarfSegmentStart - (EHFrameStart + EHFrameSize)); - assert(OutFile.tell() == DwarfSegmentStart); - - // Emit the Dwarf sections contents. - for (const MCSection &Sec : MCAsm) { - if (Sec.begin() == Sec.end()) - continue; - - uint64_t Pos = OutFile.tell(); - OutFile.write_zeros(alignTo(Pos, Sec.getAlignment()) - Pos); - MCAsm.writeSectionData(OutFile, &Sec, Layout); - } - - return true; -} -} // namespace MachOUtils -} // namespace dsymutil -} // namespace llvm + assert(OutFile.tell() == DwarfSegmentStart); + + // Emit the Dwarf sections contents. + for (const MCSection &Sec : MCAsm) { + if (Sec.begin() == Sec.end()) + continue; + + uint64_t Pos = OutFile.tell(); + OutFile.write_zeros(alignTo(Pos, Sec.getAlignment()) - Pos); + MCAsm.writeSectionData(OutFile, &Sec, Layout); + } + + return true; +} +} // namespace MachOUtils +} // namespace dsymutil +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h index b1cdd44d38..109da802b0 100644 --- a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h +++ b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h @@ -1,52 +1,52 @@ -//===-- MachOUtils.h - Mach-o specific helpers for dsymutil --------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H -#define LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H - -#include "SymbolMap.h" - -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/VirtualFileSystem.h" - -#include <string> - -namespace llvm { -class MCStreamer; -class raw_fd_ostream; -namespace dsymutil { -class DebugMap; -struct LinkOptions; -namespace MachOUtils { - -struct ArchAndFile { - std::string Arch; - std::unique_ptr<llvm::sys::fs::TempFile> File; - - llvm::Error createTempFile(); - llvm::StringRef path() const; - - ArchAndFile(StringRef Arch) : Arch(std::string(Arch)) {} - ArchAndFile(ArchAndFile &&A) = default; - ArchAndFile &operator=(ArchAndFile &&A) = default; - ~ArchAndFile(); -}; - -bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles, - StringRef OutputFileName, const LinkOptions &, - StringRef SDKPath); - -bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const DebugMap &DM, SymbolMapTranslator &Translator, - MCStreamer &MS, raw_fd_ostream &OutFile); - -std::string getArchName(StringRef Arch); -} // namespace MachOUtils -} // namespace dsymutil -} // namespace llvm -#endif // LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H +//===-- MachOUtils.h - Mach-o specific helpers for dsymutil --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H +#define LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H + +#include "SymbolMap.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/VirtualFileSystem.h" + +#include <string> + +namespace llvm { +class MCStreamer; +class raw_fd_ostream; +namespace dsymutil { +class DebugMap; +struct LinkOptions; +namespace MachOUtils { + +struct ArchAndFile { + std::string Arch; + std::unique_ptr<llvm::sys::fs::TempFile> File; + + llvm::Error createTempFile(); + llvm::StringRef path() const; + + ArchAndFile(StringRef Arch) : Arch(std::string(Arch)) {} + ArchAndFile(ArchAndFile &&A) = default; + ArchAndFile &operator=(ArchAndFile &&A) = default; + ~ArchAndFile(); +}; + +bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles, + StringRef OutputFileName, const LinkOptions &, + StringRef SDKPath); + +bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + const DebugMap &DM, SymbolMapTranslator &Translator, + MCStreamer &MS, raw_fd_ostream &OutFile); + +std::string getArchName(StringRef Arch); +} // namespace MachOUtils +} // namespace dsymutil +} // namespace llvm +#endif // LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H diff --git a/contrib/libs/llvm12/tools/dsymutil/Options.td b/contrib/libs/llvm12/tools/dsymutil/Options.td index 7bd21b0d43..f704467115 100644 --- a/contrib/libs/llvm12/tools/dsymutil/Options.td +++ b/contrib/libs/llvm12/tools/dsymutil/Options.td @@ -1,187 +1,187 @@ -include "llvm/Option/OptParser.td" - -class F<string name>: Flag<["--", "-"], name>; - -def grp_general : OptionGroup<"Dsymutil">, HelpText<"Dsymutil Options">; - -def help: F<"help">, - HelpText<"Prints this help output.">, - Group<grp_general>; -def: Flag<["-"], "h">, - Alias<help>, - HelpText<"Alias for --help">, - Group<grp_general>; - -def version: F<"version">, - HelpText<"Prints the dsymutil version.">, - Group<grp_general>; -def: Flag<["-"], "v">, - Alias<version>, - HelpText<"Alias for --version">, - Group<grp_general>; - -def verbose: F<"verbose">, - HelpText<"Enable verbose mode.">, - Group<grp_general>; - -def statistics: F<"statistics">, - HelpText<"Print statistics about the contribution of each object file to " - "the linked debug info. This prints a table after linking with the " - "object file name, the size of the debug info in the object file " - "(in bytes) and the size contributed (in bytes) to the linked dSYM. " - "The table is sorted by the output size listing the object files " - "with the largest contribution first.">, - Group<grp_general>; - -def verify: F<"verify">, - HelpText<"Run the DWARF verifier on the linked DWARF debug info.">, - Group<grp_general>; - -def no_output: F<"no-output">, - HelpText<"Do the link in memory, but do not emit the result file.">, - Group<grp_general>; - -def no_swiftmodule_timestamp: F<"no-swiftmodule-timestamp">, - HelpText<"Don't check timestamp for swiftmodule files.">, - Group<grp_general>; - -def no_odr: F<"no-odr">, - HelpText<"Do not use ODR (One Definition Rule) for type uniquing.">, - Group<grp_general>; - -def dump_debug_map: F<"dump-debug-map">, - HelpText<"Parse and dump the debug map to standard output. Not DWARF link will take place.">, - Group<grp_general>; - -def yaml_input: Flag<["-", "--"], "y">, - HelpText<"Treat the input file is a YAML debug map rather than a binary.">, - Group<grp_general>; - -def papertrail: F<"papertrail">, - HelpText<"Embed warnings in the linked DWARF debug info.">, - Group<grp_general>; - -def assembly: Flag<["-", "--"], "S">, - HelpText<"Output textual assembly instead of a binary dSYM companion file.">, - Group<grp_general>; - -def symtab: F<"symtab">, - HelpText<"Dumps the symbol table found in executable or object file(s) and exits.">, - Group<grp_general>; -def: Flag<["-"], "s">, - Alias<symtab>, - HelpText<"Alias for --symtab">, - Group<grp_general>; - -def flat: F<"flat">, - HelpText<"Produce a flat dSYM file (not a bundle).">, - Group<grp_general>; -def: Flag<["-"], "f">, - Alias<flat>, - HelpText<"Alias for --flat">, - Group<grp_general>; - -def minimize: F<"minimize">, - HelpText<"When used when creating a dSYM file with Apple accelerator tables, " - "this option will suppress the emission of the .debug_inlines, " - ".debug_pubnames, and .debug_pubtypes sections since dsymutil " - "has better equivalents: .apple_names and .apple_types. When used in " - "conjunction with --update option, this option will cause redundant " - "accelerator tables to be removed.">, - Group<grp_general>; -def: Flag<["-"], "z">, - Alias<minimize>, - HelpText<"Alias for --minimize">, - Group<grp_general>; - -def update: F<"update">, - HelpText<"Updates existing dSYM files to contain the latest accelerator tables and other DWARF optimizations.">, - Group<grp_general>; -def: Flag<["-"], "u">, - Alias<update>, - HelpText<"Alias for --update">, - Group<grp_general>; - -def output: Separate<["-", "--"], "o">, - MetaVarName<"<filename>">, - HelpText<"Specify the output file. Defaults to <input file>.dwarf">, - Group<grp_general>; -def: Separate<["--", "-"], "out">, - MetaVarName<"<filename>">, - Alias<output>, - HelpText<"Alias for -o">, - Group<grp_general>; -def: Joined<["--", "-"], "out=">, Alias<output>; -def: Joined<["-", "--"], "o=">, Alias<output>; - -def oso_prepend_path: Separate<["--", "-"], "oso-prepend-path">, - MetaVarName<"<path>">, - HelpText<"Specify a directory to prepend to the paths of object files.">, - Group<grp_general>; -def: Joined<["--", "-"], "oso-prepend-path=">, Alias<oso_prepend_path>; - -def object_prefix_map: Separate<["--", "-"], "object-prefix-map">, - MetaVarName<"<prefix=remapped>">, - HelpText<"Remap object file paths (but no source paths) before processing." - "Use this for Clang objects where the module cache location was" - "remapped using -fdebug-prefix-map; to help dsymutil" - "find the Clang module cache.">, - Group<grp_general>; -def: Joined<["--", "-"], "object-prefix-map=">, Alias<object_prefix_map>; - -def symbolmap: Separate<["--", "-"], "symbol-map">, - MetaVarName<"<bcsymbolmap>">, - HelpText<"Updates the existing dSYMs inplace using symbol map specified.">, - Group<grp_general>; -def: Joined<["--", "-"], "symbol-map=">, Alias<symbolmap>; - -def arch: Separate<["--", "-"], "arch">, - MetaVarName<"<arch>">, - HelpText<"Link DWARF debug information only for specified CPU architecture" - "types. This option can be specified multiple times, once for each" - "desired architecture. All CPU architectures will be linked by" - "default.">, - Group<grp_general>; -def: Joined<["--", "-"], "arch=">, Alias<arch>; - -def accelerator: Separate<["--", "-"], "accelerator">, - MetaVarName<"<accelerator type>">, - HelpText<"Specify the desired type of accelerator table. Valid options are 'Apple', 'Dwarf' and 'Default'">, - Group<grp_general>; -def: Joined<["--", "-"], "accelerator=">, Alias<accelerator>; - -def toolchain: Separate<["--", "-"], "toolchain">, - MetaVarName<"<toolchain>">, - HelpText<"Embed toolchain information in dSYM bundle.">, - Group<grp_general>; - -def threads: Separate<["--", "-"], "num-threads">, - MetaVarName<"<threads>">, - HelpText<"Specifies the maximum number of simultaneous threads to use when linking multiple architectures.">, - Group<grp_general>; -def: Separate<["-"], "j">, - MetaVarName<"<threads>">, - HelpText<"Alias for --num-threads">, - Group<grp_general>; - -def gen_reproducer: F<"gen-reproducer">, - HelpText<"Generate a reproducer consisting of the input object files.">, - Group<grp_general>; - -def use_reproducer: Separate<["--", "-"], "use-reproducer">, - MetaVarName<"<path>">, - HelpText<"Use the object files from the given reproducer path.">, - Group<grp_general>; -def: Joined<["--", "-"], "use-reproducer=">, Alias<use_reproducer>; - -def remarks_prepend_path: Separate<["--", "-"], "remarks-prepend-path">, - MetaVarName<"<path>">, - HelpText<"Specify a directory to prepend to the paths of the external remark files.">, - Group<grp_general>; -def: Joined<["--", "-"], "remarks-prepend-path=">, Alias<remarks_prepend_path>; - -def remarks_output_format: Separate<["--", "-"], "remarks-output-format">, - MetaVarName<"<format>">, - HelpText<"Specify the format to be used when serializing the linked remarks.">, - Group<grp_general>; -def: Joined<["--", "-"], "remarks-output-format=">, Alias<remarks_output_format>; +include "llvm/Option/OptParser.td" + +class F<string name>: Flag<["--", "-"], name>; + +def grp_general : OptionGroup<"Dsymutil">, HelpText<"Dsymutil Options">; + +def help: F<"help">, + HelpText<"Prints this help output.">, + Group<grp_general>; +def: Flag<["-"], "h">, + Alias<help>, + HelpText<"Alias for --help">, + Group<grp_general>; + +def version: F<"version">, + HelpText<"Prints the dsymutil version.">, + Group<grp_general>; +def: Flag<["-"], "v">, + Alias<version>, + HelpText<"Alias for --version">, + Group<grp_general>; + +def verbose: F<"verbose">, + HelpText<"Enable verbose mode.">, + Group<grp_general>; + +def statistics: F<"statistics">, + HelpText<"Print statistics about the contribution of each object file to " + "the linked debug info. This prints a table after linking with the " + "object file name, the size of the debug info in the object file " + "(in bytes) and the size contributed (in bytes) to the linked dSYM. " + "The table is sorted by the output size listing the object files " + "with the largest contribution first.">, + Group<grp_general>; + +def verify: F<"verify">, + HelpText<"Run the DWARF verifier on the linked DWARF debug info.">, + Group<grp_general>; + +def no_output: F<"no-output">, + HelpText<"Do the link in memory, but do not emit the result file.">, + Group<grp_general>; + +def no_swiftmodule_timestamp: F<"no-swiftmodule-timestamp">, + HelpText<"Don't check timestamp for swiftmodule files.">, + Group<grp_general>; + +def no_odr: F<"no-odr">, + HelpText<"Do not use ODR (One Definition Rule) for type uniquing.">, + Group<grp_general>; + +def dump_debug_map: F<"dump-debug-map">, + HelpText<"Parse and dump the debug map to standard output. Not DWARF link will take place.">, + Group<grp_general>; + +def yaml_input: Flag<["-", "--"], "y">, + HelpText<"Treat the input file is a YAML debug map rather than a binary.">, + Group<grp_general>; + +def papertrail: F<"papertrail">, + HelpText<"Embed warnings in the linked DWARF debug info.">, + Group<grp_general>; + +def assembly: Flag<["-", "--"], "S">, + HelpText<"Output textual assembly instead of a binary dSYM companion file.">, + Group<grp_general>; + +def symtab: F<"symtab">, + HelpText<"Dumps the symbol table found in executable or object file(s) and exits.">, + Group<grp_general>; +def: Flag<["-"], "s">, + Alias<symtab>, + HelpText<"Alias for --symtab">, + Group<grp_general>; + +def flat: F<"flat">, + HelpText<"Produce a flat dSYM file (not a bundle).">, + Group<grp_general>; +def: Flag<["-"], "f">, + Alias<flat>, + HelpText<"Alias for --flat">, + Group<grp_general>; + +def minimize: F<"minimize">, + HelpText<"When used when creating a dSYM file with Apple accelerator tables, " + "this option will suppress the emission of the .debug_inlines, " + ".debug_pubnames, and .debug_pubtypes sections since dsymutil " + "has better equivalents: .apple_names and .apple_types. When used in " + "conjunction with --update option, this option will cause redundant " + "accelerator tables to be removed.">, + Group<grp_general>; +def: Flag<["-"], "z">, + Alias<minimize>, + HelpText<"Alias for --minimize">, + Group<grp_general>; + +def update: F<"update">, + HelpText<"Updates existing dSYM files to contain the latest accelerator tables and other DWARF optimizations.">, + Group<grp_general>; +def: Flag<["-"], "u">, + Alias<update>, + HelpText<"Alias for --update">, + Group<grp_general>; + +def output: Separate<["-", "--"], "o">, + MetaVarName<"<filename>">, + HelpText<"Specify the output file. Defaults to <input file>.dwarf">, + Group<grp_general>; +def: Separate<["--", "-"], "out">, + MetaVarName<"<filename>">, + Alias<output>, + HelpText<"Alias for -o">, + Group<grp_general>; +def: Joined<["--", "-"], "out=">, Alias<output>; +def: Joined<["-", "--"], "o=">, Alias<output>; + +def oso_prepend_path: Separate<["--", "-"], "oso-prepend-path">, + MetaVarName<"<path>">, + HelpText<"Specify a directory to prepend to the paths of object files.">, + Group<grp_general>; +def: Joined<["--", "-"], "oso-prepend-path=">, Alias<oso_prepend_path>; + +def object_prefix_map: Separate<["--", "-"], "object-prefix-map">, + MetaVarName<"<prefix=remapped>">, + HelpText<"Remap object file paths (but no source paths) before processing." + "Use this for Clang objects where the module cache location was" + "remapped using -fdebug-prefix-map; to help dsymutil" + "find the Clang module cache.">, + Group<grp_general>; +def: Joined<["--", "-"], "object-prefix-map=">, Alias<object_prefix_map>; + +def symbolmap: Separate<["--", "-"], "symbol-map">, + MetaVarName<"<bcsymbolmap>">, + HelpText<"Updates the existing dSYMs inplace using symbol map specified.">, + Group<grp_general>; +def: Joined<["--", "-"], "symbol-map=">, Alias<symbolmap>; + +def arch: Separate<["--", "-"], "arch">, + MetaVarName<"<arch>">, + HelpText<"Link DWARF debug information only for specified CPU architecture" + "types. This option can be specified multiple times, once for each" + "desired architecture. All CPU architectures will be linked by" + "default.">, + Group<grp_general>; +def: Joined<["--", "-"], "arch=">, Alias<arch>; + +def accelerator: Separate<["--", "-"], "accelerator">, + MetaVarName<"<accelerator type>">, + HelpText<"Specify the desired type of accelerator table. Valid options are 'Apple', 'Dwarf' and 'Default'">, + Group<grp_general>; +def: Joined<["--", "-"], "accelerator=">, Alias<accelerator>; + +def toolchain: Separate<["--", "-"], "toolchain">, + MetaVarName<"<toolchain>">, + HelpText<"Embed toolchain information in dSYM bundle.">, + Group<grp_general>; + +def threads: Separate<["--", "-"], "num-threads">, + MetaVarName<"<threads>">, + HelpText<"Specifies the maximum number of simultaneous threads to use when linking multiple architectures.">, + Group<grp_general>; +def: Separate<["-"], "j">, + MetaVarName<"<threads>">, + HelpText<"Alias for --num-threads">, + Group<grp_general>; + +def gen_reproducer: F<"gen-reproducer">, + HelpText<"Generate a reproducer consisting of the input object files.">, + Group<grp_general>; + +def use_reproducer: Separate<["--", "-"], "use-reproducer">, + MetaVarName<"<path>">, + HelpText<"Use the object files from the given reproducer path.">, + Group<grp_general>; +def: Joined<["--", "-"], "use-reproducer=">, Alias<use_reproducer>; + +def remarks_prepend_path: Separate<["--", "-"], "remarks-prepend-path">, + MetaVarName<"<path>">, + HelpText<"Specify a directory to prepend to the paths of the external remark files.">, + Group<grp_general>; +def: Joined<["--", "-"], "remarks-prepend-path=">, Alias<remarks_prepend_path>; + +def remarks_output_format: Separate<["--", "-"], "remarks-output-format">, + MetaVarName<"<format>">, + HelpText<"Specify the format to be used when serializing the linked remarks.">, + Group<grp_general>; +def: Joined<["--", "-"], "remarks-output-format=">, Alias<remarks_output_format>; diff --git a/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp b/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp index 5c60758c6f..d064086b0f 100644 --- a/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp +++ b/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp @@ -1,85 +1,85 @@ -//===- Reproducer.cpp -----------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Reproducer.h" -#include "llvm/Support/Path.h" - -using namespace llvm; -using namespace llvm::dsymutil; - -static std::string createReproducerDir(std::error_code &EC) { - SmallString<128> Root; - if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) { - Root.assign(Path); - EC = sys::fs::create_directory(Root); - } else { - EC = sys::fs::createUniqueDirectory("dsymutil", Root); - } - return EC ? "" : std::string(Root); -} - -Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {} -Reproducer::~Reproducer() = default; - -ReproducerGenerate::ReproducerGenerate(std::error_code &EC) - : Root(createReproducerDir(EC)), FC() { - if (!Root.empty()) - FC = std::make_shared<FileCollector>(Root, Root); - VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), FC); -} - -ReproducerGenerate::~ReproducerGenerate() { - if (!FC) - return; - FC->copyFiles(false); - SmallString<128> Mapping(Root); - sys::path::append(Mapping, "mapping.yaml"); - FC->writeMapping(Mapping.str()); - outs() << "reproducer written to " << Root << '\n'; -} - -ReproducerUse::~ReproducerUse() = default; - -ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) { - SmallString<128> Mapping(Root); - sys::path::append(Mapping, "mapping.yaml"); - ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = - vfs::getRealFileSystem()->getBufferForFile(Mapping.str()); - - if (!Buffer) { - EC = Buffer.getError(); - return; - } - - VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping); -} - -llvm::Expected<std::unique_ptr<Reproducer>> -Reproducer::createReproducer(ReproducerMode Mode, StringRef Root) { - switch (Mode) { - case ReproducerMode::Generate: { - std::error_code EC; - std::unique_ptr<Reproducer> Repro = - std::make_unique<ReproducerGenerate>(EC); - if (EC) - return errorCodeToError(EC); - return std::move(Repro); - } - case ReproducerMode::Use: { - std::error_code EC; - std::unique_ptr<Reproducer> Repro = - std::make_unique<ReproducerUse>(Root, EC); - if (EC) - return errorCodeToError(EC); - return std::move(Repro); - } - case ReproducerMode::Off: - return std::make_unique<Reproducer>(); - } - llvm_unreachable("All cases handled above."); -} +//===- Reproducer.cpp -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Reproducer.h" +#include "llvm/Support/Path.h" + +using namespace llvm; +using namespace llvm::dsymutil; + +static std::string createReproducerDir(std::error_code &EC) { + SmallString<128> Root; + if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) { + Root.assign(Path); + EC = sys::fs::create_directory(Root); + } else { + EC = sys::fs::createUniqueDirectory("dsymutil", Root); + } + return EC ? "" : std::string(Root); +} + +Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {} +Reproducer::~Reproducer() = default; + +ReproducerGenerate::ReproducerGenerate(std::error_code &EC) + : Root(createReproducerDir(EC)), FC() { + if (!Root.empty()) + FC = std::make_shared<FileCollector>(Root, Root); + VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), FC); +} + +ReproducerGenerate::~ReproducerGenerate() { + if (!FC) + return; + FC->copyFiles(false); + SmallString<128> Mapping(Root); + sys::path::append(Mapping, "mapping.yaml"); + FC->writeMapping(Mapping.str()); + outs() << "reproducer written to " << Root << '\n'; +} + +ReproducerUse::~ReproducerUse() = default; + +ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) { + SmallString<128> Mapping(Root); + sys::path::append(Mapping, "mapping.yaml"); + ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = + vfs::getRealFileSystem()->getBufferForFile(Mapping.str()); + + if (!Buffer) { + EC = Buffer.getError(); + return; + } + + VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping); +} + +llvm::Expected<std::unique_ptr<Reproducer>> +Reproducer::createReproducer(ReproducerMode Mode, StringRef Root) { + switch (Mode) { + case ReproducerMode::Generate: { + std::error_code EC; + std::unique_ptr<Reproducer> Repro = + std::make_unique<ReproducerGenerate>(EC); + if (EC) + return errorCodeToError(EC); + return std::move(Repro); + } + case ReproducerMode::Use: { + std::error_code EC; + std::unique_ptr<Reproducer> Repro = + std::make_unique<ReproducerUse>(Root, EC); + if (EC) + return errorCodeToError(EC); + return std::move(Repro); + } + case ReproducerMode::Off: + return std::make_unique<Reproducer>(); + } + llvm_unreachable("All cases handled above."); +} diff --git a/contrib/libs/llvm12/tools/dsymutil/Reproducer.h b/contrib/libs/llvm12/tools/dsymutil/Reproducer.h index e965e1ceda..8b3adf63f3 100644 --- a/contrib/libs/llvm12/tools/dsymutil/Reproducer.h +++ b/contrib/libs/llvm12/tools/dsymutil/Reproducer.h @@ -1,77 +1,77 @@ -//===- tools/dsymutil/Reproducer.h ------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_DSYMUTIL_REPRODUCER_H -#define LLVM_TOOLS_DSYMUTIL_REPRODUCER_H - -#include "llvm/Support/Error.h" -#include "llvm/Support/FileCollector.h" -#include "llvm/Support/VirtualFileSystem.h" - -namespace llvm { -namespace dsymutil { - -/// The reproducer mode. -enum class ReproducerMode { - Generate, - Use, - Off, -}; - -/// The reproducer class manages the sate related to reproducers in dsymutil. -/// Instances should be created with Reproducer::createReproducer. An instance -/// of this class is returned when reproducers are off. The VFS returned by -/// this instance is the real file system. -class Reproducer { -public: - Reproducer(); - virtual ~Reproducer(); - - IntrusiveRefCntPtr<vfs::FileSystem> getVFS() const { return VFS; } - - /// Create a Reproducer instance based on the given mode. - static llvm::Expected<std::unique_ptr<Reproducer>> - createReproducer(ReproducerMode Mode, StringRef Root); - -protected: - IntrusiveRefCntPtr<vfs::FileSystem> VFS; -}; - -/// Reproducer instance used to generate a new reproducer. The VFS returned by -/// this instance is a FileCollectorFileSystem that tracks every file used by -/// dsymutil. -class ReproducerGenerate : public Reproducer { -public: - ReproducerGenerate(std::error_code &EC); - ~ReproducerGenerate() override; - -private: - /// The path to the reproducer. - std::string Root; - - /// The FileCollector used by the FileCollectorFileSystem. - std::shared_ptr<FileCollector> FC; -}; - -/// Reproducer instance used to use an existing reproducer. The VFS returned by -/// this instance is a RedirectingFileSystem that remaps paths to their -/// counterpart in the reproducer. -class ReproducerUse : public Reproducer { -public: - ReproducerUse(StringRef Root, std::error_code &EC); - ~ReproducerUse() override; - -private: - /// The path to the reproducer. - std::string Root; -}; - -} // end namespace dsymutil -} // end namespace llvm - -#endif // LLVM_TOOLS_DSYMUTIL_REPRODUCER_H +//===- tools/dsymutil/Reproducer.h ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_DSYMUTIL_REPRODUCER_H +#define LLVM_TOOLS_DSYMUTIL_REPRODUCER_H + +#include "llvm/Support/Error.h" +#include "llvm/Support/FileCollector.h" +#include "llvm/Support/VirtualFileSystem.h" + +namespace llvm { +namespace dsymutil { + +/// The reproducer mode. +enum class ReproducerMode { + Generate, + Use, + Off, +}; + +/// The reproducer class manages the sate related to reproducers in dsymutil. +/// Instances should be created with Reproducer::createReproducer. An instance +/// of this class is returned when reproducers are off. The VFS returned by +/// this instance is the real file system. +class Reproducer { +public: + Reproducer(); + virtual ~Reproducer(); + + IntrusiveRefCntPtr<vfs::FileSystem> getVFS() const { return VFS; } + + /// Create a Reproducer instance based on the given mode. + static llvm::Expected<std::unique_ptr<Reproducer>> + createReproducer(ReproducerMode Mode, StringRef Root); + +protected: + IntrusiveRefCntPtr<vfs::FileSystem> VFS; +}; + +/// Reproducer instance used to generate a new reproducer. The VFS returned by +/// this instance is a FileCollectorFileSystem that tracks every file used by +/// dsymutil. +class ReproducerGenerate : public Reproducer { +public: + ReproducerGenerate(std::error_code &EC); + ~ReproducerGenerate() override; + +private: + /// The path to the reproducer. + std::string Root; + + /// The FileCollector used by the FileCollectorFileSystem. + std::shared_ptr<FileCollector> FC; +}; + +/// Reproducer instance used to use an existing reproducer. The VFS returned by +/// this instance is a RedirectingFileSystem that remaps paths to their +/// counterpart in the reproducer. +class ReproducerUse : public Reproducer { +public: + ReproducerUse(StringRef Root, std::error_code &EC); + ~ReproducerUse() override; + +private: + /// The path to the reproducer. + std::string Root; +}; + +} // end namespace dsymutil +} // end namespace llvm + +#endif // LLVM_TOOLS_DSYMUTIL_REPRODUCER_H diff --git a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp index 07a54795a8..ed0c70888d 100644 --- a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp +++ b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp @@ -1,161 +1,161 @@ -//===- tools/dsymutil/SymbolMap.cpp ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "SymbolMap.h" -#include "DebugMap.h" -#include "MachOUtils.h" - -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/WithColor.h" - -#ifdef __APPLE__ -#include <CoreFoundation/CoreFoundation.h> -#include <uuid/uuid.h> -#endif - -namespace llvm { -namespace dsymutil { - -StringRef SymbolMapTranslator::operator()(StringRef Input) { - if (!Input.startswith("__hidden#") && !Input.startswith("___hidden#")) - return Input; - - bool MightNeedUnderscore = false; - StringRef Line = Input.drop_front(sizeof("__hidden#") - 1); - if (Line[0] == '#') { - Line = Line.drop_front(); - MightNeedUnderscore = true; - } - - std::size_t LineNumber = std::numeric_limits<std::size_t>::max(); - Line.split('_').first.getAsInteger(10, LineNumber); - if (LineNumber >= UnobfuscatedStrings.size()) { - WithColor::warning() << "reference to a unexisting unobfuscated string " - << Input << ": symbol map mismatch?\n" - << Line << '\n'; - return Input; - } - - const std::string &Translation = UnobfuscatedStrings[LineNumber]; - if (!MightNeedUnderscore || !MangleNames) - return Translation; - - // Objective-C symbols for the MachO symbol table start with a \1. Please see +//===- tools/dsymutil/SymbolMap.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SymbolMap.h" +#include "DebugMap.h" +#include "MachOUtils.h" + +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/WithColor.h" + +#ifdef __APPLE__ +#include <CoreFoundation/CoreFoundation.h> +#include <uuid/uuid.h> +#endif + +namespace llvm { +namespace dsymutil { + +StringRef SymbolMapTranslator::operator()(StringRef Input) { + if (!Input.startswith("__hidden#") && !Input.startswith("___hidden#")) + return Input; + + bool MightNeedUnderscore = false; + StringRef Line = Input.drop_front(sizeof("__hidden#") - 1); + if (Line[0] == '#') { + Line = Line.drop_front(); + MightNeedUnderscore = true; + } + + std::size_t LineNumber = std::numeric_limits<std::size_t>::max(); + Line.split('_').first.getAsInteger(10, LineNumber); + if (LineNumber >= UnobfuscatedStrings.size()) { + WithColor::warning() << "reference to a unexisting unobfuscated string " + << Input << ": symbol map mismatch?\n" + << Line << '\n'; + return Input; + } + + const std::string &Translation = UnobfuscatedStrings[LineNumber]; + if (!MightNeedUnderscore || !MangleNames) + return Translation; + + // Objective-C symbols for the MachO symbol table start with a \1. Please see // `MangleContext::mangleObjCMethodName` in clang. - if (Translation[0] == 1) - return StringRef(Translation).drop_front(); - - // We need permanent storage for the string we are about to create. Just - // append it to the vector containing translations. This should only happen - // during MachO symbol table translation, thus there should be no risk on - // exponential growth. - UnobfuscatedStrings.emplace_back("_" + Translation); - return UnobfuscatedStrings.back(); -} - -SymbolMapTranslator SymbolMapLoader::Load(StringRef InputFile, - const DebugMap &Map) const { - if (SymbolMap.empty()) - return {}; - - std::string SymbolMapPath = SymbolMap; - -#if __APPLE__ - // Look through the UUID Map. - if (sys::fs::is_directory(SymbolMapPath) && !Map.getUUID().empty()) { - uuid_string_t UUIDString; - uuid_unparse_upper((const uint8_t *)Map.getUUID().data(), UUIDString); - - SmallString<256> PlistPath( - sys::path::parent_path(sys::path::parent_path(InputFile))); - sys::path::append(PlistPath, StringRef(UUIDString).str() + ".plist"); - - CFStringRef plistFile = CFStringCreateWithCString( - kCFAllocatorDefault, PlistPath.c_str(), kCFStringEncodingUTF8); - CFURLRef fileURL = CFURLCreateWithFileSystemPath( - kCFAllocatorDefault, plistFile, kCFURLPOSIXPathStyle, false); - CFReadStreamRef resourceData = - CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL); - if (resourceData) { - CFReadStreamOpen(resourceData); - CFDictionaryRef plist = (CFDictionaryRef)CFPropertyListCreateWithStream( - kCFAllocatorDefault, resourceData, 0, kCFPropertyListImmutable, - nullptr, nullptr); - - if (plist) { - if (CFDictionaryContainsKey(plist, CFSTR("DBGOriginalUUID"))) { - CFStringRef OldUUID = (CFStringRef)CFDictionaryGetValue( - plist, CFSTR("DBGOriginalUUID")); - - StringRef UUID(CFStringGetCStringPtr(OldUUID, kCFStringEncodingUTF8)); - SmallString<256> BCSymbolMapPath(SymbolMapPath); - sys::path::append(BCSymbolMapPath, UUID.str() + ".bcsymbolmap"); - SymbolMapPath = std::string(BCSymbolMapPath); - } - CFRelease(plist); - } - CFReadStreamClose(resourceData); - CFRelease(resourceData); - } - CFRelease(fileURL); - CFRelease(plistFile); - } -#endif - - if (sys::fs::is_directory(SymbolMapPath)) { - SymbolMapPath += (Twine("/") + sys::path::filename(InputFile) + "-" + - MachOUtils::getArchName(Map.getTriple().getArchName()) + - ".bcsymbolmap") - .str(); - } - - auto ErrOrMemBuffer = MemoryBuffer::getFile(SymbolMapPath); - if (auto EC = ErrOrMemBuffer.getError()) { - WithColor::warning() << SymbolMapPath << ": " << EC.message() - << ": not unobfuscating.\n"; - return {}; - } - - std::vector<std::string> UnobfuscatedStrings; - auto &MemBuf = **ErrOrMemBuffer; - StringRef Data(MemBuf.getBufferStart(), - MemBuf.getBufferEnd() - MemBuf.getBufferStart()); - StringRef LHS; - std::tie(LHS, Data) = Data.split('\n'); - bool MangleNames = false; - - // Check version string first. - if (!LHS.startswith("BCSymbolMap Version:")) { - // Version string not present, warns but try to parse it. - WithColor::warning() << SymbolMapPath - << " is missing version string: assuming 1.0.\n"; - UnobfuscatedStrings.emplace_back(LHS); - } else if (LHS.equals("BCSymbolMap Version: 1.0")) { - MangleNames = true; - } else if (LHS.equals("BCSymbolMap Version: 2.0")) { - MangleNames = false; - } else { - StringRef VersionNum; - std::tie(LHS, VersionNum) = LHS.split(':'); - WithColor::warning() << SymbolMapPath - << " has unsupported symbol map version" << VersionNum - << ": not unobfuscating.\n"; - return {}; - } - - while (!Data.empty()) { - std::tie(LHS, Data) = Data.split('\n'); - UnobfuscatedStrings.emplace_back(LHS); - } - - return SymbolMapTranslator(std::move(UnobfuscatedStrings), MangleNames); -} - -} // namespace dsymutil -} // namespace llvm + if (Translation[0] == 1) + return StringRef(Translation).drop_front(); + + // We need permanent storage for the string we are about to create. Just + // append it to the vector containing translations. This should only happen + // during MachO symbol table translation, thus there should be no risk on + // exponential growth. + UnobfuscatedStrings.emplace_back("_" + Translation); + return UnobfuscatedStrings.back(); +} + +SymbolMapTranslator SymbolMapLoader::Load(StringRef InputFile, + const DebugMap &Map) const { + if (SymbolMap.empty()) + return {}; + + std::string SymbolMapPath = SymbolMap; + +#if __APPLE__ + // Look through the UUID Map. + if (sys::fs::is_directory(SymbolMapPath) && !Map.getUUID().empty()) { + uuid_string_t UUIDString; + uuid_unparse_upper((const uint8_t *)Map.getUUID().data(), UUIDString); + + SmallString<256> PlistPath( + sys::path::parent_path(sys::path::parent_path(InputFile))); + sys::path::append(PlistPath, StringRef(UUIDString).str() + ".plist"); + + CFStringRef plistFile = CFStringCreateWithCString( + kCFAllocatorDefault, PlistPath.c_str(), kCFStringEncodingUTF8); + CFURLRef fileURL = CFURLCreateWithFileSystemPath( + kCFAllocatorDefault, plistFile, kCFURLPOSIXPathStyle, false); + CFReadStreamRef resourceData = + CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL); + if (resourceData) { + CFReadStreamOpen(resourceData); + CFDictionaryRef plist = (CFDictionaryRef)CFPropertyListCreateWithStream( + kCFAllocatorDefault, resourceData, 0, kCFPropertyListImmutable, + nullptr, nullptr); + + if (plist) { + if (CFDictionaryContainsKey(plist, CFSTR("DBGOriginalUUID"))) { + CFStringRef OldUUID = (CFStringRef)CFDictionaryGetValue( + plist, CFSTR("DBGOriginalUUID")); + + StringRef UUID(CFStringGetCStringPtr(OldUUID, kCFStringEncodingUTF8)); + SmallString<256> BCSymbolMapPath(SymbolMapPath); + sys::path::append(BCSymbolMapPath, UUID.str() + ".bcsymbolmap"); + SymbolMapPath = std::string(BCSymbolMapPath); + } + CFRelease(plist); + } + CFReadStreamClose(resourceData); + CFRelease(resourceData); + } + CFRelease(fileURL); + CFRelease(plistFile); + } +#endif + + if (sys::fs::is_directory(SymbolMapPath)) { + SymbolMapPath += (Twine("/") + sys::path::filename(InputFile) + "-" + + MachOUtils::getArchName(Map.getTriple().getArchName()) + + ".bcsymbolmap") + .str(); + } + + auto ErrOrMemBuffer = MemoryBuffer::getFile(SymbolMapPath); + if (auto EC = ErrOrMemBuffer.getError()) { + WithColor::warning() << SymbolMapPath << ": " << EC.message() + << ": not unobfuscating.\n"; + return {}; + } + + std::vector<std::string> UnobfuscatedStrings; + auto &MemBuf = **ErrOrMemBuffer; + StringRef Data(MemBuf.getBufferStart(), + MemBuf.getBufferEnd() - MemBuf.getBufferStart()); + StringRef LHS; + std::tie(LHS, Data) = Data.split('\n'); + bool MangleNames = false; + + // Check version string first. + if (!LHS.startswith("BCSymbolMap Version:")) { + // Version string not present, warns but try to parse it. + WithColor::warning() << SymbolMapPath + << " is missing version string: assuming 1.0.\n"; + UnobfuscatedStrings.emplace_back(LHS); + } else if (LHS.equals("BCSymbolMap Version: 1.0")) { + MangleNames = true; + } else if (LHS.equals("BCSymbolMap Version: 2.0")) { + MangleNames = false; + } else { + StringRef VersionNum; + std::tie(LHS, VersionNum) = LHS.split(':'); + WithColor::warning() << SymbolMapPath + << " has unsupported symbol map version" << VersionNum + << ": not unobfuscating.\n"; + return {}; + } + + while (!Data.empty()) { + std::tie(LHS, Data) = Data.split('\n'); + UnobfuscatedStrings.emplace_back(LHS); + } + + return SymbolMapTranslator(std::move(UnobfuscatedStrings), MangleNames); +} + +} // namespace dsymutil +} // namespace llvm diff --git a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h index 977de31a5a..636a6126b7 100644 --- a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h +++ b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h @@ -1,53 +1,53 @@ -//=- tools/dsymutil/SymbolMap.h -----------------------------------*- C++ -*-=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H -#define LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H - -#include "llvm/ADT/StringRef.h" - -#include <string> -#include <vector> - -namespace llvm { -namespace dsymutil { -class DebugMap; - -/// Callable class to unobfuscate strings based on a BCSymbolMap. -class SymbolMapTranslator { -public: - SymbolMapTranslator() : MangleNames(false) {} - - SymbolMapTranslator(std::vector<std::string> UnobfuscatedStrings, - bool MangleNames) - : UnobfuscatedStrings(std::move(UnobfuscatedStrings)), - MangleNames(MangleNames) {} - - StringRef operator()(StringRef Input); - - operator bool() const { return !UnobfuscatedStrings.empty(); } - -private: - std::vector<std::string> UnobfuscatedStrings; - bool MangleNames; -}; - -/// Class to initialize SymbolMapTranslators from a BCSymbolMap. -class SymbolMapLoader { -public: - SymbolMapLoader(std::string SymbolMap) : SymbolMap(std::move(SymbolMap)) {} - - SymbolMapTranslator Load(StringRef InputFile, const DebugMap &Map) const; - -private: - const std::string SymbolMap; -}; -} // namespace dsymutil -} // namespace llvm - -#endif // LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H +//=- tools/dsymutil/SymbolMap.h -----------------------------------*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H +#define LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H + +#include "llvm/ADT/StringRef.h" + +#include <string> +#include <vector> + +namespace llvm { +namespace dsymutil { +class DebugMap; + +/// Callable class to unobfuscate strings based on a BCSymbolMap. +class SymbolMapTranslator { +public: + SymbolMapTranslator() : MangleNames(false) {} + + SymbolMapTranslator(std::vector<std::string> UnobfuscatedStrings, + bool MangleNames) + : UnobfuscatedStrings(std::move(UnobfuscatedStrings)), + MangleNames(MangleNames) {} + + StringRef operator()(StringRef Input); + + operator bool() const { return !UnobfuscatedStrings.empty(); } + +private: + std::vector<std::string> UnobfuscatedStrings; + bool MangleNames; +}; + +/// Class to initialize SymbolMapTranslators from a BCSymbolMap. +class SymbolMapLoader { +public: + SymbolMapLoader(std::string SymbolMap) : SymbolMap(std::move(SymbolMap)) {} + + SymbolMapTranslator Load(StringRef InputFile, const DebugMap &Map) const; + +private: + const std::string SymbolMap; +}; +} // namespace dsymutil +} // namespace llvm + +#endif // LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H diff --git a/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp b/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp index 347b2dd916..bd73a45cca 100644 --- a/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp +++ b/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp @@ -1,691 +1,691 @@ -//===- dsymutil.cpp - Debug info dumping utility for llvm -----------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This program is a utility that aims to be a dropin replacement for Darwin's -// dsymutil. -//===----------------------------------------------------------------------===// - -#include "dsymutil.h" -#include "BinaryHolder.h" -#include "CFBundle.h" -#include "DebugMap.h" -#include "LinkUtils.h" -#include "MachOUtils.h" -#include "Reproducer.h" +//===- dsymutil.cpp - Debug info dumping utility for llvm -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that aims to be a dropin replacement for Darwin's +// dsymutil. +//===----------------------------------------------------------------------===// + +#include "dsymutil.h" +#include "BinaryHolder.h" +#include "CFBundle.h" +#include "DebugMap.h" +#include "LinkUtils.h" +#include "MachOUtils.h" +#include "Reproducer.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/DebugInfo/DIContext.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" -#include "llvm/Object/Binary.h" -#include "llvm/Object/MachO.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileCollector.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/InitLLVM.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/ThreadPool.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/thread.h" -#include <algorithm> -#include <cstdint> -#include <cstdlib> -#include <string> -#include <system_error> - -using namespace llvm; -using namespace llvm::dsymutil; -using namespace object; - -namespace { -enum ID { - OPT_INVALID = 0, // This is not an option ID. -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES) \ - OPT_##ID, -#include "Options.inc" -#undef OPTION -}; - -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "Options.inc" -#undef PREFIX - -const opt::OptTable::Info InfoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES) \ - { \ - PREFIX, NAME, HELPTEXT, \ - METAVAR, OPT_##ID, opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, \ - OPT_##ALIAS, ALIASARGS, VALUES}, -#include "Options.inc" -#undef OPTION -}; - -class DsymutilOptTable : public opt::OptTable { -public: - DsymutilOptTable() : OptTable(InfoTable) {} -}; -} // namespace - -struct DsymutilOptions { - bool DumpDebugMap = false; - bool DumpStab = false; - bool Flat = false; - bool InputIsYAMLDebugMap = false; - bool PaperTrailWarnings = false; - bool Verify = false; - std::string SymbolMap; - std::string OutputFile; - std::string Toolchain; - std::string ReproducerPath; - std::vector<std::string> Archs; - std::vector<std::string> InputFiles; - unsigned NumThreads; - ReproducerMode ReproMode = ReproducerMode::Off; - dsymutil::LinkOptions LinkOpts; -}; - -/// Return a list of input files. This function has logic for dealing with the -/// special case where we might have dSYM bundles as input. The function -/// returns an error when the directory structure doesn't match that of a dSYM -/// bundle. -static Expected<std::vector<std::string>> getInputs(opt::InputArgList &Args, - bool DsymAsInput) { - std::vector<std::string> InputFiles; - for (auto *File : Args.filtered(OPT_INPUT)) - InputFiles.push_back(File->getValue()); - - if (!DsymAsInput) - return InputFiles; - - // If we are updating, we might get dSYM bundles as input. - std::vector<std::string> Inputs; - for (const auto &Input : InputFiles) { - if (!sys::fs::is_directory(Input)) { - Inputs.push_back(Input); - continue; - } - - // Make sure that we're dealing with a dSYM bundle. - SmallString<256> BundlePath(Input); - sys::path::append(BundlePath, "Contents", "Resources", "DWARF"); - if (!sys::fs::is_directory(BundlePath)) - return make_error<StringError>( - Input + " is a directory, but doesn't look like a dSYM bundle.", - inconvertibleErrorCode()); - - // Create a directory iterator to iterate over all the entries in the - // bundle. - std::error_code EC; - sys::fs::directory_iterator DirIt(BundlePath, EC); - sys::fs::directory_iterator DirEnd; - if (EC) - return errorCodeToError(EC); - - // Add each entry to the list of inputs. - while (DirIt != DirEnd) { - Inputs.push_back(DirIt->path()); - DirIt.increment(EC); - if (EC) - return errorCodeToError(EC); - } - } - return Inputs; -} - -// Verify that the given combination of options makes sense. -static Error verifyOptions(const DsymutilOptions &Options) { - if (Options.InputFiles.empty()) { - return make_error<StringError>("no input files specified", - errc::invalid_argument); - } - +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/MachO.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileCollector.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ThreadPool.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/thread.h" +#include <algorithm> +#include <cstdint> +#include <cstdlib> +#include <string> +#include <system_error> + +using namespace llvm; +using namespace llvm::dsymutil; +using namespace object; + +namespace { +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Options.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Options.inc" +#undef PREFIX + +const opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + { \ + PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Options.inc" +#undef OPTION +}; + +class DsymutilOptTable : public opt::OptTable { +public: + DsymutilOptTable() : OptTable(InfoTable) {} +}; +} // namespace + +struct DsymutilOptions { + bool DumpDebugMap = false; + bool DumpStab = false; + bool Flat = false; + bool InputIsYAMLDebugMap = false; + bool PaperTrailWarnings = false; + bool Verify = false; + std::string SymbolMap; + std::string OutputFile; + std::string Toolchain; + std::string ReproducerPath; + std::vector<std::string> Archs; + std::vector<std::string> InputFiles; + unsigned NumThreads; + ReproducerMode ReproMode = ReproducerMode::Off; + dsymutil::LinkOptions LinkOpts; +}; + +/// Return a list of input files. This function has logic for dealing with the +/// special case where we might have dSYM bundles as input. The function +/// returns an error when the directory structure doesn't match that of a dSYM +/// bundle. +static Expected<std::vector<std::string>> getInputs(opt::InputArgList &Args, + bool DsymAsInput) { + std::vector<std::string> InputFiles; + for (auto *File : Args.filtered(OPT_INPUT)) + InputFiles.push_back(File->getValue()); + + if (!DsymAsInput) + return InputFiles; + + // If we are updating, we might get dSYM bundles as input. + std::vector<std::string> Inputs; + for (const auto &Input : InputFiles) { + if (!sys::fs::is_directory(Input)) { + Inputs.push_back(Input); + continue; + } + + // Make sure that we're dealing with a dSYM bundle. + SmallString<256> BundlePath(Input); + sys::path::append(BundlePath, "Contents", "Resources", "DWARF"); + if (!sys::fs::is_directory(BundlePath)) + return make_error<StringError>( + Input + " is a directory, but doesn't look like a dSYM bundle.", + inconvertibleErrorCode()); + + // Create a directory iterator to iterate over all the entries in the + // bundle. + std::error_code EC; + sys::fs::directory_iterator DirIt(BundlePath, EC); + sys::fs::directory_iterator DirEnd; + if (EC) + return errorCodeToError(EC); + + // Add each entry to the list of inputs. + while (DirIt != DirEnd) { + Inputs.push_back(DirIt->path()); + DirIt.increment(EC); + if (EC) + return errorCodeToError(EC); + } + } + return Inputs; +} + +// Verify that the given combination of options makes sense. +static Error verifyOptions(const DsymutilOptions &Options) { + if (Options.InputFiles.empty()) { + return make_error<StringError>("no input files specified", + errc::invalid_argument); + } + if (Options.LinkOpts.Update && llvm::is_contained(Options.InputFiles, "-")) { - // FIXME: We cannot use stdin for an update because stdin will be - // consumed by the BinaryHolder during the debugmap parsing, and - // then we will want to consume it again in DwarfLinker. If we - // used a unique BinaryHolder object that could cache multiple - // binaries this restriction would go away. - return make_error<StringError>( - "standard input cannot be used as input for a dSYM update.", - errc::invalid_argument); - } - - if (!Options.Flat && Options.OutputFile == "-") - return make_error<StringError>( - "cannot emit to standard output without --flat.", - errc::invalid_argument); - - if (Options.InputFiles.size() > 1 && Options.Flat && - !Options.OutputFile.empty()) - return make_error<StringError>( - "cannot use -o with multiple inputs in flat mode.", - errc::invalid_argument); - - if (Options.PaperTrailWarnings && Options.InputIsYAMLDebugMap) - return make_error<StringError>( - "paper trail warnings are not supported for YAML input.", - errc::invalid_argument); - - if (!Options.ReproducerPath.empty() && - Options.ReproMode != ReproducerMode::Use) - return make_error<StringError>( - "cannot combine --gen-reproducer and --use-reproducer.", - errc::invalid_argument); - - return Error::success(); -} - -static Expected<AccelTableKind> getAccelTableKind(opt::InputArgList &Args) { - if (opt::Arg *Accelerator = Args.getLastArg(OPT_accelerator)) { - StringRef S = Accelerator->getValue(); - if (S == "Apple") - return AccelTableKind::Apple; - if (S == "Dwarf") - return AccelTableKind::Dwarf; - if (S == "Default") - return AccelTableKind::Default; - return make_error<StringError>( - "invalid accelerator type specified: '" + S + - "'. Support values are 'Apple', 'Dwarf' and 'Default'.", - inconvertibleErrorCode()); - } - return AccelTableKind::Default; -} - -/// Parses the command line options into the LinkOptions struct and performs -/// some sanity checking. Returns an error in case the latter fails. -static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) { - DsymutilOptions Options; - - Options.DumpDebugMap = Args.hasArg(OPT_dump_debug_map); - Options.DumpStab = Args.hasArg(OPT_symtab); - Options.Flat = Args.hasArg(OPT_flat); - Options.InputIsYAMLDebugMap = Args.hasArg(OPT_yaml_input); - Options.PaperTrailWarnings = Args.hasArg(OPT_papertrail); - Options.Verify = Args.hasArg(OPT_verify); - - Options.LinkOpts.Minimize = Args.hasArg(OPT_minimize); - Options.LinkOpts.NoODR = Args.hasArg(OPT_no_odr); - Options.LinkOpts.NoOutput = Args.hasArg(OPT_no_output); - Options.LinkOpts.NoTimestamp = Args.hasArg(OPT_no_swiftmodule_timestamp); - Options.LinkOpts.Update = Args.hasArg(OPT_update); - Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose); - Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics); - - if (opt::Arg *ReproducerPath = Args.getLastArg(OPT_use_reproducer)) { - Options.ReproMode = ReproducerMode::Use; - Options.ReproducerPath = ReproducerPath->getValue(); - } - - if (Args.hasArg(OPT_gen_reproducer)) - Options.ReproMode = ReproducerMode::Generate; - - if (Expected<AccelTableKind> AccelKind = getAccelTableKind(Args)) { - Options.LinkOpts.TheAccelTableKind = *AccelKind; - } else { - return AccelKind.takeError(); - } - - if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap)) - Options.SymbolMap = SymbolMap->getValue(); - - if (Args.hasArg(OPT_symbolmap)) - Options.LinkOpts.Update = true; - - if (Expected<std::vector<std::string>> InputFiles = - getInputs(Args, Options.LinkOpts.Update)) { - Options.InputFiles = std::move(*InputFiles); - } else { - return InputFiles.takeError(); - } - - for (auto *Arch : Args.filtered(OPT_arch)) - Options.Archs.push_back(Arch->getValue()); - - if (opt::Arg *OsoPrependPath = Args.getLastArg(OPT_oso_prepend_path)) - Options.LinkOpts.PrependPath = OsoPrependPath->getValue(); - - for (const auto &Arg : Args.getAllArgValues(OPT_object_prefix_map)) { - auto Split = StringRef(Arg).split('='); - Options.LinkOpts.ObjectPrefixMap.insert( - {std::string(Split.first), std::string(Split.second)}); - } - - if (opt::Arg *OutputFile = Args.getLastArg(OPT_output)) - Options.OutputFile = OutputFile->getValue(); - - if (opt::Arg *Toolchain = Args.getLastArg(OPT_toolchain)) - Options.Toolchain = Toolchain->getValue(); - - if (Args.hasArg(OPT_assembly)) - Options.LinkOpts.FileType = OutputFileType::Assembly; - - if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads)) - Options.LinkOpts.Threads = atoi(NumThreads->getValue()); - else - Options.LinkOpts.Threads = 0; // Use all available hardware threads - - if (Options.DumpDebugMap || Options.LinkOpts.Verbose) - Options.LinkOpts.Threads = 1; - - if (getenv("RC_DEBUG_OPTIONS")) - Options.PaperTrailWarnings = true; - - if (opt::Arg *RemarksPrependPath = Args.getLastArg(OPT_remarks_prepend_path)) - Options.LinkOpts.RemarksPrependPath = RemarksPrependPath->getValue(); - - if (opt::Arg *RemarksOutputFormat = - Args.getLastArg(OPT_remarks_output_format)) { - if (Expected<remarks::Format> FormatOrErr = - remarks::parseFormat(RemarksOutputFormat->getValue())) - Options.LinkOpts.RemarksFormat = *FormatOrErr; - else - return FormatOrErr.takeError(); - } - - if (Error E = verifyOptions(Options)) - return std::move(E); - return Options; -} - -static Error createPlistFile(StringRef Bin, StringRef BundleRoot, - StringRef Toolchain) { - // Create plist file to write to. - SmallString<128> InfoPlist(BundleRoot); - sys::path::append(InfoPlist, "Contents/Info.plist"); - std::error_code EC; - raw_fd_ostream PL(InfoPlist, EC, sys::fs::OF_Text); - if (EC) - return make_error<StringError>( - "cannot create Plist: " + toString(errorCodeToError(EC)), EC); - - CFBundleInfo BI = getBundleInfo(Bin); - - if (BI.IDStr.empty()) { - StringRef BundleID = *sys::path::rbegin(BundleRoot); - if (sys::path::extension(BundleRoot) == ".dSYM") - BI.IDStr = std::string(sys::path::stem(BundleID)); - else - BI.IDStr = std::string(BundleID); - } - - // Print out information to the plist file. - PL << "<?xml version=\"1.0\" encoding=\"UTF-8\"\?>\n" - << "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " - << "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" - << "<plist version=\"1.0\">\n" - << "\t<dict>\n" - << "\t\t<key>CFBundleDevelopmentRegion</key>\n" - << "\t\t<string>English</string>\n" - << "\t\t<key>CFBundleIdentifier</key>\n" - << "\t\t<string>com.apple.xcode.dsym."; - printHTMLEscaped(BI.IDStr, PL); - PL << "</string>\n" - << "\t\t<key>CFBundleInfoDictionaryVersion</key>\n" - << "\t\t<string>6.0</string>\n" - << "\t\t<key>CFBundlePackageType</key>\n" - << "\t\t<string>dSYM</string>\n" - << "\t\t<key>CFBundleSignature</key>\n" - << "\t\t<string>\?\?\?\?</string>\n"; - - if (!BI.OmitShortVersion()) { - PL << "\t\t<key>CFBundleShortVersionString</key>\n"; - PL << "\t\t<string>"; - printHTMLEscaped(BI.ShortVersionStr, PL); - PL << "</string>\n"; - } - - PL << "\t\t<key>CFBundleVersion</key>\n"; - PL << "\t\t<string>"; - printHTMLEscaped(BI.VersionStr, PL); - PL << "</string>\n"; - - if (!Toolchain.empty()) { - PL << "\t\t<key>Toolchain</key>\n"; - PL << "\t\t<string>"; - printHTMLEscaped(Toolchain, PL); - PL << "</string>\n"; - } - - PL << "\t</dict>\n" - << "</plist>\n"; - - PL.close(); - return Error::success(); -} - -static Error createBundleDir(StringRef BundleBase) { - SmallString<128> Bundle(BundleBase); - sys::path::append(Bundle, "Contents", "Resources", "DWARF"); - if (std::error_code EC = - create_directories(Bundle.str(), true, sys::fs::perms::all_all)) - return make_error<StringError>( - "cannot create bundle: " + toString(errorCodeToError(EC)), EC); - - return Error::success(); -} - -static bool verify(StringRef OutputFile, StringRef Arch, bool Verbose) { - if (OutputFile == "-") { - WithColor::warning() << "verification skipped for " << Arch - << "because writing to stdout.\n"; - return true; - } - - Expected<OwningBinary<Binary>> BinOrErr = createBinary(OutputFile); - if (!BinOrErr) { - WithColor::error() << OutputFile << ": " << toString(BinOrErr.takeError()); - return false; - } - - Binary &Binary = *BinOrErr.get().getBinary(); - if (auto *Obj = dyn_cast<MachOObjectFile>(&Binary)) { - raw_ostream &os = Verbose ? errs() : nulls(); - os << "Verifying DWARF for architecture: " << Arch << "\n"; - std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj); - DIDumpOptions DumpOpts; - bool success = DICtx->verify(os, DumpOpts.noImplicitRecursion()); - if (!success) - WithColor::error() << "verification failed for " << Arch << '\n'; - return success; - } - - return false; -} - -namespace { -struct OutputLocation { - OutputLocation(std::string DWARFFile, Optional<std::string> ResourceDir = {}) - : DWARFFile(DWARFFile), ResourceDir(ResourceDir) {} - /// This method is a workaround for older compilers. - Optional<std::string> getResourceDir() const { return ResourceDir; } - std::string DWARFFile; - Optional<std::string> ResourceDir; -}; -} // namespace - -static Expected<OutputLocation> -getOutputFileName(StringRef InputFile, const DsymutilOptions &Options) { - if (Options.OutputFile == "-") - return OutputLocation(Options.OutputFile); - - // When updating, do in place replacement. - if (Options.OutputFile.empty() && - (Options.LinkOpts.Update || !Options.SymbolMap.empty())) - return OutputLocation(std::string(InputFile)); - - // If a flat dSYM has been requested, things are pretty simple. - if (Options.Flat) { - if (Options.OutputFile.empty()) { - if (InputFile == "-") - return OutputLocation{"a.out.dwarf", {}}; - return OutputLocation((InputFile + ".dwarf").str()); - } - - return OutputLocation(Options.OutputFile); - } - - // We need to create/update a dSYM bundle. - // A bundle hierarchy looks like this: - // <bundle name>.dSYM/ - // Contents/ - // Info.plist - // Resources/ - // DWARF/ - // <DWARF file(s)> - std::string DwarfFile = - std::string(InputFile == "-" ? StringRef("a.out") : InputFile); - SmallString<128> Path(Options.OutputFile); - if (Path.empty()) - Path = DwarfFile + ".dSYM"; - if (!Options.LinkOpts.NoOutput) { - if (auto E = createBundleDir(Path)) - return std::move(E); - if (auto E = createPlistFile(DwarfFile, Path, Options.Toolchain)) - return std::move(E); - } - - sys::path::append(Path, "Contents", "Resources"); - std::string ResourceDir = std::string(Path.str()); - sys::path::append(Path, "DWARF", sys::path::filename(DwarfFile)); - return OutputLocation(std::string(Path.str()), ResourceDir); -} - -int main(int argc, char **argv) { - InitLLVM X(argc, argv); - - // Parse arguments. - DsymutilOptTable T; - unsigned MAI; - unsigned MAC; - ArrayRef<const char *> ArgsArr = makeArrayRef(argv + 1, argc - 1); - opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC); - - void *P = (void *)(intptr_t)getOutputFileName; - std::string SDKPath = sys::fs::getMainExecutable(argv[0], P); - SDKPath = std::string(sys::path::parent_path(SDKPath)); - - for (auto *Arg : Args.filtered(OPT_UNKNOWN)) { - WithColor::warning() << "ignoring unknown option: " << Arg->getSpelling() - << '\n'; - } - - if (Args.hasArg(OPT_help)) { - T.PrintHelp( - outs(), (std::string(argv[0]) + " [options] <input files>").c_str(), - "manipulate archived DWARF debug symbol files.\n\n" - "dsymutil links the DWARF debug information found in the object files\n" - "for the executable <input file> by using debug symbols information\n" - "contained in its symbol table.\n", - false); - return 0; - } - - if (Args.hasArg(OPT_version)) { - cl::PrintVersionMessage(); - return 0; - } - - auto OptionsOrErr = getOptions(Args); - if (!OptionsOrErr) { - WithColor::error() << toString(OptionsOrErr.takeError()); - return 1; - } - - auto &Options = *OptionsOrErr; - - InitializeAllTargetInfos(); - InitializeAllTargetMCs(); - InitializeAllTargets(); - InitializeAllAsmPrinters(); - - auto Repro = - Reproducer::createReproducer(Options.ReproMode, Options.ReproducerPath); - if (!Repro) { - WithColor::error() << toString(Repro.takeError()); - return 1; - } - - Options.LinkOpts.VFS = (*Repro)->getVFS(); - - for (const auto &Arch : Options.Archs) - if (Arch != "*" && Arch != "all" && - !object::MachOObjectFile::isValidArch(Arch)) { - WithColor::error() << "unsupported cpu architecture: '" << Arch << "'\n"; - return 1; - } - - SymbolMapLoader SymMapLoader(Options.SymbolMap); - - for (auto &InputFile : Options.InputFiles) { - // Dump the symbol table for each input file and requested arch - if (Options.DumpStab) { - if (!dumpStab(Options.LinkOpts.VFS, InputFile, Options.Archs, - Options.LinkOpts.PrependPath)) - return 1; - continue; - } - - auto DebugMapPtrsOrErr = - parseDebugMap(Options.LinkOpts.VFS, InputFile, Options.Archs, - Options.LinkOpts.PrependPath, Options.PaperTrailWarnings, - Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap); - - if (auto EC = DebugMapPtrsOrErr.getError()) { - WithColor::error() << "cannot parse the debug map for '" << InputFile - << "': " << EC.message() << '\n'; - return 1; - } - - // Remember the number of debug maps that are being processed to decide how - // to name the remark files. - Options.LinkOpts.NumDebugMaps = DebugMapPtrsOrErr->size(); - - if (Options.LinkOpts.Update) { - // The debug map should be empty. Add one object file corresponding to - // the input file. - for (auto &Map : *DebugMapPtrsOrErr) - Map->addDebugMapObject(InputFile, - sys::TimePoint<std::chrono::seconds>()); - } - - // Ensure that the debug map is not empty (anymore). - if (DebugMapPtrsOrErr->empty()) { - WithColor::error() << "no architecture to link\n"; - return 1; - } - - // Shared a single binary holder for all the link steps. - BinaryHolder BinHolder(Options.LinkOpts.VFS); - - // Statistics only require different architectures to be processed - // sequentially, the link itself can still happen in parallel. Change the - // thread pool strategy here instead of modifying LinkOpts.Threads. - ThreadPoolStrategy S = hardware_concurrency( - Options.LinkOpts.Statistics ? 1 : Options.LinkOpts.Threads); - if (Options.LinkOpts.Threads == 0) { - // If NumThreads is not specified, create one thread for each input, up to - // the number of hardware threads. - S.ThreadsRequested = DebugMapPtrsOrErr->size(); - S.Limit = true; - } - ThreadPool Threads(S); - - // If there is more than one link to execute, we need to generate - // temporary files. - const bool NeedsTempFiles = - !Options.DumpDebugMap && (Options.OutputFile != "-") && - (DebugMapPtrsOrErr->size() != 1 || Options.LinkOpts.Update); - const bool Verify = Options.Verify && !Options.LinkOpts.NoOutput; - - SmallVector<MachOUtils::ArchAndFile, 4> TempFiles; - std::atomic_char AllOK(1); - for (auto &Map : *DebugMapPtrsOrErr) { - if (Options.LinkOpts.Verbose || Options.DumpDebugMap) - Map->print(outs()); - - if (Options.DumpDebugMap) - continue; - - if (!Options.SymbolMap.empty()) - Options.LinkOpts.Translator = SymMapLoader.Load(InputFile, *Map); - - if (Map->begin() == Map->end()) - WithColor::warning() - << "no debug symbols in executable (-arch " - << MachOUtils::getArchName(Map->getTriple().getArchName()) << ")\n"; - - // Using a std::shared_ptr rather than std::unique_ptr because move-only - // types don't work with std::bind in the ThreadPool implementation. - std::shared_ptr<raw_fd_ostream> OS; - - Expected<OutputLocation> OutputLocationOrErr = - getOutputFileName(InputFile, Options); - if (!OutputLocationOrErr) { - WithColor::error() << toString(OutputLocationOrErr.takeError()); - return 1; - } - Options.LinkOpts.ResourceDir = OutputLocationOrErr->getResourceDir(); - - std::string OutputFile = OutputLocationOrErr->DWARFFile; - if (NeedsTempFiles) { - TempFiles.emplace_back(Map->getTriple().getArchName().str()); - - auto E = TempFiles.back().createTempFile(); - if (E) { - WithColor::error() << toString(std::move(E)); - return 1; - } - - auto &TempFile = *(TempFiles.back().File); - OS = std::make_shared<raw_fd_ostream>(TempFile.FD, - /*shouldClose*/ false); - OutputFile = TempFile.TmpName; - } else { - std::error_code EC; - OS = std::make_shared<raw_fd_ostream>( - Options.LinkOpts.NoOutput ? "-" : OutputFile, EC, sys::fs::OF_None); - if (EC) { - WithColor::error() << OutputFile << ": " << EC.message(); - return 1; - } - } - - auto LinkLambda = [&, OutputFile](std::shared_ptr<raw_fd_ostream> Stream, - LinkOptions Options) { - AllOK.fetch_and( - linkDwarf(*Stream, BinHolder, *Map, std::move(Options))); - Stream->flush(); - if (Verify) - AllOK.fetch_and(verify(OutputFile, Map->getTriple().getArchName(), - Options.Verbose)); - }; - - // FIXME: The DwarfLinker can have some very deep recursion that can max - // out the (significantly smaller) stack when using threads. We don't - // want this limitation when we only have a single thread. - if (S.ThreadsRequested == 1) - LinkLambda(OS, Options.LinkOpts); - else - Threads.async(LinkLambda, OS, Options.LinkOpts); - } - - Threads.wait(); - - if (!AllOK) - return 1; - - if (NeedsTempFiles) { - Expected<OutputLocation> OutputLocationOrErr = - getOutputFileName(InputFile, Options); - if (!OutputLocationOrErr) { - WithColor::error() << toString(OutputLocationOrErr.takeError()); - return 1; - } - if (!MachOUtils::generateUniversalBinary(TempFiles, - OutputLocationOrErr->DWARFFile, - Options.LinkOpts, SDKPath)) - return 1; - } - } - - return 0; -} + // FIXME: We cannot use stdin for an update because stdin will be + // consumed by the BinaryHolder during the debugmap parsing, and + // then we will want to consume it again in DwarfLinker. If we + // used a unique BinaryHolder object that could cache multiple + // binaries this restriction would go away. + return make_error<StringError>( + "standard input cannot be used as input for a dSYM update.", + errc::invalid_argument); + } + + if (!Options.Flat && Options.OutputFile == "-") + return make_error<StringError>( + "cannot emit to standard output without --flat.", + errc::invalid_argument); + + if (Options.InputFiles.size() > 1 && Options.Flat && + !Options.OutputFile.empty()) + return make_error<StringError>( + "cannot use -o with multiple inputs in flat mode.", + errc::invalid_argument); + + if (Options.PaperTrailWarnings && Options.InputIsYAMLDebugMap) + return make_error<StringError>( + "paper trail warnings are not supported for YAML input.", + errc::invalid_argument); + + if (!Options.ReproducerPath.empty() && + Options.ReproMode != ReproducerMode::Use) + return make_error<StringError>( + "cannot combine --gen-reproducer and --use-reproducer.", + errc::invalid_argument); + + return Error::success(); +} + +static Expected<AccelTableKind> getAccelTableKind(opt::InputArgList &Args) { + if (opt::Arg *Accelerator = Args.getLastArg(OPT_accelerator)) { + StringRef S = Accelerator->getValue(); + if (S == "Apple") + return AccelTableKind::Apple; + if (S == "Dwarf") + return AccelTableKind::Dwarf; + if (S == "Default") + return AccelTableKind::Default; + return make_error<StringError>( + "invalid accelerator type specified: '" + S + + "'. Support values are 'Apple', 'Dwarf' and 'Default'.", + inconvertibleErrorCode()); + } + return AccelTableKind::Default; +} + +/// Parses the command line options into the LinkOptions struct and performs +/// some sanity checking. Returns an error in case the latter fails. +static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) { + DsymutilOptions Options; + + Options.DumpDebugMap = Args.hasArg(OPT_dump_debug_map); + Options.DumpStab = Args.hasArg(OPT_symtab); + Options.Flat = Args.hasArg(OPT_flat); + Options.InputIsYAMLDebugMap = Args.hasArg(OPT_yaml_input); + Options.PaperTrailWarnings = Args.hasArg(OPT_papertrail); + Options.Verify = Args.hasArg(OPT_verify); + + Options.LinkOpts.Minimize = Args.hasArg(OPT_minimize); + Options.LinkOpts.NoODR = Args.hasArg(OPT_no_odr); + Options.LinkOpts.NoOutput = Args.hasArg(OPT_no_output); + Options.LinkOpts.NoTimestamp = Args.hasArg(OPT_no_swiftmodule_timestamp); + Options.LinkOpts.Update = Args.hasArg(OPT_update); + Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose); + Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics); + + if (opt::Arg *ReproducerPath = Args.getLastArg(OPT_use_reproducer)) { + Options.ReproMode = ReproducerMode::Use; + Options.ReproducerPath = ReproducerPath->getValue(); + } + + if (Args.hasArg(OPT_gen_reproducer)) + Options.ReproMode = ReproducerMode::Generate; + + if (Expected<AccelTableKind> AccelKind = getAccelTableKind(Args)) { + Options.LinkOpts.TheAccelTableKind = *AccelKind; + } else { + return AccelKind.takeError(); + } + + if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap)) + Options.SymbolMap = SymbolMap->getValue(); + + if (Args.hasArg(OPT_symbolmap)) + Options.LinkOpts.Update = true; + + if (Expected<std::vector<std::string>> InputFiles = + getInputs(Args, Options.LinkOpts.Update)) { + Options.InputFiles = std::move(*InputFiles); + } else { + return InputFiles.takeError(); + } + + for (auto *Arch : Args.filtered(OPT_arch)) + Options.Archs.push_back(Arch->getValue()); + + if (opt::Arg *OsoPrependPath = Args.getLastArg(OPT_oso_prepend_path)) + Options.LinkOpts.PrependPath = OsoPrependPath->getValue(); + + for (const auto &Arg : Args.getAllArgValues(OPT_object_prefix_map)) { + auto Split = StringRef(Arg).split('='); + Options.LinkOpts.ObjectPrefixMap.insert( + {std::string(Split.first), std::string(Split.second)}); + } + + if (opt::Arg *OutputFile = Args.getLastArg(OPT_output)) + Options.OutputFile = OutputFile->getValue(); + + if (opt::Arg *Toolchain = Args.getLastArg(OPT_toolchain)) + Options.Toolchain = Toolchain->getValue(); + + if (Args.hasArg(OPT_assembly)) + Options.LinkOpts.FileType = OutputFileType::Assembly; + + if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads)) + Options.LinkOpts.Threads = atoi(NumThreads->getValue()); + else + Options.LinkOpts.Threads = 0; // Use all available hardware threads + + if (Options.DumpDebugMap || Options.LinkOpts.Verbose) + Options.LinkOpts.Threads = 1; + + if (getenv("RC_DEBUG_OPTIONS")) + Options.PaperTrailWarnings = true; + + if (opt::Arg *RemarksPrependPath = Args.getLastArg(OPT_remarks_prepend_path)) + Options.LinkOpts.RemarksPrependPath = RemarksPrependPath->getValue(); + + if (opt::Arg *RemarksOutputFormat = + Args.getLastArg(OPT_remarks_output_format)) { + if (Expected<remarks::Format> FormatOrErr = + remarks::parseFormat(RemarksOutputFormat->getValue())) + Options.LinkOpts.RemarksFormat = *FormatOrErr; + else + return FormatOrErr.takeError(); + } + + if (Error E = verifyOptions(Options)) + return std::move(E); + return Options; +} + +static Error createPlistFile(StringRef Bin, StringRef BundleRoot, + StringRef Toolchain) { + // Create plist file to write to. + SmallString<128> InfoPlist(BundleRoot); + sys::path::append(InfoPlist, "Contents/Info.plist"); + std::error_code EC; + raw_fd_ostream PL(InfoPlist, EC, sys::fs::OF_Text); + if (EC) + return make_error<StringError>( + "cannot create Plist: " + toString(errorCodeToError(EC)), EC); + + CFBundleInfo BI = getBundleInfo(Bin); + + if (BI.IDStr.empty()) { + StringRef BundleID = *sys::path::rbegin(BundleRoot); + if (sys::path::extension(BundleRoot) == ".dSYM") + BI.IDStr = std::string(sys::path::stem(BundleID)); + else + BI.IDStr = std::string(BundleID); + } + + // Print out information to the plist file. + PL << "<?xml version=\"1.0\" encoding=\"UTF-8\"\?>\n" + << "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " + << "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + << "<plist version=\"1.0\">\n" + << "\t<dict>\n" + << "\t\t<key>CFBundleDevelopmentRegion</key>\n" + << "\t\t<string>English</string>\n" + << "\t\t<key>CFBundleIdentifier</key>\n" + << "\t\t<string>com.apple.xcode.dsym."; + printHTMLEscaped(BI.IDStr, PL); + PL << "</string>\n" + << "\t\t<key>CFBundleInfoDictionaryVersion</key>\n" + << "\t\t<string>6.0</string>\n" + << "\t\t<key>CFBundlePackageType</key>\n" + << "\t\t<string>dSYM</string>\n" + << "\t\t<key>CFBundleSignature</key>\n" + << "\t\t<string>\?\?\?\?</string>\n"; + + if (!BI.OmitShortVersion()) { + PL << "\t\t<key>CFBundleShortVersionString</key>\n"; + PL << "\t\t<string>"; + printHTMLEscaped(BI.ShortVersionStr, PL); + PL << "</string>\n"; + } + + PL << "\t\t<key>CFBundleVersion</key>\n"; + PL << "\t\t<string>"; + printHTMLEscaped(BI.VersionStr, PL); + PL << "</string>\n"; + + if (!Toolchain.empty()) { + PL << "\t\t<key>Toolchain</key>\n"; + PL << "\t\t<string>"; + printHTMLEscaped(Toolchain, PL); + PL << "</string>\n"; + } + + PL << "\t</dict>\n" + << "</plist>\n"; + + PL.close(); + return Error::success(); +} + +static Error createBundleDir(StringRef BundleBase) { + SmallString<128> Bundle(BundleBase); + sys::path::append(Bundle, "Contents", "Resources", "DWARF"); + if (std::error_code EC = + create_directories(Bundle.str(), true, sys::fs::perms::all_all)) + return make_error<StringError>( + "cannot create bundle: " + toString(errorCodeToError(EC)), EC); + + return Error::success(); +} + +static bool verify(StringRef OutputFile, StringRef Arch, bool Verbose) { + if (OutputFile == "-") { + WithColor::warning() << "verification skipped for " << Arch + << "because writing to stdout.\n"; + return true; + } + + Expected<OwningBinary<Binary>> BinOrErr = createBinary(OutputFile); + if (!BinOrErr) { + WithColor::error() << OutputFile << ": " << toString(BinOrErr.takeError()); + return false; + } + + Binary &Binary = *BinOrErr.get().getBinary(); + if (auto *Obj = dyn_cast<MachOObjectFile>(&Binary)) { + raw_ostream &os = Verbose ? errs() : nulls(); + os << "Verifying DWARF for architecture: " << Arch << "\n"; + std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj); + DIDumpOptions DumpOpts; + bool success = DICtx->verify(os, DumpOpts.noImplicitRecursion()); + if (!success) + WithColor::error() << "verification failed for " << Arch << '\n'; + return success; + } + + return false; +} + +namespace { +struct OutputLocation { + OutputLocation(std::string DWARFFile, Optional<std::string> ResourceDir = {}) + : DWARFFile(DWARFFile), ResourceDir(ResourceDir) {} + /// This method is a workaround for older compilers. + Optional<std::string> getResourceDir() const { return ResourceDir; } + std::string DWARFFile; + Optional<std::string> ResourceDir; +}; +} // namespace + +static Expected<OutputLocation> +getOutputFileName(StringRef InputFile, const DsymutilOptions &Options) { + if (Options.OutputFile == "-") + return OutputLocation(Options.OutputFile); + + // When updating, do in place replacement. + if (Options.OutputFile.empty() && + (Options.LinkOpts.Update || !Options.SymbolMap.empty())) + return OutputLocation(std::string(InputFile)); + + // If a flat dSYM has been requested, things are pretty simple. + if (Options.Flat) { + if (Options.OutputFile.empty()) { + if (InputFile == "-") + return OutputLocation{"a.out.dwarf", {}}; + return OutputLocation((InputFile + ".dwarf").str()); + } + + return OutputLocation(Options.OutputFile); + } + + // We need to create/update a dSYM bundle. + // A bundle hierarchy looks like this: + // <bundle name>.dSYM/ + // Contents/ + // Info.plist + // Resources/ + // DWARF/ + // <DWARF file(s)> + std::string DwarfFile = + std::string(InputFile == "-" ? StringRef("a.out") : InputFile); + SmallString<128> Path(Options.OutputFile); + if (Path.empty()) + Path = DwarfFile + ".dSYM"; + if (!Options.LinkOpts.NoOutput) { + if (auto E = createBundleDir(Path)) + return std::move(E); + if (auto E = createPlistFile(DwarfFile, Path, Options.Toolchain)) + return std::move(E); + } + + sys::path::append(Path, "Contents", "Resources"); + std::string ResourceDir = std::string(Path.str()); + sys::path::append(Path, "DWARF", sys::path::filename(DwarfFile)); + return OutputLocation(std::string(Path.str()), ResourceDir); +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + // Parse arguments. + DsymutilOptTable T; + unsigned MAI; + unsigned MAC; + ArrayRef<const char *> ArgsArr = makeArrayRef(argv + 1, argc - 1); + opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC); + + void *P = (void *)(intptr_t)getOutputFileName; + std::string SDKPath = sys::fs::getMainExecutable(argv[0], P); + SDKPath = std::string(sys::path::parent_path(SDKPath)); + + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) { + WithColor::warning() << "ignoring unknown option: " << Arg->getSpelling() + << '\n'; + } + + if (Args.hasArg(OPT_help)) { + T.PrintHelp( + outs(), (std::string(argv[0]) + " [options] <input files>").c_str(), + "manipulate archived DWARF debug symbol files.\n\n" + "dsymutil links the DWARF debug information found in the object files\n" + "for the executable <input file> by using debug symbols information\n" + "contained in its symbol table.\n", + false); + return 0; + } + + if (Args.hasArg(OPT_version)) { + cl::PrintVersionMessage(); + return 0; + } + + auto OptionsOrErr = getOptions(Args); + if (!OptionsOrErr) { + WithColor::error() << toString(OptionsOrErr.takeError()); + return 1; + } + + auto &Options = *OptionsOrErr; + + InitializeAllTargetInfos(); + InitializeAllTargetMCs(); + InitializeAllTargets(); + InitializeAllAsmPrinters(); + + auto Repro = + Reproducer::createReproducer(Options.ReproMode, Options.ReproducerPath); + if (!Repro) { + WithColor::error() << toString(Repro.takeError()); + return 1; + } + + Options.LinkOpts.VFS = (*Repro)->getVFS(); + + for (const auto &Arch : Options.Archs) + if (Arch != "*" && Arch != "all" && + !object::MachOObjectFile::isValidArch(Arch)) { + WithColor::error() << "unsupported cpu architecture: '" << Arch << "'\n"; + return 1; + } + + SymbolMapLoader SymMapLoader(Options.SymbolMap); + + for (auto &InputFile : Options.InputFiles) { + // Dump the symbol table for each input file and requested arch + if (Options.DumpStab) { + if (!dumpStab(Options.LinkOpts.VFS, InputFile, Options.Archs, + Options.LinkOpts.PrependPath)) + return 1; + continue; + } + + auto DebugMapPtrsOrErr = + parseDebugMap(Options.LinkOpts.VFS, InputFile, Options.Archs, + Options.LinkOpts.PrependPath, Options.PaperTrailWarnings, + Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap); + + if (auto EC = DebugMapPtrsOrErr.getError()) { + WithColor::error() << "cannot parse the debug map for '" << InputFile + << "': " << EC.message() << '\n'; + return 1; + } + + // Remember the number of debug maps that are being processed to decide how + // to name the remark files. + Options.LinkOpts.NumDebugMaps = DebugMapPtrsOrErr->size(); + + if (Options.LinkOpts.Update) { + // The debug map should be empty. Add one object file corresponding to + // the input file. + for (auto &Map : *DebugMapPtrsOrErr) + Map->addDebugMapObject(InputFile, + sys::TimePoint<std::chrono::seconds>()); + } + + // Ensure that the debug map is not empty (anymore). + if (DebugMapPtrsOrErr->empty()) { + WithColor::error() << "no architecture to link\n"; + return 1; + } + + // Shared a single binary holder for all the link steps. + BinaryHolder BinHolder(Options.LinkOpts.VFS); + + // Statistics only require different architectures to be processed + // sequentially, the link itself can still happen in parallel. Change the + // thread pool strategy here instead of modifying LinkOpts.Threads. + ThreadPoolStrategy S = hardware_concurrency( + Options.LinkOpts.Statistics ? 1 : Options.LinkOpts.Threads); + if (Options.LinkOpts.Threads == 0) { + // If NumThreads is not specified, create one thread for each input, up to + // the number of hardware threads. + S.ThreadsRequested = DebugMapPtrsOrErr->size(); + S.Limit = true; + } + ThreadPool Threads(S); + + // If there is more than one link to execute, we need to generate + // temporary files. + const bool NeedsTempFiles = + !Options.DumpDebugMap && (Options.OutputFile != "-") && + (DebugMapPtrsOrErr->size() != 1 || Options.LinkOpts.Update); + const bool Verify = Options.Verify && !Options.LinkOpts.NoOutput; + + SmallVector<MachOUtils::ArchAndFile, 4> TempFiles; + std::atomic_char AllOK(1); + for (auto &Map : *DebugMapPtrsOrErr) { + if (Options.LinkOpts.Verbose || Options.DumpDebugMap) + Map->print(outs()); + + if (Options.DumpDebugMap) + continue; + + if (!Options.SymbolMap.empty()) + Options.LinkOpts.Translator = SymMapLoader.Load(InputFile, *Map); + + if (Map->begin() == Map->end()) + WithColor::warning() + << "no debug symbols in executable (-arch " + << MachOUtils::getArchName(Map->getTriple().getArchName()) << ")\n"; + + // Using a std::shared_ptr rather than std::unique_ptr because move-only + // types don't work with std::bind in the ThreadPool implementation. + std::shared_ptr<raw_fd_ostream> OS; + + Expected<OutputLocation> OutputLocationOrErr = + getOutputFileName(InputFile, Options); + if (!OutputLocationOrErr) { + WithColor::error() << toString(OutputLocationOrErr.takeError()); + return 1; + } + Options.LinkOpts.ResourceDir = OutputLocationOrErr->getResourceDir(); + + std::string OutputFile = OutputLocationOrErr->DWARFFile; + if (NeedsTempFiles) { + TempFiles.emplace_back(Map->getTriple().getArchName().str()); + + auto E = TempFiles.back().createTempFile(); + if (E) { + WithColor::error() << toString(std::move(E)); + return 1; + } + + auto &TempFile = *(TempFiles.back().File); + OS = std::make_shared<raw_fd_ostream>(TempFile.FD, + /*shouldClose*/ false); + OutputFile = TempFile.TmpName; + } else { + std::error_code EC; + OS = std::make_shared<raw_fd_ostream>( + Options.LinkOpts.NoOutput ? "-" : OutputFile, EC, sys::fs::OF_None); + if (EC) { + WithColor::error() << OutputFile << ": " << EC.message(); + return 1; + } + } + + auto LinkLambda = [&, OutputFile](std::shared_ptr<raw_fd_ostream> Stream, + LinkOptions Options) { + AllOK.fetch_and( + linkDwarf(*Stream, BinHolder, *Map, std::move(Options))); + Stream->flush(); + if (Verify) + AllOK.fetch_and(verify(OutputFile, Map->getTriple().getArchName(), + Options.Verbose)); + }; + + // FIXME: The DwarfLinker can have some very deep recursion that can max + // out the (significantly smaller) stack when using threads. We don't + // want this limitation when we only have a single thread. + if (S.ThreadsRequested == 1) + LinkLambda(OS, Options.LinkOpts); + else + Threads.async(LinkLambda, OS, Options.LinkOpts); + } + + Threads.wait(); + + if (!AllOK) + return 1; + + if (NeedsTempFiles) { + Expected<OutputLocation> OutputLocationOrErr = + getOutputFileName(InputFile, Options); + if (!OutputLocationOrErr) { + WithColor::error() << toString(OutputLocationOrErr.takeError()); + return 1; + } + if (!MachOUtils::generateUniversalBinary(TempFiles, + OutputLocationOrErr->DWARFFile, + Options.LinkOpts, SDKPath)) + return 1; + } + } + + return 0; +} diff --git a/contrib/libs/llvm12/tools/dsymutil/dsymutil.h b/contrib/libs/llvm12/tools/dsymutil/dsymutil.h index f88f57bb20..7080b1bf3b 100644 --- a/contrib/libs/llvm12/tools/dsymutil/dsymutil.h +++ b/contrib/libs/llvm12/tools/dsymutil/dsymutil.h @@ -1,56 +1,56 @@ -//===- tools/dsymutil/dsymutil.h - dsymutil high-level functionality ------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -/// \file -/// -/// This file contains the class declaration for the code that parses STABS -/// debug maps that are embedded in the binaries symbol tables. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H -#define LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H - -#include "DebugMap.h" -#include "LinkUtils.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorOr.h" -#include <memory> -#include <string> -#include <vector> - -namespace llvm { -namespace dsymutil { - -class BinaryHolder; - -/// Extract the DebugMaps from the given file. -/// The file has to be a MachO object file. Multiple debug maps can be -/// returned when the file is universal (aka fat) binary. -ErrorOr<std::vector<std::unique_ptr<DebugMap>>> -parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - StringRef InputFile, ArrayRef<std::string> Archs, - StringRef PrependPath, bool PaperTrailWarnings, bool Verbose, - bool InputIsYAML); - -/// Dump the symbol table. -bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - StringRef InputFile, ArrayRef<std::string> Archs, - StringRef PrependPath = ""); - -/// Link the Dwarf debug info as directed by the passed DebugMap \p DM into a -/// DwarfFile named \p OutputFilename. \returns false if the link failed. -bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, - const DebugMap &DM, LinkOptions Options); - -} // end namespace dsymutil -} // end namespace llvm - -#endif // LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H +//===- tools/dsymutil/dsymutil.h - dsymutil high-level functionality ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// +/// This file contains the class declaration for the code that parses STABS +/// debug maps that are embedded in the binaries symbol tables. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H +#define LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H + +#include "DebugMap.h" +#include "LinkUtils.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorOr.h" +#include <memory> +#include <string> +#include <vector> + +namespace llvm { +namespace dsymutil { + +class BinaryHolder; + +/// Extract the DebugMaps from the given file. +/// The file has to be a MachO object file. Multiple debug maps can be +/// returned when the file is universal (aka fat) binary. +ErrorOr<std::vector<std::unique_ptr<DebugMap>>> +parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + StringRef InputFile, ArrayRef<std::string> Archs, + StringRef PrependPath, bool PaperTrailWarnings, bool Verbose, + bool InputIsYAML); + +/// Dump the symbol table. +bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + StringRef InputFile, ArrayRef<std::string> Archs, + StringRef PrependPath = ""); + +/// Link the Dwarf debug info as directed by the passed DebugMap \p DM into a +/// DwarfFile named \p OutputFilename. \returns false if the link failed. +bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, + const DebugMap &DM, LinkOptions Options); + +} // end namespace dsymutil +} // end namespace llvm + +#endif // LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H diff --git a/contrib/libs/llvm12/tools/dsymutil/ya.make b/contrib/libs/llvm12/tools/dsymutil/ya.make index 8a3b747e01..2ebc7666d2 100644 --- a/contrib/libs/llvm12/tools/dsymutil/ya.make +++ b/contrib/libs/llvm12/tools/dsymutil/ya.make @@ -1,17 +1,17 @@ -# Generated by devtools/yamaker. - -PROGRAM() - +# Generated by devtools/yamaker. + +PROGRAM() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) - + LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/include contrib/libs/llvm12/lib/Analysis @@ -70,29 +70,29 @@ PEERDIR( contrib/libs/llvm12/lib/Transforms/Scalar contrib/libs/llvm12/lib/Transforms/Utils contrib/libs/llvm12/lib/Transforms/Vectorize -) - -ADDINCL( +) + +ADDINCL( ${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/dsymutil contrib/libs/llvm12/tools/dsymutil -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - BinaryHolder.cpp - CFBundle.cpp - DebugMap.cpp - DwarfLinkerForBinary.cpp - MachODebugMapParser.cpp - MachOUtils.cpp - Reproducer.cpp - SymbolMap.cpp - dsymutil.cpp -) - +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + BinaryHolder.cpp + CFBundle.cpp + DebugMap.cpp + DwarfLinkerForBinary.cpp + MachODebugMapParser.cpp + MachOUtils.cpp + Reproducer.cpp + SymbolMap.cpp + dsymutil.cpp +) + IF (OS_DARWIN AND ARCH_AARCH64) LDFLAGS( -framework @@ -100,4 +100,4 @@ IF (OS_DARWIN AND ARCH_AARCH64) ) ENDIF() -END() +END() |