aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/tools/dsymutil
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/llvm12/tools/dsymutil
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/llvm12/tools/dsymutil')
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/.yandex_meta/licenses.list.txt7
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp285
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h172
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp185
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/CFBundle.h30
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp294
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/DebugMap.h272
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp788
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h220
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/LinkUtils.h107
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp609
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp624
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/MachOUtils.h52
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/Options.td187
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp85
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/Reproducer.h77
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp161
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/SymbolMap.h53
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp691
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/dsymutil.h56
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/ya.make103
21 files changed, 5058 insertions, 0 deletions
diff --git a/contrib/libs/llvm12/tools/dsymutil/.yandex_meta/licenses.list.txt b/contrib/libs/llvm12/tools/dsymutil/.yandex_meta/licenses.list.txt
new file mode 100644
index 0000000000..c62d353021
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/.yandex_meta/licenses.list.txt
@@ -0,0 +1,7 @@
+====================Apache-2.0 WITH LLVM-exception====================
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+
+
+====================Apache-2.0 WITH LLVM-exception====================
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
diff --git a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp
new file mode 100644
index 0000000000..f83521346c
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp
@@ -0,0 +1,285 @@
+//===-- 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);
+
+ if (Filename != "-" && Timestamp != sys::TimePoint<>()) {
+ llvm::ErrorOr<vfs::Status> Stat = VFS->status(Filename);
+ if (!Stat)
+ return errorCodeToError(Stat.getError());
+ if (Timestamp != std::chrono::time_point_cast<std::chrono::seconds>(
+ Stat->getLastModificationTime()))
+ WithColor::warning() << Filename
+ << ": timestamp mismatch between object file ("
+ << Stat->getLastModificationTime()
+ << ") 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<>() &&
+ Timestamp != std::chrono::time_point_cast<std::chrono::seconds>(
+ ModTimeOrErr.get())) {
+ 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];
+ 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
diff --git a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h
new file mode 100644
index 0000000000..5e81fe4b93
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h
@@ -0,0 +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,
+ 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
diff --git a/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp b/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp
new file mode 100644
index 0000000000..0625afb18a
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp
@@ -0,0 +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
diff --git a/contrib/libs/llvm12/tools/dsymutil/CFBundle.h b/contrib/libs/llvm12/tools/dsymutil/CFBundle.h
new file mode 100644
index 0000000000..103db03516
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/CFBundle.h
@@ -0,0 +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
diff --git a/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp b/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp
new file mode 100644
index 0000000000..605c1317b9
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp
@@ -0,0 +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());
+ 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
diff --git a/contrib/libs/llvm12/tools/dsymutil/DebugMap.h b/contrib/libs/llvm12/tools/dsymutil/DebugMap.h
new file mode 100644
index 0000000000..ee552ed983
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/DebugMap.h
@@ -0,0 +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
diff --git a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp
new file mode 100644
index 0000000000..29408e7c49
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -0,0 +1,788 @@
+//===- 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));
+
+ 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,
+ 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<>.
+ 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 {
+ 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,
+ 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;
+ 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)) {
+ 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,
+ 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))
+ findValidRelocsMachO(Section, *MachOObj, DMO, Relocs);
+ 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.
+ llvm::sort(Relocs);
+ 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.
+bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
+ 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("._"));
+ 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(),
+ ValidDebugAddrRelocs.end(), Offset);
+ return It != ValidDebugAddrRelocs.end();
+}
+
+bool DwarfLinkerForBinary::AddressManager::hasValidDebugInfoRelocationAt(
+ uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) {
+ assert(NextValidReloc == 0 ||
+ StartOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset);
+ if (NextValidReloc >= ValidDebugInfoRelocs.size())
+ 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.
+ while (RelocOffset < StartOffset &&
+ NextValidReloc < ValidDebugInfoRelocs.size() - 1)
+ RelocOffset = ValidDebugInfoRelocs[++NextValidReloc].Offset;
+
+ 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;
+}
+
+/// 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
+/// by \p Abbrev.
+/// \return [StartOffset, EndOffset) as a pair.
+static std::pair<uint64_t, uint64_t>
+getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
+ uint64_t Offset, const DWARFUnit &Unit) {
+ DataExtractor Data = Unit.getDebugInfoExtractor();
+
+ for (unsigned I = 0; I < Idx; ++I)
+ DWARFFormValue::skipValue(Abbrev->getFormByIndex(I), Data, &Offset,
+ Unit.getFormParams());
+
+ uint64_t End = Offset;
+ DWARFFormValue::skipValue(Abbrev->getFormByIndex(Idx), Data, &End,
+ Unit.getFormParams());
+
+ return std::make_pair(Offset, End);
+}
+
+bool DwarfLinkerForBinary::AddressManager::hasLiveMemoryLocation(
+ const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo) {
+ const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
+
+ Optional<uint32_t> LocationIdx =
+ Abbrev->findAttributeIndex(dwarf::DW_AT_location);
+ if (!LocationIdx)
+ return false;
+
+ uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
+ uint64_t LocationOffset, LocationEndOffset;
+ std::tie(LocationOffset, LocationEndOffset) =
+ getAttributeOffsets(Abbrev, *LocationIdx, Offset, *DIE.getDwarfUnit());
+
+ // FIXME: Support relocations debug_addr.
+ return hasValidDebugInfoRelocationAt(LocationOffset, LocationEndOffset,
+ MyInfo);
+}
+
+bool DwarfLinkerForBinary::AddressManager::hasLiveAddressRange(
+ const DWARFDie &DIE, CompileUnit::DIEInfo &MyInfo) {
+ const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
+
+ Optional<uint32_t> LowPcIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc);
+ if (!LowPcIdx)
+ return false;
+
+ dwarf::Form Form = Abbrev->getFormByIndex(*LowPcIdx);
+
+ if (Form == dwarf::DW_FORM_addr) {
+ uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
+ uint64_t LowPcOffset, LowPcEndOffset;
+ std::tie(LowPcOffset, LowPcEndOffset) =
+ getAttributeOffsets(Abbrev, *LowPcIdx, Offset, *DIE.getDwarfUnit());
+ return hasValidDebugInfoRelocationAt(LowPcOffset, LowPcEndOffset, MyInfo);
+ }
+
+ if (Form == dwarf::DW_FORM_addrx) {
+ Optional<DWARFFormValue> AddrValue = DIE.find(dwarf::DW_AT_low_pc);
+ return hasValidDebugAddrRelocationAt(*AddrValue->getAsAddress());
+ }
+
+ 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 ||
+ BaseOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset) &&
+ "BaseOffset should only be increasing.");
+ if (NextValidReloc >= ValidDebugInfoRelocs.size())
+ 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();
+ 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;
+}
+
+llvm::Expected<uint64_t>
+DwarfLinkerForBinary::AddressManager::relocateIndexedAddr(uint64_t Offset) {
+ auto It = std::lower_bound(ValidDebugAddrRelocs.begin(),
+ ValidDebugAddrRelocs.end(), Offset);
+ if (It == ValidDebugAddrRelocs.end())
+ return createStringError(
+ std::make_error_code(std::errc::invalid_argument),
+ "no relocation for offset %llu in debug_addr section", 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
diff --git a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h
new file mode 100644
index 0000000000..c6c07d689f
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h
@@ -0,0 +1,220 @@
+//===- 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.
+ /// {
+ 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) {
+ 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;
+ return !ValidDebugInfoRelocs.empty() || !ValidDebugAddrRelocs.empty();
+ }
+
+ /// \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,
+ const DebugMapObject &DMO,
+ std::vector<ValidReloc> &ValidRelocs);
+
+ 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.
+ ///
+ /// This function must be called with offsets in strictly ascending order
+ /// because it never looks back at relocations it already 'went past'.
+ /// \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);
+
+ bool hasLiveMemoryLocation(const DWARFDie &DIE,
+ CompileUnit::DIEInfo &Info) override;
+ bool hasLiveAddressRange(const DWARFDie &DIE,
+ CompileUnit::DIEInfo &Info) 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();
+ 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);
+ 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;
+ 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
diff --git a/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h b/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h
new file mode 100644
index 0000000000..52b36353c6
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h
@@ -0,0 +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
diff --git a/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp b/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp
new file mode 100644
index 0000000000..37848c561a
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp
@@ -0,0 +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;
+ 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
diff --git a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp
new file mode 100644
index 0000000000..943af43058
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp
@@ -0,0 +1,624 @@
+//===-- 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.
+//
+// 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 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,
+ 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("__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);
+ } 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);
+ 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 we have a valid eh_frame to copy, do it.
+ uint64_t EHFrameSize = 0;
+ StringRef EHFrameData;
+ for (const object::SectionRef &Section : InputBinary.sections()) {
+ Expected<StringRef> NameOrErr = Section.getName();
+ if (!NameOrErr) {
+ consumeError(NameOrErr.takeError());
+ continue;
+ }
+ StringRef SectionName = *NameOrErr;
+ SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
+ if (SectionName == "eh_frame") {
+ if (Expected<StringRef> ContentsOrErr = Section.getContents()) {
+ EHFrameData = *ContentsOrErr;
+ EHFrameSize = Section.getSize();
+ } else {
+ consumeError(ContentsOrErr.takeError());
+ }
+ }
+ }
+
+ 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)
+ 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)
+ 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);
+
+ // Pad till the EH frame start.
+ OutFile.write_zeros(EHFrameStart - (StringStart + NewStringsSize));
+ assert(OutFile.tell() == EHFrameStart);
+
+ // Transfer eh_frame.
+ if (EHFrameSize > 0)
+ OutFile << EHFrameData;
+ assert(OutFile.tell() == EHFrameStart + EHFrameSize);
+
+ // 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
diff --git a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h
new file mode 100644
index 0000000000..b1cdd44d38
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h
@@ -0,0 +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
diff --git a/contrib/libs/llvm12/tools/dsymutil/Options.td b/contrib/libs/llvm12/tools/dsymutil/Options.td
new file mode 100644
index 0000000000..7bd21b0d43
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/Options.td
@@ -0,0 +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>;
diff --git a/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp b/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp
new file mode 100644
index 0000000000..5c60758c6f
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp
@@ -0,0 +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.");
+}
diff --git a/contrib/libs/llvm12/tools/dsymutil/Reproducer.h b/contrib/libs/llvm12/tools/dsymutil/Reproducer.h
new file mode 100644
index 0000000000..e965e1ceda
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/Reproducer.h
@@ -0,0 +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
diff --git a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp
new file mode 100644
index 0000000000..07a54795a8
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp
@@ -0,0 +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
+ // `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
diff --git a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h
new file mode 100644
index 0000000000..977de31a5a
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h
@@ -0,0 +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
diff --git a/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp b/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp
new file mode 100644
index 0000000000..347b2dd916
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp
@@ -0,0 +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"
+#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);
+ }
+
+ 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;
+}
diff --git a/contrib/libs/llvm12/tools/dsymutil/dsymutil.h b/contrib/libs/llvm12/tools/dsymutil/dsymutil.h
new file mode 100644
index 0000000000..f88f57bb20
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/dsymutil.h
@@ -0,0 +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
diff --git a/contrib/libs/llvm12/tools/dsymutil/ya.make b/contrib/libs/llvm12/tools/dsymutil/ya.make
new file mode 100644
index 0000000000..8a3b747e01
--- /dev/null
+++ b/contrib/libs/llvm12/tools/dsymutil/ya.make
@@ -0,0 +1,103 @@
+# 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(
+ contrib/libs/llvm12
+ contrib/libs/llvm12/include
+ contrib/libs/llvm12/lib/Analysis
+ contrib/libs/llvm12/lib/AsmParser
+ contrib/libs/llvm12/lib/BinaryFormat
+ contrib/libs/llvm12/lib/Bitcode/Reader
+ contrib/libs/llvm12/lib/Bitcode/Writer
+ contrib/libs/llvm12/lib/Bitstream/Reader
+ contrib/libs/llvm12/lib/CodeGen
+ contrib/libs/llvm12/lib/CodeGen/AsmPrinter
+ contrib/libs/llvm12/lib/CodeGen/GlobalISel
+ contrib/libs/llvm12/lib/CodeGen/SelectionDAG
+ contrib/libs/llvm12/lib/DWARFLinker
+ contrib/libs/llvm12/lib/DebugInfo/CodeView
+ contrib/libs/llvm12/lib/DebugInfo/DWARF
+ contrib/libs/llvm12/lib/Demangle
+ contrib/libs/llvm12/lib/Frontend/OpenMP
+ contrib/libs/llvm12/lib/IR
+ contrib/libs/llvm12/lib/IRReader
+ contrib/libs/llvm12/lib/Linker
+ contrib/libs/llvm12/lib/MC
+ contrib/libs/llvm12/lib/MC/MCDisassembler
+ contrib/libs/llvm12/lib/MC/MCParser
+ contrib/libs/llvm12/lib/Object
+ contrib/libs/llvm12/lib/Option
+ contrib/libs/llvm12/lib/ProfileData
+ contrib/libs/llvm12/lib/Remarks
+ contrib/libs/llvm12/lib/Support
+ contrib/libs/llvm12/lib/Target
+ contrib/libs/llvm12/lib/Target/AArch64
+ contrib/libs/llvm12/lib/Target/AArch64/MCTargetDesc
+ contrib/libs/llvm12/lib/Target/AArch64/TargetInfo
+ contrib/libs/llvm12/lib/Target/AArch64/Utils
+ contrib/libs/llvm12/lib/Target/ARM
+ contrib/libs/llvm12/lib/Target/ARM/MCTargetDesc
+ contrib/libs/llvm12/lib/Target/ARM/TargetInfo
+ contrib/libs/llvm12/lib/Target/ARM/Utils
+ contrib/libs/llvm12/lib/Target/BPF
+ contrib/libs/llvm12/lib/Target/BPF/MCTargetDesc
+ contrib/libs/llvm12/lib/Target/BPF/TargetInfo
+ contrib/libs/llvm12/lib/Target/NVPTX
+ contrib/libs/llvm12/lib/Target/NVPTX/MCTargetDesc
+ contrib/libs/llvm12/lib/Target/NVPTX/TargetInfo
+ contrib/libs/llvm12/lib/Target/PowerPC
+ contrib/libs/llvm12/lib/Target/PowerPC/MCTargetDesc
+ contrib/libs/llvm12/lib/Target/PowerPC/TargetInfo
+ contrib/libs/llvm12/lib/Target/X86
+ contrib/libs/llvm12/lib/Target/X86/MCTargetDesc
+ contrib/libs/llvm12/lib/Target/X86/TargetInfo
+ contrib/libs/llvm12/lib/TextAPI/MachO
+ contrib/libs/llvm12/lib/Transforms/AggressiveInstCombine
+ contrib/libs/llvm12/lib/Transforms/CFGuard
+ contrib/libs/llvm12/lib/Transforms/IPO
+ contrib/libs/llvm12/lib/Transforms/InstCombine
+ contrib/libs/llvm12/lib/Transforms/Instrumentation
+ contrib/libs/llvm12/lib/Transforms/Scalar
+ contrib/libs/llvm12/lib/Transforms/Utils
+ contrib/libs/llvm12/lib/Transforms/Vectorize
+)
+
+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
+)
+
+IF (OS_DARWIN AND ARCH_AARCH64)
+ LDFLAGS(
+ -framework
+ CoreFoundation
+ )
+ENDIF()
+
+END()