aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/tools
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:44:49 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:49 +0300
commit718c552901d703c502ccbefdfc3c9028d608b947 (patch)
tree46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/libs/llvm12/tools
parente9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff)
downloadydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/llvm12/tools')
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp526
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h342
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp370
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/CFBundle.h60
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp586
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/DebugMap.h544
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp1320
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h368
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/LinkUtils.h214
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp1216
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp1122
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/MachOUtils.h104
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/Options.td374
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp170
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/Reproducer.h154
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp320
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/SymbolMap.h106
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp1378
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/dsymutil.h112
-rw-r--r--contrib/libs/llvm12/tools/dsymutil/ya.make58
-rw-r--r--contrib/libs/llvm12/tools/llvm-cvtres/Opts.td38
-rw-r--r--contrib/libs/llvm12/tools/llvm-cvtres/llvm-cvtres.cpp418
-rw-r--r--contrib/libs/llvm12/tools/llvm-cvtres/ya.make42
-rw-r--r--contrib/libs/llvm12/tools/llvm-lipo/LipoOpts.td120
-rw-r--r--contrib/libs/llvm12/tools/llvm-lipo/llvm-lipo.cpp1252
-rw-r--r--contrib/libs/llvm12/tools/llvm-lipo/ya.make42
-rw-r--r--contrib/libs/llvm12/tools/llvm-ml/Disassembler.cpp406
-rw-r--r--contrib/libs/llvm12/tools/llvm-ml/Disassembler.h74
-rw-r--r--contrib/libs/llvm12/tools/llvm-ml/llvm-ml.cpp414
-rw-r--r--contrib/libs/llvm12/tools/llvm-ml/ya.make44
-rw-r--r--contrib/libs/llvm12/tools/llvm-mt/Opts.td60
-rw-r--r--contrib/libs/llvm12/tools/llvm-mt/llvm-mt.cpp304
-rw-r--r--contrib/libs/llvm12/tools/llvm-mt/ya.make42
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/Buffer.cpp158
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/Buffer.h136
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.cpp538
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.h62
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.cpp200
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.h418
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.cpp452
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.h84
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.cpp898
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.h124
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/CommonOpts.td250
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.cpp2124
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.h560
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp266
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h88
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp1556
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h72
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp4204
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h1926
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/InstallNameToolOpts.td68
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp772
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.h96
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.cpp734
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.h62
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.cpp622
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.h102
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.cpp1026
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.h134
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.cpp298
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.h696
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/ObjcopyOpts.td458
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/StripOpts.td40
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.cpp644
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.h42
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.cpp66
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.h94
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.cpp66
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.h62
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.cpp226
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.h62
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.cpp156
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.h100
-rw-r--r--contrib/libs/llvm12/tools/llvm-objcopy/ya.make78
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/Opts.td66
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp3098
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h434
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp222
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h68
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp1708
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h384
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp588
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h1900
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp734
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h162
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def78
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h122
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp406
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ya.make52
-rw-r--r--contrib/libs/llvm12/tools/llvm-symbolizer/llvm-symbolizer.cpp332
-rw-r--r--contrib/libs/llvm12/tools/llvm-symbolizer/ya.make42
93 files changed, 21958 insertions, 21958 deletions
diff --git a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp
index f83521346c..6a90549be5 100644
--- a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp
+++ b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.cpp
@@ -1,101 +1,101 @@
-//===-- BinaryHolder.cpp --------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This program is a utility that aims to be a dropin replacement for
-// Darwin's dsymutil.
-//
-//===----------------------------------------------------------------------===//
-
-#include "BinaryHolder.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace llvm {
-namespace dsymutil {
-
-static std::pair<StringRef, StringRef>
-getArchiveAndObjectName(StringRef Filename) {
- StringRef Archive = Filename.substr(0, Filename.rfind('('));
- StringRef Object = Filename.substr(Archive.size() + 1).drop_back();
- return {Archive, Object};
-}
-
-static bool isArchive(StringRef Filename) { return Filename.endswith(")"); }
-
-static std::vector<MemoryBufferRef>
-getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
- object::MachOUniversalBinary &Fat) {
- std::vector<MemoryBufferRef> Buffers;
- StringRef FatData = Fat.getData();
- for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End;
- ++It) {
- StringRef ObjData = FatData.substr(It->getOffset(), It->getSize());
- Buffers.emplace_back(ObjData, Filename);
- }
- return Buffers;
-}
-
-Error BinaryHolder::ArchiveEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- StringRef Filename,
- TimestampTy Timestamp, bool Verbose) {
- StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first;
-
- // Try to load archive and force it to be memory mapped.
- auto ErrOrBuff = (ArchiveFilename == "-")
- ? MemoryBuffer::getSTDIN()
- : VFS->getBufferForFile(ArchiveFilename, -1, false);
- if (auto Err = ErrOrBuff.getError())
- return errorCodeToError(Err);
-
- MemBuffer = std::move(*ErrOrBuff);
-
- if (Verbose)
- WithColor::note() << "loaded archive '" << ArchiveFilename << "'\n";
-
- // Load one or more archive buffers, depending on whether we're dealing with
- // a fat binary.
- std::vector<MemoryBufferRef> ArchiveBuffers;
-
- auto ErrOrFat =
- object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef());
- if (!ErrOrFat) {
- consumeError(ErrOrFat.takeError());
- ArchiveBuffers.push_back(MemBuffer->getMemBufferRef());
- } else {
- FatBinary = std::move(*ErrOrFat);
- FatBinaryName = std::string(ArchiveFilename);
- ArchiveBuffers =
- getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary);
- }
-
- // Finally, try to load the archives.
- Archives.reserve(ArchiveBuffers.size());
- for (auto MemRef : ArchiveBuffers) {
- auto ErrOrArchive = object::Archive::create(MemRef);
- if (!ErrOrArchive)
- return ErrOrArchive.takeError();
- Archives.push_back(std::move(*ErrOrArchive));
- }
-
- return Error::success();
-}
-
-Error BinaryHolder::ObjectEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+//===-- BinaryHolder.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is a utility that aims to be a dropin replacement for
+// Darwin's dsymutil.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BinaryHolder.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace dsymutil {
+
+static std::pair<StringRef, StringRef>
+getArchiveAndObjectName(StringRef Filename) {
+ StringRef Archive = Filename.substr(0, Filename.rfind('('));
+ StringRef Object = Filename.substr(Archive.size() + 1).drop_back();
+ return {Archive, Object};
+}
+
+static bool isArchive(StringRef Filename) { return Filename.endswith(")"); }
+
+static std::vector<MemoryBufferRef>
+getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
+ object::MachOUniversalBinary &Fat) {
+ std::vector<MemoryBufferRef> Buffers;
+ StringRef FatData = Fat.getData();
+ for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End;
+ ++It) {
+ StringRef ObjData = FatData.substr(It->getOffset(), It->getSize());
+ Buffers.emplace_back(ObjData, Filename);
+ }
+ return Buffers;
+}
+
+Error BinaryHolder::ArchiveEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ StringRef Filename,
+ TimestampTy Timestamp, bool Verbose) {
+ StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first;
+
+ // Try to load archive and force it to be memory mapped.
+ auto ErrOrBuff = (ArchiveFilename == "-")
+ ? MemoryBuffer::getSTDIN()
+ : VFS->getBufferForFile(ArchiveFilename, -1, false);
+ if (auto Err = ErrOrBuff.getError())
+ return errorCodeToError(Err);
+
+ MemBuffer = std::move(*ErrOrBuff);
+
+ if (Verbose)
+ WithColor::note() << "loaded archive '" << ArchiveFilename << "'\n";
+
+ // Load one or more archive buffers, depending on whether we're dealing with
+ // a fat binary.
+ std::vector<MemoryBufferRef> ArchiveBuffers;
+
+ auto ErrOrFat =
+ object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef());
+ if (!ErrOrFat) {
+ consumeError(ErrOrFat.takeError());
+ ArchiveBuffers.push_back(MemBuffer->getMemBufferRef());
+ } else {
+ FatBinary = std::move(*ErrOrFat);
+ FatBinaryName = std::string(ArchiveFilename);
+ ArchiveBuffers =
+ getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary);
+ }
+
+ // Finally, try to load the archives.
+ Archives.reserve(ArchiveBuffers.size());
+ for (auto MemRef : ArchiveBuffers) {
+ auto ErrOrArchive = object::Archive::create(MemRef);
+ if (!ErrOrArchive)
+ return ErrOrArchive.takeError();
+ Archives.push_back(std::move(*ErrOrArchive));
+ }
+
+ return Error::success();
+}
+
+Error BinaryHolder::ObjectEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
StringRef Filename, TimestampTy Timestamp,
bool Verbose) {
- // Try to load regular binary and force it to be memory mapped.
- auto ErrOrBuff = (Filename == "-")
- ? MemoryBuffer::getSTDIN()
- : VFS->getBufferForFile(Filename, -1, false);
- if (auto Err = ErrOrBuff.getError())
- return errorCodeToError(Err);
-
+ // Try to load regular binary and force it to be memory mapped.
+ auto ErrOrBuff = (Filename == "-")
+ ? MemoryBuffer::getSTDIN()
+ : VFS->getBufferForFile(Filename, -1, false);
+ if (auto Err = ErrOrBuff.getError())
+ return errorCodeToError(Err);
+
if (Filename != "-" && Timestamp != sys::TimePoint<>()) {
llvm::ErrorOr<vfs::Status> Stat = VFS->status(Filename);
if (!Stat)
@@ -108,178 +108,178 @@ Error BinaryHolder::ObjectEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
<< ") and debug map (" << Timestamp << ")\n";
}
- MemBuffer = std::move(*ErrOrBuff);
-
- if (Verbose)
- WithColor::note() << "loaded object.\n";
-
- // Load one or more object buffers, depending on whether we're dealing with a
- // fat binary.
- std::vector<MemoryBufferRef> ObjectBuffers;
-
- auto ErrOrFat =
- object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef());
- if (!ErrOrFat) {
- consumeError(ErrOrFat.takeError());
- ObjectBuffers.push_back(MemBuffer->getMemBufferRef());
- } else {
- FatBinary = std::move(*ErrOrFat);
- FatBinaryName = std::string(Filename);
- ObjectBuffers =
- getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary);
- }
-
- Objects.reserve(ObjectBuffers.size());
- for (auto MemRef : ObjectBuffers) {
- auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemRef);
- if (!ErrOrObjectFile)
- return ErrOrObjectFile.takeError();
- Objects.push_back(std::move(*ErrOrObjectFile));
- }
-
- return Error::success();
-}
-
-std::vector<const object::ObjectFile *>
-BinaryHolder::ObjectEntry::getObjects() const {
- std::vector<const object::ObjectFile *> Result;
- Result.reserve(Objects.size());
- for (auto &Object : Objects) {
- Result.push_back(Object.get());
- }
- return Result;
-}
-Expected<const object::ObjectFile &>
-BinaryHolder::ObjectEntry::getObject(const Triple &T) const {
- for (const auto &Obj : Objects) {
- if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) {
- if (MachO->getArchTriple().str() == T.str())
- return *MachO;
- } else if (Obj->getArch() == T.getArch())
- return *Obj;
- }
- return errorCodeToError(object::object_error::arch_not_found);
-}
-
-Expected<const BinaryHolder::ObjectEntry &>
-BinaryHolder::ArchiveEntry::getObjectEntry(StringRef Filename,
- TimestampTy Timestamp,
- bool Verbose) {
- StringRef ArchiveFilename;
- StringRef ObjectFilename;
- std::tie(ArchiveFilename, ObjectFilename) = getArchiveAndObjectName(Filename);
-
- // Try the cache first.
- KeyTy Key = {ObjectFilename, Timestamp};
-
- {
- std::lock_guard<std::mutex> Lock(MemberCacheMutex);
- if (MemberCache.count(Key))
- return MemberCache[Key];
- }
-
- // Create a new ObjectEntry, but don't add it to the cache yet. Loading of
- // the archive members might fail and we don't want to lock the whole archive
- // during this operation.
- ObjectEntry OE;
-
- for (const auto &Archive : Archives) {
- Error Err = Error::success();
- for (auto Child : Archive->children(Err)) {
- if (auto NameOrErr = Child.getName()) {
- if (*NameOrErr == ObjectFilename) {
- auto ModTimeOrErr = Child.getLastModified();
- if (!ModTimeOrErr)
- return ModTimeOrErr.takeError();
-
- if (Timestamp != sys::TimePoint<>() &&
+ MemBuffer = std::move(*ErrOrBuff);
+
+ if (Verbose)
+ WithColor::note() << "loaded object.\n";
+
+ // Load one or more object buffers, depending on whether we're dealing with a
+ // fat binary.
+ std::vector<MemoryBufferRef> ObjectBuffers;
+
+ auto ErrOrFat =
+ object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef());
+ if (!ErrOrFat) {
+ consumeError(ErrOrFat.takeError());
+ ObjectBuffers.push_back(MemBuffer->getMemBufferRef());
+ } else {
+ FatBinary = std::move(*ErrOrFat);
+ FatBinaryName = std::string(Filename);
+ ObjectBuffers =
+ getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary);
+ }
+
+ Objects.reserve(ObjectBuffers.size());
+ for (auto MemRef : ObjectBuffers) {
+ auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemRef);
+ if (!ErrOrObjectFile)
+ return ErrOrObjectFile.takeError();
+ Objects.push_back(std::move(*ErrOrObjectFile));
+ }
+
+ return Error::success();
+}
+
+std::vector<const object::ObjectFile *>
+BinaryHolder::ObjectEntry::getObjects() const {
+ std::vector<const object::ObjectFile *> Result;
+ Result.reserve(Objects.size());
+ for (auto &Object : Objects) {
+ Result.push_back(Object.get());
+ }
+ return Result;
+}
+Expected<const object::ObjectFile &>
+BinaryHolder::ObjectEntry::getObject(const Triple &T) const {
+ for (const auto &Obj : Objects) {
+ if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) {
+ if (MachO->getArchTriple().str() == T.str())
+ return *MachO;
+ } else if (Obj->getArch() == T.getArch())
+ return *Obj;
+ }
+ return errorCodeToError(object::object_error::arch_not_found);
+}
+
+Expected<const BinaryHolder::ObjectEntry &>
+BinaryHolder::ArchiveEntry::getObjectEntry(StringRef Filename,
+ TimestampTy Timestamp,
+ bool Verbose) {
+ StringRef ArchiveFilename;
+ StringRef ObjectFilename;
+ std::tie(ArchiveFilename, ObjectFilename) = getArchiveAndObjectName(Filename);
+
+ // Try the cache first.
+ KeyTy Key = {ObjectFilename, Timestamp};
+
+ {
+ std::lock_guard<std::mutex> Lock(MemberCacheMutex);
+ if (MemberCache.count(Key))
+ return MemberCache[Key];
+ }
+
+ // Create a new ObjectEntry, but don't add it to the cache yet. Loading of
+ // the archive members might fail and we don't want to lock the whole archive
+ // during this operation.
+ ObjectEntry OE;
+
+ for (const auto &Archive : Archives) {
+ Error Err = Error::success();
+ for (auto Child : Archive->children(Err)) {
+ if (auto NameOrErr = Child.getName()) {
+ if (*NameOrErr == ObjectFilename) {
+ auto ModTimeOrErr = Child.getLastModified();
+ if (!ModTimeOrErr)
+ return ModTimeOrErr.takeError();
+
+ if (Timestamp != sys::TimePoint<>() &&
Timestamp != std::chrono::time_point_cast<std::chrono::seconds>(
ModTimeOrErr.get())) {
- if (Verbose)
+ if (Verbose)
WithColor::warning()
<< *NameOrErr
<< ": timestamp mismatch between archive member ("
<< ModTimeOrErr.get() << ") and debug map (" << Timestamp
<< ")\n";
- continue;
- }
-
- if (Verbose)
- WithColor::note() << "found member in archive.\n";
-
- auto ErrOrMem = Child.getMemoryBufferRef();
- if (!ErrOrMem)
- return ErrOrMem.takeError();
-
- auto ErrOrObjectFile =
- object::ObjectFile::createObjectFile(*ErrOrMem);
- if (!ErrOrObjectFile)
- return ErrOrObjectFile.takeError();
-
- OE.Objects.push_back(std::move(*ErrOrObjectFile));
- }
- }
- }
- if (Err)
- return std::move(Err);
- }
-
- if (OE.Objects.empty())
- return errorCodeToError(errc::no_such_file_or_directory);
-
- std::lock_guard<std::mutex> Lock(MemberCacheMutex);
- MemberCache.try_emplace(Key, std::move(OE));
- return MemberCache[Key];
-}
-
-Expected<const BinaryHolder::ObjectEntry &>
-BinaryHolder::getObjectEntry(StringRef Filename, TimestampTy Timestamp) {
- if (Verbose)
- WithColor::note() << "trying to open '" << Filename << "'\n";
-
- // If this is an archive, we might have either the object or the archive
- // cached. In this case we can load it without accessing the file system.
- if (isArchive(Filename)) {
- StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first;
- std::lock_guard<std::mutex> Lock(ArchiveCacheMutex);
- if (ArchiveCache.count(ArchiveFilename)) {
- return ArchiveCache[ArchiveFilename].getObjectEntry(Filename, Timestamp,
- Verbose);
- } else {
- ArchiveEntry &AE = ArchiveCache[ArchiveFilename];
- auto Err = AE.load(VFS, Filename, Timestamp, Verbose);
- if (Err) {
- ArchiveCache.erase(ArchiveFilename);
- // Don't return the error here: maybe the file wasn't an archive.
- llvm::consumeError(std::move(Err));
- } else {
- return ArchiveCache[ArchiveFilename].getObjectEntry(Filename, Timestamp,
- Verbose);
- }
- }
- }
-
- // If this is an object, we might have it cached. If not we'll have to load
- // it from the file system and cache it now.
- std::lock_guard<std::mutex> Lock(ObjectCacheMutex);
- if (!ObjectCache.count(Filename)) {
- ObjectEntry &OE = ObjectCache[Filename];
+ continue;
+ }
+
+ if (Verbose)
+ WithColor::note() << "found member in archive.\n";
+
+ auto ErrOrMem = Child.getMemoryBufferRef();
+ if (!ErrOrMem)
+ return ErrOrMem.takeError();
+
+ auto ErrOrObjectFile =
+ object::ObjectFile::createObjectFile(*ErrOrMem);
+ if (!ErrOrObjectFile)
+ return ErrOrObjectFile.takeError();
+
+ OE.Objects.push_back(std::move(*ErrOrObjectFile));
+ }
+ }
+ }
+ if (Err)
+ return std::move(Err);
+ }
+
+ if (OE.Objects.empty())
+ return errorCodeToError(errc::no_such_file_or_directory);
+
+ std::lock_guard<std::mutex> Lock(MemberCacheMutex);
+ MemberCache.try_emplace(Key, std::move(OE));
+ return MemberCache[Key];
+}
+
+Expected<const BinaryHolder::ObjectEntry &>
+BinaryHolder::getObjectEntry(StringRef Filename, TimestampTy Timestamp) {
+ if (Verbose)
+ WithColor::note() << "trying to open '" << Filename << "'\n";
+
+ // If this is an archive, we might have either the object or the archive
+ // cached. In this case we can load it without accessing the file system.
+ if (isArchive(Filename)) {
+ StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first;
+ std::lock_guard<std::mutex> Lock(ArchiveCacheMutex);
+ if (ArchiveCache.count(ArchiveFilename)) {
+ return ArchiveCache[ArchiveFilename].getObjectEntry(Filename, Timestamp,
+ Verbose);
+ } else {
+ ArchiveEntry &AE = ArchiveCache[ArchiveFilename];
+ auto Err = AE.load(VFS, Filename, Timestamp, Verbose);
+ if (Err) {
+ ArchiveCache.erase(ArchiveFilename);
+ // Don't return the error here: maybe the file wasn't an archive.
+ llvm::consumeError(std::move(Err));
+ } else {
+ return ArchiveCache[ArchiveFilename].getObjectEntry(Filename, Timestamp,
+ Verbose);
+ }
+ }
+ }
+
+ // If this is an object, we might have it cached. If not we'll have to load
+ // it from the file system and cache it now.
+ std::lock_guard<std::mutex> Lock(ObjectCacheMutex);
+ if (!ObjectCache.count(Filename)) {
+ ObjectEntry &OE = ObjectCache[Filename];
auto Err = OE.load(VFS, Filename, Timestamp, Verbose);
- if (Err) {
- ObjectCache.erase(Filename);
- return std::move(Err);
- }
- }
-
- return ObjectCache[Filename];
-}
-
-void BinaryHolder::clear() {
- std::lock_guard<std::mutex> ArchiveLock(ArchiveCacheMutex);
- std::lock_guard<std::mutex> ObjectLock(ObjectCacheMutex);
- ArchiveCache.clear();
- ObjectCache.clear();
-}
-
-} // namespace dsymutil
-} // namespace llvm
+ if (Err) {
+ ObjectCache.erase(Filename);
+ return std::move(Err);
+ }
+ }
+
+ return ObjectCache[Filename];
+}
+
+void BinaryHolder::clear() {
+ std::lock_guard<std::mutex> ArchiveLock(ArchiveCacheMutex);
+ std::lock_guard<std::mutex> ObjectLock(ObjectCacheMutex);
+ ArchiveCache.clear();
+ ObjectCache.clear();
+}
+
+} // namespace dsymutil
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h
index 5e81fe4b93..bf4bcb63b6 100644
--- a/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h
+++ b/contrib/libs/llvm12/tools/dsymutil/BinaryHolder.h
@@ -1,172 +1,172 @@
-//===-- BinaryHolder.h - Utility class for accessing binaries -------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This program is a utility that aims to be a dropin replacement for
-// Darwin's dsymutil.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
-#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Object/MachOUniversal.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/Chrono.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/VirtualFileSystem.h"
-
-#include <mutex>
-
-namespace llvm {
-namespace dsymutil {
-
-/// The BinaryHolder class is responsible for creating and owning
-/// ObjectFiles and their underlying MemoryBuffers. It differs from a simple
-/// OwningBinary in that it handles accessing and caching of archives and its
-/// members.
-class BinaryHolder {
-public:
- using TimestampTy = sys::TimePoint<std::chrono::seconds>;
-
- BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool Verbose = false)
- : VFS(VFS), Verbose(Verbose) {}
-
- // Forward declarations for friend declaration.
- class ObjectEntry;
- class ArchiveEntry;
-
- /// Base class shared by cached entries, representing objects and archives.
- class EntryBase {
- protected:
- std::unique_ptr<MemoryBuffer> MemBuffer;
- std::unique_ptr<object::MachOUniversalBinary> FatBinary;
- std::string FatBinaryName;
- };
-
- /// Cached entry holding one or more (in case of a fat binary) object files.
- class ObjectEntry : public EntryBase {
- public:
- /// Load the given object binary in memory.
- Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,
+//===-- BinaryHolder.h - Utility class for accessing binaries -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is a utility that aims to be a dropin replacement for
+// Darwin's dsymutil.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
+#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+#include <mutex>
+
+namespace llvm {
+namespace dsymutil {
+
+/// The BinaryHolder class is responsible for creating and owning
+/// ObjectFiles and their underlying MemoryBuffers. It differs from a simple
+/// OwningBinary in that it handles accessing and caching of archives and its
+/// members.
+class BinaryHolder {
+public:
+ using TimestampTy = sys::TimePoint<std::chrono::seconds>;
+
+ BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool Verbose = false)
+ : VFS(VFS), Verbose(Verbose) {}
+
+ // Forward declarations for friend declaration.
+ class ObjectEntry;
+ class ArchiveEntry;
+
+ /// Base class shared by cached entries, representing objects and archives.
+ class EntryBase {
+ protected:
+ std::unique_ptr<MemoryBuffer> MemBuffer;
+ std::unique_ptr<object::MachOUniversalBinary> FatBinary;
+ std::string FatBinaryName;
+ };
+
+ /// Cached entry holding one or more (in case of a fat binary) object files.
+ class ObjectEntry : public EntryBase {
+ public:
+ /// Load the given object binary in memory.
+ Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,
TimestampTy Timestamp, bool Verbose = false);
-
- /// Access all owned ObjectFiles.
- std::vector<const object::ObjectFile *> getObjects() const;
-
- /// Access to a derived version of all the currently owned ObjectFiles. The
- /// conversion might be invalid, in which case an Error is returned.
- template <typename ObjectFileType>
- Expected<std::vector<const ObjectFileType *>> getObjectsAs() const {
- std::vector<const ObjectFileType *> Result;
- Result.reserve(Objects.size());
- for (auto &Object : Objects) {
- const auto *Derived = dyn_cast<ObjectFileType>(Object.get());
- if (!Derived)
- return errorCodeToError(object::object_error::invalid_file_type);
- Result.push_back(Derived);
- }
- return Result;
- }
-
- /// Access the owned ObjectFile with architecture \p T.
- Expected<const object::ObjectFile &> getObject(const Triple &T) const;
-
- /// Access to a derived version of the currently owned ObjectFile with
- /// architecture \p T. The conversion must be known to be valid.
- template <typename ObjectFileType>
- Expected<const ObjectFileType &> getObjectAs(const Triple &T) const {
- auto Object = getObject(T);
- if (!Object)
- return Object.takeError();
- return cast<ObjectFileType>(*Object);
- }
-
- private:
- std::vector<std::unique_ptr<object::ObjectFile>> Objects;
- friend ArchiveEntry;
- };
-
- /// Cached entry holding one or more (in the of a fat binary) archive files.
- class ArchiveEntry : public EntryBase {
- public:
- struct KeyTy {
- std::string Filename;
- TimestampTy Timestamp;
-
- KeyTy() : Filename(), Timestamp() {}
- KeyTy(StringRef Filename, TimestampTy Timestamp)
- : Filename(Filename.str()), Timestamp(Timestamp) {}
- };
-
- /// Load the given object binary in memory.
- Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,
- TimestampTy Timestamp, bool Verbose = false);
-
- Expected<const ObjectEntry &> getObjectEntry(StringRef Filename,
- TimestampTy Timestamp,
- bool Verbose = false);
-
- private:
- std::vector<std::unique_ptr<object::Archive>> Archives;
- DenseMap<KeyTy, ObjectEntry> MemberCache;
- std::mutex MemberCacheMutex;
- };
-
- Expected<const ObjectEntry &>
- getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy());
-
- void clear();
-
-private:
- /// Cache of static archives. Objects that are part of a static archive are
- /// stored under this object, rather than in the map below.
- StringMap<ArchiveEntry> ArchiveCache;
- std::mutex ArchiveCacheMutex;
-
- /// Object entries for objects that are not in a static archive.
- StringMap<ObjectEntry> ObjectCache;
- std::mutex ObjectCacheMutex;
-
- /// Virtual File System instance.
- IntrusiveRefCntPtr<vfs::FileSystem> VFS;
-
- bool Verbose;
-};
-
-} // namespace dsymutil
-
-template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> {
-
- static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() {
- return dsymutil::BinaryHolder::ArchiveEntry::KeyTy();
- }
-
- static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() {
- return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {});
- }
-
- static unsigned
- getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) {
- return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename),
- DenseMapInfo<unsigned>::getHashValue(
- K.Timestamp.time_since_epoch().count()));
- }
-
- static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS,
- const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) {
- return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp;
- }
-};
-
-} // namespace llvm
-#endif
+
+ /// Access all owned ObjectFiles.
+ std::vector<const object::ObjectFile *> getObjects() const;
+
+ /// Access to a derived version of all the currently owned ObjectFiles. The
+ /// conversion might be invalid, in which case an Error is returned.
+ template <typename ObjectFileType>
+ Expected<std::vector<const ObjectFileType *>> getObjectsAs() const {
+ std::vector<const ObjectFileType *> Result;
+ Result.reserve(Objects.size());
+ for (auto &Object : Objects) {
+ const auto *Derived = dyn_cast<ObjectFileType>(Object.get());
+ if (!Derived)
+ return errorCodeToError(object::object_error::invalid_file_type);
+ Result.push_back(Derived);
+ }
+ return Result;
+ }
+
+ /// Access the owned ObjectFile with architecture \p T.
+ Expected<const object::ObjectFile &> getObject(const Triple &T) const;
+
+ /// Access to a derived version of the currently owned ObjectFile with
+ /// architecture \p T. The conversion must be known to be valid.
+ template <typename ObjectFileType>
+ Expected<const ObjectFileType &> getObjectAs(const Triple &T) const {
+ auto Object = getObject(T);
+ if (!Object)
+ return Object.takeError();
+ return cast<ObjectFileType>(*Object);
+ }
+
+ private:
+ std::vector<std::unique_ptr<object::ObjectFile>> Objects;
+ friend ArchiveEntry;
+ };
+
+ /// Cached entry holding one or more (in the of a fat binary) archive files.
+ class ArchiveEntry : public EntryBase {
+ public:
+ struct KeyTy {
+ std::string Filename;
+ TimestampTy Timestamp;
+
+ KeyTy() : Filename(), Timestamp() {}
+ KeyTy(StringRef Filename, TimestampTy Timestamp)
+ : Filename(Filename.str()), Timestamp(Timestamp) {}
+ };
+
+ /// Load the given object binary in memory.
+ Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,
+ TimestampTy Timestamp, bool Verbose = false);
+
+ Expected<const ObjectEntry &> getObjectEntry(StringRef Filename,
+ TimestampTy Timestamp,
+ bool Verbose = false);
+
+ private:
+ std::vector<std::unique_ptr<object::Archive>> Archives;
+ DenseMap<KeyTy, ObjectEntry> MemberCache;
+ std::mutex MemberCacheMutex;
+ };
+
+ Expected<const ObjectEntry &>
+ getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy());
+
+ void clear();
+
+private:
+ /// Cache of static archives. Objects that are part of a static archive are
+ /// stored under this object, rather than in the map below.
+ StringMap<ArchiveEntry> ArchiveCache;
+ std::mutex ArchiveCacheMutex;
+
+ /// Object entries for objects that are not in a static archive.
+ StringMap<ObjectEntry> ObjectCache;
+ std::mutex ObjectCacheMutex;
+
+ /// Virtual File System instance.
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS;
+
+ bool Verbose;
+};
+
+} // namespace dsymutil
+
+template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> {
+
+ static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() {
+ return dsymutil::BinaryHolder::ArchiveEntry::KeyTy();
+ }
+
+ static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() {
+ return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {});
+ }
+
+ static unsigned
+ getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) {
+ return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename),
+ DenseMapInfo<unsigned>::getHashValue(
+ K.Timestamp.time_since_epoch().count()));
+ }
+
+ static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS,
+ const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) {
+ return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp;
+ }
+};
+
+} // namespace llvm
+#endif
diff --git a/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp b/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp
index 0625afb18a..406c35cc59 100644
--- a/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp
+++ b/contrib/libs/llvm12/tools/dsymutil/CFBundle.cpp
@@ -1,185 +1,185 @@
-//===- tools/dsymutil/CFBundle.cpp - CFBundle helper ------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "CFBundle.h"
-
-#ifdef __APPLE__
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include <CoreFoundation/CoreFoundation.h>
-#include <assert.h>
-#include <glob.h>
-#include <memory>
-#endif
-
-namespace llvm {
-namespace dsymutil {
-
-#ifdef __APPLE__
-/// Deleter that calls CFRelease rather than deleting the pointer.
-template <typename T> struct CFDeleter {
- void operator()(T *P) {
- if (P)
- ::CFRelease(P);
- }
-};
-
-/// This helper owns any CoreFoundation pointer and will call CFRelease() on
-/// any valid pointer it owns unless that pointer is explicitly released using
-/// the release() member function.
-template <typename T>
-using CFReleaser = std::unique_ptr<std::remove_pointer_t<T>,
- CFDeleter<std::remove_pointer_t<T>>>;
-
-/// RAII wrapper around CFBundleRef.
-class CFString : public CFReleaser<CFStringRef> {
-public:
- CFString(CFStringRef CFStr = nullptr) : CFReleaser<CFStringRef>(CFStr) {}
-
- const char *UTF8(std::string &Str) const {
- return CFString::UTF8(get(), Str);
- }
-
- CFIndex GetLength() const {
- if (CFStringRef Str = get())
- return CFStringGetLength(Str);
- return 0;
- }
-
- static const char *UTF8(CFStringRef CFStr, std::string &Str);
-};
-
-/// Static function that puts a copy of the UTF-8 contents of CFStringRef into
-/// std::string and returns the C string pointer that is contained in the
-/// std::string when successful, nullptr otherwise.
-///
-/// This allows the std::string parameter to own the extracted string, and also
-/// allows that string to be returned as a C string pointer that can be used.
-const char *CFString::UTF8(CFStringRef CFStr, std::string &Str) {
- if (!CFStr)
- return nullptr;
-
- const CFStringEncoding Encoding = kCFStringEncodingUTF8;
- CFIndex MaxUTF8StrLength = CFStringGetLength(CFStr);
- MaxUTF8StrLength =
- CFStringGetMaximumSizeForEncoding(MaxUTF8StrLength, Encoding);
- if (MaxUTF8StrLength > 0) {
- Str.resize(MaxUTF8StrLength);
- if (!Str.empty() &&
- CFStringGetCString(CFStr, &Str[0], Str.size(), Encoding)) {
- Str.resize(strlen(Str.c_str()));
- return Str.c_str();
- }
- }
-
- return nullptr;
-}
-
-/// RAII wrapper around CFBundleRef.
-class CFBundle : public CFReleaser<CFBundleRef> {
-public:
- CFBundle(StringRef Path) : CFReleaser<CFBundleRef>() { SetFromPath(Path); }
-
- CFBundle(CFURLRef Url)
- : CFReleaser<CFBundleRef>(Url ? ::CFBundleCreate(nullptr, Url)
- : nullptr) {}
-
- /// Return the bundle identifier.
- CFStringRef GetIdentifier() const {
- if (CFBundleRef bundle = get())
- return ::CFBundleGetIdentifier(bundle);
- return nullptr;
- }
-
- /// Return value for key.
- CFTypeRef GetValueForInfoDictionaryKey(CFStringRef key) const {
- if (CFBundleRef bundle = get())
- return ::CFBundleGetValueForInfoDictionaryKey(bundle, key);
- return nullptr;
- }
-
-private:
- /// Helper to initialize this instance with a new bundle created from the
- /// given path. This function will recursively remove components from the
- /// path in its search for the nearest Info.plist.
- void SetFromPath(StringRef Path);
-};
-
-void CFBundle::SetFromPath(StringRef Path) {
- // Start from an empty/invalid CFBundle.
- reset();
-
- if (Path.empty() || !sys::fs::exists(Path))
- return;
-
- SmallString<256> RealPath;
- sys::fs::real_path(Path, RealPath, /*expand_tilde*/ true);
-
- do {
- // Create a CFURL from the current path and use it to create a CFBundle.
- CFReleaser<CFURLRef> BundleURL(::CFURLCreateFromFileSystemRepresentation(
- kCFAllocatorDefault, (const UInt8 *)RealPath.data(), RealPath.size(),
- false));
- reset(::CFBundleCreate(kCFAllocatorDefault, BundleURL.get()));
-
- // If we have a valid bundle and find its identifier we are done.
- if (get() != nullptr) {
- if (GetIdentifier() != nullptr)
- return;
- reset();
- }
-
- // Remove the last component of the path and try again until there's
- // nothing left but the root.
- sys::path::remove_filename(RealPath);
- } while (RealPath != sys::path::root_name(RealPath));
-}
-#endif
-
-/// On Darwin, try and find the original executable's Info.plist to extract
-/// information about the bundle. Return default values on other platforms.
-CFBundleInfo getBundleInfo(StringRef ExePath) {
- CFBundleInfo BundleInfo;
-
-#ifdef __APPLE__
- auto PrintError = [&](CFTypeID TypeID) {
- CFString TypeIDCFStr(::CFCopyTypeIDDescription(TypeID));
- std::string TypeIDStr;
- errs() << "The Info.plist key \"CFBundleShortVersionString\" is"
- << "a " << TypeIDCFStr.UTF8(TypeIDStr)
- << ", but it should be a string in: " << ExePath << ".\n";
- };
-
- CFBundle Bundle(ExePath);
- if (CFStringRef BundleID = Bundle.GetIdentifier()) {
- CFString::UTF8(BundleID, BundleInfo.IDStr);
- if (CFTypeRef TypeRef =
- Bundle.GetValueForInfoDictionaryKey(CFSTR("CFBundleVersion"))) {
- CFTypeID TypeID = ::CFGetTypeID(TypeRef);
- if (TypeID == ::CFStringGetTypeID())
- CFString::UTF8((CFStringRef)TypeRef, BundleInfo.VersionStr);
- else
- PrintError(TypeID);
- }
- if (CFTypeRef TypeRef = Bundle.GetValueForInfoDictionaryKey(
- CFSTR("CFBundleShortVersionString"))) {
- CFTypeID TypeID = ::CFGetTypeID(TypeRef);
- if (TypeID == ::CFStringGetTypeID())
- CFString::UTF8((CFStringRef)TypeRef, BundleInfo.ShortVersionStr);
- else
- PrintError(TypeID);
- }
- }
-#endif
-
- return BundleInfo;
-}
-
-} // end namespace dsymutil
-} // end namespace llvm
+//===- tools/dsymutil/CFBundle.cpp - CFBundle helper ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFBundle.h"
+
+#ifdef __APPLE__
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <assert.h>
+#include <glob.h>
+#include <memory>
+#endif
+
+namespace llvm {
+namespace dsymutil {
+
+#ifdef __APPLE__
+/// Deleter that calls CFRelease rather than deleting the pointer.
+template <typename T> struct CFDeleter {
+ void operator()(T *P) {
+ if (P)
+ ::CFRelease(P);
+ }
+};
+
+/// This helper owns any CoreFoundation pointer and will call CFRelease() on
+/// any valid pointer it owns unless that pointer is explicitly released using
+/// the release() member function.
+template <typename T>
+using CFReleaser = std::unique_ptr<std::remove_pointer_t<T>,
+ CFDeleter<std::remove_pointer_t<T>>>;
+
+/// RAII wrapper around CFBundleRef.
+class CFString : public CFReleaser<CFStringRef> {
+public:
+ CFString(CFStringRef CFStr = nullptr) : CFReleaser<CFStringRef>(CFStr) {}
+
+ const char *UTF8(std::string &Str) const {
+ return CFString::UTF8(get(), Str);
+ }
+
+ CFIndex GetLength() const {
+ if (CFStringRef Str = get())
+ return CFStringGetLength(Str);
+ return 0;
+ }
+
+ static const char *UTF8(CFStringRef CFStr, std::string &Str);
+};
+
+/// Static function that puts a copy of the UTF-8 contents of CFStringRef into
+/// std::string and returns the C string pointer that is contained in the
+/// std::string when successful, nullptr otherwise.
+///
+/// This allows the std::string parameter to own the extracted string, and also
+/// allows that string to be returned as a C string pointer that can be used.
+const char *CFString::UTF8(CFStringRef CFStr, std::string &Str) {
+ if (!CFStr)
+ return nullptr;
+
+ const CFStringEncoding Encoding = kCFStringEncodingUTF8;
+ CFIndex MaxUTF8StrLength = CFStringGetLength(CFStr);
+ MaxUTF8StrLength =
+ CFStringGetMaximumSizeForEncoding(MaxUTF8StrLength, Encoding);
+ if (MaxUTF8StrLength > 0) {
+ Str.resize(MaxUTF8StrLength);
+ if (!Str.empty() &&
+ CFStringGetCString(CFStr, &Str[0], Str.size(), Encoding)) {
+ Str.resize(strlen(Str.c_str()));
+ return Str.c_str();
+ }
+ }
+
+ return nullptr;
+}
+
+/// RAII wrapper around CFBundleRef.
+class CFBundle : public CFReleaser<CFBundleRef> {
+public:
+ CFBundle(StringRef Path) : CFReleaser<CFBundleRef>() { SetFromPath(Path); }
+
+ CFBundle(CFURLRef Url)
+ : CFReleaser<CFBundleRef>(Url ? ::CFBundleCreate(nullptr, Url)
+ : nullptr) {}
+
+ /// Return the bundle identifier.
+ CFStringRef GetIdentifier() const {
+ if (CFBundleRef bundle = get())
+ return ::CFBundleGetIdentifier(bundle);
+ return nullptr;
+ }
+
+ /// Return value for key.
+ CFTypeRef GetValueForInfoDictionaryKey(CFStringRef key) const {
+ if (CFBundleRef bundle = get())
+ return ::CFBundleGetValueForInfoDictionaryKey(bundle, key);
+ return nullptr;
+ }
+
+private:
+ /// Helper to initialize this instance with a new bundle created from the
+ /// given path. This function will recursively remove components from the
+ /// path in its search for the nearest Info.plist.
+ void SetFromPath(StringRef Path);
+};
+
+void CFBundle::SetFromPath(StringRef Path) {
+ // Start from an empty/invalid CFBundle.
+ reset();
+
+ if (Path.empty() || !sys::fs::exists(Path))
+ return;
+
+ SmallString<256> RealPath;
+ sys::fs::real_path(Path, RealPath, /*expand_tilde*/ true);
+
+ do {
+ // Create a CFURL from the current path and use it to create a CFBundle.
+ CFReleaser<CFURLRef> BundleURL(::CFURLCreateFromFileSystemRepresentation(
+ kCFAllocatorDefault, (const UInt8 *)RealPath.data(), RealPath.size(),
+ false));
+ reset(::CFBundleCreate(kCFAllocatorDefault, BundleURL.get()));
+
+ // If we have a valid bundle and find its identifier we are done.
+ if (get() != nullptr) {
+ if (GetIdentifier() != nullptr)
+ return;
+ reset();
+ }
+
+ // Remove the last component of the path and try again until there's
+ // nothing left but the root.
+ sys::path::remove_filename(RealPath);
+ } while (RealPath != sys::path::root_name(RealPath));
+}
+#endif
+
+/// On Darwin, try and find the original executable's Info.plist to extract
+/// information about the bundle. Return default values on other platforms.
+CFBundleInfo getBundleInfo(StringRef ExePath) {
+ CFBundleInfo BundleInfo;
+
+#ifdef __APPLE__
+ auto PrintError = [&](CFTypeID TypeID) {
+ CFString TypeIDCFStr(::CFCopyTypeIDDescription(TypeID));
+ std::string TypeIDStr;
+ errs() << "The Info.plist key \"CFBundleShortVersionString\" is"
+ << "a " << TypeIDCFStr.UTF8(TypeIDStr)
+ << ", but it should be a string in: " << ExePath << ".\n";
+ };
+
+ CFBundle Bundle(ExePath);
+ if (CFStringRef BundleID = Bundle.GetIdentifier()) {
+ CFString::UTF8(BundleID, BundleInfo.IDStr);
+ if (CFTypeRef TypeRef =
+ Bundle.GetValueForInfoDictionaryKey(CFSTR("CFBundleVersion"))) {
+ CFTypeID TypeID = ::CFGetTypeID(TypeRef);
+ if (TypeID == ::CFStringGetTypeID())
+ CFString::UTF8((CFStringRef)TypeRef, BundleInfo.VersionStr);
+ else
+ PrintError(TypeID);
+ }
+ if (CFTypeRef TypeRef = Bundle.GetValueForInfoDictionaryKey(
+ CFSTR("CFBundleShortVersionString"))) {
+ CFTypeID TypeID = ::CFGetTypeID(TypeRef);
+ if (TypeID == ::CFStringGetTypeID())
+ CFString::UTF8((CFStringRef)TypeRef, BundleInfo.ShortVersionStr);
+ else
+ PrintError(TypeID);
+ }
+ }
+#endif
+
+ return BundleInfo;
+}
+
+} // end namespace dsymutil
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/dsymutil/CFBundle.h b/contrib/libs/llvm12/tools/dsymutil/CFBundle.h
index 103db03516..12eb64ac0b 100644
--- a/contrib/libs/llvm12/tools/dsymutil/CFBundle.h
+++ b/contrib/libs/llvm12/tools/dsymutil/CFBundle.h
@@ -1,30 +1,30 @@
-//===- tools/dsymutil/CFBundle.h - CFBundle helper --------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_DSYMUTIL_CFBUNDLE_H
-#define LLVM_TOOLS_DSYMUTIL_CFBUNDLE_H
-
-#include "llvm/ADT/StringRef.h"
-#include <string>
-
-namespace llvm {
-namespace dsymutil {
-
-struct CFBundleInfo {
- std::string VersionStr = "1";
- std::string ShortVersionStr = "1.0";
- std::string IDStr;
- bool OmitShortVersion() const { return ShortVersionStr.empty(); }
-};
-
-CFBundleInfo getBundleInfo(llvm::StringRef ExePath);
-
-} // end namespace dsymutil
-} // end namespace llvm
-
-#endif
+//===- tools/dsymutil/CFBundle.h - CFBundle helper --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_CFBUNDLE_H
+#define LLVM_TOOLS_DSYMUTIL_CFBUNDLE_H
+
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace llvm {
+namespace dsymutil {
+
+struct CFBundleInfo {
+ std::string VersionStr = "1";
+ std::string ShortVersionStr = "1.0";
+ std::string IDStr;
+ bool OmitShortVersion() const { return ShortVersionStr.empty(); }
+};
+
+CFBundleInfo getBundleInfo(llvm::StringRef ExePath);
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp b/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp
index 605c1317b9..ba763e65c5 100644
--- a/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp
+++ b/contrib/libs/llvm12/tools/dsymutil/DebugMap.cpp
@@ -1,294 +1,294 @@
-//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "DebugMap.h"
-#include "BinaryHolder.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/BinaryFormat/MachO.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/Chrono.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/YAMLTraits.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cinttypes>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-namespace llvm {
-
-namespace dsymutil {
-
-using namespace llvm::object;
-
-DebugMapObject::DebugMapObject(StringRef ObjectFilename,
- sys::TimePoint<std::chrono::seconds> Timestamp,
- uint8_t Type)
- : Filename(std::string(ObjectFilename)), Timestamp(Timestamp), Type(Type) {}
-
-bool DebugMapObject::addSymbol(StringRef Name, Optional<uint64_t> ObjectAddress,
- uint64_t LinkedAddress, uint32_t Size) {
- auto InsertResult = Symbols.insert(
- std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
-
- if (ObjectAddress && InsertResult.second)
- AddressToMapping[*ObjectAddress] = &*InsertResult.first;
- return InsertResult.second;
-}
-
-void DebugMapObject::print(raw_ostream &OS) const {
- OS << getObjectFilename() << ":\n";
- // Sort the symbols in alphabetical order, like llvm-nm (and to get
- // deterministic output for testing).
- using Entry = std::pair<StringRef, SymbolMapping>;
- std::vector<Entry> Entries;
- Entries.reserve(Symbols.getNumItems());
+//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DebugMap.h"
+#include "BinaryHolder.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+namespace dsymutil {
+
+using namespace llvm::object;
+
+DebugMapObject::DebugMapObject(StringRef ObjectFilename,
+ sys::TimePoint<std::chrono::seconds> Timestamp,
+ uint8_t Type)
+ : Filename(std::string(ObjectFilename)), Timestamp(Timestamp), Type(Type) {}
+
+bool DebugMapObject::addSymbol(StringRef Name, Optional<uint64_t> ObjectAddress,
+ uint64_t LinkedAddress, uint32_t Size) {
+ auto InsertResult = Symbols.insert(
+ std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
+
+ if (ObjectAddress && InsertResult.second)
+ AddressToMapping[*ObjectAddress] = &*InsertResult.first;
+ return InsertResult.second;
+}
+
+void DebugMapObject::print(raw_ostream &OS) const {
+ OS << getObjectFilename() << ":\n";
+ // Sort the symbols in alphabetical order, like llvm-nm (and to get
+ // deterministic output for testing).
+ using Entry = std::pair<StringRef, SymbolMapping>;
+ std::vector<Entry> Entries;
+ Entries.reserve(Symbols.getNumItems());
for (const auto &Sym : Symbols)
- Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue()));
- llvm::sort(Entries, [](const Entry &LHS, const Entry &RHS) {
- return LHS.first < RHS.first;
- });
- for (const auto &Sym : Entries) {
- if (Sym.second.ObjectAddress)
- OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress));
- else
- OS << "\t????????????????";
- OS << format(" => %016" PRIx64 "+0x%x\t%s\n",
- uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size),
- Sym.first.data());
- }
- OS << '\n';
-}
-
-#ifndef NDEBUG
-void DebugMapObject::dump() const { print(errs()); }
-#endif
-
-DebugMapObject &
-DebugMap::addDebugMapObject(StringRef ObjectFilePath,
- sys::TimePoint<std::chrono::seconds> Timestamp,
- uint8_t Type) {
- Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type));
- return *Objects.back();
-}
-
-const DebugMapObject::DebugMapEntry *
-DebugMapObject::lookupSymbol(StringRef SymbolName) const {
- StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
- if (Sym == Symbols.end())
- return nullptr;
- return &*Sym;
-}
-
-const DebugMapObject::DebugMapEntry *
-DebugMapObject::lookupObjectAddress(uint64_t Address) const {
- auto Mapping = AddressToMapping.find(Address);
- if (Mapping == AddressToMapping.end())
- return nullptr;
- return Mapping->getSecond();
-}
-
-void DebugMap::print(raw_ostream &OS) const {
- yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
- yout << const_cast<DebugMap &>(*this);
-}
-
-#ifndef NDEBUG
-void DebugMap::dump() const { print(errs()); }
-#endif
-
-namespace {
-
-struct YAMLContext {
- StringRef PrependPath;
- Triple BinaryTriple;
-};
-
-} // end anonymous namespace
-
-ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
-DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
- bool Verbose) {
- auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
- if (auto Err = ErrOrFile.getError())
- return Err;
-
- YAMLContext Ctxt;
-
- Ctxt.PrependPath = PrependPath;
-
- std::unique_ptr<DebugMap> Res;
- yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
- yin >> Res;
-
- if (auto EC = yin.error())
- return EC;
- std::vector<std::unique_ptr<DebugMap>> Result;
- Result.push_back(std::move(Res));
- return std::move(Result);
-}
-
-} // end namespace dsymutil
-
-namespace yaml {
-
-// Normalize/Denormalize between YAML and a DebugMapObject.
-struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO {
- YamlDMO(IO &io) { Timestamp = 0; }
- YamlDMO(IO &io, dsymutil::DebugMapObject &Obj);
- dsymutil::DebugMapObject denormalize(IO &IO);
-
- std::string Filename;
- int64_t Timestamp;
- std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
-};
-
-void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>::
- mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) {
- io.mapRequired("sym", s.first);
- io.mapOptional("objAddr", s.second.ObjectAddress);
- io.mapRequired("binAddr", s.second.BinaryAddress);
- io.mapOptional("size", s.second.Size);
-}
-
-void MappingTraits<dsymutil::DebugMapObject>::mapping(
- IO &io, dsymutil::DebugMapObject &DMO) {
- MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO);
- io.mapRequired("filename", Norm->Filename);
- io.mapOptional("timestamp", Norm->Timestamp);
- io.mapRequired("symbols", Norm->Entries);
-}
-
-void ScalarTraits<Triple>::output(const Triple &val, void *, raw_ostream &out) {
- out << val.str();
-}
-
-StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) {
- value = Triple(scalar);
- return StringRef();
-}
-
-size_t
-SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size(
- IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) {
- return seq.size();
-}
-
-dsymutil::DebugMapObject &
-SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
- IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
- size_t index) {
- if (index >= seq.size()) {
- seq.resize(index + 1);
- seq[index].reset(new dsymutil::DebugMapObject);
- }
- return *seq[index];
-}
-
-void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
- dsymutil::DebugMap &DM) {
- io.mapRequired("triple", DM.BinaryTriple);
- io.mapOptional("binary-path", DM.BinaryPath);
- if (void *Ctxt = io.getContext())
- reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;
- io.mapOptional("objects", DM.Objects);
-}
-
-void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
- IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) {
- if (!DM)
- DM.reset(new DebugMap());
- io.mapRequired("triple", DM->BinaryTriple);
- io.mapOptional("binary-path", DM->BinaryPath);
- if (void *Ctxt = io.getContext())
- reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;
- io.mapOptional("objects", DM->Objects);
-}
-
-MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
- IO &io, dsymutil::DebugMapObject &Obj) {
- Filename = Obj.Filename;
- Timestamp = sys::toTimeT(Obj.getTimestamp());
- Entries.reserve(Obj.Symbols.size());
- for (auto &Entry : Obj.Symbols)
- Entries.push_back(
- std::make_pair(std::string(Entry.getKey()), Entry.getValue()));
-}
-
-dsymutil::DebugMapObject
-MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
- BinaryHolder BinHolder(vfs::getRealFileSystem(), /* Verbose =*/false);
- const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext());
- SmallString<80> Path(Ctxt.PrependPath);
- StringMap<uint64_t> SymbolAddresses;
-
- sys::path::append(Path, Filename);
-
- auto ObjectEntry = BinHolder.getObjectEntry(Path);
- if (!ObjectEntry) {
- auto Err = ObjectEntry.takeError();
- WithColor::warning() << "Unable to open " << Path << " "
- << toString(std::move(Err)) << '\n';
- } else {
- auto Object = ObjectEntry->getObject(Ctxt.BinaryTriple);
- if (!Object) {
- auto Err = Object.takeError();
- WithColor::warning() << "Unable to open " << Path << " "
- << toString(std::move(Err)) << '\n';
- } else {
- for (const auto &Sym : Object->symbols()) {
- Expected<uint64_t> AddressOrErr = Sym.getValue();
- if (!AddressOrErr) {
- // TODO: Actually report errors helpfully.
- consumeError(AddressOrErr.takeError());
- continue;
- }
- Expected<StringRef> Name = Sym.getName();
- Expected<uint32_t> FlagsOrErr = Sym.getFlags();
- if (!Name || !FlagsOrErr ||
- (*FlagsOrErr & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) {
- // TODO: Actually report errors helpfully.
- if (!FlagsOrErr)
- consumeError(FlagsOrErr.takeError());
- if (!Name)
- consumeError(Name.takeError());
- continue;
- }
- SymbolAddresses[*Name] = *AddressOrErr;
- }
- }
- }
-
- dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO);
- for (auto &Entry : Entries) {
- auto &Mapping = Entry.second;
- Optional<uint64_t> ObjAddress;
- if (Mapping.ObjectAddress)
- ObjAddress = *Mapping.ObjectAddress;
- auto AddressIt = SymbolAddresses.find(Entry.first);
- if (AddressIt != SymbolAddresses.end())
- ObjAddress = AddressIt->getValue();
- Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size);
- }
- return Res;
-}
-
-} // end namespace yaml
-} // end namespace llvm
+ Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue()));
+ llvm::sort(Entries, [](const Entry &LHS, const Entry &RHS) {
+ return LHS.first < RHS.first;
+ });
+ for (const auto &Sym : Entries) {
+ if (Sym.second.ObjectAddress)
+ OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress));
+ else
+ OS << "\t????????????????";
+ OS << format(" => %016" PRIx64 "+0x%x\t%s\n",
+ uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size),
+ Sym.first.data());
+ }
+ OS << '\n';
+}
+
+#ifndef NDEBUG
+void DebugMapObject::dump() const { print(errs()); }
+#endif
+
+DebugMapObject &
+DebugMap::addDebugMapObject(StringRef ObjectFilePath,
+ sys::TimePoint<std::chrono::seconds> Timestamp,
+ uint8_t Type) {
+ Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type));
+ return *Objects.back();
+}
+
+const DebugMapObject::DebugMapEntry *
+DebugMapObject::lookupSymbol(StringRef SymbolName) const {
+ StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
+ if (Sym == Symbols.end())
+ return nullptr;
+ return &*Sym;
+}
+
+const DebugMapObject::DebugMapEntry *
+DebugMapObject::lookupObjectAddress(uint64_t Address) const {
+ auto Mapping = AddressToMapping.find(Address);
+ if (Mapping == AddressToMapping.end())
+ return nullptr;
+ return Mapping->getSecond();
+}
+
+void DebugMap::print(raw_ostream &OS) const {
+ yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
+ yout << const_cast<DebugMap &>(*this);
+}
+
+#ifndef NDEBUG
+void DebugMap::dump() const { print(errs()); }
+#endif
+
+namespace {
+
+struct YAMLContext {
+ StringRef PrependPath;
+ Triple BinaryTriple;
+};
+
+} // end anonymous namespace
+
+ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
+DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
+ bool Verbose) {
+ auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
+ if (auto Err = ErrOrFile.getError())
+ return Err;
+
+ YAMLContext Ctxt;
+
+ Ctxt.PrependPath = PrependPath;
+
+ std::unique_ptr<DebugMap> Res;
+ yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
+ yin >> Res;
+
+ if (auto EC = yin.error())
+ return EC;
+ std::vector<std::unique_ptr<DebugMap>> Result;
+ Result.push_back(std::move(Res));
+ return std::move(Result);
+}
+
+} // end namespace dsymutil
+
+namespace yaml {
+
+// Normalize/Denormalize between YAML and a DebugMapObject.
+struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO {
+ YamlDMO(IO &io) { Timestamp = 0; }
+ YamlDMO(IO &io, dsymutil::DebugMapObject &Obj);
+ dsymutil::DebugMapObject denormalize(IO &IO);
+
+ std::string Filename;
+ int64_t Timestamp;
+ std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
+};
+
+void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>::
+ mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) {
+ io.mapRequired("sym", s.first);
+ io.mapOptional("objAddr", s.second.ObjectAddress);
+ io.mapRequired("binAddr", s.second.BinaryAddress);
+ io.mapOptional("size", s.second.Size);
+}
+
+void MappingTraits<dsymutil::DebugMapObject>::mapping(
+ IO &io, dsymutil::DebugMapObject &DMO) {
+ MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO);
+ io.mapRequired("filename", Norm->Filename);
+ io.mapOptional("timestamp", Norm->Timestamp);
+ io.mapRequired("symbols", Norm->Entries);
+}
+
+void ScalarTraits<Triple>::output(const Triple &val, void *, raw_ostream &out) {
+ out << val.str();
+}
+
+StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) {
+ value = Triple(scalar);
+ return StringRef();
+}
+
+size_t
+SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size(
+ IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) {
+ return seq.size();
+}
+
+dsymutil::DebugMapObject &
+SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
+ IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
+ size_t index) {
+ if (index >= seq.size()) {
+ seq.resize(index + 1);
+ seq[index].reset(new dsymutil::DebugMapObject);
+ }
+ return *seq[index];
+}
+
+void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
+ dsymutil::DebugMap &DM) {
+ io.mapRequired("triple", DM.BinaryTriple);
+ io.mapOptional("binary-path", DM.BinaryPath);
+ if (void *Ctxt = io.getContext())
+ reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;
+ io.mapOptional("objects", DM.Objects);
+}
+
+void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
+ IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) {
+ if (!DM)
+ DM.reset(new DebugMap());
+ io.mapRequired("triple", DM->BinaryTriple);
+ io.mapOptional("binary-path", DM->BinaryPath);
+ if (void *Ctxt = io.getContext())
+ reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;
+ io.mapOptional("objects", DM->Objects);
+}
+
+MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
+ IO &io, dsymutil::DebugMapObject &Obj) {
+ Filename = Obj.Filename;
+ Timestamp = sys::toTimeT(Obj.getTimestamp());
+ Entries.reserve(Obj.Symbols.size());
+ for (auto &Entry : Obj.Symbols)
+ Entries.push_back(
+ std::make_pair(std::string(Entry.getKey()), Entry.getValue()));
+}
+
+dsymutil::DebugMapObject
+MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
+ BinaryHolder BinHolder(vfs::getRealFileSystem(), /* Verbose =*/false);
+ const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext());
+ SmallString<80> Path(Ctxt.PrependPath);
+ StringMap<uint64_t> SymbolAddresses;
+
+ sys::path::append(Path, Filename);
+
+ auto ObjectEntry = BinHolder.getObjectEntry(Path);
+ if (!ObjectEntry) {
+ auto Err = ObjectEntry.takeError();
+ WithColor::warning() << "Unable to open " << Path << " "
+ << toString(std::move(Err)) << '\n';
+ } else {
+ auto Object = ObjectEntry->getObject(Ctxt.BinaryTriple);
+ if (!Object) {
+ auto Err = Object.takeError();
+ WithColor::warning() << "Unable to open " << Path << " "
+ << toString(std::move(Err)) << '\n';
+ } else {
+ for (const auto &Sym : Object->symbols()) {
+ Expected<uint64_t> AddressOrErr = Sym.getValue();
+ if (!AddressOrErr) {
+ // TODO: Actually report errors helpfully.
+ consumeError(AddressOrErr.takeError());
+ continue;
+ }
+ Expected<StringRef> Name = Sym.getName();
+ Expected<uint32_t> FlagsOrErr = Sym.getFlags();
+ if (!Name || !FlagsOrErr ||
+ (*FlagsOrErr & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) {
+ // TODO: Actually report errors helpfully.
+ if (!FlagsOrErr)
+ consumeError(FlagsOrErr.takeError());
+ if (!Name)
+ consumeError(Name.takeError());
+ continue;
+ }
+ SymbolAddresses[*Name] = *AddressOrErr;
+ }
+ }
+ }
+
+ dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO);
+ for (auto &Entry : Entries) {
+ auto &Mapping = Entry.second;
+ Optional<uint64_t> ObjAddress;
+ if (Mapping.ObjectAddress)
+ ObjAddress = *Mapping.ObjectAddress;
+ auto AddressIt = SymbolAddresses.find(Entry.first);
+ if (AddressIt != SymbolAddresses.end())
+ ObjAddress = AddressIt->getValue();
+ Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size);
+ }
+ return Res;
+}
+
+} // end namespace yaml
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/dsymutil/DebugMap.h b/contrib/libs/llvm12/tools/dsymutil/DebugMap.h
index ee552ed983..3ce8a33a0a 100644
--- a/contrib/libs/llvm12/tools/dsymutil/DebugMap.h
+++ b/contrib/libs/llvm12/tools/dsymutil/DebugMap.h
@@ -1,272 +1,272 @@
-//=- tools/dsymutil/DebugMap.h - Generic debug map representation -*- C++ -*-=//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-/// \file
-///
-/// This file contains the class declaration of the DebugMap
-/// entity. A DebugMap lists all the object files linked together to
-/// produce an executable along with the linked address of all the
-/// atoms used in these object files.
-/// The DebugMap is an input to the DwarfLinker class that will
-/// extract the Dwarf debug information from the referenced object
-/// files and link their usefull debug info together.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
-#define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Support/Chrono.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/YAMLTraits.h"
-#include <chrono>
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-namespace llvm {
-
-class raw_ostream;
-
-namespace dsymutil {
-
-class DebugMapObject;
-
-/// The DebugMap object stores the list of object files to query for debug
-/// information along with the mapping between the symbols' addresses in the
-/// object file to their linked address in the linked binary.
-///
-/// A DebugMap producer could look like this:
-/// DebugMap *DM = new DebugMap();
-/// for (const auto &Obj: LinkedObjects) {
-/// DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath());
-/// for (const auto &Sym: Obj.getLinkedSymbols())
-/// DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(),
-/// Sym.getBinaryAddress());
-/// }
-///
-/// A DebugMap consumer can then use the map to link the debug
-/// information. For example something along the lines of:
-/// for (const auto &DMO: DM->objects()) {
-/// auto Obj = createBinary(DMO.getObjectFilename());
-/// for (auto &DIE: Obj.getDwarfDIEs()) {
-/// if (SymbolMapping *Sym = DMO.lookup(DIE.getName()))
-/// DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress);
-/// else
-/// DIE.discardSubtree();
-/// }
-/// }
-class DebugMap {
- Triple BinaryTriple;
- std::string BinaryPath;
- std::vector<uint8_t> BinaryUUID;
- using ObjectContainer = std::vector<std::unique_ptr<DebugMapObject>>;
-
- ObjectContainer Objects;
-
- /// For YAML IO support.
- ///@{
- friend yaml::MappingTraits<std::unique_ptr<DebugMap>>;
- friend yaml::MappingTraits<DebugMap>;
-
- DebugMap() = default;
- ///@}
-
-public:
- DebugMap(const Triple &BinaryTriple, StringRef BinaryPath,
- ArrayRef<uint8_t> BinaryUUID = ArrayRef<uint8_t>())
- : BinaryTriple(BinaryTriple), BinaryPath(std::string(BinaryPath)),
- BinaryUUID(BinaryUUID.begin(), BinaryUUID.end()) {}
-
- using const_iterator = ObjectContainer::const_iterator;
-
- iterator_range<const_iterator> objects() const {
- return make_range(begin(), end());
- }
-
- const_iterator begin() const { return Objects.begin(); }
-
- const_iterator end() const { return Objects.end(); }
-
- unsigned getNumberOfObjects() const { return Objects.size(); }
-
- /// This function adds an DebugMapObject to the list owned by this
- /// debug map.
- DebugMapObject &
- addDebugMapObject(StringRef ObjectFilePath,
- sys::TimePoint<std::chrono::seconds> Timestamp,
- uint8_t Type = llvm::MachO::N_OSO);
-
- const Triple &getTriple() const { return BinaryTriple; }
-
- const ArrayRef<uint8_t> getUUID() const {
- return ArrayRef<uint8_t>(BinaryUUID);
- }
-
- StringRef getBinaryPath() const { return BinaryPath; }
-
- void print(raw_ostream &OS) const;
-
-#ifndef NDEBUG
- void dump() const;
-#endif
-
- /// Read a debug map for \a InputFile.
- static ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
- parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose);
-};
-
-/// The DebugMapObject represents one object file described by the DebugMap. It
-/// contains a list of mappings between addresses in the object file and in the
-/// linked binary for all the linked atoms in this object file.
-class DebugMapObject {
-public:
- struct SymbolMapping {
- Optional<yaml::Hex64> ObjectAddress;
- yaml::Hex64 BinaryAddress;
- yaml::Hex32 Size;
-
- SymbolMapping(Optional<uint64_t> ObjectAddr, uint64_t BinaryAddress,
- uint32_t Size)
- : BinaryAddress(BinaryAddress), Size(Size) {
- if (ObjectAddr)
- ObjectAddress = *ObjectAddr;
- }
-
- /// For YAML IO support
- SymbolMapping() = default;
- };
-
- using YAMLSymbolMapping = std::pair<std::string, SymbolMapping>;
- using DebugMapEntry = StringMapEntry<SymbolMapping>;
-
- /// Adds a symbol mapping to this DebugMapObject.
- /// \returns false if the symbol was already registered. The request
- /// is discarded in this case.
- bool addSymbol(StringRef SymName, Optional<uint64_t> ObjectAddress,
- uint64_t LinkedAddress, uint32_t Size);
-
- /// Lookup a symbol mapping.
- /// \returns null if the symbol isn't found.
- const DebugMapEntry *lookupSymbol(StringRef SymbolName) const;
-
- /// Lookup an object file address.
- /// \returns null if the address isn't found.
- const DebugMapEntry *lookupObjectAddress(uint64_t Address) const;
-
- StringRef getObjectFilename() const { return Filename; }
-
- sys::TimePoint<std::chrono::seconds> getTimestamp() const {
- return Timestamp;
- }
-
- uint8_t getType() const { return Type; }
-
- iterator_range<StringMap<SymbolMapping>::const_iterator> symbols() const {
- return make_range(Symbols.begin(), Symbols.end());
- }
-
- bool empty() const { return Symbols.empty(); }
-
- void addWarning(StringRef Warning) {
- Warnings.push_back(std::string(Warning));
- }
- const std::vector<std::string> &getWarnings() const { return Warnings; }
-
- void print(raw_ostream &OS) const;
-#ifndef NDEBUG
- void dump() const;
-#endif
-
-private:
- friend class DebugMap;
-
- /// DebugMapObjects can only be constructed by the owning DebugMap.
- DebugMapObject(StringRef ObjectFilename,
- sys::TimePoint<std::chrono::seconds> Timestamp, uint8_t Type);
-
- std::string Filename;
- sys::TimePoint<std::chrono::seconds> Timestamp;
- StringMap<SymbolMapping> Symbols;
- DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
- uint8_t Type;
-
- std::vector<std::string> Warnings;
-
- /// For YAMLIO support.
- ///@{
- friend yaml::MappingTraits<dsymutil::DebugMapObject>;
- friend yaml::SequenceTraits<std::vector<std::unique_ptr<DebugMapObject>>>;
-
- DebugMapObject() = default;
-
-public:
- DebugMapObject(DebugMapObject &&) = default;
- DebugMapObject &operator=(DebugMapObject &&) = default;
- ///@}
-};
-
-} // end namespace dsymutil
-} // end namespace llvm
-
-LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::dsymutil::DebugMapObject::YAMLSymbolMapping)
-
-namespace llvm {
-namespace yaml {
-
-using namespace llvm::dsymutil;
-
-template <>
-struct MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>> {
- static void mapping(IO &io,
- std::pair<std::string, DebugMapObject::SymbolMapping> &s);
- static const bool flow = true;
-};
-
-template <> struct MappingTraits<dsymutil::DebugMapObject> {
- struct YamlDMO;
- static void mapping(IO &io, dsymutil::DebugMapObject &DMO);
-};
-
-template <> struct ScalarTraits<Triple> {
- static void output(const Triple &val, void *, raw_ostream &out);
- static StringRef input(StringRef scalar, void *, Triple &value);
- static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
-};
-
-template <>
-struct SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>> {
- static size_t
- size(IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq);
- static dsymutil::DebugMapObject &
- element(IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
- size_t index);
-};
-
-template <> struct MappingTraits<dsymutil::DebugMap> {
- static void mapping(IO &io, dsymutil::DebugMap &DM);
-};
-
-template <> struct MappingTraits<std::unique_ptr<dsymutil::DebugMap>> {
- static void mapping(IO &io, std::unique_ptr<dsymutil::DebugMap> &DM);
-};
-
-} // end namespace yaml
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
+//=- tools/dsymutil/DebugMap.h - Generic debug map representation -*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+///
+/// This file contains the class declaration of the DebugMap
+/// entity. A DebugMap lists all the object files linked together to
+/// produce an executable along with the linked address of all the
+/// atoms used in these object files.
+/// The DebugMap is an input to the DwarfLinker class that will
+/// extract the Dwarf debug information from the referenced object
+/// files and link their usefull debug info together.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
+#define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace dsymutil {
+
+class DebugMapObject;
+
+/// The DebugMap object stores the list of object files to query for debug
+/// information along with the mapping between the symbols' addresses in the
+/// object file to their linked address in the linked binary.
+///
+/// A DebugMap producer could look like this:
+/// DebugMap *DM = new DebugMap();
+/// for (const auto &Obj: LinkedObjects) {
+/// DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath());
+/// for (const auto &Sym: Obj.getLinkedSymbols())
+/// DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(),
+/// Sym.getBinaryAddress());
+/// }
+///
+/// A DebugMap consumer can then use the map to link the debug
+/// information. For example something along the lines of:
+/// for (const auto &DMO: DM->objects()) {
+/// auto Obj = createBinary(DMO.getObjectFilename());
+/// for (auto &DIE: Obj.getDwarfDIEs()) {
+/// if (SymbolMapping *Sym = DMO.lookup(DIE.getName()))
+/// DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress);
+/// else
+/// DIE.discardSubtree();
+/// }
+/// }
+class DebugMap {
+ Triple BinaryTriple;
+ std::string BinaryPath;
+ std::vector<uint8_t> BinaryUUID;
+ using ObjectContainer = std::vector<std::unique_ptr<DebugMapObject>>;
+
+ ObjectContainer Objects;
+
+ /// For YAML IO support.
+ ///@{
+ friend yaml::MappingTraits<std::unique_ptr<DebugMap>>;
+ friend yaml::MappingTraits<DebugMap>;
+
+ DebugMap() = default;
+ ///@}
+
+public:
+ DebugMap(const Triple &BinaryTriple, StringRef BinaryPath,
+ ArrayRef<uint8_t> BinaryUUID = ArrayRef<uint8_t>())
+ : BinaryTriple(BinaryTriple), BinaryPath(std::string(BinaryPath)),
+ BinaryUUID(BinaryUUID.begin(), BinaryUUID.end()) {}
+
+ using const_iterator = ObjectContainer::const_iterator;
+
+ iterator_range<const_iterator> objects() const {
+ return make_range(begin(), end());
+ }
+
+ const_iterator begin() const { return Objects.begin(); }
+
+ const_iterator end() const { return Objects.end(); }
+
+ unsigned getNumberOfObjects() const { return Objects.size(); }
+
+ /// This function adds an DebugMapObject to the list owned by this
+ /// debug map.
+ DebugMapObject &
+ addDebugMapObject(StringRef ObjectFilePath,
+ sys::TimePoint<std::chrono::seconds> Timestamp,
+ uint8_t Type = llvm::MachO::N_OSO);
+
+ const Triple &getTriple() const { return BinaryTriple; }
+
+ const ArrayRef<uint8_t> getUUID() const {
+ return ArrayRef<uint8_t>(BinaryUUID);
+ }
+
+ StringRef getBinaryPath() const { return BinaryPath; }
+
+ void print(raw_ostream &OS) const;
+
+#ifndef NDEBUG
+ void dump() const;
+#endif
+
+ /// Read a debug map for \a InputFile.
+ static ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
+ parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose);
+};
+
+/// The DebugMapObject represents one object file described by the DebugMap. It
+/// contains a list of mappings between addresses in the object file and in the
+/// linked binary for all the linked atoms in this object file.
+class DebugMapObject {
+public:
+ struct SymbolMapping {
+ Optional<yaml::Hex64> ObjectAddress;
+ yaml::Hex64 BinaryAddress;
+ yaml::Hex32 Size;
+
+ SymbolMapping(Optional<uint64_t> ObjectAddr, uint64_t BinaryAddress,
+ uint32_t Size)
+ : BinaryAddress(BinaryAddress), Size(Size) {
+ if (ObjectAddr)
+ ObjectAddress = *ObjectAddr;
+ }
+
+ /// For YAML IO support
+ SymbolMapping() = default;
+ };
+
+ using YAMLSymbolMapping = std::pair<std::string, SymbolMapping>;
+ using DebugMapEntry = StringMapEntry<SymbolMapping>;
+
+ /// Adds a symbol mapping to this DebugMapObject.
+ /// \returns false if the symbol was already registered. The request
+ /// is discarded in this case.
+ bool addSymbol(StringRef SymName, Optional<uint64_t> ObjectAddress,
+ uint64_t LinkedAddress, uint32_t Size);
+
+ /// Lookup a symbol mapping.
+ /// \returns null if the symbol isn't found.
+ const DebugMapEntry *lookupSymbol(StringRef SymbolName) const;
+
+ /// Lookup an object file address.
+ /// \returns null if the address isn't found.
+ const DebugMapEntry *lookupObjectAddress(uint64_t Address) const;
+
+ StringRef getObjectFilename() const { return Filename; }
+
+ sys::TimePoint<std::chrono::seconds> getTimestamp() const {
+ return Timestamp;
+ }
+
+ uint8_t getType() const { return Type; }
+
+ iterator_range<StringMap<SymbolMapping>::const_iterator> symbols() const {
+ return make_range(Symbols.begin(), Symbols.end());
+ }
+
+ bool empty() const { return Symbols.empty(); }
+
+ void addWarning(StringRef Warning) {
+ Warnings.push_back(std::string(Warning));
+ }
+ const std::vector<std::string> &getWarnings() const { return Warnings; }
+
+ void print(raw_ostream &OS) const;
+#ifndef NDEBUG
+ void dump() const;
+#endif
+
+private:
+ friend class DebugMap;
+
+ /// DebugMapObjects can only be constructed by the owning DebugMap.
+ DebugMapObject(StringRef ObjectFilename,
+ sys::TimePoint<std::chrono::seconds> Timestamp, uint8_t Type);
+
+ std::string Filename;
+ sys::TimePoint<std::chrono::seconds> Timestamp;
+ StringMap<SymbolMapping> Symbols;
+ DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
+ uint8_t Type;
+
+ std::vector<std::string> Warnings;
+
+ /// For YAMLIO support.
+ ///@{
+ friend yaml::MappingTraits<dsymutil::DebugMapObject>;
+ friend yaml::SequenceTraits<std::vector<std::unique_ptr<DebugMapObject>>>;
+
+ DebugMapObject() = default;
+
+public:
+ DebugMapObject(DebugMapObject &&) = default;
+ DebugMapObject &operator=(DebugMapObject &&) = default;
+ ///@}
+};
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::dsymutil::DebugMapObject::YAMLSymbolMapping)
+
+namespace llvm {
+namespace yaml {
+
+using namespace llvm::dsymutil;
+
+template <>
+struct MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>> {
+ static void mapping(IO &io,
+ std::pair<std::string, DebugMapObject::SymbolMapping> &s);
+ static const bool flow = true;
+};
+
+template <> struct MappingTraits<dsymutil::DebugMapObject> {
+ struct YamlDMO;
+ static void mapping(IO &io, dsymutil::DebugMapObject &DMO);
+};
+
+template <> struct ScalarTraits<Triple> {
+ static void output(const Triple &val, void *, raw_ostream &out);
+ static StringRef input(StringRef scalar, void *, Triple &value);
+ static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+};
+
+template <>
+struct SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>> {
+ static size_t
+ size(IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq);
+ static dsymutil::DebugMapObject &
+ element(IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
+ size_t index);
+};
+
+template <> struct MappingTraits<dsymutil::DebugMap> {
+ static void mapping(IO &io, dsymutil::DebugMap &DM);
+};
+
+template <> struct MappingTraits<std::unique_ptr<dsymutil::DebugMap>> {
+ static void mapping(IO &io, std::unique_ptr<dsymutil::DebugMap> &DM);
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
diff --git a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp
index 29408e7c49..1cb561dbac 100644
--- a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -1,616 +1,616 @@
-//===- tools/dsymutil/DwarfLinkerForBinary.cpp ----------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "DwarfLinkerForBinary.h"
-#include "BinaryHolder.h"
-#include "DebugMap.h"
-#include "MachOUtils.h"
-#include "dsymutil.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseMapInfo.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/IntervalMap.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/PointerIntPair.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/BinaryFormat/Dwarf.h"
-#include "llvm/BinaryFormat/MachO.h"
-#include "llvm/CodeGen/AccelTable.h"
-#include "llvm/CodeGen/AsmPrinter.h"
-#include "llvm/CodeGen/DIE.h"
-#include "llvm/CodeGen/NonRelocatableStringpool.h"
-#include "llvm/Config/config.h"
-#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
-#include "llvm/DebugInfo/DIContext.h"
-#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
-#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
-#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
-#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
-#include "llvm/DebugInfo/DWARF/DWARFDie.h"
-#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
-#include "llvm/DebugInfo/DWARF/DWARFSection.h"
-#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
-#include "llvm/MC/MCAsmBackend.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCCodeEmitter.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCDwarf.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCObjectWriter.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCSection.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetOptions.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Object/SymbolicFile.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/DJB.h"
-#include "llvm/Support/DataExtractor.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/ThreadPool.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetOptions.h"
-#include "llvm/MC/MCTargetOptionsCommandFlags.h"
-#include <algorithm>
-#include <cassert>
-#include <cinttypes>
-#include <climits>
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-#include <limits>
-#include <map>
-#include <memory>
-#include <string>
-#include <system_error>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-namespace llvm {
-
-static mc::RegisterMCTargetOptionsFlags MOF;
-
-namespace dsymutil {
-
-static Error copySwiftInterfaces(
- const std::map<std::string, std::string> &ParseableSwiftInterfaces,
- StringRef Architecture, const LinkOptions &Options) {
- std::error_code EC;
- SmallString<128> InputPath;
- SmallString<128> Path;
- sys::path::append(Path, *Options.ResourceDir, "Swift", Architecture);
- if ((EC = sys::fs::create_directories(Path.str(), true,
- sys::fs::perms::all_all)))
- return make_error<StringError>(
- "cannot create directory: " + toString(errorCodeToError(EC)), EC);
- unsigned BaseLength = Path.size();
-
- for (auto &I : ParseableSwiftInterfaces) {
- StringRef ModuleName = I.first;
- StringRef InterfaceFile = I.second;
- if (!Options.PrependPath.empty()) {
- InputPath.clear();
- sys::path::append(InputPath, Options.PrependPath, InterfaceFile);
- InterfaceFile = InputPath;
- }
- sys::path::append(Path, ModuleName);
- Path.append(".swiftinterface");
- if (Options.Verbose)
- outs() << "copy parseable Swift interface " << InterfaceFile << " -> "
- << Path.str() << '\n';
-
- // copy_file attempts an APFS clone first, so this should be cheap.
- if ((EC = sys::fs::copy_file(InterfaceFile, Path.str())))
- warn(Twine("cannot copy parseable Swift interface ") + InterfaceFile +
- ": " + toString(errorCodeToError(EC)));
- Path.resize(BaseLength);
- }
- return Error::success();
-}
-
-/// Report a warning to the user, optionally including information about a
-/// specific \p DIE related to the warning.
-void DwarfLinkerForBinary::reportWarning(const Twine &Warning,
- StringRef Context,
- const DWARFDie *DIE) const {
-
- warn(Warning, Context);
-
- if (!Options.Verbose || !DIE)
- return;
-
- DIDumpOptions DumpOpts;
- DumpOpts.ChildRecurseDepth = 0;
- DumpOpts.Verbose = Options.Verbose;
-
- WithColor::note() << " in DIE:\n";
- DIE->dump(errs(), 6 /* Indent */, DumpOpts);
-}
-
-bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple,
- raw_fd_ostream &OutFile) {
- if (Options.NoOutput)
- return true;
-
- Streamer = std::make_unique<DwarfStreamer>(
- Options.FileType, OutFile, Options.Translator, Options.Minimize,
- [&](const Twine &Error, StringRef Context, const DWARFDie *) {
- error(Error, Context);
- },
- [&](const Twine &Warning, StringRef Context, const DWARFDie *) {
- warn(Warning, Context);
- });
- return Streamer->init(TheTriple);
-}
-
-ErrorOr<const object::ObjectFile &>
-DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
- const Triple &Triple) {
- auto ObjectEntry =
- BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp());
- if (!ObjectEntry) {
- auto Err = ObjectEntry.takeError();
- reportWarning(Twine(Obj.getObjectFilename()) + ": " +
- toString(std::move(Err)),
- Obj.getObjectFilename());
- return errorToErrorCode(std::move(Err));
- }
-
- auto Object = ObjectEntry->getObject(Triple);
- if (!Object) {
- auto Err = Object.takeError();
- reportWarning(Twine(Obj.getObjectFilename()) + ": " +
- toString(std::move(Err)),
- Obj.getObjectFilename());
- return errorToErrorCode(std::move(Err));
- }
-
- return *Object;
-}
-
-static Error remarksErrorHandler(const DebugMapObject &DMO,
- DwarfLinkerForBinary &Linker,
- std::unique_ptr<FileError> FE) {
- bool IsArchive = DMO.getObjectFilename().endswith(")");
- // Don't report errors for missing remark files from static
- // archives.
- if (!IsArchive)
- return Error(std::move(FE));
-
- std::string Message = FE->message();
- Error E = FE->takeError();
- Error NewE = handleErrors(std::move(E), [&](std::unique_ptr<ECError> EC) {
- if (EC->convertToErrorCode() != std::errc::no_such_file_or_directory)
- return Error(std::move(EC));
-
- Linker.reportWarning(Message, DMO.getObjectFilename());
- return Error(Error::success());
- });
-
- if (!NewE)
- return Error::success();
-
- return createFileError(FE->getFileName(), std::move(NewE));
-}
-
-static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath,
- StringRef ArchName, const remarks::RemarkLinker &RL) {
- // Make sure we don't create the directories and the file if there is nothing
- // to serialize.
- if (RL.empty())
- return Error::success();
-
- SmallString<128> InputPath;
- SmallString<128> Path;
- // Create the "Remarks" directory in the "Resources" directory.
- sys::path::append(Path, *Options.ResourceDir, "Remarks");
- if (std::error_code EC = sys::fs::create_directories(Path.str(), true,
- sys::fs::perms::all_all))
- return errorCodeToError(EC);
-
- // Append the file name.
- // For fat binaries, also append a dash and the architecture name.
- sys::path::append(Path, sys::path::filename(BinaryPath));
- if (Options.NumDebugMaps > 1) {
- // More than one debug map means we have a fat binary.
- Path += '-';
- Path += ArchName;
- }
-
- std::error_code EC;
- raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC, sys::fs::OF_None);
- if (EC)
- return errorCodeToError(EC);
-
- if (Error E = RL.serialize(OS, Options.RemarksFormat))
- return E;
-
- return Error::success();
-}
-
+//===- tools/dsymutil/DwarfLinkerForBinary.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DwarfLinkerForBinary.h"
+#include "BinaryHolder.h"
+#include "DebugMap.h"
+#include "MachOUtils.h"
+#include "dsymutil.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/CodeGen/AccelTable.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/CodeGen/NonRelocatableStringpool.h"
+#include "llvm/Config/config.h"
+#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DJB.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <climits>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <map>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+static mc::RegisterMCTargetOptionsFlags MOF;
+
+namespace dsymutil {
+
+static Error copySwiftInterfaces(
+ const std::map<std::string, std::string> &ParseableSwiftInterfaces,
+ StringRef Architecture, const LinkOptions &Options) {
+ std::error_code EC;
+ SmallString<128> InputPath;
+ SmallString<128> Path;
+ sys::path::append(Path, *Options.ResourceDir, "Swift", Architecture);
+ if ((EC = sys::fs::create_directories(Path.str(), true,
+ sys::fs::perms::all_all)))
+ return make_error<StringError>(
+ "cannot create directory: " + toString(errorCodeToError(EC)), EC);
+ unsigned BaseLength = Path.size();
+
+ for (auto &I : ParseableSwiftInterfaces) {
+ StringRef ModuleName = I.first;
+ StringRef InterfaceFile = I.second;
+ if (!Options.PrependPath.empty()) {
+ InputPath.clear();
+ sys::path::append(InputPath, Options.PrependPath, InterfaceFile);
+ InterfaceFile = InputPath;
+ }
+ sys::path::append(Path, ModuleName);
+ Path.append(".swiftinterface");
+ if (Options.Verbose)
+ outs() << "copy parseable Swift interface " << InterfaceFile << " -> "
+ << Path.str() << '\n';
+
+ // copy_file attempts an APFS clone first, so this should be cheap.
+ if ((EC = sys::fs::copy_file(InterfaceFile, Path.str())))
+ warn(Twine("cannot copy parseable Swift interface ") + InterfaceFile +
+ ": " + toString(errorCodeToError(EC)));
+ Path.resize(BaseLength);
+ }
+ return Error::success();
+}
+
+/// Report a warning to the user, optionally including information about a
+/// specific \p DIE related to the warning.
+void DwarfLinkerForBinary::reportWarning(const Twine &Warning,
+ StringRef Context,
+ const DWARFDie *DIE) const {
+
+ warn(Warning, Context);
+
+ if (!Options.Verbose || !DIE)
+ return;
+
+ DIDumpOptions DumpOpts;
+ DumpOpts.ChildRecurseDepth = 0;
+ DumpOpts.Verbose = Options.Verbose;
+
+ WithColor::note() << " in DIE:\n";
+ DIE->dump(errs(), 6 /* Indent */, DumpOpts);
+}
+
+bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple,
+ raw_fd_ostream &OutFile) {
+ if (Options.NoOutput)
+ return true;
+
+ Streamer = std::make_unique<DwarfStreamer>(
+ Options.FileType, OutFile, Options.Translator, Options.Minimize,
+ [&](const Twine &Error, StringRef Context, const DWARFDie *) {
+ error(Error, Context);
+ },
+ [&](const Twine &Warning, StringRef Context, const DWARFDie *) {
+ warn(Warning, Context);
+ });
+ return Streamer->init(TheTriple);
+}
+
+ErrorOr<const object::ObjectFile &>
+DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
+ const Triple &Triple) {
+ auto ObjectEntry =
+ BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp());
+ if (!ObjectEntry) {
+ auto Err = ObjectEntry.takeError();
+ reportWarning(Twine(Obj.getObjectFilename()) + ": " +
+ toString(std::move(Err)),
+ Obj.getObjectFilename());
+ return errorToErrorCode(std::move(Err));
+ }
+
+ auto Object = ObjectEntry->getObject(Triple);
+ if (!Object) {
+ auto Err = Object.takeError();
+ reportWarning(Twine(Obj.getObjectFilename()) + ": " +
+ toString(std::move(Err)),
+ Obj.getObjectFilename());
+ return errorToErrorCode(std::move(Err));
+ }
+
+ return *Object;
+}
+
+static Error remarksErrorHandler(const DebugMapObject &DMO,
+ DwarfLinkerForBinary &Linker,
+ std::unique_ptr<FileError> FE) {
+ bool IsArchive = DMO.getObjectFilename().endswith(")");
+ // Don't report errors for missing remark files from static
+ // archives.
+ if (!IsArchive)
+ return Error(std::move(FE));
+
+ std::string Message = FE->message();
+ Error E = FE->takeError();
+ Error NewE = handleErrors(std::move(E), [&](std::unique_ptr<ECError> EC) {
+ if (EC->convertToErrorCode() != std::errc::no_such_file_or_directory)
+ return Error(std::move(EC));
+
+ Linker.reportWarning(Message, DMO.getObjectFilename());
+ return Error(Error::success());
+ });
+
+ if (!NewE)
+ return Error::success();
+
+ return createFileError(FE->getFileName(), std::move(NewE));
+}
+
+static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath,
+ StringRef ArchName, const remarks::RemarkLinker &RL) {
+ // Make sure we don't create the directories and the file if there is nothing
+ // to serialize.
+ if (RL.empty())
+ return Error::success();
+
+ SmallString<128> InputPath;
+ SmallString<128> Path;
+ // Create the "Remarks" directory in the "Resources" directory.
+ sys::path::append(Path, *Options.ResourceDir, "Remarks");
+ if (std::error_code EC = sys::fs::create_directories(Path.str(), true,
+ sys::fs::perms::all_all))
+ return errorCodeToError(EC);
+
+ // Append the file name.
+ // For fat binaries, also append a dash and the architecture name.
+ sys::path::append(Path, sys::path::filename(BinaryPath));
+ if (Options.NumDebugMaps > 1) {
+ // More than one debug map means we have a fat binary.
+ Path += '-';
+ Path += ArchName;
+ }
+
+ std::error_code EC;
+ raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC, sys::fs::OF_None);
+ if (EC)
+ return errorCodeToError(EC);
+
+ if (Error E = RL.serialize(OS, Options.RemarksFormat))
+ return E;
+
+ return Error::success();
+}
+
ErrorOr<DWARFFile &>
-DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
- const DebugMap &DebugMap,
- remarks::RemarkLinker &RL) {
- auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());
-
- if (ErrorOrObj) {
- ContextForLinking.push_back(
- std::unique_ptr<DWARFContext>(DWARFContext::create(*ErrorOrObj)));
- AddressMapForLinking.push_back(
- std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj));
-
+DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
+ const DebugMap &DebugMap,
+ remarks::RemarkLinker &RL) {
+ auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());
+
+ if (ErrorOrObj) {
+ ContextForLinking.push_back(
+ std::unique_ptr<DWARFContext>(DWARFContext::create(*ErrorOrObj)));
+ AddressMapForLinking.push_back(
+ std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj));
+
ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
- Obj.getObjectFilename(), ContextForLinking.back().get(),
- AddressMapForLinking.back().get(),
- Obj.empty() ? Obj.getWarnings() : EmptyWarnings));
-
- Error E = RL.link(*ErrorOrObj);
- if (Error NewE = handleErrors(
- std::move(E), [&](std::unique_ptr<FileError> EC) -> Error {
- return remarksErrorHandler(Obj, *this, std::move(EC));
- }))
- return errorToErrorCode(std::move(NewE));
-
- return *ObjectsForLinking.back();
- }
-
- return ErrorOrObj.getError();
-}
-
-bool DwarfLinkerForBinary::link(const DebugMap &Map) {
- if (!createStreamer(Map.getTriple(), OutFile))
- return false;
-
- ObjectsForLinking.clear();
- ContextForLinking.clear();
- AddressMapForLinking.clear();
-
- DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
-
- DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil);
-
- remarks::RemarkLinker RL;
- if (!Options.RemarksPrependPath.empty())
- RL.setExternalFilePrependPath(Options.RemarksPrependPath);
- GeneralLinker.setObjectPrefixMap(&Options.ObjectPrefixMap);
-
- std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) {
- assert(Options.Translator);
- return Options.Translator(Input);
- };
-
- GeneralLinker.setVerbosity(Options.Verbose);
- GeneralLinker.setStatistics(Options.Statistics);
- GeneralLinker.setNoOutput(Options.NoOutput);
- GeneralLinker.setNoODR(Options.NoODR);
- GeneralLinker.setUpdate(Options.Update);
- GeneralLinker.setNumThreads(Options.Threads);
- GeneralLinker.setAccelTableKind(Options.TheAccelTableKind);
- GeneralLinker.setPrependPath(Options.PrependPath);
- if (Options.Translator)
- GeneralLinker.setStringsTranslator(TranslationLambda);
- GeneralLinker.setWarningHandler(
- [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) {
- reportWarning(Warning, Context, DIE);
- });
- GeneralLinker.setErrorHandler(
- [&](const Twine &Error, StringRef Context, const DWARFDie *) {
- error(Error, Context);
- });
- GeneralLinker.setObjFileLoader(
- [&DebugMap, &RL, this](StringRef ContainerName,
+ Obj.getObjectFilename(), ContextForLinking.back().get(),
+ AddressMapForLinking.back().get(),
+ Obj.empty() ? Obj.getWarnings() : EmptyWarnings));
+
+ Error E = RL.link(*ErrorOrObj);
+ if (Error NewE = handleErrors(
+ std::move(E), [&](std::unique_ptr<FileError> EC) -> Error {
+ return remarksErrorHandler(Obj, *this, std::move(EC));
+ }))
+ return errorToErrorCode(std::move(NewE));
+
+ return *ObjectsForLinking.back();
+ }
+
+ return ErrorOrObj.getError();
+}
+
+bool DwarfLinkerForBinary::link(const DebugMap &Map) {
+ if (!createStreamer(Map.getTriple(), OutFile))
+ return false;
+
+ ObjectsForLinking.clear();
+ ContextForLinking.clear();
+ AddressMapForLinking.clear();
+
+ DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
+
+ DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil);
+
+ remarks::RemarkLinker RL;
+ if (!Options.RemarksPrependPath.empty())
+ RL.setExternalFilePrependPath(Options.RemarksPrependPath);
+ GeneralLinker.setObjectPrefixMap(&Options.ObjectPrefixMap);
+
+ std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) {
+ assert(Options.Translator);
+ return Options.Translator(Input);
+ };
+
+ GeneralLinker.setVerbosity(Options.Verbose);
+ GeneralLinker.setStatistics(Options.Statistics);
+ GeneralLinker.setNoOutput(Options.NoOutput);
+ GeneralLinker.setNoODR(Options.NoODR);
+ GeneralLinker.setUpdate(Options.Update);
+ GeneralLinker.setNumThreads(Options.Threads);
+ GeneralLinker.setAccelTableKind(Options.TheAccelTableKind);
+ GeneralLinker.setPrependPath(Options.PrependPath);
+ if (Options.Translator)
+ GeneralLinker.setStringsTranslator(TranslationLambda);
+ GeneralLinker.setWarningHandler(
+ [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) {
+ reportWarning(Warning, Context, DIE);
+ });
+ GeneralLinker.setErrorHandler(
+ [&](const Twine &Error, StringRef Context, const DWARFDie *) {
+ error(Error, Context);
+ });
+ GeneralLinker.setObjFileLoader(
+ [&DebugMap, &RL, this](StringRef ContainerName,
StringRef Path) -> ErrorOr<DWARFFile &> {
- auto &Obj = DebugMap.addDebugMapObject(
- Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
-
- if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) {
- return *ErrorOrObj;
- } else {
- // Try and emit more helpful warnings by applying some heuristics.
- StringRef ObjFile = ContainerName;
- bool IsClangModule = sys::path::extension(Path).equals(".pcm");
- bool IsArchive = ObjFile.endswith(")");
-
- if (IsClangModule) {
- StringRef ModuleCacheDir = sys::path::parent_path(Path);
- if (sys::fs::exists(ModuleCacheDir)) {
- // If the module's parent directory exists, we assume that the
- // module cache has expired and was pruned by clang. A more
- // adventurous dsymutil would invoke clang to rebuild the module
- // now.
- if (!ModuleCacheHintDisplayed) {
- WithColor::note()
- << "The clang module cache may have expired since "
- "this object file was built. Rebuilding the "
- "object file will rebuild the module cache.\n";
- ModuleCacheHintDisplayed = true;
- }
- } else if (IsArchive) {
- // If the module cache directory doesn't exist at all and the
- // object file is inside a static library, we assume that the
- // static library was built on a different machine. We don't want
- // to discourage module debugging for convenience libraries within
- // a project though.
- if (!ArchiveHintDisplayed) {
- WithColor::note()
- << "Linking a static library that was built with "
- "-gmodules, but the module cache was not found. "
- "Redistributable static libraries should never be "
- "built with module debugging enabled. The debug "
- "experience will be degraded due to incomplete "
- "debug information.\n";
- ArchiveHintDisplayed = true;
- }
- }
- }
-
- return ErrorOrObj.getError();
- }
-
- llvm_unreachable("Unhandled DebugMap object");
- });
- GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces);
-
- for (const auto &Obj : Map.objects()) {
- // N_AST objects (swiftmodule files) should get dumped directly into the
- // appropriate DWARF section.
- if (Obj->getType() == MachO::N_AST) {
- if (Options.Verbose)
- outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
-
- StringRef File = Obj->getObjectFilename();
- auto ErrorOrMem = MemoryBuffer::getFile(File);
- if (!ErrorOrMem) {
- warn("Could not open '" + File + "'\n");
- continue;
- }
- sys::fs::file_status Stat;
- if (auto Err = sys::fs::status(File, Stat)) {
- warn(Err.message());
- continue;
- }
- if (!Options.NoTimestamp) {
- // The modification can have sub-second precision so we need to cast
- // away the extra precision that's not present in the debug map.
- auto ModificationTime =
- std::chrono::time_point_cast<std::chrono::seconds>(
- Stat.getLastModificationTime());
- if (ModificationTime != Obj->getTimestamp()) {
- // Not using the helper here as we can easily stream TimePoint<>.
+ auto &Obj = DebugMap.addDebugMapObject(
+ Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
+
+ if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) {
+ return *ErrorOrObj;
+ } else {
+ // Try and emit more helpful warnings by applying some heuristics.
+ StringRef ObjFile = ContainerName;
+ bool IsClangModule = sys::path::extension(Path).equals(".pcm");
+ bool IsArchive = ObjFile.endswith(")");
+
+ if (IsClangModule) {
+ StringRef ModuleCacheDir = sys::path::parent_path(Path);
+ if (sys::fs::exists(ModuleCacheDir)) {
+ // If the module's parent directory exists, we assume that the
+ // module cache has expired and was pruned by clang. A more
+ // adventurous dsymutil would invoke clang to rebuild the module
+ // now.
+ if (!ModuleCacheHintDisplayed) {
+ WithColor::note()
+ << "The clang module cache may have expired since "
+ "this object file was built. Rebuilding the "
+ "object file will rebuild the module cache.\n";
+ ModuleCacheHintDisplayed = true;
+ }
+ } else if (IsArchive) {
+ // If the module cache directory doesn't exist at all and the
+ // object file is inside a static library, we assume that the
+ // static library was built on a different machine. We don't want
+ // to discourage module debugging for convenience libraries within
+ // a project though.
+ if (!ArchiveHintDisplayed) {
+ WithColor::note()
+ << "Linking a static library that was built with "
+ "-gmodules, but the module cache was not found. "
+ "Redistributable static libraries should never be "
+ "built with module debugging enabled. The debug "
+ "experience will be degraded due to incomplete "
+ "debug information.\n";
+ ArchiveHintDisplayed = true;
+ }
+ }
+ }
+
+ return ErrorOrObj.getError();
+ }
+
+ llvm_unreachable("Unhandled DebugMap object");
+ });
+ GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces);
+
+ for (const auto &Obj : Map.objects()) {
+ // N_AST objects (swiftmodule files) should get dumped directly into the
+ // appropriate DWARF section.
+ if (Obj->getType() == MachO::N_AST) {
+ if (Options.Verbose)
+ outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
+
+ StringRef File = Obj->getObjectFilename();
+ auto ErrorOrMem = MemoryBuffer::getFile(File);
+ if (!ErrorOrMem) {
+ warn("Could not open '" + File + "'\n");
+ continue;
+ }
+ sys::fs::file_status Stat;
+ if (auto Err = sys::fs::status(File, Stat)) {
+ warn(Err.message());
+ continue;
+ }
+ if (!Options.NoTimestamp) {
+ // The modification can have sub-second precision so we need to cast
+ // away the extra precision that's not present in the debug map.
+ auto ModificationTime =
+ std::chrono::time_point_cast<std::chrono::seconds>(
+ Stat.getLastModificationTime());
+ if (ModificationTime != Obj->getTimestamp()) {
+ // Not using the helper here as we can easily stream TimePoint<>.
WithColor::warning()
<< File << ": timestamp mismatch between swift interface file ("
<< sys::TimePoint<>(Obj->getTimestamp()) << ") and debug map ("
<< sys::TimePoint<>(Obj->getTimestamp()) << ")\n";
- continue;
- }
- }
-
- // Copy the module into the .swift_ast section.
- if (!Options.NoOutput)
- Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
-
- continue;
- }
-
- if (auto ErrorOrObj = loadObject(*Obj, Map, RL))
- GeneralLinker.addObjectFile(*ErrorOrObj);
- else {
+ continue;
+ }
+ }
+
+ // Copy the module into the .swift_ast section.
+ if (!Options.NoOutput)
+ Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
+
+ continue;
+ }
+
+ if (auto ErrorOrObj = loadObject(*Obj, Map, RL))
+ GeneralLinker.addObjectFile(*ErrorOrObj);
+ else {
ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
- Obj->getObjectFilename(), nullptr, nullptr,
- Obj->empty() ? Obj->getWarnings() : EmptyWarnings));
- GeneralLinker.addObjectFile(*ObjectsForLinking.back());
- }
- }
-
- // link debug info for loaded object files.
- GeneralLinker.link();
-
- StringRef ArchName = Map.getTriple().getArchName();
- if (Error E = emitRemarks(Options, Map.getBinaryPath(), ArchName, RL))
- return error(toString(std::move(E)));
-
- if (Options.NoOutput)
- return true;
-
- if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) {
- StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch());
- if (auto E =
- copySwiftInterfaces(ParseableSwiftInterfaces, ArchName, Options))
- return error(toString(std::move(E)));
- }
-
- if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() &&
- Options.FileType == OutputFileType::Object)
- return MachOUtils::generateDsymCompanion(
- Options.VFS, Map, Options.Translator,
- *Streamer->getAsmPrinter().OutStreamer, OutFile);
-
- Streamer->finish();
- return true;
-}
-
-static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) {
- switch (Arch) {
- case Triple::x86:
- return RelocType == MachO::GENERIC_RELOC_SECTDIFF ||
- RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF;
- case Triple::x86_64:
- return RelocType == MachO::X86_64_RELOC_SUBTRACTOR;
- case Triple::arm:
- case Triple::thumb:
- return RelocType == MachO::ARM_RELOC_SECTDIFF ||
- RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
- RelocType == MachO::ARM_RELOC_HALF ||
- RelocType == MachO::ARM_RELOC_HALF_SECTDIFF;
- case Triple::aarch64:
- return RelocType == MachO::ARM64_RELOC_SUBTRACTOR;
- default:
- return false;
- }
-}
-
-/// Iterate over the relocations of the given \p Section and
-/// store the ones that correspond to debug map entries into the
-/// ValidRelocs array.
-void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
- const object::SectionRef &Section, const object::MachOObjectFile &Obj,
+ Obj->getObjectFilename(), nullptr, nullptr,
+ Obj->empty() ? Obj->getWarnings() : EmptyWarnings));
+ GeneralLinker.addObjectFile(*ObjectsForLinking.back());
+ }
+ }
+
+ // link debug info for loaded object files.
+ GeneralLinker.link();
+
+ StringRef ArchName = Map.getTriple().getArchName();
+ if (Error E = emitRemarks(Options, Map.getBinaryPath(), ArchName, RL))
+ return error(toString(std::move(E)));
+
+ if (Options.NoOutput)
+ return true;
+
+ if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) {
+ StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch());
+ if (auto E =
+ copySwiftInterfaces(ParseableSwiftInterfaces, ArchName, Options))
+ return error(toString(std::move(E)));
+ }
+
+ if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() &&
+ Options.FileType == OutputFileType::Object)
+ return MachOUtils::generateDsymCompanion(
+ Options.VFS, Map, Options.Translator,
+ *Streamer->getAsmPrinter().OutStreamer, OutFile);
+
+ Streamer->finish();
+ return true;
+}
+
+static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) {
+ switch (Arch) {
+ case Triple::x86:
+ return RelocType == MachO::GENERIC_RELOC_SECTDIFF ||
+ RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF;
+ case Triple::x86_64:
+ return RelocType == MachO::X86_64_RELOC_SUBTRACTOR;
+ case Triple::arm:
+ case Triple::thumb:
+ return RelocType == MachO::ARM_RELOC_SECTDIFF ||
+ RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
+ RelocType == MachO::ARM_RELOC_HALF ||
+ RelocType == MachO::ARM_RELOC_HALF_SECTDIFF;
+ case Triple::aarch64:
+ return RelocType == MachO::ARM64_RELOC_SUBTRACTOR;
+ default:
+ return false;
+ }
+}
+
+/// Iterate over the relocations of the given \p Section and
+/// store the ones that correspond to debug map entries into the
+/// ValidRelocs array.
+void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
+ const object::SectionRef &Section, const object::MachOObjectFile &Obj,
const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) {
- Expected<StringRef> ContentsOrErr = Section.getContents();
- if (!ContentsOrErr) {
- consumeError(ContentsOrErr.takeError());
- Linker.reportWarning("error reading section", DMO.getObjectFilename());
- return;
- }
- DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0);
- bool SkipNext = false;
-
- for (const object::RelocationRef &Reloc : Section.relocations()) {
- if (SkipNext) {
- SkipNext = false;
- continue;
- }
-
- object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
- MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
-
- if (isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),
- Obj.getArch())) {
- SkipNext = true;
+ Expected<StringRef> ContentsOrErr = Section.getContents();
+ if (!ContentsOrErr) {
+ consumeError(ContentsOrErr.takeError());
+ Linker.reportWarning("error reading section", DMO.getObjectFilename());
+ return;
+ }
+ DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0);
+ bool SkipNext = false;
+
+ for (const object::RelocationRef &Reloc : Section.relocations()) {
+ if (SkipNext) {
+ SkipNext = false;
+ continue;
+ }
+
+ object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
+ MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
+
+ if (isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),
+ Obj.getArch())) {
+ SkipNext = true;
Linker.reportWarning("unsupported relocation in " + *Section.getName() +
" section.",
- DMO.getObjectFilename());
- continue;
- }
-
- unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
- uint64_t Offset64 = Reloc.getOffset();
- if ((RelocSize != 4 && RelocSize != 8)) {
+ DMO.getObjectFilename());
+ continue;
+ }
+
+ unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
+ uint64_t Offset64 = Reloc.getOffset();
+ if ((RelocSize != 4 && RelocSize != 8)) {
Linker.reportWarning("unsupported relocation in " + *Section.getName() +
" section.",
- DMO.getObjectFilename());
- continue;
- }
- uint64_t OffsetCopy = Offset64;
- // Mach-o uses REL relocations, the addend is at the relocation offset.
- uint64_t Addend = Data.getUnsigned(&OffsetCopy, RelocSize);
- uint64_t SymAddress;
- int64_t SymOffset;
-
- if (Obj.isRelocationScattered(MachOReloc)) {
- // The address of the base symbol for scattered relocations is
- // stored in the reloc itself. The actual addend will store the
- // base address plus the offset.
- SymAddress = Obj.getScatteredRelocationValue(MachOReloc);
- SymOffset = int64_t(Addend) - SymAddress;
- } else {
- SymAddress = Addend;
- SymOffset = 0;
- }
-
- auto Sym = Reloc.getSymbol();
- if (Sym != Obj.symbol_end()) {
- Expected<StringRef> SymbolName = Sym->getName();
- if (!SymbolName) {
- consumeError(SymbolName.takeError());
- Linker.reportWarning("error getting relocation symbol name.",
- DMO.getObjectFilename());
- continue;
- }
- if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
- ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
- } else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) {
- // Do not store the addend. The addend was the address of the symbol in
- // the object file, the address in the binary that is stored in the debug
- // map doesn't need to be offset.
- ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping);
- }
- }
-}
-
-/// Dispatch the valid relocation finding logic to the
-/// appropriate handler depending on the object file format.
-bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
- const object::SectionRef &Section, const object::ObjectFile &Obj,
+ DMO.getObjectFilename());
+ continue;
+ }
+ uint64_t OffsetCopy = Offset64;
+ // Mach-o uses REL relocations, the addend is at the relocation offset.
+ uint64_t Addend = Data.getUnsigned(&OffsetCopy, RelocSize);
+ uint64_t SymAddress;
+ int64_t SymOffset;
+
+ if (Obj.isRelocationScattered(MachOReloc)) {
+ // The address of the base symbol for scattered relocations is
+ // stored in the reloc itself. The actual addend will store the
+ // base address plus the offset.
+ SymAddress = Obj.getScatteredRelocationValue(MachOReloc);
+ SymOffset = int64_t(Addend) - SymAddress;
+ } else {
+ SymAddress = Addend;
+ SymOffset = 0;
+ }
+
+ auto Sym = Reloc.getSymbol();
+ if (Sym != Obj.symbol_end()) {
+ Expected<StringRef> SymbolName = Sym->getName();
+ if (!SymbolName) {
+ consumeError(SymbolName.takeError());
+ Linker.reportWarning("error getting relocation symbol name.",
+ DMO.getObjectFilename());
+ continue;
+ }
+ if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
+ ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
+ } else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) {
+ // Do not store the addend. The addend was the address of the symbol in
+ // the object file, the address in the binary that is stored in the debug
+ // map doesn't need to be offset.
+ ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping);
+ }
+ }
+}
+
+/// Dispatch the valid relocation finding logic to the
+/// appropriate handler depending on the object file format.
+bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
+ const object::SectionRef &Section, const object::ObjectFile &Obj,
const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
- // Dispatch to the right handler depending on the file type.
- if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
+ // Dispatch to the right handler depending on the file type.
+ if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
findValidRelocsMachO(Section, *MachOObj, DMO, Relocs);
- else
- Linker.reportWarning(Twine("unsupported object file type: ") +
- Obj.getFileName(),
- DMO.getObjectFilename());
+ else
+ Linker.reportWarning(Twine("unsupported object file type: ") +
+ Obj.getFileName(),
+ DMO.getObjectFilename());
if (Relocs.empty())
- return false;
-
- // Sort the relocations by offset. We will walk the DIEs linearly in
- // the file, this allows us to just keep an index in the relocation
- // array that we advance during our walk, rather than resorting to
- // some associative container. See DwarfLinkerForBinary::NextValidReloc.
+ return false;
+
+ // Sort the relocations by offset. We will walk the DIEs linearly in
+ // the file, this allows us to just keep an index in the relocation
+ // array that we advance during our walk, rather than resorting to
+ // some associative container. See DwarfLinkerForBinary::NextValidReloc.
llvm::sort(Relocs);
- return true;
-}
-
+ return true;
+}
+
/// Look for relocations in the debug_info and debug_addr section that match
/// entries in the debug map. These relocations will drive the Dwarf link by
/// indicating which DIEs refer to symbols present in the linked binary.
-/// \returns whether there are any valid relocations in the debug info.
+/// \returns whether there are any valid relocations in the debug info.
bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
- const object::ObjectFile &Obj, const DebugMapObject &DMO) {
- // Find the debug_info section.
+ const object::ObjectFile &Obj, const DebugMapObject &DMO) {
+ // Find the debug_info section.
bool FoundValidRelocs = false;
- for (const object::SectionRef &Section : Obj.sections()) {
- StringRef SectionName;
- if (Expected<StringRef> NameOrErr = Section.getName())
- SectionName = *NameOrErr;
- else
- consumeError(NameOrErr.takeError());
-
- SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
+ for (const object::SectionRef &Section : Obj.sections()) {
+ StringRef SectionName;
+ if (Expected<StringRef> NameOrErr = Section.getName())
+ SectionName = *NameOrErr;
+ else
+ consumeError(NameOrErr.takeError());
+
+ SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
if (SectionName == "debug_info")
FoundValidRelocs |=
findValidRelocs(Section, Obj, DMO, ValidDebugInfoRelocs);
if (SectionName == "debug_addr")
FoundValidRelocs |=
findValidRelocs(Section, Obj, DMO, ValidDebugAddrRelocs);
- }
+ }
return FoundValidRelocs;
-}
-
+}
+
bool DwarfLinkerForBinary::AddressManager::hasValidDebugAddrRelocationAt(
uint64_t Offset) {
auto It = std::lower_bound(ValidDebugAddrRelocs.begin(),
@@ -619,44 +619,44 @@ bool DwarfLinkerForBinary::AddressManager::hasValidDebugAddrRelocationAt(
}
bool DwarfLinkerForBinary::AddressManager::hasValidDebugInfoRelocationAt(
- uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) {
- assert(NextValidReloc == 0 ||
+ uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) {
+ assert(NextValidReloc == 0 ||
StartOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset);
if (NextValidReloc >= ValidDebugInfoRelocs.size())
- return false;
-
+ return false;
+
uint64_t RelocOffset = ValidDebugInfoRelocs[NextValidReloc].Offset;
-
- // We might need to skip some relocs that we didn't consider. For
- // example the high_pc of a discarded DIE might contain a reloc that
- // is in the list because it actually corresponds to the start of a
- // function that is in the debug map.
+
+ // We might need to skip some relocs that we didn't consider. For
+ // example the high_pc of a discarded DIE might contain a reloc that
+ // is in the list because it actually corresponds to the start of a
+ // function that is in the debug map.
while (RelocOffset < StartOffset &&
NextValidReloc < ValidDebugInfoRelocs.size() - 1)
RelocOffset = ValidDebugInfoRelocs[++NextValidReloc].Offset;
-
- if (RelocOffset < StartOffset || RelocOffset >= EndOffset)
- return false;
-
+
+ if (RelocOffset < StartOffset || RelocOffset >= EndOffset)
+ return false;
+
const auto &ValidReloc = ValidDebugInfoRelocs[NextValidReloc++];
- const auto &Mapping = ValidReloc.Mapping->getValue();
- const uint64_t BinaryAddress = Mapping.BinaryAddress;
- const uint64_t ObjectAddress = Mapping.ObjectAddress
- ? uint64_t(*Mapping.ObjectAddress)
- : std::numeric_limits<uint64_t>::max();
- if (Linker.Options.Verbose)
- outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey()
- << "\t"
- << format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress,
- BinaryAddress);
-
- Info.AddrAdjust = BinaryAddress + ValidReloc.Addend;
- if (Mapping.ObjectAddress)
- Info.AddrAdjust -= ObjectAddress;
- Info.InDebugMap = true;
- return true;
-}
-
+ const auto &Mapping = ValidReloc.Mapping->getValue();
+ const uint64_t BinaryAddress = Mapping.BinaryAddress;
+ const uint64_t ObjectAddress = Mapping.ObjectAddress
+ ? uint64_t(*Mapping.ObjectAddress)
+ : std::numeric_limits<uint64_t>::max();
+ if (Linker.Options.Verbose)
+ outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey()
+ << "\t"
+ << format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress,
+ BinaryAddress);
+
+ Info.AddrAdjust = BinaryAddress + ValidReloc.Addend;
+ if (Mapping.ObjectAddress)
+ Info.AddrAdjust -= ObjectAddress;
+ Info.InDebugMap = true;
+ return true;
+}
+
/// Get the starting and ending (exclusive) offset for the
/// attribute with index \p Idx descibed by \p Abbrev. \p Offset is
/// supposed to point to the position of the first attribute described
@@ -722,51 +722,51 @@ bool DwarfLinkerForBinary::AddressManager::hasLiveAddressRange(
return false;
}
-/// Apply the valid relocations found by findValidRelocs() to
-/// the buffer \p Data, taking into account that Data is at \p BaseOffset
-/// in the debug_info section.
-///
-/// Like for findValidRelocs(), this function must be called with
-/// monotonic \p BaseOffset values.
-///
-/// \returns whether any reloc has been applied.
-bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
- MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
- assert(areRelocationsResolved());
- assert((NextValidReloc == 0 ||
+/// Apply the valid relocations found by findValidRelocs() to
+/// the buffer \p Data, taking into account that Data is at \p BaseOffset
+/// in the debug_info section.
+///
+/// Like for findValidRelocs(), this function must be called with
+/// monotonic \p BaseOffset values.
+///
+/// \returns whether any reloc has been applied.
+bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
+ MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
+ assert(areRelocationsResolved());
+ assert((NextValidReloc == 0 ||
BaseOffset > ValidDebugInfoRelocs[NextValidReloc - 1].Offset) &&
- "BaseOffset should only be increasing.");
+ "BaseOffset should only be increasing.");
if (NextValidReloc >= ValidDebugInfoRelocs.size())
- return false;
-
- // Skip relocs that haven't been applied.
+ return false;
+
+ // Skip relocs that haven't been applied.
while (NextValidReloc < ValidDebugInfoRelocs.size() &&
ValidDebugInfoRelocs[NextValidReloc].Offset < BaseOffset)
- ++NextValidReloc;
-
- bool Applied = false;
- uint64_t EndOffset = BaseOffset + Data.size();
+ ++NextValidReloc;
+
+ bool Applied = false;
+ uint64_t EndOffset = BaseOffset + Data.size();
while (NextValidReloc < ValidDebugInfoRelocs.size() &&
ValidDebugInfoRelocs[NextValidReloc].Offset >= BaseOffset &&
ValidDebugInfoRelocs[NextValidReloc].Offset < EndOffset) {
const auto &ValidReloc = ValidDebugInfoRelocs[NextValidReloc++];
- assert(ValidReloc.Offset - BaseOffset < Data.size());
- assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size());
- char Buf[8];
- uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress;
- Value += ValidReloc.Addend;
- for (unsigned I = 0; I != ValidReloc.Size; ++I) {
- unsigned Index = IsLittleEndian ? I : (ValidReloc.Size - I - 1);
- Buf[I] = uint8_t(Value >> (Index * 8));
- }
- assert(ValidReloc.Size <= sizeof(Buf));
- memcpy(&Data[ValidReloc.Offset - BaseOffset], Buf, ValidReloc.Size);
- Applied = true;
- }
-
- return Applied;
-}
-
+ assert(ValidReloc.Offset - BaseOffset < Data.size());
+ assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size());
+ char Buf[8];
+ uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress;
+ Value += ValidReloc.Addend;
+ for (unsigned I = 0; I != ValidReloc.Size; ++I) {
+ unsigned Index = IsLittleEndian ? I : (ValidReloc.Size - I - 1);
+ Buf[I] = uint8_t(Value >> (Index * 8));
+ }
+ assert(ValidReloc.Size <= sizeof(Buf));
+ memcpy(&Data[ValidReloc.Offset - BaseOffset], Buf, ValidReloc.Size);
+ Applied = true;
+ }
+
+ return Applied;
+}
+
llvm::Expected<uint64_t>
DwarfLinkerForBinary::AddressManager::relocateIndexedAddr(uint64_t Offset) {
auto It = std::lower_bound(ValidDebugAddrRelocs.begin(),
@@ -778,11 +778,11 @@ DwarfLinkerForBinary::AddressManager::relocateIndexedAddr(uint64_t Offset) {
return It->Mapping->getValue().BinaryAddress + It->Addend;
}
-bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
- const DebugMap &DM, LinkOptions Options) {
- DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options));
- return Linker.link(DM);
-}
-
-} // namespace dsymutil
-} // namespace llvm
+bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
+ const DebugMap &DM, LinkOptions Options) {
+ DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options));
+ return Linker.link(DM);
+}
+
+} // namespace dsymutil
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h
index c6c07d689f..849d2c7fa5 100644
--- a/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h
+++ b/contrib/libs/llvm12/tools/dsymutil/DwarfLinkerForBinary.h
@@ -1,154 +1,154 @@
-//===- tools/dsymutil/DwarfLinkerForBinary.h --------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
-#define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
-
-#include "BinaryHolder.h"
-#include "DebugMap.h"
-#include "LinkUtils.h"
-#include "llvm/DWARFLinker/DWARFLinker.h"
-#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
-#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
-#include "llvm/DWARFLinker/DWARFStreamer.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
-#include "llvm/Remarks/RemarkFormat.h"
-#include "llvm/Remarks/RemarkLinker.h"
-
-namespace llvm {
-namespace dsymutil {
-
-/// The core of the Dsymutil Dwarf linking logic.
-///
-/// The link of the dwarf information from the object files will be
-/// driven by DWARFLinker. DwarfLinkerForBinary reads DebugMap objects
-/// and pass information to the DWARFLinker. DWARFLinker
-/// optimizes DWARF taking into account valid relocations.
-/// Finally, optimized DWARF is passed to DwarfLinkerForBinary through
-/// DWARFEmitter interface.
-class DwarfLinkerForBinary {
-public:
- DwarfLinkerForBinary(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
- LinkOptions Options)
- : OutFile(OutFile), BinHolder(BinHolder), Options(std::move(Options)) {}
-
- /// Link the contents of the DebugMap.
- bool link(const DebugMap &);
-
- void reportWarning(const Twine &Warning, StringRef Context,
- const DWARFDie *DIE = nullptr) const;
-
- /// Flags passed to DwarfLinker::lookForDIEsToKeep
- enum TraversalFlags {
- TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept.
- TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope.
- TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE.
- TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE.
- TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents.
- TF_SkipPC = 1 << 5, ///< Skip all location attributes.
- };
-
-private:
-
- /// Keeps track of relocations.
- class AddressManager : public AddressesMap {
- struct ValidReloc {
- uint64_t Offset;
- uint32_t Size;
- uint64_t Addend;
- const DebugMapObject::DebugMapEntry *Mapping;
-
- ValidReloc(uint64_t Offset, uint32_t Size, uint64_t Addend,
- const DebugMapObject::DebugMapEntry *Mapping)
- : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
-
- bool operator<(const ValidReloc &RHS) const {
- return Offset < RHS.Offset;
- }
+//===- tools/dsymutil/DwarfLinkerForBinary.h --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
+#define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
+
+#include "BinaryHolder.h"
+#include "DebugMap.h"
+#include "LinkUtils.h"
+#include "llvm/DWARFLinker/DWARFLinker.h"
+#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
+#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
+#include "llvm/DWARFLinker/DWARFStreamer.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Remarks/RemarkFormat.h"
+#include "llvm/Remarks/RemarkLinker.h"
+
+namespace llvm {
+namespace dsymutil {
+
+/// The core of the Dsymutil Dwarf linking logic.
+///
+/// The link of the dwarf information from the object files will be
+/// driven by DWARFLinker. DwarfLinkerForBinary reads DebugMap objects
+/// and pass information to the DWARFLinker. DWARFLinker
+/// optimizes DWARF taking into account valid relocations.
+/// Finally, optimized DWARF is passed to DwarfLinkerForBinary through
+/// DWARFEmitter interface.
+class DwarfLinkerForBinary {
+public:
+ DwarfLinkerForBinary(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
+ LinkOptions Options)
+ : OutFile(OutFile), BinHolder(BinHolder), Options(std::move(Options)) {}
+
+ /// Link the contents of the DebugMap.
+ bool link(const DebugMap &);
+
+ void reportWarning(const Twine &Warning, StringRef Context,
+ const DWARFDie *DIE = nullptr) const;
+
+ /// Flags passed to DwarfLinker::lookForDIEsToKeep
+ enum TraversalFlags {
+ TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept.
+ TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope.
+ TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE.
+ TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE.
+ TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents.
+ TF_SkipPC = 1 << 5, ///< Skip all location attributes.
+ };
+
+private:
+
+ /// Keeps track of relocations.
+ class AddressManager : public AddressesMap {
+ struct ValidReloc {
+ uint64_t Offset;
+ uint32_t Size;
+ uint64_t Addend;
+ const DebugMapObject::DebugMapEntry *Mapping;
+
+ ValidReloc(uint64_t Offset, uint32_t Size, uint64_t Addend,
+ const DebugMapObject::DebugMapEntry *Mapping)
+ : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
+
+ bool operator<(const ValidReloc &RHS) const {
+ return Offset < RHS.Offset;
+ }
bool operator<(uint64_t RHS) const { return Offset < RHS; }
- };
-
- const DwarfLinkerForBinary &Linker;
-
- /// The valid relocations for the current DebugMapObject.
- /// This vector is sorted by relocation offset.
+ };
+
+ const DwarfLinkerForBinary &Linker;
+
+ /// The valid relocations for the current DebugMapObject.
+ /// This vector is sorted by relocation offset.
/// {
std::vector<ValidReloc> ValidDebugInfoRelocs;
std::vector<ValidReloc> ValidDebugAddrRelocs;
/// }
-
- /// Index into ValidRelocs of the next relocation to consider. As we walk
- /// the DIEs in acsending file offset and as ValidRelocs is sorted by file
- /// offset, keeping this index up to date is all we have to do to have a
- /// cheap lookup during the root DIE selection and during DIE cloning.
- unsigned NextValidReloc = 0;
-
- RangesTy AddressRanges;
-
- public:
- AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj,
- const DebugMapObject &DMO)
- : Linker(Linker) {
+
+ /// Index into ValidRelocs of the next relocation to consider. As we walk
+ /// the DIEs in acsending file offset and as ValidRelocs is sorted by file
+ /// offset, keeping this index up to date is all we have to do to have a
+ /// cheap lookup during the root DIE selection and during DIE cloning.
+ unsigned NextValidReloc = 0;
+
+ RangesTy AddressRanges;
+
+ public:
+ AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj,
+ const DebugMapObject &DMO)
+ : Linker(Linker) {
findValidRelocsInDebugSections(Obj, DMO);
-
- // Iterate over the debug map entries and put all the ones that are
- // functions (because they have a size) into the Ranges map. This map is
- // very similar to the FunctionRanges that are stored in each unit, with 2
- // notable differences:
- //
- // 1. Obviously this one is global, while the other ones are per-unit.
- //
- // 2. This one contains not only the functions described in the DIE
- // tree, but also the ones that are only in the debug map.
- //
- // The latter information is required to reproduce dsymutil's logic while
- // linking line tables. The cases where this information matters look like
- // bugs that need to be investigated, but for now we need to reproduce
- // dsymutil's behavior.
- // FIXME: Once we understood exactly if that information is needed,
- // maybe totally remove this (or try to use it to do a real
- // -gline-tables-only on Darwin.
- for (const auto &Entry : DMO.symbols()) {
- const auto &Mapping = Entry.getValue();
- if (Mapping.Size && Mapping.ObjectAddress)
- AddressRanges[*Mapping.ObjectAddress] = ObjFileAddressRange(
- *Mapping.ObjectAddress + Mapping.Size,
- int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress);
- }
- }
- virtual ~AddressManager() override { clear(); }
-
- virtual bool areRelocationsResolved() const override { return true; }
-
- bool hasValidRelocs(bool ResetRelocsPtr = true) override {
- if (ResetRelocsPtr)
- NextValidReloc = 0;
+
+ // Iterate over the debug map entries and put all the ones that are
+ // functions (because they have a size) into the Ranges map. This map is
+ // very similar to the FunctionRanges that are stored in each unit, with 2
+ // notable differences:
+ //
+ // 1. Obviously this one is global, while the other ones are per-unit.
+ //
+ // 2. This one contains not only the functions described in the DIE
+ // tree, but also the ones that are only in the debug map.
+ //
+ // The latter information is required to reproduce dsymutil's logic while
+ // linking line tables. The cases where this information matters look like
+ // bugs that need to be investigated, but for now we need to reproduce
+ // dsymutil's behavior.
+ // FIXME: Once we understood exactly if that information is needed,
+ // maybe totally remove this (or try to use it to do a real
+ // -gline-tables-only on Darwin.
+ for (const auto &Entry : DMO.symbols()) {
+ const auto &Mapping = Entry.getValue();
+ if (Mapping.Size && Mapping.ObjectAddress)
+ AddressRanges[*Mapping.ObjectAddress] = ObjFileAddressRange(
+ *Mapping.ObjectAddress + Mapping.Size,
+ int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress);
+ }
+ }
+ virtual ~AddressManager() override { clear(); }
+
+ virtual bool areRelocationsResolved() const override { return true; }
+
+ bool hasValidRelocs(bool ResetRelocsPtr = true) override {
+ if (ResetRelocsPtr)
+ NextValidReloc = 0;
return !ValidDebugInfoRelocs.empty() || !ValidDebugAddrRelocs.empty();
- }
-
- /// \defgroup FindValidRelocations Translate debug map into a list
- /// of relevant relocations
- ///
- /// @{
+ }
+
+ /// \defgroup FindValidRelocations Translate debug map into a list
+ /// of relevant relocations
+ ///
+ /// @{
bool findValidRelocsInDebugSections(const object::ObjectFile &Obj,
const DebugMapObject &DMO);
-
- bool findValidRelocs(const object::SectionRef &Section,
- const object::ObjectFile &Obj,
+
+ bool findValidRelocs(const object::SectionRef &Section,
+ const object::ObjectFile &Obj,
const DebugMapObject &DMO,
std::vector<ValidReloc> &ValidRelocs);
-
- void findValidRelocsMachO(const object::SectionRef &Section,
- const object::MachOObjectFile &Obj,
+
+ void findValidRelocsMachO(const object::SectionRef &Section,
+ const object::MachOObjectFile &Obj,
const DebugMapObject &DMO,
std::vector<ValidReloc> &ValidRelocs);
- /// @}
-
+ /// @}
+
/// Checks that there is a relocation in the debug_addr section against a
/// debug map entry between \p StartOffset and \p NextOffset.
///
@@ -157,7 +157,7 @@ private:
/// \returns true and sets Info.InDebugMap if it is the case.
bool hasValidDebugInfoRelocationAt(uint64_t StartOffset, uint64_t EndOffset,
CompileUnit::DIEInfo &Info);
-
+
/// Checks that there is a relocation in the debug_addr section against a
/// debug map entry at the given offset.
bool hasValidDebugAddrRelocationAt(uint64_t Offset);
@@ -167,54 +167,54 @@ private:
bool hasLiveAddressRange(const DWARFDie &DIE,
CompileUnit::DIEInfo &Info) override;
- bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
- bool IsLittleEndian) override;
-
+ bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
+ bool IsLittleEndian) override;
+
llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t Offset) override;
- RangesTy &getValidAddressRanges() override { return AddressRanges; }
-
- void clear() override {
- AddressRanges.clear();
+ RangesTy &getValidAddressRanges() override { return AddressRanges; }
+
+ void clear() override {
+ AddressRanges.clear();
ValidDebugInfoRelocs.clear();
ValidDebugAddrRelocs.clear();
- NextValidReloc = 0;
- }
- };
-
-private:
- /// \defgroup Helpers Various helper methods.
- ///
- /// @{
- bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile);
-
- /// Attempt to load a debug object from disk.
- ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
- const Triple &triple);
+ NextValidReloc = 0;
+ }
+ };
+
+private:
+ /// \defgroup Helpers Various helper methods.
+ ///
+ /// @{
+ bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile);
+
+ /// Attempt to load a debug object from disk.
+ ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
+ const Triple &triple);
ErrorOr<DWARFFile &> loadObject(const DebugMapObject &Obj,
- const DebugMap &DebugMap,
- remarks::RemarkLinker &RL);
-
- raw_fd_ostream &OutFile;
- BinaryHolder &BinHolder;
- LinkOptions Options;
- std::unique_ptr<DwarfStreamer> Streamer;
+ const DebugMap &DebugMap,
+ remarks::RemarkLinker &RL);
+
+ raw_fd_ostream &OutFile;
+ BinaryHolder &BinHolder;
+ LinkOptions Options;
+ std::unique_ptr<DwarfStreamer> Streamer;
std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking;
- std::vector<std::unique_ptr<DWARFContext>> ContextForLinking;
- std::vector<std::unique_ptr<AddressManager>> AddressMapForLinking;
- std::vector<std::string> EmptyWarnings;
-
- /// A list of all .swiftinterface files referenced by the debug
- /// info, mapping Module name to path on disk. The entries need to
- /// be uniqued and sorted and there are only few entries expected
- /// per compile unit, which is why this is a std::map.
- std::map<std::string, std::string> ParseableSwiftInterfaces;
-
- bool ModuleCacheHintDisplayed = false;
- bool ArchiveHintDisplayed = false;
-};
-
-} // end namespace dsymutil
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
+ std::vector<std::unique_ptr<DWARFContext>> ContextForLinking;
+ std::vector<std::unique_ptr<AddressManager>> AddressMapForLinking;
+ std::vector<std::string> EmptyWarnings;
+
+ /// A list of all .swiftinterface files referenced by the debug
+ /// info, mapping Module name to path on disk. The entries need to
+ /// be uniqued and sorted and there are only few entries expected
+ /// per compile unit, which is why this is a std::map.
+ std::map<std::string, std::string> ParseableSwiftInterfaces;
+
+ bool ModuleCacheHintDisplayed = false;
+ bool ArchiveHintDisplayed = false;
+};
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
diff --git a/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h b/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h
index 52b36353c6..5b2e372547 100644
--- a/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h
+++ b/contrib/libs/llvm12/tools/dsymutil/LinkUtils.h
@@ -1,107 +1,107 @@
-//===- tools/dsymutil/LinkUtils.h - Dwarf linker utilities ------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
-#define LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
-
-#include "SymbolMap.h"
-
-#include "llvm/ADT/Twine.h"
-#include "llvm/Remarks/RemarkFormat.h"
-#include "llvm/Support/VirtualFileSystem.h"
-#include "llvm/Support/WithColor.h"
-
-#include "llvm/DWARFLinker/DWARFLinker.h"
-#include "llvm/DWARFLinker/DWARFStreamer.h"
-#include <string>
-
-namespace llvm {
-namespace dsymutil {
-
-struct LinkOptions {
- /// Verbosity
- bool Verbose = false;
-
- /// Statistics
- bool Statistics = false;
-
- /// Skip emitting output
- bool NoOutput = false;
-
- /// Do not unique types according to ODR
- bool NoODR = false;
-
- /// Update
- bool Update = false;
-
- /// Minimize
- bool Minimize = false;
-
- /// Do not check swiftmodule timestamp
- bool NoTimestamp = false;
-
- /// Number of threads.
- unsigned Threads = 1;
-
- // Output file type.
- OutputFileType FileType = OutputFileType::Object;
-
- /// The accelerator table kind
- AccelTableKind TheAccelTableKind;
-
- /// -oso-prepend-path
- std::string PrependPath;
-
- /// The -object-prefix-map.
- std::map<std::string, std::string> ObjectPrefixMap;
-
- /// The Resources directory in the .dSYM bundle.
- Optional<std::string> ResourceDir;
-
- /// Symbol map translator.
- SymbolMapTranslator Translator;
-
- /// Virtual File System.
- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
- vfs::getRealFileSystem();
-
- /// Fields used for linking and placing remarks into the .dSYM bundle.
- /// @{
-
- /// Number of debug maps processed in total.
- unsigned NumDebugMaps = 0;
-
- /// -remarks-prepend-path: prepend a path to all the external remark file
- /// paths found in remark metadata.
- std::string RemarksPrependPath;
-
- /// The output format of the remarks.
- remarks::Format RemarksFormat = remarks::Format::Bitstream;
-
- /// @}
-
- LinkOptions() = default;
-};
-
-inline void warn(Twine Warning, Twine Context = {}) {
- WithColor::warning() << Warning + "\n";
- if (!Context.isTriviallyEmpty())
- WithColor::note() << Twine("while processing ") + Context + "\n";
-}
-
-inline bool error(Twine Error, Twine Context = {}) {
- WithColor::error() << Error + "\n";
- if (!Context.isTriviallyEmpty())
- WithColor::note() << Twine("while processing ") + Context + "\n";
- return false;
-}
-
-} // end namespace dsymutil
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
+//===- tools/dsymutil/LinkUtils.h - Dwarf linker utilities ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
+#define LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
+
+#include "SymbolMap.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Remarks/RemarkFormat.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/WithColor.h"
+
+#include "llvm/DWARFLinker/DWARFLinker.h"
+#include "llvm/DWARFLinker/DWARFStreamer.h"
+#include <string>
+
+namespace llvm {
+namespace dsymutil {
+
+struct LinkOptions {
+ /// Verbosity
+ bool Verbose = false;
+
+ /// Statistics
+ bool Statistics = false;
+
+ /// Skip emitting output
+ bool NoOutput = false;
+
+ /// Do not unique types according to ODR
+ bool NoODR = false;
+
+ /// Update
+ bool Update = false;
+
+ /// Minimize
+ bool Minimize = false;
+
+ /// Do not check swiftmodule timestamp
+ bool NoTimestamp = false;
+
+ /// Number of threads.
+ unsigned Threads = 1;
+
+ // Output file type.
+ OutputFileType FileType = OutputFileType::Object;
+
+ /// The accelerator table kind
+ AccelTableKind TheAccelTableKind;
+
+ /// -oso-prepend-path
+ std::string PrependPath;
+
+ /// The -object-prefix-map.
+ std::map<std::string, std::string> ObjectPrefixMap;
+
+ /// The Resources directory in the .dSYM bundle.
+ Optional<std::string> ResourceDir;
+
+ /// Symbol map translator.
+ SymbolMapTranslator Translator;
+
+ /// Virtual File System.
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
+ vfs::getRealFileSystem();
+
+ /// Fields used for linking and placing remarks into the .dSYM bundle.
+ /// @{
+
+ /// Number of debug maps processed in total.
+ unsigned NumDebugMaps = 0;
+
+ /// -remarks-prepend-path: prepend a path to all the external remark file
+ /// paths found in remark metadata.
+ std::string RemarksPrependPath;
+
+ /// The output format of the remarks.
+ remarks::Format RemarksFormat = remarks::Format::Bitstream;
+
+ /// @}
+
+ LinkOptions() = default;
+};
+
+inline void warn(Twine Warning, Twine Context = {}) {
+ WithColor::warning() << Warning + "\n";
+ if (!Context.isTriviallyEmpty())
+ WithColor::note() << Twine("while processing ") + Context + "\n";
+}
+
+inline bool error(Twine Error, Twine Context = {}) {
+ WithColor::error() << Error + "\n";
+ if (!Context.isTriviallyEmpty())
+ WithColor::note() << Twine("while processing ") + Context + "\n";
+ return false;
+}
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_LINKOPTIONS_H
diff --git a/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp b/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp
index 37848c561a..4c05326dc2 100644
--- a/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp
+++ b/contrib/libs/llvm12/tools/dsymutil/MachODebugMapParser.cpp
@@ -1,609 +1,609 @@
-//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "BinaryHolder.h"
-#include "DebugMap.h"
-#include "MachOUtils.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-#include <vector>
-
-namespace {
-using namespace llvm;
-using namespace llvm::dsymutil;
-using namespace llvm::object;
-
-class MachODebugMapParser {
-public:
- MachODebugMapParser(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- StringRef BinaryPath, ArrayRef<std::string> Archs,
- StringRef PathPrefix = "",
- bool PaperTrailWarnings = false, bool Verbose = false)
- : BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()),
- PathPrefix(std::string(PathPrefix)),
- PaperTrailWarnings(PaperTrailWarnings), BinHolder(VFS, Verbose),
- CurrentDebugMapObject(nullptr) {}
-
- /// Parses and returns the DebugMaps of the input binary. The binary contains
- /// multiple maps in case it is a universal binary.
- /// \returns an error in case the provided BinaryPath doesn't exist
- /// or isn't of a supported type.
- ErrorOr<std::vector<std::unique_ptr<DebugMap>>> parse();
-
- /// Walk the symbol table and dump it.
- bool dumpStab();
-
-private:
- std::string BinaryPath;
- SmallVector<StringRef, 1> Archs;
- std::string PathPrefix;
- bool PaperTrailWarnings;
-
- /// Owns the MemoryBuffer for the main binary.
- BinaryHolder BinHolder;
- /// Map of the binary symbol addresses.
- StringMap<uint64_t> MainBinarySymbolAddresses;
- StringRef MainBinaryStrings;
- /// The constructed DebugMap.
- std::unique_ptr<DebugMap> Result;
- /// List of common symbols that need to be added to the debug map.
- std::vector<std::string> CommonSymbols;
-
- /// Map of the currently processed object file symbol addresses.
- StringMap<Optional<uint64_t>> CurrentObjectAddresses;
- /// Element of the debug map corresponding to the current object file.
- DebugMapObject *CurrentDebugMapObject;
-
- /// Holds function info while function scope processing.
- const char *CurrentFunctionName;
- uint64_t CurrentFunctionAddress;
-
- std::unique_ptr<DebugMap> parseOneBinary(const MachOObjectFile &MainBinary,
- StringRef BinaryPath);
-
- void
- switchToNewDebugMapObject(StringRef Filename,
- sys::TimePoint<std::chrono::seconds> Timestamp);
- void resetParserState();
- uint64_t getMainBinarySymbolAddress(StringRef Name);
- std::vector<StringRef> getMainBinarySymbolNames(uint64_t Value);
- void loadMainBinarySymbols(const MachOObjectFile &MainBinary);
- void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj);
- void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
- uint8_t SectionIndex, uint16_t Flags,
- uint64_t Value);
-
- template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) {
- handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
- STE.n_value);
- }
-
- void addCommonSymbols();
-
- /// Dump the symbol table output header.
- void dumpSymTabHeader(raw_ostream &OS, StringRef Arch);
-
- /// Dump the contents of nlist entries.
- void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, uint32_t StringIndex,
- uint8_t Type, uint8_t SectionIndex, uint16_t Flags,
- uint64_t Value);
-
- template <typename STEType>
- void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, const STEType &STE) {
- dumpSymTabEntry(OS, Index, STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
- STE.n_value);
- }
- void dumpOneBinaryStab(const MachOObjectFile &MainBinary,
- StringRef BinaryPath);
-
- void Warning(const Twine &Msg, StringRef File = StringRef()) {
- WithColor::warning() << "("
- << MachOUtils::getArchName(
- Result->getTriple().getArchName())
- << ") " << File << " " << Msg << "\n";
-
- if (PaperTrailWarnings) {
- if (!File.empty())
- Result->addDebugMapObject(File, sys::TimePoint<std::chrono::seconds>());
- if (Result->end() != Result->begin()) {
- auto it = Result->end();
- (*--it)->addWarning(Msg.str());
- }
- }
- }
-};
-
-} // anonymous namespace
-
-/// Reset the parser state corresponding to the current object
-/// file. This is to be called after an object file is finished
-/// processing.
-void MachODebugMapParser::resetParserState() {
- CommonSymbols.clear();
- CurrentObjectAddresses.clear();
- CurrentDebugMapObject = nullptr;
-}
-
-/// Commons symbols won't show up in the symbol map but might need to be
-/// relocated. We can add them to the symbol table ourselves by combining the
-/// information in the object file (the symbol name) and the main binary (the
-/// address).
-void MachODebugMapParser::addCommonSymbols() {
- for (auto &CommonSymbol : CommonSymbols) {
- uint64_t CommonAddr = getMainBinarySymbolAddress(CommonSymbol);
- if (CommonAddr == 0) {
- // The main binary doesn't have an address for the given symbol.
- continue;
- }
- if (!CurrentDebugMapObject->addSymbol(CommonSymbol, None /*ObjectAddress*/,
- CommonAddr, 0 /*size*/)) {
- // The symbol is already present.
- continue;
- }
- }
-}
-
-/// Create a new DebugMapObject. This function resets the state of the
-/// parser that was referring to the last object file and sets
-/// everything up to add symbols to the new one.
-void MachODebugMapParser::switchToNewDebugMapObject(
- StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) {
- addCommonSymbols();
- resetParserState();
-
- SmallString<80> Path(PathPrefix);
- sys::path::append(Path, Filename);
-
- auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp);
- if (!ObjectEntry) {
- auto Err = ObjectEntry.takeError();
- Warning("unable to open object file: " + toString(std::move(Err)),
- Path.str());
- return;
- }
-
- auto Object = ObjectEntry->getObjectAs<MachOObjectFile>(Result->getTriple());
- if (!Object) {
- auto Err = Object.takeError();
- Warning("unable to open object file: " + toString(std::move(Err)),
- Path.str());
- return;
- }
-
- CurrentDebugMapObject =
- &Result->addDebugMapObject(Path, Timestamp, MachO::N_OSO);
- loadCurrentObjectFileSymbols(*Object);
-}
-
-static std::string getArchName(const object::MachOObjectFile &Obj) {
- Triple T = Obj.getArchTriple();
- return std::string(T.getArchName());
-}
-
-std::unique_ptr<DebugMap>
-MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
- StringRef BinaryPath) {
- loadMainBinarySymbols(MainBinary);
- ArrayRef<uint8_t> UUID = MainBinary.getUuid();
- Result =
- std::make_unique<DebugMap>(MainBinary.getArchTriple(), BinaryPath, UUID);
- MainBinaryStrings = MainBinary.getStringTableData();
- for (const SymbolRef &Symbol : MainBinary.symbols()) {
- const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
- if (MainBinary.is64Bit())
- handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI));
- else
- handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI));
- }
-
- resetParserState();
- return std::move(Result);
-}
-
-// Table that maps Darwin's Mach-O stab constants to strings to allow printing.
-// llvm-nm has very similar code, the strings used here are however slightly
-// different and part of the interface of dsymutil (some project's build-systems
-// parse the ouptut of dsymutil -s), thus they shouldn't be changed.
-struct DarwinStabName {
- uint8_t NType;
- const char *Name;
-};
-
-static const struct DarwinStabName DarwinStabNames[] = {
- {MachO::N_GSYM, "N_GSYM"}, {MachO::N_FNAME, "N_FNAME"},
- {MachO::N_FUN, "N_FUN"}, {MachO::N_STSYM, "N_STSYM"},
- {MachO::N_LCSYM, "N_LCSYM"}, {MachO::N_BNSYM, "N_BNSYM"},
- {MachO::N_PC, "N_PC"}, {MachO::N_AST, "N_AST"},
- {MachO::N_OPT, "N_OPT"}, {MachO::N_RSYM, "N_RSYM"},
- {MachO::N_SLINE, "N_SLINE"}, {MachO::N_ENSYM, "N_ENSYM"},
- {MachO::N_SSYM, "N_SSYM"}, {MachO::N_SO, "N_SO"},
- {MachO::N_OSO, "N_OSO"}, {MachO::N_LSYM, "N_LSYM"},
- {MachO::N_BINCL, "N_BINCL"}, {MachO::N_SOL, "N_SOL"},
- {MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"},
- {MachO::N_OLEVEL, "N_OLEV"}, {MachO::N_PSYM, "N_PSYM"},
- {MachO::N_EINCL, "N_EINCL"}, {MachO::N_ENTRY, "N_ENTRY"},
- {MachO::N_LBRAC, "N_LBRAC"}, {MachO::N_EXCL, "N_EXCL"},
- {MachO::N_RBRAC, "N_RBRAC"}, {MachO::N_BCOMM, "N_BCOMM"},
- {MachO::N_ECOMM, "N_ECOMM"}, {MachO::N_ECOML, "N_ECOML"},
- {MachO::N_LENG, "N_LENG"}, {0, nullptr}};
-
-static const char *getDarwinStabString(uint8_t NType) {
- for (unsigned i = 0; DarwinStabNames[i].Name; i++) {
- if (DarwinStabNames[i].NType == NType)
- return DarwinStabNames[i].Name;
- }
- return nullptr;
-}
-
-void MachODebugMapParser::dumpSymTabHeader(raw_ostream &OS, StringRef Arch) {
- OS << "-----------------------------------"
- "-----------------------------------\n";
- OS << "Symbol table for: '" << BinaryPath << "' (" << Arch.data() << ")\n";
- OS << "-----------------------------------"
- "-----------------------------------\n";
- OS << "Index n_strx n_type n_sect n_desc n_value\n";
- OS << "======== -------- ------------------ ------ ------ ----------------\n";
-}
-
-void MachODebugMapParser::dumpSymTabEntry(raw_ostream &OS, uint64_t Index,
- uint32_t StringIndex, uint8_t Type,
- uint8_t SectionIndex, uint16_t Flags,
- uint64_t Value) {
- // Index
- OS << '[' << format_decimal(Index, 6)
- << "] "
- // n_strx
- << format_hex_no_prefix(StringIndex, 8)
- << ' '
- // n_type...
- << format_hex_no_prefix(Type, 2) << " (";
-
- if (Type & MachO::N_STAB)
- OS << left_justify(getDarwinStabString(Type), 13);
- else {
- if (Type & MachO::N_PEXT)
- OS << "PEXT ";
- else
- OS << " ";
- switch (Type & MachO::N_TYPE) {
- case MachO::N_UNDF: // 0x0 undefined, n_sect == NO_SECT
- OS << "UNDF";
- break;
- case MachO::N_ABS: // 0x2 absolute, n_sect == NO_SECT
- OS << "ABS ";
- break;
- case MachO::N_SECT: // 0xe defined in section number n_sect
- OS << "SECT";
- break;
- case MachO::N_PBUD: // 0xc prebound undefined (defined in a dylib)
- OS << "PBUD";
- break;
- case MachO::N_INDR: // 0xa indirect
- OS << "INDR";
- break;
- default:
- OS << format_hex_no_prefix(Type, 2) << " ";
- break;
- }
- if (Type & MachO::N_EXT)
- OS << " EXT";
- else
- OS << " ";
- }
-
- OS << ") "
- // n_sect
- << format_hex_no_prefix(SectionIndex, 2)
- << " "
- // n_desc
- << format_hex_no_prefix(Flags, 4)
- << " "
- // n_value
- << format_hex_no_prefix(Value, 16);
-
- const char *Name = &MainBinaryStrings.data()[StringIndex];
- if (Name && Name[0])
- OS << " '" << Name << "'";
-
- OS << "\n";
-}
-
-void MachODebugMapParser::dumpOneBinaryStab(const MachOObjectFile &MainBinary,
- StringRef BinaryPath) {
- loadMainBinarySymbols(MainBinary);
- MainBinaryStrings = MainBinary.getStringTableData();
- raw_ostream &OS(llvm::outs());
-
- dumpSymTabHeader(OS, getArchName(MainBinary));
- uint64_t Idx = 0;
- for (const SymbolRef &Symbol : MainBinary.symbols()) {
- const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
- if (MainBinary.is64Bit())
- dumpSymTabEntry(OS, Idx, MainBinary.getSymbol64TableEntry(DRI));
- else
- dumpSymTabEntry(OS, Idx, MainBinary.getSymbolTableEntry(DRI));
- Idx++;
- }
-
- OS << "\n\n";
- resetParserState();
-}
-
-static bool shouldLinkArch(SmallVectorImpl<StringRef> &Archs, StringRef Arch) {
- if (Archs.empty() || is_contained(Archs, "all") || is_contained(Archs, "*"))
- return true;
-
- if (Arch.startswith("arm") && Arch != "arm64" && is_contained(Archs, "arm"))
- return true;
-
- SmallString<16> ArchName = Arch;
- if (Arch.startswith("thumb"))
- ArchName = ("arm" + Arch.substr(5)).str();
-
- return is_contained(Archs, ArchName);
-}
-
-bool MachODebugMapParser::dumpStab() {
- auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath);
- if (!ObjectEntry) {
- auto Err = ObjectEntry.takeError();
- WithColor::error() << "cannot load '" << BinaryPath
- << "': " << toString(std::move(Err)) << '\n';
- return false;
- }
-
- auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>();
- if (!Objects) {
- auto Err = Objects.takeError();
- WithColor::error() << "cannot get '" << BinaryPath
- << "' as MachO file: " << toString(std::move(Err))
- << "\n";
- return false;
- }
-
- for (const auto *Object : *Objects)
- if (shouldLinkArch(Archs, Object->getArchTriple().getArchName()))
- dumpOneBinaryStab(*Object, BinaryPath);
-
- return true;
-}
-
-/// This main parsing routine tries to open the main binary and if
-/// successful iterates over the STAB entries. The real parsing is
-/// done in handleStabSymbolTableEntry.
-ErrorOr<std::vector<std::unique_ptr<DebugMap>>> MachODebugMapParser::parse() {
- auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath);
- if (!ObjectEntry) {
- return errorToErrorCode(ObjectEntry.takeError());
- }
-
- auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>();
- if (!Objects) {
- return errorToErrorCode(Objects.takeError());
- }
-
- std::vector<std::unique_ptr<DebugMap>> Results;
- for (const auto *Object : *Objects)
- if (shouldLinkArch(Archs, Object->getArchTriple().getArchName()))
- Results.push_back(parseOneBinary(*Object, BinaryPath));
-
- return std::move(Results);
-}
-
-/// Interpret the STAB entries to fill the DebugMap.
-void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
- uint8_t Type,
- uint8_t SectionIndex,
- uint16_t Flags,
- uint64_t Value) {
- if (!(Type & MachO::N_STAB))
- return;
-
- const char *Name = &MainBinaryStrings.data()[StringIndex];
-
- // An N_OSO entry represents the start of a new object file description.
- if (Type == MachO::N_OSO)
- return switchToNewDebugMapObject(Name, sys::toTimePoint(Value));
-
- if (Type == MachO::N_AST) {
- SmallString<80> Path(PathPrefix);
- sys::path::append(Path, Name);
- Result->addDebugMapObject(Path, sys::toTimePoint(Value), Type);
- return;
- }
-
- // If the last N_OSO object file wasn't found, CurrentDebugMapObject will be
- // null. Do not update anything until we find the next valid N_OSO entry.
- if (!CurrentDebugMapObject)
- return;
-
- uint32_t Size = 0;
- switch (Type) {
- case MachO::N_GSYM:
- // This is a global variable. We need to query the main binary
- // symbol table to find its address as it might not be in the
- // debug map (for common symbols).
- Value = getMainBinarySymbolAddress(Name);
- break;
- case MachO::N_FUN:
- // Functions are scopes in STABS. They have an end marker that
- // contains the function size.
- if (Name[0] == '\0') {
- Size = Value;
- Value = CurrentFunctionAddress;
- Name = CurrentFunctionName;
- break;
- } else {
- CurrentFunctionName = Name;
- CurrentFunctionAddress = Value;
- return;
- }
- case MachO::N_STSYM:
- break;
- default:
- return;
- }
-
- auto ObjectSymIt = CurrentObjectAddresses.find(Name);
-
- // If the name of a (non-static) symbol is not in the current object, we
- // check all its aliases from the main binary.
- if (ObjectSymIt == CurrentObjectAddresses.end() && Type != MachO::N_STSYM) {
- for (const auto &Alias : getMainBinarySymbolNames(Value)) {
- ObjectSymIt = CurrentObjectAddresses.find(Alias);
- if (ObjectSymIt != CurrentObjectAddresses.end())
- break;
- }
- }
-
- if (ObjectSymIt == CurrentObjectAddresses.end()) {
- Warning("could not find object file symbol for symbol " + Twine(Name));
- return;
- }
-
- if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value,
- Size)) {
- Warning(Twine("failed to insert symbol '") + Name + "' in the debug map.");
- return;
- }
-}
-
-/// Load the current object file symbols into CurrentObjectAddresses.
-void MachODebugMapParser::loadCurrentObjectFileSymbols(
- const object::MachOObjectFile &Obj) {
- CurrentObjectAddresses.clear();
-
- for (auto Sym : Obj.symbols()) {
- uint64_t Addr = cantFail(Sym.getValue());
- Expected<StringRef> Name = Sym.getName();
- if (!Name) {
- // TODO: Actually report errors helpfully.
- consumeError(Name.takeError());
- continue;
- }
- // The value of some categories of symbols isn't meaningful. For
- // example common symbols store their size in the value field, not
- // their address. Absolute symbols have a fixed address that can
- // conflict with standard symbols. These symbols (especially the
- // common ones), might still be referenced by relocations. These
- // relocations will use the symbol itself, and won't need an
- // object file address. The object file address field is optional
- // in the DebugMap, leave it unassigned for these symbols.
- uint32_t Flags = cantFail(Sym.getFlags());
- if (Flags & SymbolRef::SF_Absolute) {
- CurrentObjectAddresses[*Name] = None;
- } else if (Flags & SymbolRef::SF_Common) {
- CurrentObjectAddresses[*Name] = None;
- CommonSymbols.push_back(std::string(*Name));
- } else {
- CurrentObjectAddresses[*Name] = Addr;
- }
- }
-}
-
-/// Lookup a symbol address in the main binary symbol table. The
-/// parser only needs to query common symbols, thus not every symbol's
-/// address is available through this function.
-uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) {
- auto Sym = MainBinarySymbolAddresses.find(Name);
- if (Sym == MainBinarySymbolAddresses.end())
- return 0;
- return Sym->second;
-}
-
-/// Get all symbol names in the main binary for the given value.
-std::vector<StringRef>
-MachODebugMapParser::getMainBinarySymbolNames(uint64_t Value) {
- std::vector<StringRef> Names;
- for (const auto &Entry : MainBinarySymbolAddresses) {
- if (Entry.second == Value)
- Names.push_back(Entry.first());
- }
- return Names;
-}
-
-/// Load the interesting main binary symbols' addresses into
-/// MainBinarySymbolAddresses.
-void MachODebugMapParser::loadMainBinarySymbols(
- const MachOObjectFile &MainBinary) {
- section_iterator Section = MainBinary.section_end();
- MainBinarySymbolAddresses.clear();
- for (const auto &Sym : MainBinary.symbols()) {
- Expected<SymbolRef::Type> TypeOrErr = Sym.getType();
- if (!TypeOrErr) {
- // TODO: Actually report errors helpfully.
- consumeError(TypeOrErr.takeError());
- continue;
- }
- SymbolRef::Type Type = *TypeOrErr;
- // Skip undefined and STAB entries.
- if ((Type == SymbolRef::ST_Debug) || (Type == SymbolRef::ST_Unknown))
- continue;
- // In theory, the only symbols of interest are the global variables. These
- // are the only ones that need to be queried because the address of common
- // data won't be described in the debug map. All other addresses should be
- // fetched for the debug map. In reality, by playing with 'ld -r' and
- // export lists, you can get symbols described as N_GSYM in the debug map,
- // but associated with a local symbol. Gather all the symbols, but prefer
- // the global ones.
- uint8_t SymType =
- MainBinary.getSymbolTableEntry(Sym.getRawDataRefImpl()).n_type;
- bool Extern = SymType & (MachO::N_EXT | MachO::N_PEXT);
- Expected<section_iterator> SectionOrErr = Sym.getSection();
- if (!SectionOrErr) {
- // TODO: Actually report errors helpfully.
- consumeError(SectionOrErr.takeError());
- continue;
- }
- Section = *SectionOrErr;
+//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "BinaryHolder.h"
+#include "DebugMap.h"
+#include "MachOUtils.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
+
+namespace {
+using namespace llvm;
+using namespace llvm::dsymutil;
+using namespace llvm::object;
+
+class MachODebugMapParser {
+public:
+ MachODebugMapParser(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+ StringRef BinaryPath, ArrayRef<std::string> Archs,
+ StringRef PathPrefix = "",
+ bool PaperTrailWarnings = false, bool Verbose = false)
+ : BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()),
+ PathPrefix(std::string(PathPrefix)),
+ PaperTrailWarnings(PaperTrailWarnings), BinHolder(VFS, Verbose),
+ CurrentDebugMapObject(nullptr) {}
+
+ /// Parses and returns the DebugMaps of the input binary. The binary contains
+ /// multiple maps in case it is a universal binary.
+ /// \returns an error in case the provided BinaryPath doesn't exist
+ /// or isn't of a supported type.
+ ErrorOr<std::vector<std::unique_ptr<DebugMap>>> parse();
+
+ /// Walk the symbol table and dump it.
+ bool dumpStab();
+
+private:
+ std::string BinaryPath;
+ SmallVector<StringRef, 1> Archs;
+ std::string PathPrefix;
+ bool PaperTrailWarnings;
+
+ /// Owns the MemoryBuffer for the main binary.
+ BinaryHolder BinHolder;
+ /// Map of the binary symbol addresses.
+ StringMap<uint64_t> MainBinarySymbolAddresses;
+ StringRef MainBinaryStrings;
+ /// The constructed DebugMap.
+ std::unique_ptr<DebugMap> Result;
+ /// List of common symbols that need to be added to the debug map.
+ std::vector<std::string> CommonSymbols;
+
+ /// Map of the currently processed object file symbol addresses.
+ StringMap<Optional<uint64_t>> CurrentObjectAddresses;
+ /// Element of the debug map corresponding to the current object file.
+ DebugMapObject *CurrentDebugMapObject;
+
+ /// Holds function info while function scope processing.
+ const char *CurrentFunctionName;
+ uint64_t CurrentFunctionAddress;
+
+ std::unique_ptr<DebugMap> parseOneBinary(const MachOObjectFile &MainBinary,
+ StringRef BinaryPath);
+
+ void
+ switchToNewDebugMapObject(StringRef Filename,
+ sys::TimePoint<std::chrono::seconds> Timestamp);
+ void resetParserState();
+ uint64_t getMainBinarySymbolAddress(StringRef Name);
+ std::vector<StringRef> getMainBinarySymbolNames(uint64_t Value);
+ void loadMainBinarySymbols(const MachOObjectFile &MainBinary);
+ void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj);
+ void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
+ uint8_t SectionIndex, uint16_t Flags,
+ uint64_t Value);
+
+ template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) {
+ handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
+ STE.n_value);
+ }
+
+ void addCommonSymbols();
+
+ /// Dump the symbol table output header.
+ void dumpSymTabHeader(raw_ostream &OS, StringRef Arch);
+
+ /// Dump the contents of nlist entries.
+ void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, uint32_t StringIndex,
+ uint8_t Type, uint8_t SectionIndex, uint16_t Flags,
+ uint64_t Value);
+
+ template <typename STEType>
+ void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, const STEType &STE) {
+ dumpSymTabEntry(OS, Index, STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
+ STE.n_value);
+ }
+ void dumpOneBinaryStab(const MachOObjectFile &MainBinary,
+ StringRef BinaryPath);
+
+ void Warning(const Twine &Msg, StringRef File = StringRef()) {
+ WithColor::warning() << "("
+ << MachOUtils::getArchName(
+ Result->getTriple().getArchName())
+ << ") " << File << " " << Msg << "\n";
+
+ if (PaperTrailWarnings) {
+ if (!File.empty())
+ Result->addDebugMapObject(File, sys::TimePoint<std::chrono::seconds>());
+ if (Result->end() != Result->begin()) {
+ auto it = Result->end();
+ (*--it)->addWarning(Msg.str());
+ }
+ }
+ }
+};
+
+} // anonymous namespace
+
+/// Reset the parser state corresponding to the current object
+/// file. This is to be called after an object file is finished
+/// processing.
+void MachODebugMapParser::resetParserState() {
+ CommonSymbols.clear();
+ CurrentObjectAddresses.clear();
+ CurrentDebugMapObject = nullptr;
+}
+
+/// Commons symbols won't show up in the symbol map but might need to be
+/// relocated. We can add them to the symbol table ourselves by combining the
+/// information in the object file (the symbol name) and the main binary (the
+/// address).
+void MachODebugMapParser::addCommonSymbols() {
+ for (auto &CommonSymbol : CommonSymbols) {
+ uint64_t CommonAddr = getMainBinarySymbolAddress(CommonSymbol);
+ if (CommonAddr == 0) {
+ // The main binary doesn't have an address for the given symbol.
+ continue;
+ }
+ if (!CurrentDebugMapObject->addSymbol(CommonSymbol, None /*ObjectAddress*/,
+ CommonAddr, 0 /*size*/)) {
+ // The symbol is already present.
+ continue;
+ }
+ }
+}
+
+/// Create a new DebugMapObject. This function resets the state of the
+/// parser that was referring to the last object file and sets
+/// everything up to add symbols to the new one.
+void MachODebugMapParser::switchToNewDebugMapObject(
+ StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) {
+ addCommonSymbols();
+ resetParserState();
+
+ SmallString<80> Path(PathPrefix);
+ sys::path::append(Path, Filename);
+
+ auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp);
+ if (!ObjectEntry) {
+ auto Err = ObjectEntry.takeError();
+ Warning("unable to open object file: " + toString(std::move(Err)),
+ Path.str());
+ return;
+ }
+
+ auto Object = ObjectEntry->getObjectAs<MachOObjectFile>(Result->getTriple());
+ if (!Object) {
+ auto Err = Object.takeError();
+ Warning("unable to open object file: " + toString(std::move(Err)),
+ Path.str());
+ return;
+ }
+
+ CurrentDebugMapObject =
+ &Result->addDebugMapObject(Path, Timestamp, MachO::N_OSO);
+ loadCurrentObjectFileSymbols(*Object);
+}
+
+static std::string getArchName(const object::MachOObjectFile &Obj) {
+ Triple T = Obj.getArchTriple();
+ return std::string(T.getArchName());
+}
+
+std::unique_ptr<DebugMap>
+MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
+ StringRef BinaryPath) {
+ loadMainBinarySymbols(MainBinary);
+ ArrayRef<uint8_t> UUID = MainBinary.getUuid();
+ Result =
+ std::make_unique<DebugMap>(MainBinary.getArchTriple(), BinaryPath, UUID);
+ MainBinaryStrings = MainBinary.getStringTableData();
+ for (const SymbolRef &Symbol : MainBinary.symbols()) {
+ const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
+ if (MainBinary.is64Bit())
+ handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI));
+ else
+ handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI));
+ }
+
+ resetParserState();
+ return std::move(Result);
+}
+
+// Table that maps Darwin's Mach-O stab constants to strings to allow printing.
+// llvm-nm has very similar code, the strings used here are however slightly
+// different and part of the interface of dsymutil (some project's build-systems
+// parse the ouptut of dsymutil -s), thus they shouldn't be changed.
+struct DarwinStabName {
+ uint8_t NType;
+ const char *Name;
+};
+
+static const struct DarwinStabName DarwinStabNames[] = {
+ {MachO::N_GSYM, "N_GSYM"}, {MachO::N_FNAME, "N_FNAME"},
+ {MachO::N_FUN, "N_FUN"}, {MachO::N_STSYM, "N_STSYM"},
+ {MachO::N_LCSYM, "N_LCSYM"}, {MachO::N_BNSYM, "N_BNSYM"},
+ {MachO::N_PC, "N_PC"}, {MachO::N_AST, "N_AST"},
+ {MachO::N_OPT, "N_OPT"}, {MachO::N_RSYM, "N_RSYM"},
+ {MachO::N_SLINE, "N_SLINE"}, {MachO::N_ENSYM, "N_ENSYM"},
+ {MachO::N_SSYM, "N_SSYM"}, {MachO::N_SO, "N_SO"},
+ {MachO::N_OSO, "N_OSO"}, {MachO::N_LSYM, "N_LSYM"},
+ {MachO::N_BINCL, "N_BINCL"}, {MachO::N_SOL, "N_SOL"},
+ {MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"},
+ {MachO::N_OLEVEL, "N_OLEV"}, {MachO::N_PSYM, "N_PSYM"},
+ {MachO::N_EINCL, "N_EINCL"}, {MachO::N_ENTRY, "N_ENTRY"},
+ {MachO::N_LBRAC, "N_LBRAC"}, {MachO::N_EXCL, "N_EXCL"},
+ {MachO::N_RBRAC, "N_RBRAC"}, {MachO::N_BCOMM, "N_BCOMM"},
+ {MachO::N_ECOMM, "N_ECOMM"}, {MachO::N_ECOML, "N_ECOML"},
+ {MachO::N_LENG, "N_LENG"}, {0, nullptr}};
+
+static const char *getDarwinStabString(uint8_t NType) {
+ for (unsigned i = 0; DarwinStabNames[i].Name; i++) {
+ if (DarwinStabNames[i].NType == NType)
+ return DarwinStabNames[i].Name;
+ }
+ return nullptr;
+}
+
+void MachODebugMapParser::dumpSymTabHeader(raw_ostream &OS, StringRef Arch) {
+ OS << "-----------------------------------"
+ "-----------------------------------\n";
+ OS << "Symbol table for: '" << BinaryPath << "' (" << Arch.data() << ")\n";
+ OS << "-----------------------------------"
+ "-----------------------------------\n";
+ OS << "Index n_strx n_type n_sect n_desc n_value\n";
+ OS << "======== -------- ------------------ ------ ------ ----------------\n";
+}
+
+void MachODebugMapParser::dumpSymTabEntry(raw_ostream &OS, uint64_t Index,
+ uint32_t StringIndex, uint8_t Type,
+ uint8_t SectionIndex, uint16_t Flags,
+ uint64_t Value) {
+ // Index
+ OS << '[' << format_decimal(Index, 6)
+ << "] "
+ // n_strx
+ << format_hex_no_prefix(StringIndex, 8)
+ << ' '
+ // n_type...
+ << format_hex_no_prefix(Type, 2) << " (";
+
+ if (Type & MachO::N_STAB)
+ OS << left_justify(getDarwinStabString(Type), 13);
+ else {
+ if (Type & MachO::N_PEXT)
+ OS << "PEXT ";
+ else
+ OS << " ";
+ switch (Type & MachO::N_TYPE) {
+ case MachO::N_UNDF: // 0x0 undefined, n_sect == NO_SECT
+ OS << "UNDF";
+ break;
+ case MachO::N_ABS: // 0x2 absolute, n_sect == NO_SECT
+ OS << "ABS ";
+ break;
+ case MachO::N_SECT: // 0xe defined in section number n_sect
+ OS << "SECT";
+ break;
+ case MachO::N_PBUD: // 0xc prebound undefined (defined in a dylib)
+ OS << "PBUD";
+ break;
+ case MachO::N_INDR: // 0xa indirect
+ OS << "INDR";
+ break;
+ default:
+ OS << format_hex_no_prefix(Type, 2) << " ";
+ break;
+ }
+ if (Type & MachO::N_EXT)
+ OS << " EXT";
+ else
+ OS << " ";
+ }
+
+ OS << ") "
+ // n_sect
+ << format_hex_no_prefix(SectionIndex, 2)
+ << " "
+ // n_desc
+ << format_hex_no_prefix(Flags, 4)
+ << " "
+ // n_value
+ << format_hex_no_prefix(Value, 16);
+
+ const char *Name = &MainBinaryStrings.data()[StringIndex];
+ if (Name && Name[0])
+ OS << " '" << Name << "'";
+
+ OS << "\n";
+}
+
+void MachODebugMapParser::dumpOneBinaryStab(const MachOObjectFile &MainBinary,
+ StringRef BinaryPath) {
+ loadMainBinarySymbols(MainBinary);
+ MainBinaryStrings = MainBinary.getStringTableData();
+ raw_ostream &OS(llvm::outs());
+
+ dumpSymTabHeader(OS, getArchName(MainBinary));
+ uint64_t Idx = 0;
+ for (const SymbolRef &Symbol : MainBinary.symbols()) {
+ const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
+ if (MainBinary.is64Bit())
+ dumpSymTabEntry(OS, Idx, MainBinary.getSymbol64TableEntry(DRI));
+ else
+ dumpSymTabEntry(OS, Idx, MainBinary.getSymbolTableEntry(DRI));
+ Idx++;
+ }
+
+ OS << "\n\n";
+ resetParserState();
+}
+
+static bool shouldLinkArch(SmallVectorImpl<StringRef> &Archs, StringRef Arch) {
+ if (Archs.empty() || is_contained(Archs, "all") || is_contained(Archs, "*"))
+ return true;
+
+ if (Arch.startswith("arm") && Arch != "arm64" && is_contained(Archs, "arm"))
+ return true;
+
+ SmallString<16> ArchName = Arch;
+ if (Arch.startswith("thumb"))
+ ArchName = ("arm" + Arch.substr(5)).str();
+
+ return is_contained(Archs, ArchName);
+}
+
+bool MachODebugMapParser::dumpStab() {
+ auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath);
+ if (!ObjectEntry) {
+ auto Err = ObjectEntry.takeError();
+ WithColor::error() << "cannot load '" << BinaryPath
+ << "': " << toString(std::move(Err)) << '\n';
+ return false;
+ }
+
+ auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>();
+ if (!Objects) {
+ auto Err = Objects.takeError();
+ WithColor::error() << "cannot get '" << BinaryPath
+ << "' as MachO file: " << toString(std::move(Err))
+ << "\n";
+ return false;
+ }
+
+ for (const auto *Object : *Objects)
+ if (shouldLinkArch(Archs, Object->getArchTriple().getArchName()))
+ dumpOneBinaryStab(*Object, BinaryPath);
+
+ return true;
+}
+
+/// This main parsing routine tries to open the main binary and if
+/// successful iterates over the STAB entries. The real parsing is
+/// done in handleStabSymbolTableEntry.
+ErrorOr<std::vector<std::unique_ptr<DebugMap>>> MachODebugMapParser::parse() {
+ auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath);
+ if (!ObjectEntry) {
+ return errorToErrorCode(ObjectEntry.takeError());
+ }
+
+ auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>();
+ if (!Objects) {
+ return errorToErrorCode(Objects.takeError());
+ }
+
+ std::vector<std::unique_ptr<DebugMap>> Results;
+ for (const auto *Object : *Objects)
+ if (shouldLinkArch(Archs, Object->getArchTriple().getArchName()))
+ Results.push_back(parseOneBinary(*Object, BinaryPath));
+
+ return std::move(Results);
+}
+
+/// Interpret the STAB entries to fill the DebugMap.
+void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
+ uint8_t Type,
+ uint8_t SectionIndex,
+ uint16_t Flags,
+ uint64_t Value) {
+ if (!(Type & MachO::N_STAB))
+ return;
+
+ const char *Name = &MainBinaryStrings.data()[StringIndex];
+
+ // An N_OSO entry represents the start of a new object file description.
+ if (Type == MachO::N_OSO)
+ return switchToNewDebugMapObject(Name, sys::toTimePoint(Value));
+
+ if (Type == MachO::N_AST) {
+ SmallString<80> Path(PathPrefix);
+ sys::path::append(Path, Name);
+ Result->addDebugMapObject(Path, sys::toTimePoint(Value), Type);
+ return;
+ }
+
+ // If the last N_OSO object file wasn't found, CurrentDebugMapObject will be
+ // null. Do not update anything until we find the next valid N_OSO entry.
+ if (!CurrentDebugMapObject)
+ return;
+
+ uint32_t Size = 0;
+ switch (Type) {
+ case MachO::N_GSYM:
+ // This is a global variable. We need to query the main binary
+ // symbol table to find its address as it might not be in the
+ // debug map (for common symbols).
+ Value = getMainBinarySymbolAddress(Name);
+ break;
+ case MachO::N_FUN:
+ // Functions are scopes in STABS. They have an end marker that
+ // contains the function size.
+ if (Name[0] == '\0') {
+ Size = Value;
+ Value = CurrentFunctionAddress;
+ Name = CurrentFunctionName;
+ break;
+ } else {
+ CurrentFunctionName = Name;
+ CurrentFunctionAddress = Value;
+ return;
+ }
+ case MachO::N_STSYM:
+ break;
+ default:
+ return;
+ }
+
+ auto ObjectSymIt = CurrentObjectAddresses.find(Name);
+
+ // If the name of a (non-static) symbol is not in the current object, we
+ // check all its aliases from the main binary.
+ if (ObjectSymIt == CurrentObjectAddresses.end() && Type != MachO::N_STSYM) {
+ for (const auto &Alias : getMainBinarySymbolNames(Value)) {
+ ObjectSymIt = CurrentObjectAddresses.find(Alias);
+ if (ObjectSymIt != CurrentObjectAddresses.end())
+ break;
+ }
+ }
+
+ if (ObjectSymIt == CurrentObjectAddresses.end()) {
+ Warning("could not find object file symbol for symbol " + Twine(Name));
+ return;
+ }
+
+ if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value,
+ Size)) {
+ Warning(Twine("failed to insert symbol '") + Name + "' in the debug map.");
+ return;
+ }
+}
+
+/// Load the current object file symbols into CurrentObjectAddresses.
+void MachODebugMapParser::loadCurrentObjectFileSymbols(
+ const object::MachOObjectFile &Obj) {
+ CurrentObjectAddresses.clear();
+
+ for (auto Sym : Obj.symbols()) {
+ uint64_t Addr = cantFail(Sym.getValue());
+ Expected<StringRef> Name = Sym.getName();
+ if (!Name) {
+ // TODO: Actually report errors helpfully.
+ consumeError(Name.takeError());
+ continue;
+ }
+ // The value of some categories of symbols isn't meaningful. For
+ // example common symbols store their size in the value field, not
+ // their address. Absolute symbols have a fixed address that can
+ // conflict with standard symbols. These symbols (especially the
+ // common ones), might still be referenced by relocations. These
+ // relocations will use the symbol itself, and won't need an
+ // object file address. The object file address field is optional
+ // in the DebugMap, leave it unassigned for these symbols.
+ uint32_t Flags = cantFail(Sym.getFlags());
+ if (Flags & SymbolRef::SF_Absolute) {
+ CurrentObjectAddresses[*Name] = None;
+ } else if (Flags & SymbolRef::SF_Common) {
+ CurrentObjectAddresses[*Name] = None;
+ CommonSymbols.push_back(std::string(*Name));
+ } else {
+ CurrentObjectAddresses[*Name] = Addr;
+ }
+ }
+}
+
+/// Lookup a symbol address in the main binary symbol table. The
+/// parser only needs to query common symbols, thus not every symbol's
+/// address is available through this function.
+uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) {
+ auto Sym = MainBinarySymbolAddresses.find(Name);
+ if (Sym == MainBinarySymbolAddresses.end())
+ return 0;
+ return Sym->second;
+}
+
+/// Get all symbol names in the main binary for the given value.
+std::vector<StringRef>
+MachODebugMapParser::getMainBinarySymbolNames(uint64_t Value) {
+ std::vector<StringRef> Names;
+ for (const auto &Entry : MainBinarySymbolAddresses) {
+ if (Entry.second == Value)
+ Names.push_back(Entry.first());
+ }
+ return Names;
+}
+
+/// Load the interesting main binary symbols' addresses into
+/// MainBinarySymbolAddresses.
+void MachODebugMapParser::loadMainBinarySymbols(
+ const MachOObjectFile &MainBinary) {
+ section_iterator Section = MainBinary.section_end();
+ MainBinarySymbolAddresses.clear();
+ for (const auto &Sym : MainBinary.symbols()) {
+ Expected<SymbolRef::Type> TypeOrErr = Sym.getType();
+ if (!TypeOrErr) {
+ // TODO: Actually report errors helpfully.
+ consumeError(TypeOrErr.takeError());
+ continue;
+ }
+ SymbolRef::Type Type = *TypeOrErr;
+ // Skip undefined and STAB entries.
+ if ((Type == SymbolRef::ST_Debug) || (Type == SymbolRef::ST_Unknown))
+ continue;
+ // In theory, the only symbols of interest are the global variables. These
+ // are the only ones that need to be queried because the address of common
+ // data won't be described in the debug map. All other addresses should be
+ // fetched for the debug map. In reality, by playing with 'ld -r' and
+ // export lists, you can get symbols described as N_GSYM in the debug map,
+ // but associated with a local symbol. Gather all the symbols, but prefer
+ // the global ones.
+ uint8_t SymType =
+ MainBinary.getSymbolTableEntry(Sym.getRawDataRefImpl()).n_type;
+ bool Extern = SymType & (MachO::N_EXT | MachO::N_PEXT);
+ Expected<section_iterator> SectionOrErr = Sym.getSection();
+ if (!SectionOrErr) {
+ // TODO: Actually report errors helpfully.
+ consumeError(SectionOrErr.takeError());
+ continue;
+ }
+ Section = *SectionOrErr;
if ((Section == MainBinary.section_end() || Section->isText()) && !Extern)
- continue;
- uint64_t Addr = cantFail(Sym.getValue());
- Expected<StringRef> NameOrErr = Sym.getName();
- if (!NameOrErr) {
- // TODO: Actually report errors helpfully.
- consumeError(NameOrErr.takeError());
- continue;
- }
- StringRef Name = *NameOrErr;
- if (Name.size() == 0 || Name[0] == '\0')
- continue;
- // Override only if the new key is global.
- if (Extern)
- MainBinarySymbolAddresses[Name] = Addr;
- else
- MainBinarySymbolAddresses.try_emplace(Name, Addr);
- }
-}
-
-namespace llvm {
-namespace dsymutil {
-llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
-parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- StringRef InputFile, ArrayRef<std::string> Archs,
- StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
- bool InputIsYAML) {
- if (InputIsYAML)
- return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose);
-
- MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath,
- PaperTrailWarnings, Verbose);
- return Parser.parse();
-}
-
-bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- StringRef InputFile, ArrayRef<std::string> Archs,
- StringRef PrependPath) {
- MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, false);
- return Parser.dumpStab();
-}
-} // namespace dsymutil
-} // namespace llvm
+ continue;
+ uint64_t Addr = cantFail(Sym.getValue());
+ Expected<StringRef> NameOrErr = Sym.getName();
+ if (!NameOrErr) {
+ // TODO: Actually report errors helpfully.
+ consumeError(NameOrErr.takeError());
+ continue;
+ }
+ StringRef Name = *NameOrErr;
+ if (Name.size() == 0 || Name[0] == '\0')
+ continue;
+ // Override only if the new key is global.
+ if (Extern)
+ MainBinarySymbolAddresses[Name] = Addr;
+ else
+ MainBinarySymbolAddresses.try_emplace(Name, Addr);
+ }
+}
+
+namespace llvm {
+namespace dsymutil {
+llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
+parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+ StringRef InputFile, ArrayRef<std::string> Archs,
+ StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
+ bool InputIsYAML) {
+ if (InputIsYAML)
+ return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose);
+
+ MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath,
+ PaperTrailWarnings, Verbose);
+ return Parser.parse();
+}
+
+bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+ StringRef InputFile, ArrayRef<std::string> Archs,
+ StringRef PrependPath) {
+ MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, false);
+ return Parser.dumpStab();
+}
+} // namespace dsymutil
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp
index 943af43058..c91be23ac6 100644
--- a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp
+++ b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.cpp
@@ -1,436 +1,436 @@
-//===-- MachOUtils.cpp - Mach-o specific helpers for dsymutil ------------===//
+//===-- MachOUtils.cpp - Mach-o specific helpers for dsymutil ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachOUtils.h"
+#include "BinaryHolder.h"
+#include "DebugMap.h"
+#include "LinkUtils.h"
+#include "llvm/CodeGen/NonRelocatableStringpool.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCMachObjectWriter.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace dsymutil {
+namespace MachOUtils {
+
+llvm::Error ArchAndFile::createTempFile() {
+ llvm::SmallString<128> TmpModel;
+ llvm::sys::path::system_temp_directory(true, TmpModel);
+ llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf");
+ Expected<sys::fs::TempFile> T = sys::fs::TempFile::create(TmpModel);
+
+ if (!T)
+ return T.takeError();
+
+ File = std::make_unique<sys::fs::TempFile>(std::move(*T));
+ return Error::success();
+}
+
+llvm::StringRef ArchAndFile::path() const { return File->TmpName; }
+
+ArchAndFile::~ArchAndFile() {
+ if (File)
+ if (auto E = File->discard())
+ llvm::consumeError(std::move(E));
+}
+
+std::string getArchName(StringRef Arch) {
+ if (Arch.startswith("thumb"))
+ return (llvm::Twine("arm") + Arch.drop_front(5)).str();
+ return std::string(Arch);
+}
+
+static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) {
+ auto Path = sys::findProgramByName("lipo", makeArrayRef(SDKPath));
+ if (!Path)
+ Path = sys::findProgramByName("lipo");
+
+ if (!Path) {
+ WithColor::error() << "lipo: " << Path.getError().message() << "\n";
+ return false;
+ }
+
+ std::string ErrMsg;
+ int result = sys::ExecuteAndWait(*Path, Args, None, {}, 0, 0, &ErrMsg);
+ if (result) {
+ WithColor::error() << "lipo: " << ErrMsg << "\n";
+ return false;
+ }
+
+ return true;
+}
+
+bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
+ StringRef OutputFileName,
+ const LinkOptions &Options, StringRef SDKPath) {
+ // No need to merge one file into a universal fat binary.
+ if (ArchFiles.size() == 1) {
+ if (auto E = ArchFiles.front().File->keep(OutputFileName)) {
+ WithColor::error() << "while keeping " << ArchFiles.front().path()
+ << " as " << OutputFileName << ": "
+ << toString(std::move(E)) << "\n";
+ return false;
+ }
+ return true;
+ }
+
+ SmallVector<StringRef, 8> Args;
+ Args.push_back("lipo");
+ Args.push_back("-create");
+
+ for (auto &Thin : ArchFiles)
+ Args.push_back(Thin.path());
+
+ // Align segments to match dsymutil-classic alignment
+ for (auto &Thin : ArchFiles) {
+ Thin.Arch = getArchName(Thin.Arch);
+ Args.push_back("-segalign");
+ Args.push_back(Thin.Arch);
+ Args.push_back("20");
+ }
+
+ Args.push_back("-output");
+ Args.push_back(OutputFileName.data());
+
+ if (Options.Verbose) {
+ outs() << "Running lipo\n";
+ for (auto Arg : Args)
+ outs() << ' ' << Arg;
+ outs() << "\n";
+ }
+
+ return Options.NoOutput ? true : runLipo(SDKPath, Args);
+}
+
+// Return a MachO::segment_command_64 that holds the same values as the passed
+// MachO::segment_command. We do that to avoid having to duplicate the logic
+// for 32bits and 64bits segments.
+struct MachO::segment_command_64 adaptFrom32bits(MachO::segment_command Seg) {
+ MachO::segment_command_64 Seg64;
+ Seg64.cmd = Seg.cmd;
+ Seg64.cmdsize = Seg.cmdsize;
+ memcpy(Seg64.segname, Seg.segname, sizeof(Seg.segname));
+ Seg64.vmaddr = Seg.vmaddr;
+ Seg64.vmsize = Seg.vmsize;
+ Seg64.fileoff = Seg.fileoff;
+ Seg64.filesize = Seg.filesize;
+ Seg64.maxprot = Seg.maxprot;
+ Seg64.initprot = Seg.initprot;
+ Seg64.nsects = Seg.nsects;
+ Seg64.flags = Seg.flags;
+ return Seg64;
+}
+
+// Iterate on all \a Obj segments, and apply \a Handler to them.
+template <typename FunctionTy>
+static void iterateOnSegments(const object::MachOObjectFile &Obj,
+ FunctionTy Handler) {
+ for (const auto &LCI : Obj.load_commands()) {
+ MachO::segment_command_64 Segment;
+ if (LCI.C.cmd == MachO::LC_SEGMENT)
+ Segment = adaptFrom32bits(Obj.getSegmentLoadCommand(LCI));
+ else if (LCI.C.cmd == MachO::LC_SEGMENT_64)
+ Segment = Obj.getSegment64LoadCommand(LCI);
+ else
+ continue;
+
+ Handler(Segment);
+ }
+}
+
+// Transfer the symbols described by \a NList to \a NewSymtab which is just the
+// raw contents of the symbol table for the dSYM companion file. \returns
+// whether the symbol was transferred or not.
+template <typename NListTy>
+static bool transferSymbol(NListTy NList, bool IsLittleEndian,
+ StringRef Strings, SmallVectorImpl<char> &NewSymtab,
+ NonRelocatableStringpool &NewStrings,
+ bool &InDebugNote) {
+ // Do not transfer undefined symbols, we want real addresses.
+ if ((NList.n_type & MachO::N_TYPE) == MachO::N_UNDF)
+ return false;
+
+ // Do not transfer N_AST symbols as their content is copied into a section of
+ // the Mach-O companion file.
+ if (NList.n_type == MachO::N_AST)
+ return false;
+
+ StringRef Name = StringRef(Strings.begin() + NList.n_strx);
+
+ // An N_SO with a filename opens a debugging scope and another one without a
+ // name closes it. Don't transfer anything in the debugging scope.
+ if (InDebugNote) {
+ InDebugNote =
+ (NList.n_type != MachO::N_SO) || (!Name.empty() && Name[0] != '\0');
+ return false;
+ } else if (NList.n_type == MachO::N_SO) {
+ InDebugNote = true;
+ return false;
+ }
+
+ // FIXME: The + 1 is here to mimic dsymutil-classic that has 2 empty
+ // strings at the start of the generated string table (There is
+ // corresponding code in the string table emission).
+ NList.n_strx = NewStrings.getStringOffset(Name) + 1;
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(NList);
+
+ NewSymtab.append(reinterpret_cast<char *>(&NList),
+ reinterpret_cast<char *>(&NList + 1));
+ return true;
+}
+
+// Wrapper around transferSymbol to transfer all of \a Obj symbols
+// to \a NewSymtab. This function does not write in the output file.
+// \returns the number of symbols in \a NewSymtab.
+static unsigned transferSymbols(const object::MachOObjectFile &Obj,
+ SmallVectorImpl<char> &NewSymtab,
+ NonRelocatableStringpool &NewStrings) {
+ unsigned Syms = 0;
+ StringRef Strings = Obj.getStringTableData();
+ bool IsLittleEndian = Obj.isLittleEndian();
+ bool InDebugNote = false;
+
+ if (Obj.is64Bit()) {
+ for (const object::SymbolRef &Symbol : Obj.symbols()) {
+ object::DataRefImpl DRI = Symbol.getRawDataRefImpl();
+ if (transferSymbol(Obj.getSymbol64TableEntry(DRI), IsLittleEndian,
+ Strings, NewSymtab, NewStrings, InDebugNote))
+ ++Syms;
+ }
+ } else {
+ for (const object::SymbolRef &Symbol : Obj.symbols()) {
+ object::DataRefImpl DRI = Symbol.getRawDataRefImpl();
+ if (transferSymbol(Obj.getSymbolTableEntry(DRI), IsLittleEndian, Strings,
+ NewSymtab, NewStrings, InDebugNote))
+ ++Syms;
+ }
+ }
+ return Syms;
+}
+
+static MachO::section
+getSection(const object::MachOObjectFile &Obj,
+ const MachO::segment_command &Seg,
+ const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) {
+ return Obj.getSection(LCI, Idx);
+}
+
+static MachO::section_64
+getSection(const object::MachOObjectFile &Obj,
+ const MachO::segment_command_64 &Seg,
+ const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) {
+ return Obj.getSection64(LCI, Idx);
+}
+
+// Transfer \a Segment from \a Obj to the output file. This calls into \a Writer
+// to write these load commands directly in the output file at the current
+// position.
//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// The function also tries to find a hole in the address map to fit the __DWARF
+// segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the
+// highest segment address.
//
-//===----------------------------------------------------------------------===//
-
-#include "MachOUtils.h"
-#include "BinaryHolder.h"
-#include "DebugMap.h"
-#include "LinkUtils.h"
-#include "llvm/CodeGen/NonRelocatableStringpool.h"
-#include "llvm/MC/MCAsmLayout.h"
-#include "llvm/MC/MCMachObjectWriter.h"
-#include "llvm/MC/MCObjectStreamer.h"
-#include "llvm/MC/MCSectionMachO.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace llvm {
-namespace dsymutil {
-namespace MachOUtils {
-
-llvm::Error ArchAndFile::createTempFile() {
- llvm::SmallString<128> TmpModel;
- llvm::sys::path::system_temp_directory(true, TmpModel);
- llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf");
- Expected<sys::fs::TempFile> T = sys::fs::TempFile::create(TmpModel);
-
- if (!T)
- return T.takeError();
-
- File = std::make_unique<sys::fs::TempFile>(std::move(*T));
- return Error::success();
-}
-
-llvm::StringRef ArchAndFile::path() const { return File->TmpName; }
-
-ArchAndFile::~ArchAndFile() {
- if (File)
- if (auto E = File->discard())
- llvm::consumeError(std::move(E));
-}
-
-std::string getArchName(StringRef Arch) {
- if (Arch.startswith("thumb"))
- return (llvm::Twine("arm") + Arch.drop_front(5)).str();
- return std::string(Arch);
-}
-
-static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) {
- auto Path = sys::findProgramByName("lipo", makeArrayRef(SDKPath));
- if (!Path)
- Path = sys::findProgramByName("lipo");
-
- if (!Path) {
- WithColor::error() << "lipo: " << Path.getError().message() << "\n";
- return false;
- }
-
- std::string ErrMsg;
- int result = sys::ExecuteAndWait(*Path, Args, None, {}, 0, 0, &ErrMsg);
- if (result) {
- WithColor::error() << "lipo: " << ErrMsg << "\n";
- return false;
- }
-
- return true;
-}
-
-bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
- StringRef OutputFileName,
- const LinkOptions &Options, StringRef SDKPath) {
- // No need to merge one file into a universal fat binary.
- if (ArchFiles.size() == 1) {
- if (auto E = ArchFiles.front().File->keep(OutputFileName)) {
- WithColor::error() << "while keeping " << ArchFiles.front().path()
- << " as " << OutputFileName << ": "
- << toString(std::move(E)) << "\n";
- return false;
- }
- return true;
- }
-
- SmallVector<StringRef, 8> Args;
- Args.push_back("lipo");
- Args.push_back("-create");
-
- for (auto &Thin : ArchFiles)
- Args.push_back(Thin.path());
-
- // Align segments to match dsymutil-classic alignment
- for (auto &Thin : ArchFiles) {
- Thin.Arch = getArchName(Thin.Arch);
- Args.push_back("-segalign");
- Args.push_back(Thin.Arch);
- Args.push_back("20");
- }
-
- Args.push_back("-output");
- Args.push_back(OutputFileName.data());
-
- if (Options.Verbose) {
- outs() << "Running lipo\n";
- for (auto Arg : Args)
- outs() << ' ' << Arg;
- outs() << "\n";
- }
-
- return Options.NoOutput ? true : runLipo(SDKPath, Args);
-}
-
-// Return a MachO::segment_command_64 that holds the same values as the passed
-// MachO::segment_command. We do that to avoid having to duplicate the logic
-// for 32bits and 64bits segments.
-struct MachO::segment_command_64 adaptFrom32bits(MachO::segment_command Seg) {
- MachO::segment_command_64 Seg64;
- Seg64.cmd = Seg.cmd;
- Seg64.cmdsize = Seg.cmdsize;
- memcpy(Seg64.segname, Seg.segname, sizeof(Seg.segname));
- Seg64.vmaddr = Seg.vmaddr;
- Seg64.vmsize = Seg.vmsize;
- Seg64.fileoff = Seg.fileoff;
- Seg64.filesize = Seg.filesize;
- Seg64.maxprot = Seg.maxprot;
- Seg64.initprot = Seg.initprot;
- Seg64.nsects = Seg.nsects;
- Seg64.flags = Seg.flags;
- return Seg64;
-}
-
-// Iterate on all \a Obj segments, and apply \a Handler to them.
-template <typename FunctionTy>
-static void iterateOnSegments(const object::MachOObjectFile &Obj,
- FunctionTy Handler) {
- for (const auto &LCI : Obj.load_commands()) {
- MachO::segment_command_64 Segment;
- if (LCI.C.cmd == MachO::LC_SEGMENT)
- Segment = adaptFrom32bits(Obj.getSegmentLoadCommand(LCI));
- else if (LCI.C.cmd == MachO::LC_SEGMENT_64)
- Segment = Obj.getSegment64LoadCommand(LCI);
- else
- continue;
-
- Handler(Segment);
- }
-}
-
-// Transfer the symbols described by \a NList to \a NewSymtab which is just the
-// raw contents of the symbol table for the dSYM companion file. \returns
-// whether the symbol was transferred or not.
-template <typename NListTy>
-static bool transferSymbol(NListTy NList, bool IsLittleEndian,
- StringRef Strings, SmallVectorImpl<char> &NewSymtab,
- NonRelocatableStringpool &NewStrings,
- bool &InDebugNote) {
- // Do not transfer undefined symbols, we want real addresses.
- if ((NList.n_type & MachO::N_TYPE) == MachO::N_UNDF)
- return false;
-
- // Do not transfer N_AST symbols as their content is copied into a section of
- // the Mach-O companion file.
- if (NList.n_type == MachO::N_AST)
- return false;
-
- StringRef Name = StringRef(Strings.begin() + NList.n_strx);
-
- // An N_SO with a filename opens a debugging scope and another one without a
- // name closes it. Don't transfer anything in the debugging scope.
- if (InDebugNote) {
- InDebugNote =
- (NList.n_type != MachO::N_SO) || (!Name.empty() && Name[0] != '\0');
- return false;
- } else if (NList.n_type == MachO::N_SO) {
- InDebugNote = true;
- return false;
- }
-
- // FIXME: The + 1 is here to mimic dsymutil-classic that has 2 empty
- // strings at the start of the generated string table (There is
- // corresponding code in the string table emission).
- NList.n_strx = NewStrings.getStringOffset(Name) + 1;
- if (IsLittleEndian != sys::IsLittleEndianHost)
- MachO::swapStruct(NList);
-
- NewSymtab.append(reinterpret_cast<char *>(&NList),
- reinterpret_cast<char *>(&NList + 1));
- return true;
-}
-
-// Wrapper around transferSymbol to transfer all of \a Obj symbols
-// to \a NewSymtab. This function does not write in the output file.
-// \returns the number of symbols in \a NewSymtab.
-static unsigned transferSymbols(const object::MachOObjectFile &Obj,
- SmallVectorImpl<char> &NewSymtab,
- NonRelocatableStringpool &NewStrings) {
- unsigned Syms = 0;
- StringRef Strings = Obj.getStringTableData();
- bool IsLittleEndian = Obj.isLittleEndian();
- bool InDebugNote = false;
-
- if (Obj.is64Bit()) {
- for (const object::SymbolRef &Symbol : Obj.symbols()) {
- object::DataRefImpl DRI = Symbol.getRawDataRefImpl();
- if (transferSymbol(Obj.getSymbol64TableEntry(DRI), IsLittleEndian,
- Strings, NewSymtab, NewStrings, InDebugNote))
- ++Syms;
- }
- } else {
- for (const object::SymbolRef &Symbol : Obj.symbols()) {
- object::DataRefImpl DRI = Symbol.getRawDataRefImpl();
- if (transferSymbol(Obj.getSymbolTableEntry(DRI), IsLittleEndian, Strings,
- NewSymtab, NewStrings, InDebugNote))
- ++Syms;
- }
- }
- return Syms;
-}
-
-static MachO::section
-getSection(const object::MachOObjectFile &Obj,
- const MachO::segment_command &Seg,
- const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) {
- return Obj.getSection(LCI, Idx);
-}
-
-static MachO::section_64
-getSection(const object::MachOObjectFile &Obj,
- const MachO::segment_command_64 &Seg,
- const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) {
- return Obj.getSection64(LCI, Idx);
-}
-
-// Transfer \a Segment from \a Obj to the output file. This calls into \a Writer
-// to write these load commands directly in the output file at the current
-// position.
-//
-// The function also tries to find a hole in the address map to fit the __DWARF
-// segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the
-// highest segment address.
-//
-// When the __LINKEDIT segment is transferred, its offset and size are set resp.
-// to \a LinkeditOffset and \a LinkeditSize.
+// When the __LINKEDIT segment is transferred, its offset and size are set resp.
+// to \a LinkeditOffset and \a LinkeditSize.
//
// When the eh_frame section is transferred, its offset and size are set resp.
// to \a EHFrameOffset and \a EHFrameSize.
-template <typename SegmentTy>
-static void transferSegmentAndSections(
- const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment,
- const object::MachOObjectFile &Obj, MachObjectWriter &Writer,
+template <typename SegmentTy>
+static void transferSegmentAndSections(
+ const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment,
+ const object::MachOObjectFile &Obj, MachObjectWriter &Writer,
uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t EHFrameOffset,
uint64_t EHFrameSize, uint64_t DwarfSegmentSize, uint64_t &GapForDwarf,
uint64_t &EndAddress) {
- if (StringRef("__DWARF") == Segment.segname)
- return;
-
+ if (StringRef("__DWARF") == Segment.segname)
+ return;
+
if (StringRef("__TEXT") == Segment.segname && EHFrameSize > 0) {
Segment.fileoff = EHFrameOffset;
Segment.filesize = EHFrameSize;
} else if (StringRef("__LINKEDIT") == Segment.segname) {
- Segment.fileoff = LinkeditOffset;
- Segment.filesize = LinkeditSize;
- // Resize vmsize by rounding to the page size.
- Segment.vmsize = alignTo(LinkeditSize, 0x1000);
+ Segment.fileoff = LinkeditOffset;
+ Segment.filesize = LinkeditSize;
+ // Resize vmsize by rounding to the page size.
+ Segment.vmsize = alignTo(LinkeditSize, 0x1000);
} else {
Segment.fileoff = Segment.filesize = 0;
- }
-
- // Check if the end address of the last segment and our current
- // start address leave a sufficient gap to store the __DWARF
- // segment.
- uint64_t PrevEndAddress = EndAddress;
- EndAddress = alignTo(EndAddress, 0x1000);
- if (GapForDwarf == UINT64_MAX && Segment.vmaddr > EndAddress &&
- Segment.vmaddr - EndAddress >= DwarfSegmentSize)
- GapForDwarf = EndAddress;
-
- // The segments are not necessarily sorted by their vmaddr.
- EndAddress =
- std::max<uint64_t>(PrevEndAddress, Segment.vmaddr + Segment.vmsize);
- unsigned nsects = Segment.nsects;
- if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
- MachO::swapStruct(Segment);
- Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment));
- for (unsigned i = 0; i < nsects; ++i) {
- auto Sect = getSection(Obj, Segment, LCI, i);
+ }
+
+ // Check if the end address of the last segment and our current
+ // start address leave a sufficient gap to store the __DWARF
+ // segment.
+ uint64_t PrevEndAddress = EndAddress;
+ EndAddress = alignTo(EndAddress, 0x1000);
+ if (GapForDwarf == UINT64_MAX && Segment.vmaddr > EndAddress &&
+ Segment.vmaddr - EndAddress >= DwarfSegmentSize)
+ GapForDwarf = EndAddress;
+
+ // The segments are not necessarily sorted by their vmaddr.
+ EndAddress =
+ std::max<uint64_t>(PrevEndAddress, Segment.vmaddr + Segment.vmsize);
+ unsigned nsects = Segment.nsects;
+ if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(Segment);
+ Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment));
+ for (unsigned i = 0; i < nsects; ++i) {
+ auto Sect = getSection(Obj, Segment, LCI, i);
if (StringRef("__eh_frame") == Sect.sectname) {
Sect.offset = EHFrameOffset;
Sect.reloff = Sect.nreloc = 0;
} else {
Sect.offset = Sect.reloff = Sect.nreloc = 0;
}
- if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
- MachO::swapStruct(Sect);
- Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect));
- }
-}
-
-// Write the __DWARF segment load command to the output file.
-static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset,
- uint64_t FileSize, unsigned NumSections,
- MCAsmLayout &Layout, MachObjectWriter &Writer) {
- Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr,
- alignTo(FileSize, 0x1000), FileOffset,
- FileSize, /* MaxProt */ 7,
- /* InitProt =*/3);
-
- for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) {
- MCSection *Sec = Layout.getSectionOrder()[i];
- if (Sec->begin() == Sec->end() || !Layout.getSectionFileSize(Sec))
- continue;
-
- unsigned Align = Sec->getAlignment();
- if (Align > 1) {
- VMAddr = alignTo(VMAddr, Align);
- FileOffset = alignTo(FileOffset, Align);
- }
- Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0);
-
- FileOffset += Layout.getSectionAddressSize(Sec);
- VMAddr += Layout.getSectionAddressSize(Sec);
- }
-}
-
-static bool isExecutable(const object::MachOObjectFile &Obj) {
- if (Obj.is64Bit())
- return Obj.getHeader64().filetype != MachO::MH_OBJECT;
- else
- return Obj.getHeader().filetype != MachO::MH_OBJECT;
-}
-
-static bool hasLinkEditSegment(const object::MachOObjectFile &Obj) {
- bool HasLinkEditSegment = false;
- iterateOnSegments(Obj, [&](const MachO::segment_command_64 &Segment) {
- if (StringRef("__LINKEDIT") == Segment.segname)
- HasLinkEditSegment = true;
- });
- return HasLinkEditSegment;
-}
-
-static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) {
- if (Is64Bit)
- return sizeof(MachO::segment_command_64) +
- NumSections * sizeof(MachO::section_64);
-
- return sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section);
-}
-
-// Stream a dSYM companion binary file corresponding to the binary referenced
-// by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to
-// \a OutFile and it must be using a MachObjectWriter object to do so.
-bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- const DebugMap &DM, SymbolMapTranslator &Translator,
- MCStreamer &MS, raw_fd_ostream &OutFile) {
- auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS);
- MCAssembler &MCAsm = ObjectStreamer.getAssembler();
- auto &Writer = static_cast<MachObjectWriter &>(MCAsm.getWriter());
-
- // Layout but don't emit.
- ObjectStreamer.flushPendingLabels();
- MCAsmLayout Layout(MCAsm);
- MCAsm.layout(Layout);
-
- BinaryHolder InputBinaryHolder(VFS, false);
-
- auto ObjectEntry = InputBinaryHolder.getObjectEntry(DM.getBinaryPath());
- if (!ObjectEntry) {
- auto Err = ObjectEntry.takeError();
- return error(Twine("opening ") + DM.getBinaryPath() + ": " +
- toString(std::move(Err)),
- "output file streaming");
- }
-
- auto Object =
- ObjectEntry->getObjectAs<object::MachOObjectFile>(DM.getTriple());
- if (!Object) {
- auto Err = Object.takeError();
- return error(Twine("opening ") + DM.getBinaryPath() + ": " +
- toString(std::move(Err)),
- "output file streaming");
- }
-
- auto &InputBinary = *Object;
-
- bool Is64Bit = Writer.is64Bit();
- MachO::symtab_command SymtabCmd = InputBinary.getSymtabLoadCommand();
-
- // Compute the number of load commands we will need.
- unsigned LoadCommandSize = 0;
- unsigned NumLoadCommands = 0;
-
- // Get LC_UUID and LC_BUILD_VERSION.
- MachO::uuid_command UUIDCmd;
- SmallVector<MachO::build_version_command, 2> BuildVersionCmd;
- memset(&UUIDCmd, 0, sizeof(UUIDCmd));
- for (auto &LCI : InputBinary.load_commands()) {
- switch (LCI.C.cmd) {
- case MachO::LC_UUID:
- if (UUIDCmd.cmd)
- return error("Binary contains more than one UUID");
- UUIDCmd = InputBinary.getUuidCommand(LCI);
- ++NumLoadCommands;
- LoadCommandSize += sizeof(UUIDCmd);
- break;
- case MachO::LC_BUILD_VERSION: {
- MachO::build_version_command Cmd;
- memset(&Cmd, 0, sizeof(Cmd));
- Cmd = InputBinary.getBuildVersionLoadCommand(LCI);
- ++NumLoadCommands;
- LoadCommandSize += sizeof(Cmd);
- // LLDB doesn't care about the build tools for now.
- Cmd.ntools = 0;
- BuildVersionCmd.push_back(Cmd);
- break;
- }
- default:
- break;
- }
- }
-
- // If we have a valid symtab to copy, do it.
- bool ShouldEmitSymtab =
- isExecutable(InputBinary) && hasLinkEditSegment(InputBinary);
- if (ShouldEmitSymtab) {
- LoadCommandSize += sizeof(MachO::symtab_command);
- ++NumLoadCommands;
- }
-
+ if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(Sect);
+ Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect));
+ }
+}
+
+// Write the __DWARF segment load command to the output file.
+static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset,
+ uint64_t FileSize, unsigned NumSections,
+ MCAsmLayout &Layout, MachObjectWriter &Writer) {
+ Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr,
+ alignTo(FileSize, 0x1000), FileOffset,
+ FileSize, /* MaxProt */ 7,
+ /* InitProt =*/3);
+
+ for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) {
+ MCSection *Sec = Layout.getSectionOrder()[i];
+ if (Sec->begin() == Sec->end() || !Layout.getSectionFileSize(Sec))
+ continue;
+
+ unsigned Align = Sec->getAlignment();
+ if (Align > 1) {
+ VMAddr = alignTo(VMAddr, Align);
+ FileOffset = alignTo(FileOffset, Align);
+ }
+ Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0);
+
+ FileOffset += Layout.getSectionAddressSize(Sec);
+ VMAddr += Layout.getSectionAddressSize(Sec);
+ }
+}
+
+static bool isExecutable(const object::MachOObjectFile &Obj) {
+ if (Obj.is64Bit())
+ return Obj.getHeader64().filetype != MachO::MH_OBJECT;
+ else
+ return Obj.getHeader().filetype != MachO::MH_OBJECT;
+}
+
+static bool hasLinkEditSegment(const object::MachOObjectFile &Obj) {
+ bool HasLinkEditSegment = false;
+ iterateOnSegments(Obj, [&](const MachO::segment_command_64 &Segment) {
+ if (StringRef("__LINKEDIT") == Segment.segname)
+ HasLinkEditSegment = true;
+ });
+ return HasLinkEditSegment;
+}
+
+static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) {
+ if (Is64Bit)
+ return sizeof(MachO::segment_command_64) +
+ NumSections * sizeof(MachO::section_64);
+
+ return sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section);
+}
+
+// Stream a dSYM companion binary file corresponding to the binary referenced
+// by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to
+// \a OutFile and it must be using a MachObjectWriter object to do so.
+bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+ const DebugMap &DM, SymbolMapTranslator &Translator,
+ MCStreamer &MS, raw_fd_ostream &OutFile) {
+ auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS);
+ MCAssembler &MCAsm = ObjectStreamer.getAssembler();
+ auto &Writer = static_cast<MachObjectWriter &>(MCAsm.getWriter());
+
+ // Layout but don't emit.
+ ObjectStreamer.flushPendingLabels();
+ MCAsmLayout Layout(MCAsm);
+ MCAsm.layout(Layout);
+
+ BinaryHolder InputBinaryHolder(VFS, false);
+
+ auto ObjectEntry = InputBinaryHolder.getObjectEntry(DM.getBinaryPath());
+ if (!ObjectEntry) {
+ auto Err = ObjectEntry.takeError();
+ return error(Twine("opening ") + DM.getBinaryPath() + ": " +
+ toString(std::move(Err)),
+ "output file streaming");
+ }
+
+ auto Object =
+ ObjectEntry->getObjectAs<object::MachOObjectFile>(DM.getTriple());
+ if (!Object) {
+ auto Err = Object.takeError();
+ return error(Twine("opening ") + DM.getBinaryPath() + ": " +
+ toString(std::move(Err)),
+ "output file streaming");
+ }
+
+ auto &InputBinary = *Object;
+
+ bool Is64Bit = Writer.is64Bit();
+ MachO::symtab_command SymtabCmd = InputBinary.getSymtabLoadCommand();
+
+ // Compute the number of load commands we will need.
+ unsigned LoadCommandSize = 0;
+ unsigned NumLoadCommands = 0;
+
+ // Get LC_UUID and LC_BUILD_VERSION.
+ MachO::uuid_command UUIDCmd;
+ SmallVector<MachO::build_version_command, 2> BuildVersionCmd;
+ memset(&UUIDCmd, 0, sizeof(UUIDCmd));
+ for (auto &LCI : InputBinary.load_commands()) {
+ switch (LCI.C.cmd) {
+ case MachO::LC_UUID:
+ if (UUIDCmd.cmd)
+ return error("Binary contains more than one UUID");
+ UUIDCmd = InputBinary.getUuidCommand(LCI);
+ ++NumLoadCommands;
+ LoadCommandSize += sizeof(UUIDCmd);
+ break;
+ case MachO::LC_BUILD_VERSION: {
+ MachO::build_version_command Cmd;
+ memset(&Cmd, 0, sizeof(Cmd));
+ Cmd = InputBinary.getBuildVersionLoadCommand(LCI);
+ ++NumLoadCommands;
+ LoadCommandSize += sizeof(Cmd);
+ // LLDB doesn't care about the build tools for now.
+ Cmd.ntools = 0;
+ BuildVersionCmd.push_back(Cmd);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // If we have a valid symtab to copy, do it.
+ bool ShouldEmitSymtab =
+ isExecutable(InputBinary) && hasLinkEditSegment(InputBinary);
+ if (ShouldEmitSymtab) {
+ LoadCommandSize += sizeof(MachO::symtab_command);
+ ++NumLoadCommands;
+ }
+
// If we have a valid eh_frame to copy, do it.
uint64_t EHFrameSize = 0;
StringRef EHFrameData;
@@ -452,148 +452,148 @@ bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
}
}
- unsigned HeaderSize =
- Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
- // We will copy every segment that isn't __DWARF.
- iterateOnSegments(InputBinary, [&](const MachO::segment_command_64 &Segment) {
- if (StringRef("__DWARF") == Segment.segname)
- return;
-
- ++NumLoadCommands;
- LoadCommandSize += segmentLoadCommandSize(Is64Bit, Segment.nsects);
- });
-
- // We will add our own brand new __DWARF segment if we have debug
- // info.
- unsigned NumDwarfSections = 0;
- uint64_t DwarfSegmentSize = 0;
-
- for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) {
- MCSection *Sec = Layout.getSectionOrder()[i];
- if (Sec->begin() == Sec->end())
- continue;
-
- if (uint64_t Size = Layout.getSectionFileSize(Sec)) {
- DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlignment());
- DwarfSegmentSize += Size;
- ++NumDwarfSections;
- }
- }
-
- if (NumDwarfSections) {
- ++NumLoadCommands;
- LoadCommandSize += segmentLoadCommandSize(Is64Bit, NumDwarfSections);
- }
-
- SmallString<0> NewSymtab;
- std::function<StringRef(StringRef)> TranslationLambda =
- Translator ? [&](StringRef Input) { return Translator(Input); }
- : static_cast<std::function<StringRef(StringRef)>>(nullptr);
- // Legacy dsymutil puts an empty string at the start of the line table.
- // thus we set NonRelocatableStringpool(,PutEmptyString=true)
- NonRelocatableStringpool NewStrings(TranslationLambda, true);
- unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
- unsigned NumSyms = 0;
- uint64_t NewStringsSize = 0;
- if (ShouldEmitSymtab) {
- NewSymtab.reserve(SymtabCmd.nsyms * NListSize / 2);
- NumSyms = transferSymbols(InputBinary, NewSymtab, NewStrings);
- NewStringsSize = NewStrings.getSize() + 1;
- }
-
- uint64_t SymtabStart = LoadCommandSize;
- SymtabStart += HeaderSize;
- SymtabStart = alignTo(SymtabStart, 0x1000);
-
- // We gathered all the information we need, start emitting the output file.
- Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false);
-
- // Write the load commands.
- assert(OutFile.tell() == HeaderSize);
- if (UUIDCmd.cmd != 0) {
- Writer.W.write<uint32_t>(UUIDCmd.cmd);
- Writer.W.write<uint32_t>(sizeof(UUIDCmd));
- OutFile.write(reinterpret_cast<const char *>(UUIDCmd.uuid), 16);
- assert(OutFile.tell() == HeaderSize + sizeof(UUIDCmd));
- }
- for (auto Cmd : BuildVersionCmd) {
- Writer.W.write<uint32_t>(Cmd.cmd);
- Writer.W.write<uint32_t>(sizeof(Cmd));
- Writer.W.write<uint32_t>(Cmd.platform);
- Writer.W.write<uint32_t>(Cmd.minos);
- Writer.W.write<uint32_t>(Cmd.sdk);
- Writer.W.write<uint32_t>(Cmd.ntools);
- }
-
- assert(SymtabCmd.cmd && "No symbol table.");
- uint64_t StringStart = SymtabStart + NumSyms * NListSize;
- if (ShouldEmitSymtab)
- Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart,
- NewStringsSize);
-
+ unsigned HeaderSize =
+ Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
+ // We will copy every segment that isn't __DWARF.
+ iterateOnSegments(InputBinary, [&](const MachO::segment_command_64 &Segment) {
+ if (StringRef("__DWARF") == Segment.segname)
+ return;
+
+ ++NumLoadCommands;
+ LoadCommandSize += segmentLoadCommandSize(Is64Bit, Segment.nsects);
+ });
+
+ // We will add our own brand new __DWARF segment if we have debug
+ // info.
+ unsigned NumDwarfSections = 0;
+ uint64_t DwarfSegmentSize = 0;
+
+ for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) {
+ MCSection *Sec = Layout.getSectionOrder()[i];
+ if (Sec->begin() == Sec->end())
+ continue;
+
+ if (uint64_t Size = Layout.getSectionFileSize(Sec)) {
+ DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlignment());
+ DwarfSegmentSize += Size;
+ ++NumDwarfSections;
+ }
+ }
+
+ if (NumDwarfSections) {
+ ++NumLoadCommands;
+ LoadCommandSize += segmentLoadCommandSize(Is64Bit, NumDwarfSections);
+ }
+
+ SmallString<0> NewSymtab;
+ std::function<StringRef(StringRef)> TranslationLambda =
+ Translator ? [&](StringRef Input) { return Translator(Input); }
+ : static_cast<std::function<StringRef(StringRef)>>(nullptr);
+ // Legacy dsymutil puts an empty string at the start of the line table.
+ // thus we set NonRelocatableStringpool(,PutEmptyString=true)
+ NonRelocatableStringpool NewStrings(TranslationLambda, true);
+ unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
+ unsigned NumSyms = 0;
+ uint64_t NewStringsSize = 0;
+ if (ShouldEmitSymtab) {
+ NewSymtab.reserve(SymtabCmd.nsyms * NListSize / 2);
+ NumSyms = transferSymbols(InputBinary, NewSymtab, NewStrings);
+ NewStringsSize = NewStrings.getSize() + 1;
+ }
+
+ uint64_t SymtabStart = LoadCommandSize;
+ SymtabStart += HeaderSize;
+ SymtabStart = alignTo(SymtabStart, 0x1000);
+
+ // We gathered all the information we need, start emitting the output file.
+ Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false);
+
+ // Write the load commands.
+ assert(OutFile.tell() == HeaderSize);
+ if (UUIDCmd.cmd != 0) {
+ Writer.W.write<uint32_t>(UUIDCmd.cmd);
+ Writer.W.write<uint32_t>(sizeof(UUIDCmd));
+ OutFile.write(reinterpret_cast<const char *>(UUIDCmd.uuid), 16);
+ assert(OutFile.tell() == HeaderSize + sizeof(UUIDCmd));
+ }
+ for (auto Cmd : BuildVersionCmd) {
+ Writer.W.write<uint32_t>(Cmd.cmd);
+ Writer.W.write<uint32_t>(sizeof(Cmd));
+ Writer.W.write<uint32_t>(Cmd.platform);
+ Writer.W.write<uint32_t>(Cmd.minos);
+ Writer.W.write<uint32_t>(Cmd.sdk);
+ Writer.W.write<uint32_t>(Cmd.ntools);
+ }
+
+ assert(SymtabCmd.cmd && "No symbol table.");
+ uint64_t StringStart = SymtabStart + NumSyms * NListSize;
+ if (ShouldEmitSymtab)
+ Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart,
+ NewStringsSize);
+
uint64_t EHFrameStart = StringStart + NewStringsSize;
EHFrameStart = alignTo(EHFrameStart, 0x1000);
uint64_t DwarfSegmentStart = EHFrameStart + EHFrameSize;
- DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000);
-
- // Write the load commands for the segments and sections we 'import' from
- // the original binary.
- uint64_t EndAddress = 0;
- uint64_t GapForDwarf = UINT64_MAX;
- for (auto &LCI : InputBinary.load_commands()) {
- if (LCI.C.cmd == MachO::LC_SEGMENT)
+ DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000);
+
+ // Write the load commands for the segments and sections we 'import' from
+ // the original binary.
+ uint64_t EndAddress = 0;
+ uint64_t GapForDwarf = UINT64_MAX;
+ for (auto &LCI : InputBinary.load_commands()) {
+ if (LCI.C.cmd == MachO::LC_SEGMENT)
transferSegmentAndSections(
LCI, InputBinary.getSegmentLoadCommand(LCI), InputBinary, Writer,
SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,
EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);
- else if (LCI.C.cmd == MachO::LC_SEGMENT_64)
+ else if (LCI.C.cmd == MachO::LC_SEGMENT_64)
transferSegmentAndSections(
LCI, InputBinary.getSegment64LoadCommand(LCI), InputBinary, Writer,
SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,
EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);
- }
-
- uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000);
- uint64_t DwarfVMMax = Is64Bit ? UINT64_MAX : UINT32_MAX;
- if (DwarfVMAddr + DwarfSegmentSize > DwarfVMMax ||
- DwarfVMAddr + DwarfSegmentSize < DwarfVMAddr /* Overflow */) {
- // There is no room for the __DWARF segment at the end of the
- // address space. Look through segments to find a gap.
- DwarfVMAddr = GapForDwarf;
- if (DwarfVMAddr == UINT64_MAX)
- warn("not enough VM space for the __DWARF segment.",
- "output file streaming");
- }
-
- // Write the load command for the __DWARF segment.
- createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize,
- NumDwarfSections, Layout, Writer);
-
- assert(OutFile.tell() == LoadCommandSize + HeaderSize);
- OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize));
- assert(OutFile.tell() == SymtabStart);
-
- // Transfer symbols.
- if (ShouldEmitSymtab) {
- OutFile << NewSymtab.str();
- assert(OutFile.tell() == StringStart);
-
- // Transfer string table.
- // FIXME: The NonRelocatableStringpool starts with an empty string, but
- // dsymutil-classic starts the reconstructed string table with 2 of these.
- // Reproduce that behavior for now (there is corresponding code in
- // transferSymbol).
- OutFile << '\0';
- std::vector<DwarfStringPoolEntryRef> Strings =
- NewStrings.getEntriesForEmission();
- for (auto EntryRef : Strings) {
- OutFile.write(EntryRef.getString().data(),
- EntryRef.getString().size() + 1);
- }
- }
- assert(OutFile.tell() == StringStart + NewStringsSize);
-
+ }
+
+ uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000);
+ uint64_t DwarfVMMax = Is64Bit ? UINT64_MAX : UINT32_MAX;
+ if (DwarfVMAddr + DwarfSegmentSize > DwarfVMMax ||
+ DwarfVMAddr + DwarfSegmentSize < DwarfVMAddr /* Overflow */) {
+ // There is no room for the __DWARF segment at the end of the
+ // address space. Look through segments to find a gap.
+ DwarfVMAddr = GapForDwarf;
+ if (DwarfVMAddr == UINT64_MAX)
+ warn("not enough VM space for the __DWARF segment.",
+ "output file streaming");
+ }
+
+ // Write the load command for the __DWARF segment.
+ createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize,
+ NumDwarfSections, Layout, Writer);
+
+ assert(OutFile.tell() == LoadCommandSize + HeaderSize);
+ OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize));
+ assert(OutFile.tell() == SymtabStart);
+
+ // Transfer symbols.
+ if (ShouldEmitSymtab) {
+ OutFile << NewSymtab.str();
+ assert(OutFile.tell() == StringStart);
+
+ // Transfer string table.
+ // FIXME: The NonRelocatableStringpool starts with an empty string, but
+ // dsymutil-classic starts the reconstructed string table with 2 of these.
+ // Reproduce that behavior for now (there is corresponding code in
+ // transferSymbol).
+ OutFile << '\0';
+ std::vector<DwarfStringPoolEntryRef> Strings =
+ NewStrings.getEntriesForEmission();
+ for (auto EntryRef : Strings) {
+ OutFile.write(EntryRef.getString().data(),
+ EntryRef.getString().size() + 1);
+ }
+ }
+ assert(OutFile.tell() == StringStart + NewStringsSize);
+
// Pad till the EH frame start.
OutFile.write_zeros(EHFrameStart - (StringStart + NewStringsSize));
assert(OutFile.tell() == EHFrameStart);
@@ -603,22 +603,22 @@ bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
OutFile << EHFrameData;
assert(OutFile.tell() == EHFrameStart + EHFrameSize);
- // Pad till the Dwarf segment start.
+ // Pad till the Dwarf segment start.
OutFile.write_zeros(DwarfSegmentStart - (EHFrameStart + EHFrameSize));
- assert(OutFile.tell() == DwarfSegmentStart);
-
- // Emit the Dwarf sections contents.
- for (const MCSection &Sec : MCAsm) {
- if (Sec.begin() == Sec.end())
- continue;
-
- uint64_t Pos = OutFile.tell();
- OutFile.write_zeros(alignTo(Pos, Sec.getAlignment()) - Pos);
- MCAsm.writeSectionData(OutFile, &Sec, Layout);
- }
-
- return true;
-}
-} // namespace MachOUtils
-} // namespace dsymutil
-} // namespace llvm
+ assert(OutFile.tell() == DwarfSegmentStart);
+
+ // Emit the Dwarf sections contents.
+ for (const MCSection &Sec : MCAsm) {
+ if (Sec.begin() == Sec.end())
+ continue;
+
+ uint64_t Pos = OutFile.tell();
+ OutFile.write_zeros(alignTo(Pos, Sec.getAlignment()) - Pos);
+ MCAsm.writeSectionData(OutFile, &Sec, Layout);
+ }
+
+ return true;
+}
+} // namespace MachOUtils
+} // namespace dsymutil
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h
index b1cdd44d38..109da802b0 100644
--- a/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h
+++ b/contrib/libs/llvm12/tools/dsymutil/MachOUtils.h
@@ -1,52 +1,52 @@
-//===-- MachOUtils.h - Mach-o specific helpers for dsymutil --------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
-#define LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
-
-#include "SymbolMap.h"
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/VirtualFileSystem.h"
-
-#include <string>
-
-namespace llvm {
-class MCStreamer;
-class raw_fd_ostream;
-namespace dsymutil {
-class DebugMap;
-struct LinkOptions;
-namespace MachOUtils {
-
-struct ArchAndFile {
- std::string Arch;
- std::unique_ptr<llvm::sys::fs::TempFile> File;
-
- llvm::Error createTempFile();
- llvm::StringRef path() const;
-
- ArchAndFile(StringRef Arch) : Arch(std::string(Arch)) {}
- ArchAndFile(ArchAndFile &&A) = default;
- ArchAndFile &operator=(ArchAndFile &&A) = default;
- ~ArchAndFile();
-};
-
-bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
- StringRef OutputFileName, const LinkOptions &,
- StringRef SDKPath);
-
-bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- const DebugMap &DM, SymbolMapTranslator &Translator,
- MCStreamer &MS, raw_fd_ostream &OutFile);
-
-std::string getArchName(StringRef Arch);
-} // namespace MachOUtils
-} // namespace dsymutil
-} // namespace llvm
-#endif // LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
+//===-- MachOUtils.h - Mach-o specific helpers for dsymutil --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
+#define LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
+
+#include "SymbolMap.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+#include <string>
+
+namespace llvm {
+class MCStreamer;
+class raw_fd_ostream;
+namespace dsymutil {
+class DebugMap;
+struct LinkOptions;
+namespace MachOUtils {
+
+struct ArchAndFile {
+ std::string Arch;
+ std::unique_ptr<llvm::sys::fs::TempFile> File;
+
+ llvm::Error createTempFile();
+ llvm::StringRef path() const;
+
+ ArchAndFile(StringRef Arch) : Arch(std::string(Arch)) {}
+ ArchAndFile(ArchAndFile &&A) = default;
+ ArchAndFile &operator=(ArchAndFile &&A) = default;
+ ~ArchAndFile();
+};
+
+bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,
+ StringRef OutputFileName, const LinkOptions &,
+ StringRef SDKPath);
+
+bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+ const DebugMap &DM, SymbolMapTranslator &Translator,
+ MCStreamer &MS, raw_fd_ostream &OutFile);
+
+std::string getArchName(StringRef Arch);
+} // namespace MachOUtils
+} // namespace dsymutil
+} // namespace llvm
+#endif // LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
diff --git a/contrib/libs/llvm12/tools/dsymutil/Options.td b/contrib/libs/llvm12/tools/dsymutil/Options.td
index 7bd21b0d43..f704467115 100644
--- a/contrib/libs/llvm12/tools/dsymutil/Options.td
+++ b/contrib/libs/llvm12/tools/dsymutil/Options.td
@@ -1,187 +1,187 @@
-include "llvm/Option/OptParser.td"
-
-class F<string name>: Flag<["--", "-"], name>;
-
-def grp_general : OptionGroup<"Dsymutil">, HelpText<"Dsymutil Options">;
-
-def help: F<"help">,
- HelpText<"Prints this help output.">,
- Group<grp_general>;
-def: Flag<["-"], "h">,
- Alias<help>,
- HelpText<"Alias for --help">,
- Group<grp_general>;
-
-def version: F<"version">,
- HelpText<"Prints the dsymutil version.">,
- Group<grp_general>;
-def: Flag<["-"], "v">,
- Alias<version>,
- HelpText<"Alias for --version">,
- Group<grp_general>;
-
-def verbose: F<"verbose">,
- HelpText<"Enable verbose mode.">,
- Group<grp_general>;
-
-def statistics: F<"statistics">,
- HelpText<"Print statistics about the contribution of each object file to "
- "the linked debug info. This prints a table after linking with the "
- "object file name, the size of the debug info in the object file "
- "(in bytes) and the size contributed (in bytes) to the linked dSYM. "
- "The table is sorted by the output size listing the object files "
- "with the largest contribution first.">,
- Group<grp_general>;
-
-def verify: F<"verify">,
- HelpText<"Run the DWARF verifier on the linked DWARF debug info.">,
- Group<grp_general>;
-
-def no_output: F<"no-output">,
- HelpText<"Do the link in memory, but do not emit the result file.">,
- Group<grp_general>;
-
-def no_swiftmodule_timestamp: F<"no-swiftmodule-timestamp">,
- HelpText<"Don't check timestamp for swiftmodule files.">,
- Group<grp_general>;
-
-def no_odr: F<"no-odr">,
- HelpText<"Do not use ODR (One Definition Rule) for type uniquing.">,
- Group<grp_general>;
-
-def dump_debug_map: F<"dump-debug-map">,
- HelpText<"Parse and dump the debug map to standard output. Not DWARF link will take place.">,
- Group<grp_general>;
-
-def yaml_input: Flag<["-", "--"], "y">,
- HelpText<"Treat the input file is a YAML debug map rather than a binary.">,
- Group<grp_general>;
-
-def papertrail: F<"papertrail">,
- HelpText<"Embed warnings in the linked DWARF debug info.">,
- Group<grp_general>;
-
-def assembly: Flag<["-", "--"], "S">,
- HelpText<"Output textual assembly instead of a binary dSYM companion file.">,
- Group<grp_general>;
-
-def symtab: F<"symtab">,
- HelpText<"Dumps the symbol table found in executable or object file(s) and exits.">,
- Group<grp_general>;
-def: Flag<["-"], "s">,
- Alias<symtab>,
- HelpText<"Alias for --symtab">,
- Group<grp_general>;
-
-def flat: F<"flat">,
- HelpText<"Produce a flat dSYM file (not a bundle).">,
- Group<grp_general>;
-def: Flag<["-"], "f">,
- Alias<flat>,
- HelpText<"Alias for --flat">,
- Group<grp_general>;
-
-def minimize: F<"minimize">,
- HelpText<"When used when creating a dSYM file with Apple accelerator tables, "
- "this option will suppress the emission of the .debug_inlines, "
- ".debug_pubnames, and .debug_pubtypes sections since dsymutil "
- "has better equivalents: .apple_names and .apple_types. When used in "
- "conjunction with --update option, this option will cause redundant "
- "accelerator tables to be removed.">,
- Group<grp_general>;
-def: Flag<["-"], "z">,
- Alias<minimize>,
- HelpText<"Alias for --minimize">,
- Group<grp_general>;
-
-def update: F<"update">,
- HelpText<"Updates existing dSYM files to contain the latest accelerator tables and other DWARF optimizations.">,
- Group<grp_general>;
-def: Flag<["-"], "u">,
- Alias<update>,
- HelpText<"Alias for --update">,
- Group<grp_general>;
-
-def output: Separate<["-", "--"], "o">,
- MetaVarName<"<filename>">,
- HelpText<"Specify the output file. Defaults to <input file>.dwarf">,
- Group<grp_general>;
-def: Separate<["--", "-"], "out">,
- MetaVarName<"<filename>">,
- Alias<output>,
- HelpText<"Alias for -o">,
- Group<grp_general>;
-def: Joined<["--", "-"], "out=">, Alias<output>;
-def: Joined<["-", "--"], "o=">, Alias<output>;
-
-def oso_prepend_path: Separate<["--", "-"], "oso-prepend-path">,
- MetaVarName<"<path>">,
- HelpText<"Specify a directory to prepend to the paths of object files.">,
- Group<grp_general>;
-def: Joined<["--", "-"], "oso-prepend-path=">, Alias<oso_prepend_path>;
-
-def object_prefix_map: Separate<["--", "-"], "object-prefix-map">,
- MetaVarName<"<prefix=remapped>">,
- HelpText<"Remap object file paths (but no source paths) before processing."
- "Use this for Clang objects where the module cache location was"
- "remapped using -fdebug-prefix-map; to help dsymutil"
- "find the Clang module cache.">,
- Group<grp_general>;
-def: Joined<["--", "-"], "object-prefix-map=">, Alias<object_prefix_map>;
-
-def symbolmap: Separate<["--", "-"], "symbol-map">,
- MetaVarName<"<bcsymbolmap>">,
- HelpText<"Updates the existing dSYMs inplace using symbol map specified.">,
- Group<grp_general>;
-def: Joined<["--", "-"], "symbol-map=">, Alias<symbolmap>;
-
-def arch: Separate<["--", "-"], "arch">,
- MetaVarName<"<arch>">,
- HelpText<"Link DWARF debug information only for specified CPU architecture"
- "types. This option can be specified multiple times, once for each"
- "desired architecture. All CPU architectures will be linked by"
- "default.">,
- Group<grp_general>;
-def: Joined<["--", "-"], "arch=">, Alias<arch>;
-
-def accelerator: Separate<["--", "-"], "accelerator">,
- MetaVarName<"<accelerator type>">,
- HelpText<"Specify the desired type of accelerator table. Valid options are 'Apple', 'Dwarf' and 'Default'">,
- Group<grp_general>;
-def: Joined<["--", "-"], "accelerator=">, Alias<accelerator>;
-
-def toolchain: Separate<["--", "-"], "toolchain">,
- MetaVarName<"<toolchain>">,
- HelpText<"Embed toolchain information in dSYM bundle.">,
- Group<grp_general>;
-
-def threads: Separate<["--", "-"], "num-threads">,
- MetaVarName<"<threads>">,
- HelpText<"Specifies the maximum number of simultaneous threads to use when linking multiple architectures.">,
- Group<grp_general>;
-def: Separate<["-"], "j">,
- MetaVarName<"<threads>">,
- HelpText<"Alias for --num-threads">,
- Group<grp_general>;
-
-def gen_reproducer: F<"gen-reproducer">,
- HelpText<"Generate a reproducer consisting of the input object files.">,
- Group<grp_general>;
-
-def use_reproducer: Separate<["--", "-"], "use-reproducer">,
- MetaVarName<"<path>">,
- HelpText<"Use the object files from the given reproducer path.">,
- Group<grp_general>;
-def: Joined<["--", "-"], "use-reproducer=">, Alias<use_reproducer>;
-
-def remarks_prepend_path: Separate<["--", "-"], "remarks-prepend-path">,
- MetaVarName<"<path>">,
- HelpText<"Specify a directory to prepend to the paths of the external remark files.">,
- Group<grp_general>;
-def: Joined<["--", "-"], "remarks-prepend-path=">, Alias<remarks_prepend_path>;
-
-def remarks_output_format: Separate<["--", "-"], "remarks-output-format">,
- MetaVarName<"<format>">,
- HelpText<"Specify the format to be used when serializing the linked remarks.">,
- Group<grp_general>;
-def: Joined<["--", "-"], "remarks-output-format=">, Alias<remarks_output_format>;
+include "llvm/Option/OptParser.td"
+
+class F<string name>: Flag<["--", "-"], name>;
+
+def grp_general : OptionGroup<"Dsymutil">, HelpText<"Dsymutil Options">;
+
+def help: F<"help">,
+ HelpText<"Prints this help output.">,
+ Group<grp_general>;
+def: Flag<["-"], "h">,
+ Alias<help>,
+ HelpText<"Alias for --help">,
+ Group<grp_general>;
+
+def version: F<"version">,
+ HelpText<"Prints the dsymutil version.">,
+ Group<grp_general>;
+def: Flag<["-"], "v">,
+ Alias<version>,
+ HelpText<"Alias for --version">,
+ Group<grp_general>;
+
+def verbose: F<"verbose">,
+ HelpText<"Enable verbose mode.">,
+ Group<grp_general>;
+
+def statistics: F<"statistics">,
+ HelpText<"Print statistics about the contribution of each object file to "
+ "the linked debug info. This prints a table after linking with the "
+ "object file name, the size of the debug info in the object file "
+ "(in bytes) and the size contributed (in bytes) to the linked dSYM. "
+ "The table is sorted by the output size listing the object files "
+ "with the largest contribution first.">,
+ Group<grp_general>;
+
+def verify: F<"verify">,
+ HelpText<"Run the DWARF verifier on the linked DWARF debug info.">,
+ Group<grp_general>;
+
+def no_output: F<"no-output">,
+ HelpText<"Do the link in memory, but do not emit the result file.">,
+ Group<grp_general>;
+
+def no_swiftmodule_timestamp: F<"no-swiftmodule-timestamp">,
+ HelpText<"Don't check timestamp for swiftmodule files.">,
+ Group<grp_general>;
+
+def no_odr: F<"no-odr">,
+ HelpText<"Do not use ODR (One Definition Rule) for type uniquing.">,
+ Group<grp_general>;
+
+def dump_debug_map: F<"dump-debug-map">,
+ HelpText<"Parse and dump the debug map to standard output. Not DWARF link will take place.">,
+ Group<grp_general>;
+
+def yaml_input: Flag<["-", "--"], "y">,
+ HelpText<"Treat the input file is a YAML debug map rather than a binary.">,
+ Group<grp_general>;
+
+def papertrail: F<"papertrail">,
+ HelpText<"Embed warnings in the linked DWARF debug info.">,
+ Group<grp_general>;
+
+def assembly: Flag<["-", "--"], "S">,
+ HelpText<"Output textual assembly instead of a binary dSYM companion file.">,
+ Group<grp_general>;
+
+def symtab: F<"symtab">,
+ HelpText<"Dumps the symbol table found in executable or object file(s) and exits.">,
+ Group<grp_general>;
+def: Flag<["-"], "s">,
+ Alias<symtab>,
+ HelpText<"Alias for --symtab">,
+ Group<grp_general>;
+
+def flat: F<"flat">,
+ HelpText<"Produce a flat dSYM file (not a bundle).">,
+ Group<grp_general>;
+def: Flag<["-"], "f">,
+ Alias<flat>,
+ HelpText<"Alias for --flat">,
+ Group<grp_general>;
+
+def minimize: F<"minimize">,
+ HelpText<"When used when creating a dSYM file with Apple accelerator tables, "
+ "this option will suppress the emission of the .debug_inlines, "
+ ".debug_pubnames, and .debug_pubtypes sections since dsymutil "
+ "has better equivalents: .apple_names and .apple_types. When used in "
+ "conjunction with --update option, this option will cause redundant "
+ "accelerator tables to be removed.">,
+ Group<grp_general>;
+def: Flag<["-"], "z">,
+ Alias<minimize>,
+ HelpText<"Alias for --minimize">,
+ Group<grp_general>;
+
+def update: F<"update">,
+ HelpText<"Updates existing dSYM files to contain the latest accelerator tables and other DWARF optimizations.">,
+ Group<grp_general>;
+def: Flag<["-"], "u">,
+ Alias<update>,
+ HelpText<"Alias for --update">,
+ Group<grp_general>;
+
+def output: Separate<["-", "--"], "o">,
+ MetaVarName<"<filename>">,
+ HelpText<"Specify the output file. Defaults to <input file>.dwarf">,
+ Group<grp_general>;
+def: Separate<["--", "-"], "out">,
+ MetaVarName<"<filename>">,
+ Alias<output>,
+ HelpText<"Alias for -o">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "out=">, Alias<output>;
+def: Joined<["-", "--"], "o=">, Alias<output>;
+
+def oso_prepend_path: Separate<["--", "-"], "oso-prepend-path">,
+ MetaVarName<"<path>">,
+ HelpText<"Specify a directory to prepend to the paths of object files.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "oso-prepend-path=">, Alias<oso_prepend_path>;
+
+def object_prefix_map: Separate<["--", "-"], "object-prefix-map">,
+ MetaVarName<"<prefix=remapped>">,
+ HelpText<"Remap object file paths (but no source paths) before processing."
+ "Use this for Clang objects where the module cache location was"
+ "remapped using -fdebug-prefix-map; to help dsymutil"
+ "find the Clang module cache.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "object-prefix-map=">, Alias<object_prefix_map>;
+
+def symbolmap: Separate<["--", "-"], "symbol-map">,
+ MetaVarName<"<bcsymbolmap>">,
+ HelpText<"Updates the existing dSYMs inplace using symbol map specified.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "symbol-map=">, Alias<symbolmap>;
+
+def arch: Separate<["--", "-"], "arch">,
+ MetaVarName<"<arch>">,
+ HelpText<"Link DWARF debug information only for specified CPU architecture"
+ "types. This option can be specified multiple times, once for each"
+ "desired architecture. All CPU architectures will be linked by"
+ "default.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "arch=">, Alias<arch>;
+
+def accelerator: Separate<["--", "-"], "accelerator">,
+ MetaVarName<"<accelerator type>">,
+ HelpText<"Specify the desired type of accelerator table. Valid options are 'Apple', 'Dwarf' and 'Default'">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "accelerator=">, Alias<accelerator>;
+
+def toolchain: Separate<["--", "-"], "toolchain">,
+ MetaVarName<"<toolchain>">,
+ HelpText<"Embed toolchain information in dSYM bundle.">,
+ Group<grp_general>;
+
+def threads: Separate<["--", "-"], "num-threads">,
+ MetaVarName<"<threads>">,
+ HelpText<"Specifies the maximum number of simultaneous threads to use when linking multiple architectures.">,
+ Group<grp_general>;
+def: Separate<["-"], "j">,
+ MetaVarName<"<threads>">,
+ HelpText<"Alias for --num-threads">,
+ Group<grp_general>;
+
+def gen_reproducer: F<"gen-reproducer">,
+ HelpText<"Generate a reproducer consisting of the input object files.">,
+ Group<grp_general>;
+
+def use_reproducer: Separate<["--", "-"], "use-reproducer">,
+ MetaVarName<"<path>">,
+ HelpText<"Use the object files from the given reproducer path.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "use-reproducer=">, Alias<use_reproducer>;
+
+def remarks_prepend_path: Separate<["--", "-"], "remarks-prepend-path">,
+ MetaVarName<"<path>">,
+ HelpText<"Specify a directory to prepend to the paths of the external remark files.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "remarks-prepend-path=">, Alias<remarks_prepend_path>;
+
+def remarks_output_format: Separate<["--", "-"], "remarks-output-format">,
+ MetaVarName<"<format>">,
+ HelpText<"Specify the format to be used when serializing the linked remarks.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "remarks-output-format=">, Alias<remarks_output_format>;
diff --git a/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp b/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp
index 5c60758c6f..d064086b0f 100644
--- a/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp
+++ b/contrib/libs/llvm12/tools/dsymutil/Reproducer.cpp
@@ -1,85 +1,85 @@
-//===- Reproducer.cpp -----------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "Reproducer.h"
-#include "llvm/Support/Path.h"
-
-using namespace llvm;
-using namespace llvm::dsymutil;
-
-static std::string createReproducerDir(std::error_code &EC) {
- SmallString<128> Root;
- if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) {
- Root.assign(Path);
- EC = sys::fs::create_directory(Root);
- } else {
- EC = sys::fs::createUniqueDirectory("dsymutil", Root);
- }
- return EC ? "" : std::string(Root);
-}
-
-Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {}
-Reproducer::~Reproducer() = default;
-
-ReproducerGenerate::ReproducerGenerate(std::error_code &EC)
- : Root(createReproducerDir(EC)), FC() {
- if (!Root.empty())
- FC = std::make_shared<FileCollector>(Root, Root);
- VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), FC);
-}
-
-ReproducerGenerate::~ReproducerGenerate() {
- if (!FC)
- return;
- FC->copyFiles(false);
- SmallString<128> Mapping(Root);
- sys::path::append(Mapping, "mapping.yaml");
- FC->writeMapping(Mapping.str());
- outs() << "reproducer written to " << Root << '\n';
-}
-
-ReproducerUse::~ReproducerUse() = default;
-
-ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) {
- SmallString<128> Mapping(Root);
- sys::path::append(Mapping, "mapping.yaml");
- ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
- vfs::getRealFileSystem()->getBufferForFile(Mapping.str());
-
- if (!Buffer) {
- EC = Buffer.getError();
- return;
- }
-
- VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping);
-}
-
-llvm::Expected<std::unique_ptr<Reproducer>>
-Reproducer::createReproducer(ReproducerMode Mode, StringRef Root) {
- switch (Mode) {
- case ReproducerMode::Generate: {
- std::error_code EC;
- std::unique_ptr<Reproducer> Repro =
- std::make_unique<ReproducerGenerate>(EC);
- if (EC)
- return errorCodeToError(EC);
- return std::move(Repro);
- }
- case ReproducerMode::Use: {
- std::error_code EC;
- std::unique_ptr<Reproducer> Repro =
- std::make_unique<ReproducerUse>(Root, EC);
- if (EC)
- return errorCodeToError(EC);
- return std::move(Repro);
- }
- case ReproducerMode::Off:
- return std::make_unique<Reproducer>();
- }
- llvm_unreachable("All cases handled above.");
-}
+//===- Reproducer.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Reproducer.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace llvm::dsymutil;
+
+static std::string createReproducerDir(std::error_code &EC) {
+ SmallString<128> Root;
+ if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) {
+ Root.assign(Path);
+ EC = sys::fs::create_directory(Root);
+ } else {
+ EC = sys::fs::createUniqueDirectory("dsymutil", Root);
+ }
+ return EC ? "" : std::string(Root);
+}
+
+Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {}
+Reproducer::~Reproducer() = default;
+
+ReproducerGenerate::ReproducerGenerate(std::error_code &EC)
+ : Root(createReproducerDir(EC)), FC() {
+ if (!Root.empty())
+ FC = std::make_shared<FileCollector>(Root, Root);
+ VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), FC);
+}
+
+ReproducerGenerate::~ReproducerGenerate() {
+ if (!FC)
+ return;
+ FC->copyFiles(false);
+ SmallString<128> Mapping(Root);
+ sys::path::append(Mapping, "mapping.yaml");
+ FC->writeMapping(Mapping.str());
+ outs() << "reproducer written to " << Root << '\n';
+}
+
+ReproducerUse::~ReproducerUse() = default;
+
+ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) {
+ SmallString<128> Mapping(Root);
+ sys::path::append(Mapping, "mapping.yaml");
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
+ vfs::getRealFileSystem()->getBufferForFile(Mapping.str());
+
+ if (!Buffer) {
+ EC = Buffer.getError();
+ return;
+ }
+
+ VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping);
+}
+
+llvm::Expected<std::unique_ptr<Reproducer>>
+Reproducer::createReproducer(ReproducerMode Mode, StringRef Root) {
+ switch (Mode) {
+ case ReproducerMode::Generate: {
+ std::error_code EC;
+ std::unique_ptr<Reproducer> Repro =
+ std::make_unique<ReproducerGenerate>(EC);
+ if (EC)
+ return errorCodeToError(EC);
+ return std::move(Repro);
+ }
+ case ReproducerMode::Use: {
+ std::error_code EC;
+ std::unique_ptr<Reproducer> Repro =
+ std::make_unique<ReproducerUse>(Root, EC);
+ if (EC)
+ return errorCodeToError(EC);
+ return std::move(Repro);
+ }
+ case ReproducerMode::Off:
+ return std::make_unique<Reproducer>();
+ }
+ llvm_unreachable("All cases handled above.");
+}
diff --git a/contrib/libs/llvm12/tools/dsymutil/Reproducer.h b/contrib/libs/llvm12/tools/dsymutil/Reproducer.h
index e965e1ceda..8b3adf63f3 100644
--- a/contrib/libs/llvm12/tools/dsymutil/Reproducer.h
+++ b/contrib/libs/llvm12/tools/dsymutil/Reproducer.h
@@ -1,77 +1,77 @@
-//===- tools/dsymutil/Reproducer.h ------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_DSYMUTIL_REPRODUCER_H
-#define LLVM_TOOLS_DSYMUTIL_REPRODUCER_H
-
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileCollector.h"
-#include "llvm/Support/VirtualFileSystem.h"
-
-namespace llvm {
-namespace dsymutil {
-
-/// The reproducer mode.
-enum class ReproducerMode {
- Generate,
- Use,
- Off,
-};
-
-/// The reproducer class manages the sate related to reproducers in dsymutil.
-/// Instances should be created with Reproducer::createReproducer. An instance
-/// of this class is returned when reproducers are off. The VFS returned by
-/// this instance is the real file system.
-class Reproducer {
-public:
- Reproducer();
- virtual ~Reproducer();
-
- IntrusiveRefCntPtr<vfs::FileSystem> getVFS() const { return VFS; }
-
- /// Create a Reproducer instance based on the given mode.
- static llvm::Expected<std::unique_ptr<Reproducer>>
- createReproducer(ReproducerMode Mode, StringRef Root);
-
-protected:
- IntrusiveRefCntPtr<vfs::FileSystem> VFS;
-};
-
-/// Reproducer instance used to generate a new reproducer. The VFS returned by
-/// this instance is a FileCollectorFileSystem that tracks every file used by
-/// dsymutil.
-class ReproducerGenerate : public Reproducer {
-public:
- ReproducerGenerate(std::error_code &EC);
- ~ReproducerGenerate() override;
-
-private:
- /// The path to the reproducer.
- std::string Root;
-
- /// The FileCollector used by the FileCollectorFileSystem.
- std::shared_ptr<FileCollector> FC;
-};
-
-/// Reproducer instance used to use an existing reproducer. The VFS returned by
-/// this instance is a RedirectingFileSystem that remaps paths to their
-/// counterpart in the reproducer.
-class ReproducerUse : public Reproducer {
-public:
- ReproducerUse(StringRef Root, std::error_code &EC);
- ~ReproducerUse() override;
-
-private:
- /// The path to the reproducer.
- std::string Root;
-};
-
-} // end namespace dsymutil
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_DSYMUTIL_REPRODUCER_H
+//===- tools/dsymutil/Reproducer.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_REPRODUCER_H
+#define LLVM_TOOLS_DSYMUTIL_REPRODUCER_H
+
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileCollector.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+namespace llvm {
+namespace dsymutil {
+
+/// The reproducer mode.
+enum class ReproducerMode {
+ Generate,
+ Use,
+ Off,
+};
+
+/// The reproducer class manages the sate related to reproducers in dsymutil.
+/// Instances should be created with Reproducer::createReproducer. An instance
+/// of this class is returned when reproducers are off. The VFS returned by
+/// this instance is the real file system.
+class Reproducer {
+public:
+ Reproducer();
+ virtual ~Reproducer();
+
+ IntrusiveRefCntPtr<vfs::FileSystem> getVFS() const { return VFS; }
+
+ /// Create a Reproducer instance based on the given mode.
+ static llvm::Expected<std::unique_ptr<Reproducer>>
+ createReproducer(ReproducerMode Mode, StringRef Root);
+
+protected:
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS;
+};
+
+/// Reproducer instance used to generate a new reproducer. The VFS returned by
+/// this instance is a FileCollectorFileSystem that tracks every file used by
+/// dsymutil.
+class ReproducerGenerate : public Reproducer {
+public:
+ ReproducerGenerate(std::error_code &EC);
+ ~ReproducerGenerate() override;
+
+private:
+ /// The path to the reproducer.
+ std::string Root;
+
+ /// The FileCollector used by the FileCollectorFileSystem.
+ std::shared_ptr<FileCollector> FC;
+};
+
+/// Reproducer instance used to use an existing reproducer. The VFS returned by
+/// this instance is a RedirectingFileSystem that remaps paths to their
+/// counterpart in the reproducer.
+class ReproducerUse : public Reproducer {
+public:
+ ReproducerUse(StringRef Root, std::error_code &EC);
+ ~ReproducerUse() override;
+
+private:
+ /// The path to the reproducer.
+ std::string Root;
+};
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_REPRODUCER_H
diff --git a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp
index 07a54795a8..ed0c70888d 100644
--- a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp
+++ b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.cpp
@@ -1,161 +1,161 @@
-//===- tools/dsymutil/SymbolMap.cpp ---------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "SymbolMap.h"
-#include "DebugMap.h"
-#include "MachOUtils.h"
-
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/WithColor.h"
-
-#ifdef __APPLE__
-#include <CoreFoundation/CoreFoundation.h>
-#include <uuid/uuid.h>
-#endif
-
-namespace llvm {
-namespace dsymutil {
-
-StringRef SymbolMapTranslator::operator()(StringRef Input) {
- if (!Input.startswith("__hidden#") && !Input.startswith("___hidden#"))
- return Input;
-
- bool MightNeedUnderscore = false;
- StringRef Line = Input.drop_front(sizeof("__hidden#") - 1);
- if (Line[0] == '#') {
- Line = Line.drop_front();
- MightNeedUnderscore = true;
- }
-
- std::size_t LineNumber = std::numeric_limits<std::size_t>::max();
- Line.split('_').first.getAsInteger(10, LineNumber);
- if (LineNumber >= UnobfuscatedStrings.size()) {
- WithColor::warning() << "reference to a unexisting unobfuscated string "
- << Input << ": symbol map mismatch?\n"
- << Line << '\n';
- return Input;
- }
-
- const std::string &Translation = UnobfuscatedStrings[LineNumber];
- if (!MightNeedUnderscore || !MangleNames)
- return Translation;
-
- // Objective-C symbols for the MachO symbol table start with a \1. Please see
+//===- tools/dsymutil/SymbolMap.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolMap.h"
+#include "DebugMap.h"
+#include "MachOUtils.h"
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/WithColor.h"
+
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#include <uuid/uuid.h>
+#endif
+
+namespace llvm {
+namespace dsymutil {
+
+StringRef SymbolMapTranslator::operator()(StringRef Input) {
+ if (!Input.startswith("__hidden#") && !Input.startswith("___hidden#"))
+ return Input;
+
+ bool MightNeedUnderscore = false;
+ StringRef Line = Input.drop_front(sizeof("__hidden#") - 1);
+ if (Line[0] == '#') {
+ Line = Line.drop_front();
+ MightNeedUnderscore = true;
+ }
+
+ std::size_t LineNumber = std::numeric_limits<std::size_t>::max();
+ Line.split('_').first.getAsInteger(10, LineNumber);
+ if (LineNumber >= UnobfuscatedStrings.size()) {
+ WithColor::warning() << "reference to a unexisting unobfuscated string "
+ << Input << ": symbol map mismatch?\n"
+ << Line << '\n';
+ return Input;
+ }
+
+ const std::string &Translation = UnobfuscatedStrings[LineNumber];
+ if (!MightNeedUnderscore || !MangleNames)
+ return Translation;
+
+ // Objective-C symbols for the MachO symbol table start with a \1. Please see
// `MangleContext::mangleObjCMethodName` in clang.
- if (Translation[0] == 1)
- return StringRef(Translation).drop_front();
-
- // We need permanent storage for the string we are about to create. Just
- // append it to the vector containing translations. This should only happen
- // during MachO symbol table translation, thus there should be no risk on
- // exponential growth.
- UnobfuscatedStrings.emplace_back("_" + Translation);
- return UnobfuscatedStrings.back();
-}
-
-SymbolMapTranslator SymbolMapLoader::Load(StringRef InputFile,
- const DebugMap &Map) const {
- if (SymbolMap.empty())
- return {};
-
- std::string SymbolMapPath = SymbolMap;
-
-#if __APPLE__
- // Look through the UUID Map.
- if (sys::fs::is_directory(SymbolMapPath) && !Map.getUUID().empty()) {
- uuid_string_t UUIDString;
- uuid_unparse_upper((const uint8_t *)Map.getUUID().data(), UUIDString);
-
- SmallString<256> PlistPath(
- sys::path::parent_path(sys::path::parent_path(InputFile)));
- sys::path::append(PlistPath, StringRef(UUIDString).str() + ".plist");
-
- CFStringRef plistFile = CFStringCreateWithCString(
- kCFAllocatorDefault, PlistPath.c_str(), kCFStringEncodingUTF8);
- CFURLRef fileURL = CFURLCreateWithFileSystemPath(
- kCFAllocatorDefault, plistFile, kCFURLPOSIXPathStyle, false);
- CFReadStreamRef resourceData =
- CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
- if (resourceData) {
- CFReadStreamOpen(resourceData);
- CFDictionaryRef plist = (CFDictionaryRef)CFPropertyListCreateWithStream(
- kCFAllocatorDefault, resourceData, 0, kCFPropertyListImmutable,
- nullptr, nullptr);
-
- if (plist) {
- if (CFDictionaryContainsKey(plist, CFSTR("DBGOriginalUUID"))) {
- CFStringRef OldUUID = (CFStringRef)CFDictionaryGetValue(
- plist, CFSTR("DBGOriginalUUID"));
-
- StringRef UUID(CFStringGetCStringPtr(OldUUID, kCFStringEncodingUTF8));
- SmallString<256> BCSymbolMapPath(SymbolMapPath);
- sys::path::append(BCSymbolMapPath, UUID.str() + ".bcsymbolmap");
- SymbolMapPath = std::string(BCSymbolMapPath);
- }
- CFRelease(plist);
- }
- CFReadStreamClose(resourceData);
- CFRelease(resourceData);
- }
- CFRelease(fileURL);
- CFRelease(plistFile);
- }
-#endif
-
- if (sys::fs::is_directory(SymbolMapPath)) {
- SymbolMapPath += (Twine("/") + sys::path::filename(InputFile) + "-" +
- MachOUtils::getArchName(Map.getTriple().getArchName()) +
- ".bcsymbolmap")
- .str();
- }
-
- auto ErrOrMemBuffer = MemoryBuffer::getFile(SymbolMapPath);
- if (auto EC = ErrOrMemBuffer.getError()) {
- WithColor::warning() << SymbolMapPath << ": " << EC.message()
- << ": not unobfuscating.\n";
- return {};
- }
-
- std::vector<std::string> UnobfuscatedStrings;
- auto &MemBuf = **ErrOrMemBuffer;
- StringRef Data(MemBuf.getBufferStart(),
- MemBuf.getBufferEnd() - MemBuf.getBufferStart());
- StringRef LHS;
- std::tie(LHS, Data) = Data.split('\n');
- bool MangleNames = false;
-
- // Check version string first.
- if (!LHS.startswith("BCSymbolMap Version:")) {
- // Version string not present, warns but try to parse it.
- WithColor::warning() << SymbolMapPath
- << " is missing version string: assuming 1.0.\n";
- UnobfuscatedStrings.emplace_back(LHS);
- } else if (LHS.equals("BCSymbolMap Version: 1.0")) {
- MangleNames = true;
- } else if (LHS.equals("BCSymbolMap Version: 2.0")) {
- MangleNames = false;
- } else {
- StringRef VersionNum;
- std::tie(LHS, VersionNum) = LHS.split(':');
- WithColor::warning() << SymbolMapPath
- << " has unsupported symbol map version" << VersionNum
- << ": not unobfuscating.\n";
- return {};
- }
-
- while (!Data.empty()) {
- std::tie(LHS, Data) = Data.split('\n');
- UnobfuscatedStrings.emplace_back(LHS);
- }
-
- return SymbolMapTranslator(std::move(UnobfuscatedStrings), MangleNames);
-}
-
-} // namespace dsymutil
-} // namespace llvm
+ if (Translation[0] == 1)
+ return StringRef(Translation).drop_front();
+
+ // We need permanent storage for the string we are about to create. Just
+ // append it to the vector containing translations. This should only happen
+ // during MachO symbol table translation, thus there should be no risk on
+ // exponential growth.
+ UnobfuscatedStrings.emplace_back("_" + Translation);
+ return UnobfuscatedStrings.back();
+}
+
+SymbolMapTranslator SymbolMapLoader::Load(StringRef InputFile,
+ const DebugMap &Map) const {
+ if (SymbolMap.empty())
+ return {};
+
+ std::string SymbolMapPath = SymbolMap;
+
+#if __APPLE__
+ // Look through the UUID Map.
+ if (sys::fs::is_directory(SymbolMapPath) && !Map.getUUID().empty()) {
+ uuid_string_t UUIDString;
+ uuid_unparse_upper((const uint8_t *)Map.getUUID().data(), UUIDString);
+
+ SmallString<256> PlistPath(
+ sys::path::parent_path(sys::path::parent_path(InputFile)));
+ sys::path::append(PlistPath, StringRef(UUIDString).str() + ".plist");
+
+ CFStringRef plistFile = CFStringCreateWithCString(
+ kCFAllocatorDefault, PlistPath.c_str(), kCFStringEncodingUTF8);
+ CFURLRef fileURL = CFURLCreateWithFileSystemPath(
+ kCFAllocatorDefault, plistFile, kCFURLPOSIXPathStyle, false);
+ CFReadStreamRef resourceData =
+ CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
+ if (resourceData) {
+ CFReadStreamOpen(resourceData);
+ CFDictionaryRef plist = (CFDictionaryRef)CFPropertyListCreateWithStream(
+ kCFAllocatorDefault, resourceData, 0, kCFPropertyListImmutable,
+ nullptr, nullptr);
+
+ if (plist) {
+ if (CFDictionaryContainsKey(plist, CFSTR("DBGOriginalUUID"))) {
+ CFStringRef OldUUID = (CFStringRef)CFDictionaryGetValue(
+ plist, CFSTR("DBGOriginalUUID"));
+
+ StringRef UUID(CFStringGetCStringPtr(OldUUID, kCFStringEncodingUTF8));
+ SmallString<256> BCSymbolMapPath(SymbolMapPath);
+ sys::path::append(BCSymbolMapPath, UUID.str() + ".bcsymbolmap");
+ SymbolMapPath = std::string(BCSymbolMapPath);
+ }
+ CFRelease(plist);
+ }
+ CFReadStreamClose(resourceData);
+ CFRelease(resourceData);
+ }
+ CFRelease(fileURL);
+ CFRelease(plistFile);
+ }
+#endif
+
+ if (sys::fs::is_directory(SymbolMapPath)) {
+ SymbolMapPath += (Twine("/") + sys::path::filename(InputFile) + "-" +
+ MachOUtils::getArchName(Map.getTriple().getArchName()) +
+ ".bcsymbolmap")
+ .str();
+ }
+
+ auto ErrOrMemBuffer = MemoryBuffer::getFile(SymbolMapPath);
+ if (auto EC = ErrOrMemBuffer.getError()) {
+ WithColor::warning() << SymbolMapPath << ": " << EC.message()
+ << ": not unobfuscating.\n";
+ return {};
+ }
+
+ std::vector<std::string> UnobfuscatedStrings;
+ auto &MemBuf = **ErrOrMemBuffer;
+ StringRef Data(MemBuf.getBufferStart(),
+ MemBuf.getBufferEnd() - MemBuf.getBufferStart());
+ StringRef LHS;
+ std::tie(LHS, Data) = Data.split('\n');
+ bool MangleNames = false;
+
+ // Check version string first.
+ if (!LHS.startswith("BCSymbolMap Version:")) {
+ // Version string not present, warns but try to parse it.
+ WithColor::warning() << SymbolMapPath
+ << " is missing version string: assuming 1.0.\n";
+ UnobfuscatedStrings.emplace_back(LHS);
+ } else if (LHS.equals("BCSymbolMap Version: 1.0")) {
+ MangleNames = true;
+ } else if (LHS.equals("BCSymbolMap Version: 2.0")) {
+ MangleNames = false;
+ } else {
+ StringRef VersionNum;
+ std::tie(LHS, VersionNum) = LHS.split(':');
+ WithColor::warning() << SymbolMapPath
+ << " has unsupported symbol map version" << VersionNum
+ << ": not unobfuscating.\n";
+ return {};
+ }
+
+ while (!Data.empty()) {
+ std::tie(LHS, Data) = Data.split('\n');
+ UnobfuscatedStrings.emplace_back(LHS);
+ }
+
+ return SymbolMapTranslator(std::move(UnobfuscatedStrings), MangleNames);
+}
+
+} // namespace dsymutil
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h
index 977de31a5a..636a6126b7 100644
--- a/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h
+++ b/contrib/libs/llvm12/tools/dsymutil/SymbolMap.h
@@ -1,53 +1,53 @@
-//=- tools/dsymutil/SymbolMap.h -----------------------------------*- C++ -*-=//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
-#define LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
-
-#include "llvm/ADT/StringRef.h"
-
-#include <string>
-#include <vector>
-
-namespace llvm {
-namespace dsymutil {
-class DebugMap;
-
-/// Callable class to unobfuscate strings based on a BCSymbolMap.
-class SymbolMapTranslator {
-public:
- SymbolMapTranslator() : MangleNames(false) {}
-
- SymbolMapTranslator(std::vector<std::string> UnobfuscatedStrings,
- bool MangleNames)
- : UnobfuscatedStrings(std::move(UnobfuscatedStrings)),
- MangleNames(MangleNames) {}
-
- StringRef operator()(StringRef Input);
-
- operator bool() const { return !UnobfuscatedStrings.empty(); }
-
-private:
- std::vector<std::string> UnobfuscatedStrings;
- bool MangleNames;
-};
-
-/// Class to initialize SymbolMapTranslators from a BCSymbolMap.
-class SymbolMapLoader {
-public:
- SymbolMapLoader(std::string SymbolMap) : SymbolMap(std::move(SymbolMap)) {}
-
- SymbolMapTranslator Load(StringRef InputFile, const DebugMap &Map) const;
-
-private:
- const std::string SymbolMap;
-};
-} // namespace dsymutil
-} // namespace llvm
-
-#endif // LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
+//=- tools/dsymutil/SymbolMap.h -----------------------------------*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
+#define LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
+
+#include "llvm/ADT/StringRef.h"
+
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace dsymutil {
+class DebugMap;
+
+/// Callable class to unobfuscate strings based on a BCSymbolMap.
+class SymbolMapTranslator {
+public:
+ SymbolMapTranslator() : MangleNames(false) {}
+
+ SymbolMapTranslator(std::vector<std::string> UnobfuscatedStrings,
+ bool MangleNames)
+ : UnobfuscatedStrings(std::move(UnobfuscatedStrings)),
+ MangleNames(MangleNames) {}
+
+ StringRef operator()(StringRef Input);
+
+ operator bool() const { return !UnobfuscatedStrings.empty(); }
+
+private:
+ std::vector<std::string> UnobfuscatedStrings;
+ bool MangleNames;
+};
+
+/// Class to initialize SymbolMapTranslators from a BCSymbolMap.
+class SymbolMapLoader {
+public:
+ SymbolMapLoader(std::string SymbolMap) : SymbolMap(std::move(SymbolMap)) {}
+
+ SymbolMapTranslator Load(StringRef InputFile, const DebugMap &Map) const;
+
+private:
+ const std::string SymbolMap;
+};
+} // namespace dsymutil
+} // namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_SYMBOLMAP_H
diff --git a/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp b/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp
index 347b2dd916..bd73a45cca 100644
--- a/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp
+++ b/contrib/libs/llvm12/tools/dsymutil/dsymutil.cpp
@@ -1,691 +1,691 @@
-//===- dsymutil.cpp - Debug info dumping utility for llvm -----------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This program is a utility that aims to be a dropin replacement for Darwin's
-// dsymutil.
-//===----------------------------------------------------------------------===//
-
-#include "dsymutil.h"
-#include "BinaryHolder.h"
-#include "CFBundle.h"
-#include "DebugMap.h"
-#include "LinkUtils.h"
-#include "MachOUtils.h"
-#include "Reproducer.h"
+//===- dsymutil.cpp - Debug info dumping utility for llvm -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is a utility that aims to be a dropin replacement for Darwin's
+// dsymutil.
+//===----------------------------------------------------------------------===//
+
+#include "dsymutil.h"
+#include "BinaryHolder.h"
+#include "CFBundle.h"
+#include "DebugMap.h"
+#include "LinkUtils.h"
+#include "MachOUtils.h"
+#include "Reproducer.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/DebugInfo/DIContext.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
-#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
-#include "llvm/Object/Binary.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/FileCollector.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/TargetSelect.h"
-#include "llvm/Support/ThreadPool.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/thread.h"
-#include <algorithm>
-#include <cstdint>
-#include <cstdlib>
-#include <string>
-#include <system_error>
-
-using namespace llvm;
-using namespace llvm::dsymutil;
-using namespace object;
-
-namespace {
-enum ID {
- OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
-#include "Options.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#include "Options.inc"
-#undef PREFIX
-
-const opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
-#include "Options.inc"
-#undef OPTION
-};
-
-class DsymutilOptTable : public opt::OptTable {
-public:
- DsymutilOptTable() : OptTable(InfoTable) {}
-};
-} // namespace
-
-struct DsymutilOptions {
- bool DumpDebugMap = false;
- bool DumpStab = false;
- bool Flat = false;
- bool InputIsYAMLDebugMap = false;
- bool PaperTrailWarnings = false;
- bool Verify = false;
- std::string SymbolMap;
- std::string OutputFile;
- std::string Toolchain;
- std::string ReproducerPath;
- std::vector<std::string> Archs;
- std::vector<std::string> InputFiles;
- unsigned NumThreads;
- ReproducerMode ReproMode = ReproducerMode::Off;
- dsymutil::LinkOptions LinkOpts;
-};
-
-/// Return a list of input files. This function has logic for dealing with the
-/// special case where we might have dSYM bundles as input. The function
-/// returns an error when the directory structure doesn't match that of a dSYM
-/// bundle.
-static Expected<std::vector<std::string>> getInputs(opt::InputArgList &Args,
- bool DsymAsInput) {
- std::vector<std::string> InputFiles;
- for (auto *File : Args.filtered(OPT_INPUT))
- InputFiles.push_back(File->getValue());
-
- if (!DsymAsInput)
- return InputFiles;
-
- // If we are updating, we might get dSYM bundles as input.
- std::vector<std::string> Inputs;
- for (const auto &Input : InputFiles) {
- if (!sys::fs::is_directory(Input)) {
- Inputs.push_back(Input);
- continue;
- }
-
- // Make sure that we're dealing with a dSYM bundle.
- SmallString<256> BundlePath(Input);
- sys::path::append(BundlePath, "Contents", "Resources", "DWARF");
- if (!sys::fs::is_directory(BundlePath))
- return make_error<StringError>(
- Input + " is a directory, but doesn't look like a dSYM bundle.",
- inconvertibleErrorCode());
-
- // Create a directory iterator to iterate over all the entries in the
- // bundle.
- std::error_code EC;
- sys::fs::directory_iterator DirIt(BundlePath, EC);
- sys::fs::directory_iterator DirEnd;
- if (EC)
- return errorCodeToError(EC);
-
- // Add each entry to the list of inputs.
- while (DirIt != DirEnd) {
- Inputs.push_back(DirIt->path());
- DirIt.increment(EC);
- if (EC)
- return errorCodeToError(EC);
- }
- }
- return Inputs;
-}
-
-// Verify that the given combination of options makes sense.
-static Error verifyOptions(const DsymutilOptions &Options) {
- if (Options.InputFiles.empty()) {
- return make_error<StringError>("no input files specified",
- errc::invalid_argument);
- }
-
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileCollector.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/thread.h"
+#include <algorithm>
+#include <cstdint>
+#include <cstdlib>
+#include <string>
+#include <system_error>
+
+using namespace llvm;
+using namespace llvm::dsymutil;
+using namespace object;
+
+namespace {
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+const opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ { \
+ PREFIX, NAME, HELPTEXT, \
+ METAVAR, OPT_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, \
+ OPT_##ALIAS, ALIASARGS, VALUES},
+#include "Options.inc"
+#undef OPTION
+};
+
+class DsymutilOptTable : public opt::OptTable {
+public:
+ DsymutilOptTable() : OptTable(InfoTable) {}
+};
+} // namespace
+
+struct DsymutilOptions {
+ bool DumpDebugMap = false;
+ bool DumpStab = false;
+ bool Flat = false;
+ bool InputIsYAMLDebugMap = false;
+ bool PaperTrailWarnings = false;
+ bool Verify = false;
+ std::string SymbolMap;
+ std::string OutputFile;
+ std::string Toolchain;
+ std::string ReproducerPath;
+ std::vector<std::string> Archs;
+ std::vector<std::string> InputFiles;
+ unsigned NumThreads;
+ ReproducerMode ReproMode = ReproducerMode::Off;
+ dsymutil::LinkOptions LinkOpts;
+};
+
+/// Return a list of input files. This function has logic for dealing with the
+/// special case where we might have dSYM bundles as input. The function
+/// returns an error when the directory structure doesn't match that of a dSYM
+/// bundle.
+static Expected<std::vector<std::string>> getInputs(opt::InputArgList &Args,
+ bool DsymAsInput) {
+ std::vector<std::string> InputFiles;
+ for (auto *File : Args.filtered(OPT_INPUT))
+ InputFiles.push_back(File->getValue());
+
+ if (!DsymAsInput)
+ return InputFiles;
+
+ // If we are updating, we might get dSYM bundles as input.
+ std::vector<std::string> Inputs;
+ for (const auto &Input : InputFiles) {
+ if (!sys::fs::is_directory(Input)) {
+ Inputs.push_back(Input);
+ continue;
+ }
+
+ // Make sure that we're dealing with a dSYM bundle.
+ SmallString<256> BundlePath(Input);
+ sys::path::append(BundlePath, "Contents", "Resources", "DWARF");
+ if (!sys::fs::is_directory(BundlePath))
+ return make_error<StringError>(
+ Input + " is a directory, but doesn't look like a dSYM bundle.",
+ inconvertibleErrorCode());
+
+ // Create a directory iterator to iterate over all the entries in the
+ // bundle.
+ std::error_code EC;
+ sys::fs::directory_iterator DirIt(BundlePath, EC);
+ sys::fs::directory_iterator DirEnd;
+ if (EC)
+ return errorCodeToError(EC);
+
+ // Add each entry to the list of inputs.
+ while (DirIt != DirEnd) {
+ Inputs.push_back(DirIt->path());
+ DirIt.increment(EC);
+ if (EC)
+ return errorCodeToError(EC);
+ }
+ }
+ return Inputs;
+}
+
+// Verify that the given combination of options makes sense.
+static Error verifyOptions(const DsymutilOptions &Options) {
+ if (Options.InputFiles.empty()) {
+ return make_error<StringError>("no input files specified",
+ errc::invalid_argument);
+ }
+
if (Options.LinkOpts.Update && llvm::is_contained(Options.InputFiles, "-")) {
- // FIXME: We cannot use stdin for an update because stdin will be
- // consumed by the BinaryHolder during the debugmap parsing, and
- // then we will want to consume it again in DwarfLinker. If we
- // used a unique BinaryHolder object that could cache multiple
- // binaries this restriction would go away.
- return make_error<StringError>(
- "standard input cannot be used as input for a dSYM update.",
- errc::invalid_argument);
- }
-
- if (!Options.Flat && Options.OutputFile == "-")
- return make_error<StringError>(
- "cannot emit to standard output without --flat.",
- errc::invalid_argument);
-
- if (Options.InputFiles.size() > 1 && Options.Flat &&
- !Options.OutputFile.empty())
- return make_error<StringError>(
- "cannot use -o with multiple inputs in flat mode.",
- errc::invalid_argument);
-
- if (Options.PaperTrailWarnings && Options.InputIsYAMLDebugMap)
- return make_error<StringError>(
- "paper trail warnings are not supported for YAML input.",
- errc::invalid_argument);
-
- if (!Options.ReproducerPath.empty() &&
- Options.ReproMode != ReproducerMode::Use)
- return make_error<StringError>(
- "cannot combine --gen-reproducer and --use-reproducer.",
- errc::invalid_argument);
-
- return Error::success();
-}
-
-static Expected<AccelTableKind> getAccelTableKind(opt::InputArgList &Args) {
- if (opt::Arg *Accelerator = Args.getLastArg(OPT_accelerator)) {
- StringRef S = Accelerator->getValue();
- if (S == "Apple")
- return AccelTableKind::Apple;
- if (S == "Dwarf")
- return AccelTableKind::Dwarf;
- if (S == "Default")
- return AccelTableKind::Default;
- return make_error<StringError>(
- "invalid accelerator type specified: '" + S +
- "'. Support values are 'Apple', 'Dwarf' and 'Default'.",
- inconvertibleErrorCode());
- }
- return AccelTableKind::Default;
-}
-
-/// Parses the command line options into the LinkOptions struct and performs
-/// some sanity checking. Returns an error in case the latter fails.
-static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
- DsymutilOptions Options;
-
- Options.DumpDebugMap = Args.hasArg(OPT_dump_debug_map);
- Options.DumpStab = Args.hasArg(OPT_symtab);
- Options.Flat = Args.hasArg(OPT_flat);
- Options.InputIsYAMLDebugMap = Args.hasArg(OPT_yaml_input);
- Options.PaperTrailWarnings = Args.hasArg(OPT_papertrail);
- Options.Verify = Args.hasArg(OPT_verify);
-
- Options.LinkOpts.Minimize = Args.hasArg(OPT_minimize);
- Options.LinkOpts.NoODR = Args.hasArg(OPT_no_odr);
- Options.LinkOpts.NoOutput = Args.hasArg(OPT_no_output);
- Options.LinkOpts.NoTimestamp = Args.hasArg(OPT_no_swiftmodule_timestamp);
- Options.LinkOpts.Update = Args.hasArg(OPT_update);
- Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose);
- Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics);
-
- if (opt::Arg *ReproducerPath = Args.getLastArg(OPT_use_reproducer)) {
- Options.ReproMode = ReproducerMode::Use;
- Options.ReproducerPath = ReproducerPath->getValue();
- }
-
- if (Args.hasArg(OPT_gen_reproducer))
- Options.ReproMode = ReproducerMode::Generate;
-
- if (Expected<AccelTableKind> AccelKind = getAccelTableKind(Args)) {
- Options.LinkOpts.TheAccelTableKind = *AccelKind;
- } else {
- return AccelKind.takeError();
- }
-
- if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap))
- Options.SymbolMap = SymbolMap->getValue();
-
- if (Args.hasArg(OPT_symbolmap))
- Options.LinkOpts.Update = true;
-
- if (Expected<std::vector<std::string>> InputFiles =
- getInputs(Args, Options.LinkOpts.Update)) {
- Options.InputFiles = std::move(*InputFiles);
- } else {
- return InputFiles.takeError();
- }
-
- for (auto *Arch : Args.filtered(OPT_arch))
- Options.Archs.push_back(Arch->getValue());
-
- if (opt::Arg *OsoPrependPath = Args.getLastArg(OPT_oso_prepend_path))
- Options.LinkOpts.PrependPath = OsoPrependPath->getValue();
-
- for (const auto &Arg : Args.getAllArgValues(OPT_object_prefix_map)) {
- auto Split = StringRef(Arg).split('=');
- Options.LinkOpts.ObjectPrefixMap.insert(
- {std::string(Split.first), std::string(Split.second)});
- }
-
- if (opt::Arg *OutputFile = Args.getLastArg(OPT_output))
- Options.OutputFile = OutputFile->getValue();
-
- if (opt::Arg *Toolchain = Args.getLastArg(OPT_toolchain))
- Options.Toolchain = Toolchain->getValue();
-
- if (Args.hasArg(OPT_assembly))
- Options.LinkOpts.FileType = OutputFileType::Assembly;
-
- if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads))
- Options.LinkOpts.Threads = atoi(NumThreads->getValue());
- else
- Options.LinkOpts.Threads = 0; // Use all available hardware threads
-
- if (Options.DumpDebugMap || Options.LinkOpts.Verbose)
- Options.LinkOpts.Threads = 1;
-
- if (getenv("RC_DEBUG_OPTIONS"))
- Options.PaperTrailWarnings = true;
-
- if (opt::Arg *RemarksPrependPath = Args.getLastArg(OPT_remarks_prepend_path))
- Options.LinkOpts.RemarksPrependPath = RemarksPrependPath->getValue();
-
- if (opt::Arg *RemarksOutputFormat =
- Args.getLastArg(OPT_remarks_output_format)) {
- if (Expected<remarks::Format> FormatOrErr =
- remarks::parseFormat(RemarksOutputFormat->getValue()))
- Options.LinkOpts.RemarksFormat = *FormatOrErr;
- else
- return FormatOrErr.takeError();
- }
-
- if (Error E = verifyOptions(Options))
- return std::move(E);
- return Options;
-}
-
-static Error createPlistFile(StringRef Bin, StringRef BundleRoot,
- StringRef Toolchain) {
- // Create plist file to write to.
- SmallString<128> InfoPlist(BundleRoot);
- sys::path::append(InfoPlist, "Contents/Info.plist");
- std::error_code EC;
- raw_fd_ostream PL(InfoPlist, EC, sys::fs::OF_Text);
- if (EC)
- return make_error<StringError>(
- "cannot create Plist: " + toString(errorCodeToError(EC)), EC);
-
- CFBundleInfo BI = getBundleInfo(Bin);
-
- if (BI.IDStr.empty()) {
- StringRef BundleID = *sys::path::rbegin(BundleRoot);
- if (sys::path::extension(BundleRoot) == ".dSYM")
- BI.IDStr = std::string(sys::path::stem(BundleID));
- else
- BI.IDStr = std::string(BundleID);
- }
-
- // Print out information to the plist file.
- PL << "<?xml version=\"1.0\" encoding=\"UTF-8\"\?>\n"
- << "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
- << "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
- << "<plist version=\"1.0\">\n"
- << "\t<dict>\n"
- << "\t\t<key>CFBundleDevelopmentRegion</key>\n"
- << "\t\t<string>English</string>\n"
- << "\t\t<key>CFBundleIdentifier</key>\n"
- << "\t\t<string>com.apple.xcode.dsym.";
- printHTMLEscaped(BI.IDStr, PL);
- PL << "</string>\n"
- << "\t\t<key>CFBundleInfoDictionaryVersion</key>\n"
- << "\t\t<string>6.0</string>\n"
- << "\t\t<key>CFBundlePackageType</key>\n"
- << "\t\t<string>dSYM</string>\n"
- << "\t\t<key>CFBundleSignature</key>\n"
- << "\t\t<string>\?\?\?\?</string>\n";
-
- if (!BI.OmitShortVersion()) {
- PL << "\t\t<key>CFBundleShortVersionString</key>\n";
- PL << "\t\t<string>";
- printHTMLEscaped(BI.ShortVersionStr, PL);
- PL << "</string>\n";
- }
-
- PL << "\t\t<key>CFBundleVersion</key>\n";
- PL << "\t\t<string>";
- printHTMLEscaped(BI.VersionStr, PL);
- PL << "</string>\n";
-
- if (!Toolchain.empty()) {
- PL << "\t\t<key>Toolchain</key>\n";
- PL << "\t\t<string>";
- printHTMLEscaped(Toolchain, PL);
- PL << "</string>\n";
- }
-
- PL << "\t</dict>\n"
- << "</plist>\n";
-
- PL.close();
- return Error::success();
-}
-
-static Error createBundleDir(StringRef BundleBase) {
- SmallString<128> Bundle(BundleBase);
- sys::path::append(Bundle, "Contents", "Resources", "DWARF");
- if (std::error_code EC =
- create_directories(Bundle.str(), true, sys::fs::perms::all_all))
- return make_error<StringError>(
- "cannot create bundle: " + toString(errorCodeToError(EC)), EC);
-
- return Error::success();
-}
-
-static bool verify(StringRef OutputFile, StringRef Arch, bool Verbose) {
- if (OutputFile == "-") {
- WithColor::warning() << "verification skipped for " << Arch
- << "because writing to stdout.\n";
- return true;
- }
-
- Expected<OwningBinary<Binary>> BinOrErr = createBinary(OutputFile);
- if (!BinOrErr) {
- WithColor::error() << OutputFile << ": " << toString(BinOrErr.takeError());
- return false;
- }
-
- Binary &Binary = *BinOrErr.get().getBinary();
- if (auto *Obj = dyn_cast<MachOObjectFile>(&Binary)) {
- raw_ostream &os = Verbose ? errs() : nulls();
- os << "Verifying DWARF for architecture: " << Arch << "\n";
- std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
- DIDumpOptions DumpOpts;
- bool success = DICtx->verify(os, DumpOpts.noImplicitRecursion());
- if (!success)
- WithColor::error() << "verification failed for " << Arch << '\n';
- return success;
- }
-
- return false;
-}
-
-namespace {
-struct OutputLocation {
- OutputLocation(std::string DWARFFile, Optional<std::string> ResourceDir = {})
- : DWARFFile(DWARFFile), ResourceDir(ResourceDir) {}
- /// This method is a workaround for older compilers.
- Optional<std::string> getResourceDir() const { return ResourceDir; }
- std::string DWARFFile;
- Optional<std::string> ResourceDir;
-};
-} // namespace
-
-static Expected<OutputLocation>
-getOutputFileName(StringRef InputFile, const DsymutilOptions &Options) {
- if (Options.OutputFile == "-")
- return OutputLocation(Options.OutputFile);
-
- // When updating, do in place replacement.
- if (Options.OutputFile.empty() &&
- (Options.LinkOpts.Update || !Options.SymbolMap.empty()))
- return OutputLocation(std::string(InputFile));
-
- // If a flat dSYM has been requested, things are pretty simple.
- if (Options.Flat) {
- if (Options.OutputFile.empty()) {
- if (InputFile == "-")
- return OutputLocation{"a.out.dwarf", {}};
- return OutputLocation((InputFile + ".dwarf").str());
- }
-
- return OutputLocation(Options.OutputFile);
- }
-
- // We need to create/update a dSYM bundle.
- // A bundle hierarchy looks like this:
- // <bundle name>.dSYM/
- // Contents/
- // Info.plist
- // Resources/
- // DWARF/
- // <DWARF file(s)>
- std::string DwarfFile =
- std::string(InputFile == "-" ? StringRef("a.out") : InputFile);
- SmallString<128> Path(Options.OutputFile);
- if (Path.empty())
- Path = DwarfFile + ".dSYM";
- if (!Options.LinkOpts.NoOutput) {
- if (auto E = createBundleDir(Path))
- return std::move(E);
- if (auto E = createPlistFile(DwarfFile, Path, Options.Toolchain))
- return std::move(E);
- }
-
- sys::path::append(Path, "Contents", "Resources");
- std::string ResourceDir = std::string(Path.str());
- sys::path::append(Path, "DWARF", sys::path::filename(DwarfFile));
- return OutputLocation(std::string(Path.str()), ResourceDir);
-}
-
-int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
-
- // Parse arguments.
- DsymutilOptTable T;
- unsigned MAI;
- unsigned MAC;
- ArrayRef<const char *> ArgsArr = makeArrayRef(argv + 1, argc - 1);
- opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC);
-
- void *P = (void *)(intptr_t)getOutputFileName;
- std::string SDKPath = sys::fs::getMainExecutable(argv[0], P);
- SDKPath = std::string(sys::path::parent_path(SDKPath));
-
- for (auto *Arg : Args.filtered(OPT_UNKNOWN)) {
- WithColor::warning() << "ignoring unknown option: " << Arg->getSpelling()
- << '\n';
- }
-
- if (Args.hasArg(OPT_help)) {
- T.PrintHelp(
- outs(), (std::string(argv[0]) + " [options] <input files>").c_str(),
- "manipulate archived DWARF debug symbol files.\n\n"
- "dsymutil links the DWARF debug information found in the object files\n"
- "for the executable <input file> by using debug symbols information\n"
- "contained in its symbol table.\n",
- false);
- return 0;
- }
-
- if (Args.hasArg(OPT_version)) {
- cl::PrintVersionMessage();
- return 0;
- }
-
- auto OptionsOrErr = getOptions(Args);
- if (!OptionsOrErr) {
- WithColor::error() << toString(OptionsOrErr.takeError());
- return 1;
- }
-
- auto &Options = *OptionsOrErr;
-
- InitializeAllTargetInfos();
- InitializeAllTargetMCs();
- InitializeAllTargets();
- InitializeAllAsmPrinters();
-
- auto Repro =
- Reproducer::createReproducer(Options.ReproMode, Options.ReproducerPath);
- if (!Repro) {
- WithColor::error() << toString(Repro.takeError());
- return 1;
- }
-
- Options.LinkOpts.VFS = (*Repro)->getVFS();
-
- for (const auto &Arch : Options.Archs)
- if (Arch != "*" && Arch != "all" &&
- !object::MachOObjectFile::isValidArch(Arch)) {
- WithColor::error() << "unsupported cpu architecture: '" << Arch << "'\n";
- return 1;
- }
-
- SymbolMapLoader SymMapLoader(Options.SymbolMap);
-
- for (auto &InputFile : Options.InputFiles) {
- // Dump the symbol table for each input file and requested arch
- if (Options.DumpStab) {
- if (!dumpStab(Options.LinkOpts.VFS, InputFile, Options.Archs,
- Options.LinkOpts.PrependPath))
- return 1;
- continue;
- }
-
- auto DebugMapPtrsOrErr =
- parseDebugMap(Options.LinkOpts.VFS, InputFile, Options.Archs,
- Options.LinkOpts.PrependPath, Options.PaperTrailWarnings,
- Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap);
-
- if (auto EC = DebugMapPtrsOrErr.getError()) {
- WithColor::error() << "cannot parse the debug map for '" << InputFile
- << "': " << EC.message() << '\n';
- return 1;
- }
-
- // Remember the number of debug maps that are being processed to decide how
- // to name the remark files.
- Options.LinkOpts.NumDebugMaps = DebugMapPtrsOrErr->size();
-
- if (Options.LinkOpts.Update) {
- // The debug map should be empty. Add one object file corresponding to
- // the input file.
- for (auto &Map : *DebugMapPtrsOrErr)
- Map->addDebugMapObject(InputFile,
- sys::TimePoint<std::chrono::seconds>());
- }
-
- // Ensure that the debug map is not empty (anymore).
- if (DebugMapPtrsOrErr->empty()) {
- WithColor::error() << "no architecture to link\n";
- return 1;
- }
-
- // Shared a single binary holder for all the link steps.
- BinaryHolder BinHolder(Options.LinkOpts.VFS);
-
- // Statistics only require different architectures to be processed
- // sequentially, the link itself can still happen in parallel. Change the
- // thread pool strategy here instead of modifying LinkOpts.Threads.
- ThreadPoolStrategy S = hardware_concurrency(
- Options.LinkOpts.Statistics ? 1 : Options.LinkOpts.Threads);
- if (Options.LinkOpts.Threads == 0) {
- // If NumThreads is not specified, create one thread for each input, up to
- // the number of hardware threads.
- S.ThreadsRequested = DebugMapPtrsOrErr->size();
- S.Limit = true;
- }
- ThreadPool Threads(S);
-
- // If there is more than one link to execute, we need to generate
- // temporary files.
- const bool NeedsTempFiles =
- !Options.DumpDebugMap && (Options.OutputFile != "-") &&
- (DebugMapPtrsOrErr->size() != 1 || Options.LinkOpts.Update);
- const bool Verify = Options.Verify && !Options.LinkOpts.NoOutput;
-
- SmallVector<MachOUtils::ArchAndFile, 4> TempFiles;
- std::atomic_char AllOK(1);
- for (auto &Map : *DebugMapPtrsOrErr) {
- if (Options.LinkOpts.Verbose || Options.DumpDebugMap)
- Map->print(outs());
-
- if (Options.DumpDebugMap)
- continue;
-
- if (!Options.SymbolMap.empty())
- Options.LinkOpts.Translator = SymMapLoader.Load(InputFile, *Map);
-
- if (Map->begin() == Map->end())
- WithColor::warning()
- << "no debug symbols in executable (-arch "
- << MachOUtils::getArchName(Map->getTriple().getArchName()) << ")\n";
-
- // Using a std::shared_ptr rather than std::unique_ptr because move-only
- // types don't work with std::bind in the ThreadPool implementation.
- std::shared_ptr<raw_fd_ostream> OS;
-
- Expected<OutputLocation> OutputLocationOrErr =
- getOutputFileName(InputFile, Options);
- if (!OutputLocationOrErr) {
- WithColor::error() << toString(OutputLocationOrErr.takeError());
- return 1;
- }
- Options.LinkOpts.ResourceDir = OutputLocationOrErr->getResourceDir();
-
- std::string OutputFile = OutputLocationOrErr->DWARFFile;
- if (NeedsTempFiles) {
- TempFiles.emplace_back(Map->getTriple().getArchName().str());
-
- auto E = TempFiles.back().createTempFile();
- if (E) {
- WithColor::error() << toString(std::move(E));
- return 1;
- }
-
- auto &TempFile = *(TempFiles.back().File);
- OS = std::make_shared<raw_fd_ostream>(TempFile.FD,
- /*shouldClose*/ false);
- OutputFile = TempFile.TmpName;
- } else {
- std::error_code EC;
- OS = std::make_shared<raw_fd_ostream>(
- Options.LinkOpts.NoOutput ? "-" : OutputFile, EC, sys::fs::OF_None);
- if (EC) {
- WithColor::error() << OutputFile << ": " << EC.message();
- return 1;
- }
- }
-
- auto LinkLambda = [&, OutputFile](std::shared_ptr<raw_fd_ostream> Stream,
- LinkOptions Options) {
- AllOK.fetch_and(
- linkDwarf(*Stream, BinHolder, *Map, std::move(Options)));
- Stream->flush();
- if (Verify)
- AllOK.fetch_and(verify(OutputFile, Map->getTriple().getArchName(),
- Options.Verbose));
- };
-
- // FIXME: The DwarfLinker can have some very deep recursion that can max
- // out the (significantly smaller) stack when using threads. We don't
- // want this limitation when we only have a single thread.
- if (S.ThreadsRequested == 1)
- LinkLambda(OS, Options.LinkOpts);
- else
- Threads.async(LinkLambda, OS, Options.LinkOpts);
- }
-
- Threads.wait();
-
- if (!AllOK)
- return 1;
-
- if (NeedsTempFiles) {
- Expected<OutputLocation> OutputLocationOrErr =
- getOutputFileName(InputFile, Options);
- if (!OutputLocationOrErr) {
- WithColor::error() << toString(OutputLocationOrErr.takeError());
- return 1;
- }
- if (!MachOUtils::generateUniversalBinary(TempFiles,
- OutputLocationOrErr->DWARFFile,
- Options.LinkOpts, SDKPath))
- return 1;
- }
- }
-
- return 0;
-}
+ // FIXME: We cannot use stdin for an update because stdin will be
+ // consumed by the BinaryHolder during the debugmap parsing, and
+ // then we will want to consume it again in DwarfLinker. If we
+ // used a unique BinaryHolder object that could cache multiple
+ // binaries this restriction would go away.
+ return make_error<StringError>(
+ "standard input cannot be used as input for a dSYM update.",
+ errc::invalid_argument);
+ }
+
+ if (!Options.Flat && Options.OutputFile == "-")
+ return make_error<StringError>(
+ "cannot emit to standard output without --flat.",
+ errc::invalid_argument);
+
+ if (Options.InputFiles.size() > 1 && Options.Flat &&
+ !Options.OutputFile.empty())
+ return make_error<StringError>(
+ "cannot use -o with multiple inputs in flat mode.",
+ errc::invalid_argument);
+
+ if (Options.PaperTrailWarnings && Options.InputIsYAMLDebugMap)
+ return make_error<StringError>(
+ "paper trail warnings are not supported for YAML input.",
+ errc::invalid_argument);
+
+ if (!Options.ReproducerPath.empty() &&
+ Options.ReproMode != ReproducerMode::Use)
+ return make_error<StringError>(
+ "cannot combine --gen-reproducer and --use-reproducer.",
+ errc::invalid_argument);
+
+ return Error::success();
+}
+
+static Expected<AccelTableKind> getAccelTableKind(opt::InputArgList &Args) {
+ if (opt::Arg *Accelerator = Args.getLastArg(OPT_accelerator)) {
+ StringRef S = Accelerator->getValue();
+ if (S == "Apple")
+ return AccelTableKind::Apple;
+ if (S == "Dwarf")
+ return AccelTableKind::Dwarf;
+ if (S == "Default")
+ return AccelTableKind::Default;
+ return make_error<StringError>(
+ "invalid accelerator type specified: '" + S +
+ "'. Support values are 'Apple', 'Dwarf' and 'Default'.",
+ inconvertibleErrorCode());
+ }
+ return AccelTableKind::Default;
+}
+
+/// Parses the command line options into the LinkOptions struct and performs
+/// some sanity checking. Returns an error in case the latter fails.
+static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
+ DsymutilOptions Options;
+
+ Options.DumpDebugMap = Args.hasArg(OPT_dump_debug_map);
+ Options.DumpStab = Args.hasArg(OPT_symtab);
+ Options.Flat = Args.hasArg(OPT_flat);
+ Options.InputIsYAMLDebugMap = Args.hasArg(OPT_yaml_input);
+ Options.PaperTrailWarnings = Args.hasArg(OPT_papertrail);
+ Options.Verify = Args.hasArg(OPT_verify);
+
+ Options.LinkOpts.Minimize = Args.hasArg(OPT_minimize);
+ Options.LinkOpts.NoODR = Args.hasArg(OPT_no_odr);
+ Options.LinkOpts.NoOutput = Args.hasArg(OPT_no_output);
+ Options.LinkOpts.NoTimestamp = Args.hasArg(OPT_no_swiftmodule_timestamp);
+ Options.LinkOpts.Update = Args.hasArg(OPT_update);
+ Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose);
+ Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics);
+
+ if (opt::Arg *ReproducerPath = Args.getLastArg(OPT_use_reproducer)) {
+ Options.ReproMode = ReproducerMode::Use;
+ Options.ReproducerPath = ReproducerPath->getValue();
+ }
+
+ if (Args.hasArg(OPT_gen_reproducer))
+ Options.ReproMode = ReproducerMode::Generate;
+
+ if (Expected<AccelTableKind> AccelKind = getAccelTableKind(Args)) {
+ Options.LinkOpts.TheAccelTableKind = *AccelKind;
+ } else {
+ return AccelKind.takeError();
+ }
+
+ if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap))
+ Options.SymbolMap = SymbolMap->getValue();
+
+ if (Args.hasArg(OPT_symbolmap))
+ Options.LinkOpts.Update = true;
+
+ if (Expected<std::vector<std::string>> InputFiles =
+ getInputs(Args, Options.LinkOpts.Update)) {
+ Options.InputFiles = std::move(*InputFiles);
+ } else {
+ return InputFiles.takeError();
+ }
+
+ for (auto *Arch : Args.filtered(OPT_arch))
+ Options.Archs.push_back(Arch->getValue());
+
+ if (opt::Arg *OsoPrependPath = Args.getLastArg(OPT_oso_prepend_path))
+ Options.LinkOpts.PrependPath = OsoPrependPath->getValue();
+
+ for (const auto &Arg : Args.getAllArgValues(OPT_object_prefix_map)) {
+ auto Split = StringRef(Arg).split('=');
+ Options.LinkOpts.ObjectPrefixMap.insert(
+ {std::string(Split.first), std::string(Split.second)});
+ }
+
+ if (opt::Arg *OutputFile = Args.getLastArg(OPT_output))
+ Options.OutputFile = OutputFile->getValue();
+
+ if (opt::Arg *Toolchain = Args.getLastArg(OPT_toolchain))
+ Options.Toolchain = Toolchain->getValue();
+
+ if (Args.hasArg(OPT_assembly))
+ Options.LinkOpts.FileType = OutputFileType::Assembly;
+
+ if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads))
+ Options.LinkOpts.Threads = atoi(NumThreads->getValue());
+ else
+ Options.LinkOpts.Threads = 0; // Use all available hardware threads
+
+ if (Options.DumpDebugMap || Options.LinkOpts.Verbose)
+ Options.LinkOpts.Threads = 1;
+
+ if (getenv("RC_DEBUG_OPTIONS"))
+ Options.PaperTrailWarnings = true;
+
+ if (opt::Arg *RemarksPrependPath = Args.getLastArg(OPT_remarks_prepend_path))
+ Options.LinkOpts.RemarksPrependPath = RemarksPrependPath->getValue();
+
+ if (opt::Arg *RemarksOutputFormat =
+ Args.getLastArg(OPT_remarks_output_format)) {
+ if (Expected<remarks::Format> FormatOrErr =
+ remarks::parseFormat(RemarksOutputFormat->getValue()))
+ Options.LinkOpts.RemarksFormat = *FormatOrErr;
+ else
+ return FormatOrErr.takeError();
+ }
+
+ if (Error E = verifyOptions(Options))
+ return std::move(E);
+ return Options;
+}
+
+static Error createPlistFile(StringRef Bin, StringRef BundleRoot,
+ StringRef Toolchain) {
+ // Create plist file to write to.
+ SmallString<128> InfoPlist(BundleRoot);
+ sys::path::append(InfoPlist, "Contents/Info.plist");
+ std::error_code EC;
+ raw_fd_ostream PL(InfoPlist, EC, sys::fs::OF_Text);
+ if (EC)
+ return make_error<StringError>(
+ "cannot create Plist: " + toString(errorCodeToError(EC)), EC);
+
+ CFBundleInfo BI = getBundleInfo(Bin);
+
+ if (BI.IDStr.empty()) {
+ StringRef BundleID = *sys::path::rbegin(BundleRoot);
+ if (sys::path::extension(BundleRoot) == ".dSYM")
+ BI.IDStr = std::string(sys::path::stem(BundleID));
+ else
+ BI.IDStr = std::string(BundleID);
+ }
+
+ // Print out information to the plist file.
+ PL << "<?xml version=\"1.0\" encoding=\"UTF-8\"\?>\n"
+ << "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
+ << "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+ << "<plist version=\"1.0\">\n"
+ << "\t<dict>\n"
+ << "\t\t<key>CFBundleDevelopmentRegion</key>\n"
+ << "\t\t<string>English</string>\n"
+ << "\t\t<key>CFBundleIdentifier</key>\n"
+ << "\t\t<string>com.apple.xcode.dsym.";
+ printHTMLEscaped(BI.IDStr, PL);
+ PL << "</string>\n"
+ << "\t\t<key>CFBundleInfoDictionaryVersion</key>\n"
+ << "\t\t<string>6.0</string>\n"
+ << "\t\t<key>CFBundlePackageType</key>\n"
+ << "\t\t<string>dSYM</string>\n"
+ << "\t\t<key>CFBundleSignature</key>\n"
+ << "\t\t<string>\?\?\?\?</string>\n";
+
+ if (!BI.OmitShortVersion()) {
+ PL << "\t\t<key>CFBundleShortVersionString</key>\n";
+ PL << "\t\t<string>";
+ printHTMLEscaped(BI.ShortVersionStr, PL);
+ PL << "</string>\n";
+ }
+
+ PL << "\t\t<key>CFBundleVersion</key>\n";
+ PL << "\t\t<string>";
+ printHTMLEscaped(BI.VersionStr, PL);
+ PL << "</string>\n";
+
+ if (!Toolchain.empty()) {
+ PL << "\t\t<key>Toolchain</key>\n";
+ PL << "\t\t<string>";
+ printHTMLEscaped(Toolchain, PL);
+ PL << "</string>\n";
+ }
+
+ PL << "\t</dict>\n"
+ << "</plist>\n";
+
+ PL.close();
+ return Error::success();
+}
+
+static Error createBundleDir(StringRef BundleBase) {
+ SmallString<128> Bundle(BundleBase);
+ sys::path::append(Bundle, "Contents", "Resources", "DWARF");
+ if (std::error_code EC =
+ create_directories(Bundle.str(), true, sys::fs::perms::all_all))
+ return make_error<StringError>(
+ "cannot create bundle: " + toString(errorCodeToError(EC)), EC);
+
+ return Error::success();
+}
+
+static bool verify(StringRef OutputFile, StringRef Arch, bool Verbose) {
+ if (OutputFile == "-") {
+ WithColor::warning() << "verification skipped for " << Arch
+ << "because writing to stdout.\n";
+ return true;
+ }
+
+ Expected<OwningBinary<Binary>> BinOrErr = createBinary(OutputFile);
+ if (!BinOrErr) {
+ WithColor::error() << OutputFile << ": " << toString(BinOrErr.takeError());
+ return false;
+ }
+
+ Binary &Binary = *BinOrErr.get().getBinary();
+ if (auto *Obj = dyn_cast<MachOObjectFile>(&Binary)) {
+ raw_ostream &os = Verbose ? errs() : nulls();
+ os << "Verifying DWARF for architecture: " << Arch << "\n";
+ std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
+ DIDumpOptions DumpOpts;
+ bool success = DICtx->verify(os, DumpOpts.noImplicitRecursion());
+ if (!success)
+ WithColor::error() << "verification failed for " << Arch << '\n';
+ return success;
+ }
+
+ return false;
+}
+
+namespace {
+struct OutputLocation {
+ OutputLocation(std::string DWARFFile, Optional<std::string> ResourceDir = {})
+ : DWARFFile(DWARFFile), ResourceDir(ResourceDir) {}
+ /// This method is a workaround for older compilers.
+ Optional<std::string> getResourceDir() const { return ResourceDir; }
+ std::string DWARFFile;
+ Optional<std::string> ResourceDir;
+};
+} // namespace
+
+static Expected<OutputLocation>
+getOutputFileName(StringRef InputFile, const DsymutilOptions &Options) {
+ if (Options.OutputFile == "-")
+ return OutputLocation(Options.OutputFile);
+
+ // When updating, do in place replacement.
+ if (Options.OutputFile.empty() &&
+ (Options.LinkOpts.Update || !Options.SymbolMap.empty()))
+ return OutputLocation(std::string(InputFile));
+
+ // If a flat dSYM has been requested, things are pretty simple.
+ if (Options.Flat) {
+ if (Options.OutputFile.empty()) {
+ if (InputFile == "-")
+ return OutputLocation{"a.out.dwarf", {}};
+ return OutputLocation((InputFile + ".dwarf").str());
+ }
+
+ return OutputLocation(Options.OutputFile);
+ }
+
+ // We need to create/update a dSYM bundle.
+ // A bundle hierarchy looks like this:
+ // <bundle name>.dSYM/
+ // Contents/
+ // Info.plist
+ // Resources/
+ // DWARF/
+ // <DWARF file(s)>
+ std::string DwarfFile =
+ std::string(InputFile == "-" ? StringRef("a.out") : InputFile);
+ SmallString<128> Path(Options.OutputFile);
+ if (Path.empty())
+ Path = DwarfFile + ".dSYM";
+ if (!Options.LinkOpts.NoOutput) {
+ if (auto E = createBundleDir(Path))
+ return std::move(E);
+ if (auto E = createPlistFile(DwarfFile, Path, Options.Toolchain))
+ return std::move(E);
+ }
+
+ sys::path::append(Path, "Contents", "Resources");
+ std::string ResourceDir = std::string(Path.str());
+ sys::path::append(Path, "DWARF", sys::path::filename(DwarfFile));
+ return OutputLocation(std::string(Path.str()), ResourceDir);
+}
+
+int main(int argc, char **argv) {
+ InitLLVM X(argc, argv);
+
+ // Parse arguments.
+ DsymutilOptTable T;
+ unsigned MAI;
+ unsigned MAC;
+ ArrayRef<const char *> ArgsArr = makeArrayRef(argv + 1, argc - 1);
+ opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC);
+
+ void *P = (void *)(intptr_t)getOutputFileName;
+ std::string SDKPath = sys::fs::getMainExecutable(argv[0], P);
+ SDKPath = std::string(sys::path::parent_path(SDKPath));
+
+ for (auto *Arg : Args.filtered(OPT_UNKNOWN)) {
+ WithColor::warning() << "ignoring unknown option: " << Arg->getSpelling()
+ << '\n';
+ }
+
+ if (Args.hasArg(OPT_help)) {
+ T.PrintHelp(
+ outs(), (std::string(argv[0]) + " [options] <input files>").c_str(),
+ "manipulate archived DWARF debug symbol files.\n\n"
+ "dsymutil links the DWARF debug information found in the object files\n"
+ "for the executable <input file> by using debug symbols information\n"
+ "contained in its symbol table.\n",
+ false);
+ return 0;
+ }
+
+ if (Args.hasArg(OPT_version)) {
+ cl::PrintVersionMessage();
+ return 0;
+ }
+
+ auto OptionsOrErr = getOptions(Args);
+ if (!OptionsOrErr) {
+ WithColor::error() << toString(OptionsOrErr.takeError());
+ return 1;
+ }
+
+ auto &Options = *OptionsOrErr;
+
+ InitializeAllTargetInfos();
+ InitializeAllTargetMCs();
+ InitializeAllTargets();
+ InitializeAllAsmPrinters();
+
+ auto Repro =
+ Reproducer::createReproducer(Options.ReproMode, Options.ReproducerPath);
+ if (!Repro) {
+ WithColor::error() << toString(Repro.takeError());
+ return 1;
+ }
+
+ Options.LinkOpts.VFS = (*Repro)->getVFS();
+
+ for (const auto &Arch : Options.Archs)
+ if (Arch != "*" && Arch != "all" &&
+ !object::MachOObjectFile::isValidArch(Arch)) {
+ WithColor::error() << "unsupported cpu architecture: '" << Arch << "'\n";
+ return 1;
+ }
+
+ SymbolMapLoader SymMapLoader(Options.SymbolMap);
+
+ for (auto &InputFile : Options.InputFiles) {
+ // Dump the symbol table for each input file and requested arch
+ if (Options.DumpStab) {
+ if (!dumpStab(Options.LinkOpts.VFS, InputFile, Options.Archs,
+ Options.LinkOpts.PrependPath))
+ return 1;
+ continue;
+ }
+
+ auto DebugMapPtrsOrErr =
+ parseDebugMap(Options.LinkOpts.VFS, InputFile, Options.Archs,
+ Options.LinkOpts.PrependPath, Options.PaperTrailWarnings,
+ Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap);
+
+ if (auto EC = DebugMapPtrsOrErr.getError()) {
+ WithColor::error() << "cannot parse the debug map for '" << InputFile
+ << "': " << EC.message() << '\n';
+ return 1;
+ }
+
+ // Remember the number of debug maps that are being processed to decide how
+ // to name the remark files.
+ Options.LinkOpts.NumDebugMaps = DebugMapPtrsOrErr->size();
+
+ if (Options.LinkOpts.Update) {
+ // The debug map should be empty. Add one object file corresponding to
+ // the input file.
+ for (auto &Map : *DebugMapPtrsOrErr)
+ Map->addDebugMapObject(InputFile,
+ sys::TimePoint<std::chrono::seconds>());
+ }
+
+ // Ensure that the debug map is not empty (anymore).
+ if (DebugMapPtrsOrErr->empty()) {
+ WithColor::error() << "no architecture to link\n";
+ return 1;
+ }
+
+ // Shared a single binary holder for all the link steps.
+ BinaryHolder BinHolder(Options.LinkOpts.VFS);
+
+ // Statistics only require different architectures to be processed
+ // sequentially, the link itself can still happen in parallel. Change the
+ // thread pool strategy here instead of modifying LinkOpts.Threads.
+ ThreadPoolStrategy S = hardware_concurrency(
+ Options.LinkOpts.Statistics ? 1 : Options.LinkOpts.Threads);
+ if (Options.LinkOpts.Threads == 0) {
+ // If NumThreads is not specified, create one thread for each input, up to
+ // the number of hardware threads.
+ S.ThreadsRequested = DebugMapPtrsOrErr->size();
+ S.Limit = true;
+ }
+ ThreadPool Threads(S);
+
+ // If there is more than one link to execute, we need to generate
+ // temporary files.
+ const bool NeedsTempFiles =
+ !Options.DumpDebugMap && (Options.OutputFile != "-") &&
+ (DebugMapPtrsOrErr->size() != 1 || Options.LinkOpts.Update);
+ const bool Verify = Options.Verify && !Options.LinkOpts.NoOutput;
+
+ SmallVector<MachOUtils::ArchAndFile, 4> TempFiles;
+ std::atomic_char AllOK(1);
+ for (auto &Map : *DebugMapPtrsOrErr) {
+ if (Options.LinkOpts.Verbose || Options.DumpDebugMap)
+ Map->print(outs());
+
+ if (Options.DumpDebugMap)
+ continue;
+
+ if (!Options.SymbolMap.empty())
+ Options.LinkOpts.Translator = SymMapLoader.Load(InputFile, *Map);
+
+ if (Map->begin() == Map->end())
+ WithColor::warning()
+ << "no debug symbols in executable (-arch "
+ << MachOUtils::getArchName(Map->getTriple().getArchName()) << ")\n";
+
+ // Using a std::shared_ptr rather than std::unique_ptr because move-only
+ // types don't work with std::bind in the ThreadPool implementation.
+ std::shared_ptr<raw_fd_ostream> OS;
+
+ Expected<OutputLocation> OutputLocationOrErr =
+ getOutputFileName(InputFile, Options);
+ if (!OutputLocationOrErr) {
+ WithColor::error() << toString(OutputLocationOrErr.takeError());
+ return 1;
+ }
+ Options.LinkOpts.ResourceDir = OutputLocationOrErr->getResourceDir();
+
+ std::string OutputFile = OutputLocationOrErr->DWARFFile;
+ if (NeedsTempFiles) {
+ TempFiles.emplace_back(Map->getTriple().getArchName().str());
+
+ auto E = TempFiles.back().createTempFile();
+ if (E) {
+ WithColor::error() << toString(std::move(E));
+ return 1;
+ }
+
+ auto &TempFile = *(TempFiles.back().File);
+ OS = std::make_shared<raw_fd_ostream>(TempFile.FD,
+ /*shouldClose*/ false);
+ OutputFile = TempFile.TmpName;
+ } else {
+ std::error_code EC;
+ OS = std::make_shared<raw_fd_ostream>(
+ Options.LinkOpts.NoOutput ? "-" : OutputFile, EC, sys::fs::OF_None);
+ if (EC) {
+ WithColor::error() << OutputFile << ": " << EC.message();
+ return 1;
+ }
+ }
+
+ auto LinkLambda = [&, OutputFile](std::shared_ptr<raw_fd_ostream> Stream,
+ LinkOptions Options) {
+ AllOK.fetch_and(
+ linkDwarf(*Stream, BinHolder, *Map, std::move(Options)));
+ Stream->flush();
+ if (Verify)
+ AllOK.fetch_and(verify(OutputFile, Map->getTriple().getArchName(),
+ Options.Verbose));
+ };
+
+ // FIXME: The DwarfLinker can have some very deep recursion that can max
+ // out the (significantly smaller) stack when using threads. We don't
+ // want this limitation when we only have a single thread.
+ if (S.ThreadsRequested == 1)
+ LinkLambda(OS, Options.LinkOpts);
+ else
+ Threads.async(LinkLambda, OS, Options.LinkOpts);
+ }
+
+ Threads.wait();
+
+ if (!AllOK)
+ return 1;
+
+ if (NeedsTempFiles) {
+ Expected<OutputLocation> OutputLocationOrErr =
+ getOutputFileName(InputFile, Options);
+ if (!OutputLocationOrErr) {
+ WithColor::error() << toString(OutputLocationOrErr.takeError());
+ return 1;
+ }
+ if (!MachOUtils::generateUniversalBinary(TempFiles,
+ OutputLocationOrErr->DWARFFile,
+ Options.LinkOpts, SDKPath))
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/contrib/libs/llvm12/tools/dsymutil/dsymutil.h b/contrib/libs/llvm12/tools/dsymutil/dsymutil.h
index f88f57bb20..7080b1bf3b 100644
--- a/contrib/libs/llvm12/tools/dsymutil/dsymutil.h
+++ b/contrib/libs/llvm12/tools/dsymutil/dsymutil.h
@@ -1,56 +1,56 @@
-//===- tools/dsymutil/dsymutil.h - dsymutil high-level functionality ------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-/// \file
-///
-/// This file contains the class declaration for the code that parses STABS
-/// debug maps that are embedded in the binaries symbol tables.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H
-#define LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H
-
-#include "DebugMap.h"
-#include "LinkUtils.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/ErrorOr.h"
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace llvm {
-namespace dsymutil {
-
-class BinaryHolder;
-
-/// Extract the DebugMaps from the given file.
-/// The file has to be a MachO object file. Multiple debug maps can be
-/// returned when the file is universal (aka fat) binary.
-ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
-parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- StringRef InputFile, ArrayRef<std::string> Archs,
- StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
- bool InputIsYAML);
-
-/// Dump the symbol table.
-bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
- StringRef InputFile, ArrayRef<std::string> Archs,
- StringRef PrependPath = "");
-
-/// Link the Dwarf debug info as directed by the passed DebugMap \p DM into a
-/// DwarfFile named \p OutputFilename. \returns false if the link failed.
-bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
- const DebugMap &DM, LinkOptions Options);
-
-} // end namespace dsymutil
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H
+//===- tools/dsymutil/dsymutil.h - dsymutil high-level functionality ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+///
+/// This file contains the class declaration for the code that parses STABS
+/// debug maps that are embedded in the binaries symbol tables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H
+#define LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H
+
+#include "DebugMap.h"
+#include "LinkUtils.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorOr.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace dsymutil {
+
+class BinaryHolder;
+
+/// Extract the DebugMaps from the given file.
+/// The file has to be a MachO object file. Multiple debug maps can be
+/// returned when the file is universal (aka fat) binary.
+ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
+parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+ StringRef InputFile, ArrayRef<std::string> Archs,
+ StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
+ bool InputIsYAML);
+
+/// Dump the symbol table.
+bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+ StringRef InputFile, ArrayRef<std::string> Archs,
+ StringRef PrependPath = "");
+
+/// Link the Dwarf debug info as directed by the passed DebugMap \p DM into a
+/// DwarfFile named \p OutputFilename. \returns false if the link failed.
+bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
+ const DebugMap &DM, LinkOptions Options);
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H
diff --git a/contrib/libs/llvm12/tools/dsymutil/ya.make b/contrib/libs/llvm12/tools/dsymutil/ya.make
index 8a3b747e01..2ebc7666d2 100644
--- a/contrib/libs/llvm12/tools/dsymutil/ya.make
+++ b/contrib/libs/llvm12/tools/dsymutil/ya.make
@@ -1,17 +1,17 @@
-# Generated by devtools/yamaker.
-
-PROGRAM()
-
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
-
+
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/Analysis
@@ -70,29 +70,29 @@ PEERDIR(
contrib/libs/llvm12/lib/Transforms/Scalar
contrib/libs/llvm12/lib/Transforms/Utils
contrib/libs/llvm12/lib/Transforms/Vectorize
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/dsymutil
contrib/libs/llvm12/tools/dsymutil
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- BinaryHolder.cpp
- CFBundle.cpp
- DebugMap.cpp
- DwarfLinkerForBinary.cpp
- MachODebugMapParser.cpp
- MachOUtils.cpp
- Reproducer.cpp
- SymbolMap.cpp
- dsymutil.cpp
-)
-
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ BinaryHolder.cpp
+ CFBundle.cpp
+ DebugMap.cpp
+ DwarfLinkerForBinary.cpp
+ MachODebugMapParser.cpp
+ MachOUtils.cpp
+ Reproducer.cpp
+ SymbolMap.cpp
+ dsymutil.cpp
+)
+
IF (OS_DARWIN AND ARCH_AARCH64)
LDFLAGS(
-framework
@@ -100,4 +100,4 @@ IF (OS_DARWIN AND ARCH_AARCH64)
)
ENDIF()
-END()
+END()
diff --git a/contrib/libs/llvm12/tools/llvm-cvtres/Opts.td b/contrib/libs/llvm12/tools/llvm-cvtres/Opts.td
index 8687d4701c..e418c30346 100644
--- a/contrib/libs/llvm12/tools/llvm-cvtres/Opts.td
+++ b/contrib/libs/llvm12/tools/llvm-cvtres/Opts.td
@@ -1,19 +1,19 @@
-include "llvm/Option/OptParser.td"
-
-// All the switches can be preceded by either '/' or '-'.
-
-def DEFINE : Joined<["/", "-"], "DEFINE:">, HelpText<"">, MetaVarName<"symbol">;
-def FOLDDUPS : Flag<["/", "-"], "FOLDDUPS:">, HelpText<"">;
-def MACHINE : Joined<["/", "-"], "MACHINE:">, HelpText<"">, MetaVarName<"{ARM|ARM64|EBC|IA64|X64|X86}">;
-def NOLOGO : Flag<["/", "-"], "NOLOGO">, HelpText<"">;
-def OUT : Joined<["/", "-"], "OUT:">, HelpText<"">, MetaVarName<"filename">;
-def READONLY : Flag<["/", "-"], "READONLY">, HelpText<"">;
-def VERBOSE : Flag<["/", "-"], "VERBOSE">, HelpText<"">;
-def HELP : Flag<["/", "-"], "HELP">;
-def H : Flag<["/", "-"], "H">, Alias<HELP>;
-def HELP_Q : Flag<["/?", "-?"], "">, Alias<HELP>;
-
-// Extensions.
-
-def TIMESTAMP : Joined<["/", "-"], "TIMESTAMP:">,
- HelpText<"Timestamp for coff header, defaults to current time">;
+include "llvm/Option/OptParser.td"
+
+// All the switches can be preceded by either '/' or '-'.
+
+def DEFINE : Joined<["/", "-"], "DEFINE:">, HelpText<"">, MetaVarName<"symbol">;
+def FOLDDUPS : Flag<["/", "-"], "FOLDDUPS:">, HelpText<"">;
+def MACHINE : Joined<["/", "-"], "MACHINE:">, HelpText<"">, MetaVarName<"{ARM|ARM64|EBC|IA64|X64|X86}">;
+def NOLOGO : Flag<["/", "-"], "NOLOGO">, HelpText<"">;
+def OUT : Joined<["/", "-"], "OUT:">, HelpText<"">, MetaVarName<"filename">;
+def READONLY : Flag<["/", "-"], "READONLY">, HelpText<"">;
+def VERBOSE : Flag<["/", "-"], "VERBOSE">, HelpText<"">;
+def HELP : Flag<["/", "-"], "HELP">;
+def H : Flag<["/", "-"], "H">, Alias<HELP>;
+def HELP_Q : Flag<["/?", "-?"], "">, Alias<HELP>;
+
+// Extensions.
+
+def TIMESTAMP : Joined<["/", "-"], "TIMESTAMP:">,
+ HelpText<"Timestamp for coff header, defaults to current time">;
diff --git a/contrib/libs/llvm12/tools/llvm-cvtres/llvm-cvtres.cpp b/contrib/libs/llvm12/tools/llvm-cvtres/llvm-cvtres.cpp
index 11cfb466e1..0c43c923b0 100644
--- a/contrib/libs/llvm12/tools/llvm-cvtres/llvm-cvtres.cpp
+++ b/contrib/libs/llvm12/tools/llvm-cvtres/llvm-cvtres.cpp
@@ -1,211 +1,211 @@
-//===- llvm-cvtres.cpp - Serialize .res files into .obj ---------*- 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
-//
-//===----------------------------------------------------------------------===//
-//
-// Serialize .res files into .obj files. This is intended to be a
-// platform-independent port of Microsoft's cvtres.exe.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/Binary.h"
-#include "llvm/Object/WindowsMachineFlag.h"
-#include "llvm/Object/WindowsResource.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/BinaryStreamError.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/ScopedPrinter.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <system_error>
-
-using namespace llvm;
-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 "Opts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#include "Opts.inc"
-#undef PREFIX
-
-static 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 "Opts.inc"
-#undef OPTION
-};
-
-class CvtResOptTable : public opt::OptTable {
-public:
- CvtResOptTable() : OptTable(InfoTable, true) {}
-};
-}
-
+//===- llvm-cvtres.cpp - Serialize .res files into .obj ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Serialize .res files into .obj files. This is intended to be a
+// platform-independent port of Microsoft's cvtres.exe.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/WindowsMachineFlag.h"
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <system_error>
+
+using namespace llvm;
+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 "Opts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Opts.inc"
+#undef PREFIX
+
+static 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 "Opts.inc"
+#undef OPTION
+};
+
+class CvtResOptTable : public opt::OptTable {
+public:
+ CvtResOptTable() : OptTable(InfoTable, true) {}
+};
+}
+
static LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
- errs() << Msg;
- exit(1);
-}
-
-static void reportError(StringRef Input, std::error_code EC) {
- reportError(Twine(Input) + ": " + EC.message() + ".\n");
-}
-
+ errs() << Msg;
+ exit(1);
+}
+
+static void reportError(StringRef Input, std::error_code EC) {
+ reportError(Twine(Input) + ": " + EC.message() + ".\n");
+}
+
static void error(Error EC) {
- if (!EC)
- return;
- handleAllErrors(std::move(EC),
- [&](const ErrorInfoBase &EI) { reportError(EI.message()); });
-}
-
-static uint32_t getTime() {
- std::time_t Now = time(nullptr);
- if (Now < 0 || !isUInt<32>(Now))
- return UINT32_MAX;
- return static_cast<uint32_t>(Now);
-}
-
-template <typename T> T error(Expected<T> EC) {
- if (!EC)
- error(EC.takeError());
- return std::move(EC.get());
-}
-
-int main(int Argc, const char **Argv) {
- InitLLVM X(Argc, Argv);
-
- CvtResOptTable T;
- unsigned MAI, MAC;
- ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
- opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
-
- if (InputArgs.hasArg(OPT_HELP)) {
- T.PrintHelp(outs(), "llvm-cvtres [options] file...", "Resource Converter");
- return 0;
- }
-
- bool Verbose = InputArgs.hasArg(OPT_VERBOSE);
-
- COFF::MachineTypes MachineType;
-
- if (opt::Arg *Arg = InputArgs.getLastArg(OPT_MACHINE)) {
- MachineType = getMachineType(Arg->getValue());
- if (MachineType == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
- reportError(Twine("Unsupported machine architecture ") + Arg->getValue() +
- "\n");
- }
- } else {
- if (Verbose)
- outs() << "Machine architecture not specified; assumed X64.\n";
- MachineType = COFF::IMAGE_FILE_MACHINE_AMD64;
- }
-
- std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
-
- if (InputFiles.size() == 0) {
- reportError("No input file specified.\n");
- }
-
- SmallString<128> OutputFile;
-
- if (opt::Arg *Arg = InputArgs.getLastArg(OPT_OUT)) {
- OutputFile = Arg->getValue();
- } else {
- OutputFile = sys::path::filename(StringRef(InputFiles[0]));
- sys::path::replace_extension(OutputFile, ".obj");
- }
-
- uint32_t DateTimeStamp;
- if (llvm::opt::Arg *Arg = InputArgs.getLastArg(OPT_TIMESTAMP)) {
- StringRef Value(Arg->getValue());
- if (Value.getAsInteger(0, DateTimeStamp))
- reportError(Twine("invalid timestamp: ") + Value +
- ". Expected 32-bit integer\n");
- } else {
- DateTimeStamp = getTime();
- }
-
- if (Verbose)
- outs() << "Machine: " << machineToStr(MachineType) << '\n';
-
- WindowsResourceParser Parser;
-
- for (const auto &File : InputFiles) {
- Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
- if (!BinaryOrErr)
- reportError(File, errorToErrorCode(BinaryOrErr.takeError()));
-
- Binary &Binary = *BinaryOrErr.get().getBinary();
-
- WindowsResource *RF = dyn_cast<WindowsResource>(&Binary);
- if (!RF)
- reportError(File + ": unrecognized file format.\n");
-
- if (Verbose) {
- int EntryNumber = 0;
- ResourceEntryRef Entry = error(RF->getHeadEntry());
- bool End = false;
- while (!End) {
- error(Entry.moveNext(End));
- EntryNumber++;
- }
- outs() << "Number of resources: " << EntryNumber << "\n";
- }
-
- std::vector<std::string> Duplicates;
- error(Parser.parse(RF, Duplicates));
- for (const auto& DupeDiag : Duplicates)
- reportError(DupeDiag);
- }
-
- if (Verbose) {
- Parser.printTree(outs());
- }
-
- std::unique_ptr<MemoryBuffer> OutputBuffer =
- error(llvm::object::writeWindowsResourceCOFF(MachineType, Parser,
- DateTimeStamp));
- auto FileOrErr =
- FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
- if (!FileOrErr)
- reportError(OutputFile, errorToErrorCode(FileOrErr.takeError()));
- std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
- std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
- FileBuffer->getBufferStart());
- error(FileBuffer->commit());
-
- if (Verbose) {
- Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(OutputFile);
- if (!BinaryOrErr)
- reportError(OutputFile, errorToErrorCode(BinaryOrErr.takeError()));
- Binary &Binary = *BinaryOrErr.get().getBinary();
- ScopedPrinter W(errs());
- W.printBinaryBlock("Output File Raw Data", Binary.getData());
- }
-
- return 0;
-}
+ if (!EC)
+ return;
+ handleAllErrors(std::move(EC),
+ [&](const ErrorInfoBase &EI) { reportError(EI.message()); });
+}
+
+static uint32_t getTime() {
+ std::time_t Now = time(nullptr);
+ if (Now < 0 || !isUInt<32>(Now))
+ return UINT32_MAX;
+ return static_cast<uint32_t>(Now);
+}
+
+template <typename T> T error(Expected<T> EC) {
+ if (!EC)
+ error(EC.takeError());
+ return std::move(EC.get());
+}
+
+int main(int Argc, const char **Argv) {
+ InitLLVM X(Argc, Argv);
+
+ CvtResOptTable T;
+ unsigned MAI, MAC;
+ ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
+ opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
+
+ if (InputArgs.hasArg(OPT_HELP)) {
+ T.PrintHelp(outs(), "llvm-cvtres [options] file...", "Resource Converter");
+ return 0;
+ }
+
+ bool Verbose = InputArgs.hasArg(OPT_VERBOSE);
+
+ COFF::MachineTypes MachineType;
+
+ if (opt::Arg *Arg = InputArgs.getLastArg(OPT_MACHINE)) {
+ MachineType = getMachineType(Arg->getValue());
+ if (MachineType == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
+ reportError(Twine("Unsupported machine architecture ") + Arg->getValue() +
+ "\n");
+ }
+ } else {
+ if (Verbose)
+ outs() << "Machine architecture not specified; assumed X64.\n";
+ MachineType = COFF::IMAGE_FILE_MACHINE_AMD64;
+ }
+
+ std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
+
+ if (InputFiles.size() == 0) {
+ reportError("No input file specified.\n");
+ }
+
+ SmallString<128> OutputFile;
+
+ if (opt::Arg *Arg = InputArgs.getLastArg(OPT_OUT)) {
+ OutputFile = Arg->getValue();
+ } else {
+ OutputFile = sys::path::filename(StringRef(InputFiles[0]));
+ sys::path::replace_extension(OutputFile, ".obj");
+ }
+
+ uint32_t DateTimeStamp;
+ if (llvm::opt::Arg *Arg = InputArgs.getLastArg(OPT_TIMESTAMP)) {
+ StringRef Value(Arg->getValue());
+ if (Value.getAsInteger(0, DateTimeStamp))
+ reportError(Twine("invalid timestamp: ") + Value +
+ ". Expected 32-bit integer\n");
+ } else {
+ DateTimeStamp = getTime();
+ }
+
+ if (Verbose)
+ outs() << "Machine: " << machineToStr(MachineType) << '\n';
+
+ WindowsResourceParser Parser;
+
+ for (const auto &File : InputFiles) {
+ Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
+ if (!BinaryOrErr)
+ reportError(File, errorToErrorCode(BinaryOrErr.takeError()));
+
+ Binary &Binary = *BinaryOrErr.get().getBinary();
+
+ WindowsResource *RF = dyn_cast<WindowsResource>(&Binary);
+ if (!RF)
+ reportError(File + ": unrecognized file format.\n");
+
+ if (Verbose) {
+ int EntryNumber = 0;
+ ResourceEntryRef Entry = error(RF->getHeadEntry());
+ bool End = false;
+ while (!End) {
+ error(Entry.moveNext(End));
+ EntryNumber++;
+ }
+ outs() << "Number of resources: " << EntryNumber << "\n";
+ }
+
+ std::vector<std::string> Duplicates;
+ error(Parser.parse(RF, Duplicates));
+ for (const auto& DupeDiag : Duplicates)
+ reportError(DupeDiag);
+ }
+
+ if (Verbose) {
+ Parser.printTree(outs());
+ }
+
+ std::unique_ptr<MemoryBuffer> OutputBuffer =
+ error(llvm::object::writeWindowsResourceCOFF(MachineType, Parser,
+ DateTimeStamp));
+ auto FileOrErr =
+ FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
+ if (!FileOrErr)
+ reportError(OutputFile, errorToErrorCode(FileOrErr.takeError()));
+ std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
+ std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
+ FileBuffer->getBufferStart());
+ error(FileBuffer->commit());
+
+ if (Verbose) {
+ Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(OutputFile);
+ if (!BinaryOrErr)
+ reportError(OutputFile, errorToErrorCode(BinaryOrErr.takeError()));
+ Binary &Binary = *BinaryOrErr.get().getBinary();
+ ScopedPrinter W(errs());
+ W.printBinaryBlock("Output File Raw Data", Binary.getData());
+ }
+
+ return 0;
+}
diff --git a/contrib/libs/llvm12/tools/llvm-cvtres/ya.make b/contrib/libs/llvm12/tools/llvm-cvtres/ya.make
index fc7b01fdb7..ab0eff49cc 100644
--- a/contrib/libs/llvm12/tools/llvm-cvtres/ya.make
+++ b/contrib/libs/llvm12/tools/llvm-cvtres/ya.make
@@ -1,17 +1,17 @@
-# Generated by devtools/yamaker.
-
-PROGRAM()
-
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
-
+
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/BinaryFormat
@@ -26,19 +26,19 @@ PEERDIR(
contrib/libs/llvm12/lib/Remarks
contrib/libs/llvm12/lib/Support
contrib/libs/llvm12/lib/TextAPI/MachO
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/llvm-cvtres
contrib/libs/llvm12/tools/llvm-cvtres
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- llvm-cvtres.cpp
-)
-
-END()
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ llvm-cvtres.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm12/tools/llvm-lipo/LipoOpts.td b/contrib/libs/llvm12/tools/llvm-lipo/LipoOpts.td
index 866353573c..f1a8d1140b 100644
--- a/contrib/libs/llvm12/tools/llvm-lipo/LipoOpts.td
+++ b/contrib/libs/llvm12/tools/llvm-lipo/LipoOpts.td
@@ -1,60 +1,60 @@
-include "llvm/Option/OptParser.td"
-
-def help : Flag<["-", "--"], "help">;
-def h : Flag<["-"], "h">, Alias<help>;
-
-def version : Flag<["-", "--"], "version">,
- HelpText<"Print the version and exit.">;
-
-def segalign
- : MultiArg<["-", "--"], "segalign", 2>,
- HelpText<"Specifies the segment alignment for the specified "
- "architecture when creating a universal binary file. The "
- "alignment is a hexadecimal number that is a power of 2.">;
-
-def arch
- : MultiArg<["-", "--"], "arch", 2>,
- HelpText<"Specifies the architecture and the corresponding input file">;
-
-def action_group : OptionGroup<"action group">;
-
-def verify_arch
- : Option<["-", "--"], "verify_arch", KIND_REMAINING_ARGS>,
- Group<action_group>,
- HelpText<
- "Verify that the specified arch_types are present in the input file">;
-
-def archs : Option<["-", "--"], "archs", KIND_FLAG>,
- Group<action_group>,
- HelpText<"Display the arch_types present in the input file">;
-
-def info : Option<["-", "--"], "info", KIND_FLAG>,
- Group<action_group>,
- HelpText<"Display descriptions of each input file including "
- "filename and arch_types. Groups universal binaries "
- "together followed by thin files">;
-
-def thin : Option<["-", "--"], "thin", KIND_SEPARATE>,
- Group<action_group>,
- HelpText<"Create a thin output file of specified arch_type from the "
- "fat input file. Requires -output option">;
-
-def extract : Option<["-", "--"], "extract", KIND_SEPARATE>,
- Group<action_group>,
- HelpText<"Create a universal output file containing only the specified "
- "arch_type from the fat input file. Requires -output option">;
-
-def create : Option<["-", "--"], "create", KIND_FLAG>,
- Group<action_group>,
- HelpText<"Create a universal binary output file from the input "
- "files. Requires -output option">;
-
-def replace
- : MultiArg<["-", "--"], "replace", 2>,
- Group<action_group>,
- HelpText<"Replace the specified arch type with the contents of the "
- "input_file in a universal binary. Requires -output option">;
-
-def output : Option<["-", "--"], "output", KIND_SEPARATE>,
- HelpText<"Create output file with specified name">;
-def o : JoinedOrSeparate<["-"], "o">, Alias<output>;
+include "llvm/Option/OptParser.td"
+
+def help : Flag<["-", "--"], "help">;
+def h : Flag<["-"], "h">, Alias<help>;
+
+def version : Flag<["-", "--"], "version">,
+ HelpText<"Print the version and exit.">;
+
+def segalign
+ : MultiArg<["-", "--"], "segalign", 2>,
+ HelpText<"Specifies the segment alignment for the specified "
+ "architecture when creating a universal binary file. The "
+ "alignment is a hexadecimal number that is a power of 2.">;
+
+def arch
+ : MultiArg<["-", "--"], "arch", 2>,
+ HelpText<"Specifies the architecture and the corresponding input file">;
+
+def action_group : OptionGroup<"action group">;
+
+def verify_arch
+ : Option<["-", "--"], "verify_arch", KIND_REMAINING_ARGS>,
+ Group<action_group>,
+ HelpText<
+ "Verify that the specified arch_types are present in the input file">;
+
+def archs : Option<["-", "--"], "archs", KIND_FLAG>,
+ Group<action_group>,
+ HelpText<"Display the arch_types present in the input file">;
+
+def info : Option<["-", "--"], "info", KIND_FLAG>,
+ Group<action_group>,
+ HelpText<"Display descriptions of each input file including "
+ "filename and arch_types. Groups universal binaries "
+ "together followed by thin files">;
+
+def thin : Option<["-", "--"], "thin", KIND_SEPARATE>,
+ Group<action_group>,
+ HelpText<"Create a thin output file of specified arch_type from the "
+ "fat input file. Requires -output option">;
+
+def extract : Option<["-", "--"], "extract", KIND_SEPARATE>,
+ Group<action_group>,
+ HelpText<"Create a universal output file containing only the specified "
+ "arch_type from the fat input file. Requires -output option">;
+
+def create : Option<["-", "--"], "create", KIND_FLAG>,
+ Group<action_group>,
+ HelpText<"Create a universal binary output file from the input "
+ "files. Requires -output option">;
+
+def replace
+ : MultiArg<["-", "--"], "replace", 2>,
+ Group<action_group>,
+ HelpText<"Replace the specified arch type with the contents of the "
+ "input_file in a universal binary. Requires -output option">;
+
+def output : Option<["-", "--"], "output", KIND_SEPARATE>,
+ HelpText<"Create output file with specified name">;
+def o : JoinedOrSeparate<["-"], "o">, Alias<output>;
diff --git a/contrib/libs/llvm12/tools/llvm-lipo/llvm-lipo.cpp b/contrib/libs/llvm12/tools/llvm-lipo/llvm-lipo.cpp
index 7fbe489ecc..e1881745b1 100644
--- a/contrib/libs/llvm12/tools/llvm-lipo/llvm-lipo.cpp
+++ b/contrib/libs/llvm12/tools/llvm-lipo/llvm-lipo.cpp
@@ -1,47 +1,47 @@
-//===-- llvm-lipo.cpp - a tool for manipulating universal 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
-//
-//===----------------------------------------------------------------------===//
-//
-// A utility for creating / splitting / inspecting universal binaries.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/Triple.h"
+//===-- llvm-lipo.cpp - a tool for manipulating universal 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
+//
+//===----------------------------------------------------------------------===//
+//
+// A utility for creating / splitting / inspecting universal binaries.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
-#include "llvm/Object/Binary.h"
+#include "llvm/Object/Binary.h"
#include "llvm/Object/IRObjectFile.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/MachOUniversalWriter.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/TextAPI/MachO/Architecture.h"
-
-using namespace llvm;
-using namespace llvm::object;
-
-static const StringRef ToolName = "llvm-lipo";
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/TextAPI/MachO/Architecture.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+static const StringRef ToolName = "llvm-lipo";
static LLVMContext LLVMCtx;
-
-LLVM_ATTRIBUTE_NORETURN static void reportError(Twine Message) {
- WithColor::error(errs(), ToolName) << Message << "\n";
- errs().flush();
- exit(EXIT_FAILURE);
-}
-
+
+LLVM_ATTRIBUTE_NORETURN static void reportError(Twine Message) {
+ WithColor::error(errs(), ToolName) << Message << "\n";
+ errs().flush();
+ exit(EXIT_FAILURE);
+}
+
LLVM_ATTRIBUTE_NORETURN static void reportError(Error E) {
assert(E);
std::string Buf;
@@ -51,347 +51,347 @@ LLVM_ATTRIBUTE_NORETURN static void reportError(Error E) {
reportError(Buf);
}
-LLVM_ATTRIBUTE_NORETURN static void reportError(StringRef File, Error E) {
- assert(E);
- std::string Buf;
- raw_string_ostream OS(Buf);
- logAllUnhandledErrors(std::move(E), OS);
- OS.flush();
- WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
- exit(EXIT_FAILURE);
-}
-
-namespace {
-enum LipoID {
- LIPO_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- LIPO_##ID,
-#include "LipoOpts.inc"
-#undef OPTION
-};
-
-// LipoInfoTable below references LIPO_##PREFIX. OptionGroup has prefix nullptr.
-const char *const *LIPO_nullptr = nullptr;
-#define PREFIX(NAME, VALUE) const char *const LIPO_##NAME[] = VALUE;
-#include "LipoOpts.inc"
-#undef PREFIX
-
-static const opt::OptTable::Info LipoInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {LIPO_##PREFIX, NAME, HELPTEXT, \
- METAVAR, LIPO_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, LIPO_##GROUP, \
- LIPO_##ALIAS, ALIASARGS, VALUES},
-#include "LipoOpts.inc"
-#undef OPTION
-};
-
-class LipoOptTable : public opt::OptTable {
-public:
- LipoOptTable() : OptTable(LipoInfoTable) {}
-};
-
-enum class LipoAction {
- PrintArchs,
- PrintInfo,
- VerifyArch,
- ThinArch,
- ExtractArch,
- CreateUniversal,
- ReplaceArch,
-};
-
-struct InputFile {
- Optional<StringRef> ArchType;
- StringRef FileName;
-};
-
-struct Config {
- SmallVector<InputFile, 1> InputFiles;
- SmallVector<std::string, 1> VerifyArchList;
- SmallVector<InputFile, 1> ReplacementFiles;
- StringMap<const uint32_t> SegmentAlignments;
- std::string ArchType;
- std::string OutputFile;
- LipoAction ActionToPerform;
-};
-
+LLVM_ATTRIBUTE_NORETURN static void reportError(StringRef File, Error E) {
+ assert(E);
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(std::move(E), OS);
+ OS.flush();
+ WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
+ exit(EXIT_FAILURE);
+}
+
+namespace {
+enum LipoID {
+ LIPO_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ LIPO_##ID,
+#include "LipoOpts.inc"
+#undef OPTION
+};
+
+// LipoInfoTable below references LIPO_##PREFIX. OptionGroup has prefix nullptr.
+const char *const *LIPO_nullptr = nullptr;
+#define PREFIX(NAME, VALUE) const char *const LIPO_##NAME[] = VALUE;
+#include "LipoOpts.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info LipoInfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {LIPO_##PREFIX, NAME, HELPTEXT, \
+ METAVAR, LIPO_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, LIPO_##GROUP, \
+ LIPO_##ALIAS, ALIASARGS, VALUES},
+#include "LipoOpts.inc"
+#undef OPTION
+};
+
+class LipoOptTable : public opt::OptTable {
+public:
+ LipoOptTable() : OptTable(LipoInfoTable) {}
+};
+
+enum class LipoAction {
+ PrintArchs,
+ PrintInfo,
+ VerifyArch,
+ ThinArch,
+ ExtractArch,
+ CreateUniversal,
+ ReplaceArch,
+};
+
+struct InputFile {
+ Optional<StringRef> ArchType;
+ StringRef FileName;
+};
+
+struct Config {
+ SmallVector<InputFile, 1> InputFiles;
+ SmallVector<std::string, 1> VerifyArchList;
+ SmallVector<InputFile, 1> ReplacementFiles;
+ StringMap<const uint32_t> SegmentAlignments;
+ std::string ArchType;
+ std::string OutputFile;
+ LipoAction ActionToPerform;
+};
+
static Slice createSliceFromArchive(const Archive &A) {
Expected<Slice> ArchiveOrSlice = Slice::create(A, &LLVMCtx);
if (!ArchiveOrSlice)
reportError(A.getFileName(), ArchiveOrSlice.takeError());
return *ArchiveOrSlice;
-}
-
+}
+
static Slice createSliceFromIR(const IRObjectFile &IRO, unsigned Align) {
Expected<Slice> IROrErr = Slice::create(IRO, Align);
if (!IROrErr)
reportError(IRO.getFileName(), IROrErr.takeError());
return *IROrErr;
-}
-
-} // end namespace
-
-static void validateArchitectureName(StringRef ArchitectureName) {
- if (!MachOObjectFile::isValidArch(ArchitectureName)) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS << "Invalid architecture: " << ArchitectureName
- << "\nValid architecture names are:";
- for (auto arch : MachOObjectFile::getValidArchs())
- OS << " " << arch;
- reportError(OS.str());
- }
-}
-
-static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
- Config C;
- LipoOptTable T;
- unsigned MissingArgumentIndex, MissingArgumentCount;
- opt::InputArgList InputArgs =
- T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
-
- if (MissingArgumentCount)
- reportError("missing argument to " +
- StringRef(InputArgs.getArgString(MissingArgumentIndex)) +
- " option");
-
- if (InputArgs.size() == 0) {
- // PrintHelp does not accept Twine.
- T.PrintHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
- exit(EXIT_FAILURE);
- }
-
- if (InputArgs.hasArg(LIPO_help)) {
- // PrintHelp does not accept Twine.
- T.PrintHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
- exit(EXIT_SUCCESS);
- }
-
- if (InputArgs.hasArg(LIPO_version)) {
- outs() << ToolName + "\n";
- cl::PrintVersionMessage();
- exit(EXIT_SUCCESS);
- }
-
- for (auto Arg : InputArgs.filtered(LIPO_UNKNOWN))
- reportError("unknown argument '" + Arg->getAsString(InputArgs) + "'");
-
- for (auto Arg : InputArgs.filtered(LIPO_INPUT))
- C.InputFiles.push_back({None, Arg->getValue()});
- for (auto Arg : InputArgs.filtered(LIPO_arch)) {
- validateArchitectureName(Arg->getValue(0));
- if (!Arg->getValue(1))
- reportError(
- "arch is missing an argument: expects -arch arch_type file_name");
- C.InputFiles.push_back({StringRef(Arg->getValue(0)), Arg->getValue(1)});
- }
-
- if (C.InputFiles.empty())
- reportError("at least one input file should be specified");
-
- if (InputArgs.hasArg(LIPO_output))
- C.OutputFile = std::string(InputArgs.getLastArgValue(LIPO_output));
-
- for (auto Segalign : InputArgs.filtered(LIPO_segalign)) {
- if (!Segalign->getValue(1))
- reportError("segalign is missing an argument: expects -segalign "
- "arch_type alignment_value");
-
- validateArchitectureName(Segalign->getValue(0));
-
- uint32_t AlignmentValue;
- if (!to_integer<uint32_t>(Segalign->getValue(1), AlignmentValue, 16))
- reportError("argument to -segalign <arch_type> " +
- Twine(Segalign->getValue(1)) +
- " (hex) is not a proper hexadecimal number");
- if (!isPowerOf2_32(AlignmentValue))
- reportError("argument to -segalign <arch_type> " +
- Twine(Segalign->getValue(1)) +
- " (hex) must be a non-zero power of two");
- if (Log2_32(AlignmentValue) > MachOUniversalBinary::MaxSectionAlignment)
- reportError(
- "argument to -segalign <arch_type> " + Twine(Segalign->getValue(1)) +
- " (hex) must be less than or equal to the maximum section align 2^" +
- Twine(MachOUniversalBinary::MaxSectionAlignment));
- auto Entry = C.SegmentAlignments.try_emplace(Segalign->getValue(0),
- Log2_32(AlignmentValue));
- if (!Entry.second)
- reportError("-segalign " + Twine(Segalign->getValue(0)) +
- " <alignment_value> specified multiple times: " +
- Twine(1 << Entry.first->second) + ", " +
- Twine(AlignmentValue));
- }
-
- SmallVector<opt::Arg *, 1> ActionArgs(InputArgs.filtered(LIPO_action_group));
- if (ActionArgs.empty())
- reportError("at least one action should be specified");
- // errors if multiple actions specified other than replace
- // multiple replace flags may be specified, as long as they are not mixed with
- // other action flags
- auto ReplacementArgsRange = InputArgs.filtered(LIPO_replace);
- if (ActionArgs.size() > 1 &&
- ActionArgs.size() !=
- static_cast<size_t>(std::distance(ReplacementArgsRange.begin(),
- ReplacementArgsRange.end()))) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS << "only one of the following actions can be specified:";
- for (auto Arg : ActionArgs)
- OS << " " << Arg->getSpelling();
- reportError(OS.str());
- }
-
- switch (ActionArgs[0]->getOption().getID()) {
- case LIPO_verify_arch:
- for (auto A : InputArgs.getAllArgValues(LIPO_verify_arch))
- C.VerifyArchList.push_back(A);
- if (C.VerifyArchList.empty())
- reportError(
- "verify_arch requires at least one architecture to be specified");
- if (C.InputFiles.size() > 1)
- reportError("verify_arch expects a single input file");
- C.ActionToPerform = LipoAction::VerifyArch;
- return C;
-
- case LIPO_archs:
- if (C.InputFiles.size() > 1)
- reportError("archs expects a single input file");
- C.ActionToPerform = LipoAction::PrintArchs;
- return C;
-
- case LIPO_info:
- C.ActionToPerform = LipoAction::PrintInfo;
- return C;
-
- case LIPO_thin:
- if (C.InputFiles.size() > 1)
- reportError("thin expects a single input file");
- if (C.OutputFile.empty())
- reportError("thin expects a single output file");
- C.ArchType = ActionArgs[0]->getValue();
- validateArchitectureName(C.ArchType);
- C.ActionToPerform = LipoAction::ThinArch;
- return C;
-
- case LIPO_extract:
- if (C.InputFiles.size() > 1)
- reportError("extract expects a single input file");
- if (C.OutputFile.empty())
- reportError("extract expects a single output file");
- C.ArchType = ActionArgs[0]->getValue();
- validateArchitectureName(C.ArchType);
- C.ActionToPerform = LipoAction::ExtractArch;
- return C;
-
- case LIPO_create:
- if (C.OutputFile.empty())
- reportError("create expects a single output file to be specified");
- C.ActionToPerform = LipoAction::CreateUniversal;
- return C;
-
- case LIPO_replace:
- for (auto Action : ActionArgs) {
- if (!Action->getValue(1))
- reportError(
- "replace is missing an argument: expects -replace arch_type "
- "file_name");
- validateArchitectureName(Action->getValue(0));
- C.ReplacementFiles.push_back(
- {StringRef(Action->getValue(0)), Action->getValue(1)});
- }
-
- if (C.OutputFile.empty())
- reportError("replace expects a single output file to be specified");
- if (C.InputFiles.size() > 1)
- reportError("replace expects a single input file");
- C.ActionToPerform = LipoAction::ReplaceArch;
- return C;
-
- default:
- reportError("llvm-lipo action unspecified");
- }
-}
-
-static SmallVector<OwningBinary<Binary>, 1>
-readInputBinaries(ArrayRef<InputFile> InputFiles) {
- SmallVector<OwningBinary<Binary>, 1> InputBinaries;
- for (const InputFile &IF : InputFiles) {
+}
+
+} // end namespace
+
+static void validateArchitectureName(StringRef ArchitectureName) {
+ if (!MachOObjectFile::isValidArch(ArchitectureName)) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS << "Invalid architecture: " << ArchitectureName
+ << "\nValid architecture names are:";
+ for (auto arch : MachOObjectFile::getValidArchs())
+ OS << " " << arch;
+ reportError(OS.str());
+ }
+}
+
+static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
+ Config C;
+ LipoOptTable T;
+ unsigned MissingArgumentIndex, MissingArgumentCount;
+ opt::InputArgList InputArgs =
+ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
+
+ if (MissingArgumentCount)
+ reportError("missing argument to " +
+ StringRef(InputArgs.getArgString(MissingArgumentIndex)) +
+ " option");
+
+ if (InputArgs.size() == 0) {
+ // PrintHelp does not accept Twine.
+ T.PrintHelp(errs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
+ exit(EXIT_FAILURE);
+ }
+
+ if (InputArgs.hasArg(LIPO_help)) {
+ // PrintHelp does not accept Twine.
+ T.PrintHelp(outs(), "llvm-lipo input[s] option[s]", "llvm-lipo");
+ exit(EXIT_SUCCESS);
+ }
+
+ if (InputArgs.hasArg(LIPO_version)) {
+ outs() << ToolName + "\n";
+ cl::PrintVersionMessage();
+ exit(EXIT_SUCCESS);
+ }
+
+ for (auto Arg : InputArgs.filtered(LIPO_UNKNOWN))
+ reportError("unknown argument '" + Arg->getAsString(InputArgs) + "'");
+
+ for (auto Arg : InputArgs.filtered(LIPO_INPUT))
+ C.InputFiles.push_back({None, Arg->getValue()});
+ for (auto Arg : InputArgs.filtered(LIPO_arch)) {
+ validateArchitectureName(Arg->getValue(0));
+ if (!Arg->getValue(1))
+ reportError(
+ "arch is missing an argument: expects -arch arch_type file_name");
+ C.InputFiles.push_back({StringRef(Arg->getValue(0)), Arg->getValue(1)});
+ }
+
+ if (C.InputFiles.empty())
+ reportError("at least one input file should be specified");
+
+ if (InputArgs.hasArg(LIPO_output))
+ C.OutputFile = std::string(InputArgs.getLastArgValue(LIPO_output));
+
+ for (auto Segalign : InputArgs.filtered(LIPO_segalign)) {
+ if (!Segalign->getValue(1))
+ reportError("segalign is missing an argument: expects -segalign "
+ "arch_type alignment_value");
+
+ validateArchitectureName(Segalign->getValue(0));
+
+ uint32_t AlignmentValue;
+ if (!to_integer<uint32_t>(Segalign->getValue(1), AlignmentValue, 16))
+ reportError("argument to -segalign <arch_type> " +
+ Twine(Segalign->getValue(1)) +
+ " (hex) is not a proper hexadecimal number");
+ if (!isPowerOf2_32(AlignmentValue))
+ reportError("argument to -segalign <arch_type> " +
+ Twine(Segalign->getValue(1)) +
+ " (hex) must be a non-zero power of two");
+ if (Log2_32(AlignmentValue) > MachOUniversalBinary::MaxSectionAlignment)
+ reportError(
+ "argument to -segalign <arch_type> " + Twine(Segalign->getValue(1)) +
+ " (hex) must be less than or equal to the maximum section align 2^" +
+ Twine(MachOUniversalBinary::MaxSectionAlignment));
+ auto Entry = C.SegmentAlignments.try_emplace(Segalign->getValue(0),
+ Log2_32(AlignmentValue));
+ if (!Entry.second)
+ reportError("-segalign " + Twine(Segalign->getValue(0)) +
+ " <alignment_value> specified multiple times: " +
+ Twine(1 << Entry.first->second) + ", " +
+ Twine(AlignmentValue));
+ }
+
+ SmallVector<opt::Arg *, 1> ActionArgs(InputArgs.filtered(LIPO_action_group));
+ if (ActionArgs.empty())
+ reportError("at least one action should be specified");
+ // errors if multiple actions specified other than replace
+ // multiple replace flags may be specified, as long as they are not mixed with
+ // other action flags
+ auto ReplacementArgsRange = InputArgs.filtered(LIPO_replace);
+ if (ActionArgs.size() > 1 &&
+ ActionArgs.size() !=
+ static_cast<size_t>(std::distance(ReplacementArgsRange.begin(),
+ ReplacementArgsRange.end()))) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS << "only one of the following actions can be specified:";
+ for (auto Arg : ActionArgs)
+ OS << " " << Arg->getSpelling();
+ reportError(OS.str());
+ }
+
+ switch (ActionArgs[0]->getOption().getID()) {
+ case LIPO_verify_arch:
+ for (auto A : InputArgs.getAllArgValues(LIPO_verify_arch))
+ C.VerifyArchList.push_back(A);
+ if (C.VerifyArchList.empty())
+ reportError(
+ "verify_arch requires at least one architecture to be specified");
+ if (C.InputFiles.size() > 1)
+ reportError("verify_arch expects a single input file");
+ C.ActionToPerform = LipoAction::VerifyArch;
+ return C;
+
+ case LIPO_archs:
+ if (C.InputFiles.size() > 1)
+ reportError("archs expects a single input file");
+ C.ActionToPerform = LipoAction::PrintArchs;
+ return C;
+
+ case LIPO_info:
+ C.ActionToPerform = LipoAction::PrintInfo;
+ return C;
+
+ case LIPO_thin:
+ if (C.InputFiles.size() > 1)
+ reportError("thin expects a single input file");
+ if (C.OutputFile.empty())
+ reportError("thin expects a single output file");
+ C.ArchType = ActionArgs[0]->getValue();
+ validateArchitectureName(C.ArchType);
+ C.ActionToPerform = LipoAction::ThinArch;
+ return C;
+
+ case LIPO_extract:
+ if (C.InputFiles.size() > 1)
+ reportError("extract expects a single input file");
+ if (C.OutputFile.empty())
+ reportError("extract expects a single output file");
+ C.ArchType = ActionArgs[0]->getValue();
+ validateArchitectureName(C.ArchType);
+ C.ActionToPerform = LipoAction::ExtractArch;
+ return C;
+
+ case LIPO_create:
+ if (C.OutputFile.empty())
+ reportError("create expects a single output file to be specified");
+ C.ActionToPerform = LipoAction::CreateUniversal;
+ return C;
+
+ case LIPO_replace:
+ for (auto Action : ActionArgs) {
+ if (!Action->getValue(1))
+ reportError(
+ "replace is missing an argument: expects -replace arch_type "
+ "file_name");
+ validateArchitectureName(Action->getValue(0));
+ C.ReplacementFiles.push_back(
+ {StringRef(Action->getValue(0)), Action->getValue(1)});
+ }
+
+ if (C.OutputFile.empty())
+ reportError("replace expects a single output file to be specified");
+ if (C.InputFiles.size() > 1)
+ reportError("replace expects a single input file");
+ C.ActionToPerform = LipoAction::ReplaceArch;
+ return C;
+
+ default:
+ reportError("llvm-lipo action unspecified");
+ }
+}
+
+static SmallVector<OwningBinary<Binary>, 1>
+readInputBinaries(ArrayRef<InputFile> InputFiles) {
+ SmallVector<OwningBinary<Binary>, 1> InputBinaries;
+ for (const InputFile &IF : InputFiles) {
Expected<OwningBinary<Binary>> BinaryOrErr =
createBinary(IF.FileName, &LLVMCtx);
- if (!BinaryOrErr)
- reportError(IF.FileName, BinaryOrErr.takeError());
- const Binary *B = BinaryOrErr->getBinary();
+ if (!BinaryOrErr)
+ reportError(IF.FileName, BinaryOrErr.takeError());
+ const Binary *B = BinaryOrErr->getBinary();
if (!B->isArchive() && !B->isMachO() && !B->isMachOUniversalBinary() &&
!B->isIR())
- reportError("File " + IF.FileName + " has unsupported binary format");
+ reportError("File " + IF.FileName + " has unsupported binary format");
if (IF.ArchType && (B->isMachO() || B->isArchive() || B->isIR())) {
const auto S = B->isMachO()
? Slice(*cast<MachOObjectFile>(B))
: B->isArchive()
? createSliceFromArchive(*cast<Archive>(B))
: createSliceFromIR(*cast<IRObjectFile>(B), 0);
- const auto SpecifiedCPUType = MachO::getCPUTypeFromArchitecture(
- MachO::getArchitectureFromName(
- Triple(*IF.ArchType).getArchName()))
- .first;
- // For compatibility with cctools' lipo the comparison is relaxed just to
- // checking cputypes.
- if (S.getCPUType() != SpecifiedCPUType)
- reportError("specified architecture: " + *IF.ArchType +
- " for file: " + B->getFileName() +
- " does not match the file's architecture (" +
- S.getArchString() + ")");
- }
- InputBinaries.push_back(std::move(*BinaryOrErr));
- }
- return InputBinaries;
-}
-
-LLVM_ATTRIBUTE_NORETURN
-static void verifyArch(ArrayRef<OwningBinary<Binary>> InputBinaries,
- ArrayRef<std::string> VerifyArchList) {
- assert(!VerifyArchList.empty() &&
- "The list of architectures should be non-empty");
- assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
-
- for (StringRef Arch : VerifyArchList)
- validateArchitectureName(Arch);
-
- if (auto UO =
- dyn_cast<MachOUniversalBinary>(InputBinaries.front().getBinary())) {
- for (StringRef Arch : VerifyArchList) {
- Expected<MachOUniversalBinary::ObjectForArch> Obj =
- UO->getObjectForArch(Arch);
- if (!Obj)
- exit(EXIT_FAILURE);
- }
- } else if (auto O =
- dyn_cast<MachOObjectFile>(InputBinaries.front().getBinary())) {
- const Triple::ArchType ObjectArch = O->getArch();
- for (StringRef Arch : VerifyArchList)
- if (ObjectArch != Triple(Arch).getArch())
- exit(EXIT_FAILURE);
- } else {
- llvm_unreachable("Unexpected binary format");
- }
- exit(EXIT_SUCCESS);
-}
-
-static void printBinaryArchs(const Binary *Binary, raw_ostream &OS) {
- // Prints trailing space for compatibility with cctools lipo.
- if (auto UO = dyn_cast<MachOUniversalBinary>(Binary)) {
- for (const auto &O : UO->objects()) {
+ const auto SpecifiedCPUType = MachO::getCPUTypeFromArchitecture(
+ MachO::getArchitectureFromName(
+ Triple(*IF.ArchType).getArchName()))
+ .first;
+ // For compatibility with cctools' lipo the comparison is relaxed just to
+ // checking cputypes.
+ if (S.getCPUType() != SpecifiedCPUType)
+ reportError("specified architecture: " + *IF.ArchType +
+ " for file: " + B->getFileName() +
+ " does not match the file's architecture (" +
+ S.getArchString() + ")");
+ }
+ InputBinaries.push_back(std::move(*BinaryOrErr));
+ }
+ return InputBinaries;
+}
+
+LLVM_ATTRIBUTE_NORETURN
+static void verifyArch(ArrayRef<OwningBinary<Binary>> InputBinaries,
+ ArrayRef<std::string> VerifyArchList) {
+ assert(!VerifyArchList.empty() &&
+ "The list of architectures should be non-empty");
+ assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
+
+ for (StringRef Arch : VerifyArchList)
+ validateArchitectureName(Arch);
+
+ if (auto UO =
+ dyn_cast<MachOUniversalBinary>(InputBinaries.front().getBinary())) {
+ for (StringRef Arch : VerifyArchList) {
+ Expected<MachOUniversalBinary::ObjectForArch> Obj =
+ UO->getObjectForArch(Arch);
+ if (!Obj)
+ exit(EXIT_FAILURE);
+ }
+ } else if (auto O =
+ dyn_cast<MachOObjectFile>(InputBinaries.front().getBinary())) {
+ const Triple::ArchType ObjectArch = O->getArch();
+ for (StringRef Arch : VerifyArchList)
+ if (ObjectArch != Triple(Arch).getArch())
+ exit(EXIT_FAILURE);
+ } else {
+ llvm_unreachable("Unexpected binary format");
+ }
+ exit(EXIT_SUCCESS);
+}
+
+static void printBinaryArchs(const Binary *Binary, raw_ostream &OS) {
+ // Prints trailing space for compatibility with cctools lipo.
+ if (auto UO = dyn_cast<MachOUniversalBinary>(Binary)) {
+ for (const auto &O : UO->objects()) {
// Order here is important, because both MachOObjectFile and
// IRObjectFile can be created with a binary that has embedded bitcode.
- Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrError =
- O.getAsObjectFile();
- if (MachOObjOrError) {
+ Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrError =
+ O.getAsObjectFile();
+ if (MachOObjOrError) {
OS << Slice(*(MachOObjOrError->get())).getArchString() << " ";
- continue;
- }
+ continue;
+ }
Expected<std::unique_ptr<IRObjectFile>> IROrError =
O.getAsIRObject(LLVMCtx);
if (IROrError) {
@@ -404,20 +404,20 @@ static void printBinaryArchs(const Binary *Binary, raw_ostream &OS) {
OS << SliceOrErr.get().getArchString() << " ";
continue;
}
- Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive();
- if (ArchiveOrError) {
- consumeError(MachOObjOrError.takeError());
+ Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive();
+ if (ArchiveOrError) {
+ consumeError(MachOObjOrError.takeError());
consumeError(IROrError.takeError());
OS << createSliceFromArchive(**ArchiveOrError).getArchString() << " ";
- continue;
- }
- consumeError(ArchiveOrError.takeError());
- reportError(Binary->getFileName(), MachOObjOrError.takeError());
+ continue;
+ }
+ consumeError(ArchiveOrError.takeError());
+ reportError(Binary->getFileName(), MachOObjOrError.takeError());
reportError(Binary->getFileName(), IROrError.takeError());
- }
- OS << "\n";
- return;
- }
+ }
+ OS << "\n";
+ return;
+ }
if (const auto *MachO = dyn_cast<MachOObjectFile>(Binary)) {
OS << Slice(*MachO).getArchString() << " \n";
@@ -431,62 +431,62 @@ static void printBinaryArchs(const Binary *Binary, raw_ostream &OS) {
reportError(IR->getFileName(), SliceOrErr.takeError());
OS << SliceOrErr->getArchString() << " \n";
-}
-
-LLVM_ATTRIBUTE_NORETURN
-static void printArchs(ArrayRef<OwningBinary<Binary>> InputBinaries) {
- assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
- printBinaryArchs(InputBinaries.front().getBinary(), outs());
- exit(EXIT_SUCCESS);
-}
-
-LLVM_ATTRIBUTE_NORETURN
-static void printInfo(ArrayRef<OwningBinary<Binary>> InputBinaries) {
- // Group universal and thin files together for compatibility with cctools lipo
- for (auto &IB : InputBinaries) {
- const Binary *Binary = IB.getBinary();
- if (Binary->isMachOUniversalBinary()) {
- outs() << "Architectures in the fat file: " << Binary->getFileName()
- << " are: ";
- printBinaryArchs(Binary, outs());
- }
- }
- for (auto &IB : InputBinaries) {
- const Binary *Binary = IB.getBinary();
- if (!Binary->isMachOUniversalBinary()) {
- assert(Binary->isMachO() && "expected MachO binary");
- outs() << "Non-fat file: " << Binary->getFileName()
- << " is architecture: ";
- printBinaryArchs(Binary, outs());
- }
- }
- exit(EXIT_SUCCESS);
-}
-
-LLVM_ATTRIBUTE_NORETURN
-static void thinSlice(ArrayRef<OwningBinary<Binary>> InputBinaries,
- StringRef ArchType, StringRef OutputFileName) {
- assert(!ArchType.empty() && "The architecture type should be non-empty");
- assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
- assert(!OutputFileName.empty() && "Thin expects a single output file");
-
- if (InputBinaries.front().getBinary()->isMachO()) {
- reportError("input file " +
- InputBinaries.front().getBinary()->getFileName() +
- " must be a fat file when the -thin option is specified");
- exit(EXIT_FAILURE);
- }
-
- auto *UO = cast<MachOUniversalBinary>(InputBinaries.front().getBinary());
- Expected<std::unique_ptr<MachOObjectFile>> Obj =
- UO->getMachOObjectForArch(ArchType);
+}
+
+LLVM_ATTRIBUTE_NORETURN
+static void printArchs(ArrayRef<OwningBinary<Binary>> InputBinaries) {
+ assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
+ printBinaryArchs(InputBinaries.front().getBinary(), outs());
+ exit(EXIT_SUCCESS);
+}
+
+LLVM_ATTRIBUTE_NORETURN
+static void printInfo(ArrayRef<OwningBinary<Binary>> InputBinaries) {
+ // Group universal and thin files together for compatibility with cctools lipo
+ for (auto &IB : InputBinaries) {
+ const Binary *Binary = IB.getBinary();
+ if (Binary->isMachOUniversalBinary()) {
+ outs() << "Architectures in the fat file: " << Binary->getFileName()
+ << " are: ";
+ printBinaryArchs(Binary, outs());
+ }
+ }
+ for (auto &IB : InputBinaries) {
+ const Binary *Binary = IB.getBinary();
+ if (!Binary->isMachOUniversalBinary()) {
+ assert(Binary->isMachO() && "expected MachO binary");
+ outs() << "Non-fat file: " << Binary->getFileName()
+ << " is architecture: ";
+ printBinaryArchs(Binary, outs());
+ }
+ }
+ exit(EXIT_SUCCESS);
+}
+
+LLVM_ATTRIBUTE_NORETURN
+static void thinSlice(ArrayRef<OwningBinary<Binary>> InputBinaries,
+ StringRef ArchType, StringRef OutputFileName) {
+ assert(!ArchType.empty() && "The architecture type should be non-empty");
+ assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
+ assert(!OutputFileName.empty() && "Thin expects a single output file");
+
+ if (InputBinaries.front().getBinary()->isMachO()) {
+ reportError("input file " +
+ InputBinaries.front().getBinary()->getFileName() +
+ " must be a fat file when the -thin option is specified");
+ exit(EXIT_FAILURE);
+ }
+
+ auto *UO = cast<MachOUniversalBinary>(InputBinaries.front().getBinary());
+ Expected<std::unique_ptr<MachOObjectFile>> Obj =
+ UO->getMachOObjectForArch(ArchType);
Expected<std::unique_ptr<IRObjectFile>> IRObj =
UO->getIRObjectForArch(ArchType, LLVMCtx);
- Expected<std::unique_ptr<Archive>> Ar = UO->getArchiveForArch(ArchType);
+ Expected<std::unique_ptr<Archive>> Ar = UO->getArchiveForArch(ArchType);
if (!Obj && !IRObj && !Ar)
- reportError("fat input file " + UO->getFileName() +
- " does not contain the specified architecture " + ArchType +
- " to thin it to");
+ reportError("fat input file " + UO->getFileName() +
+ " does not contain the specified architecture " + ArchType +
+ " to thin it to");
Binary *B;
// Order here is important, because both Obj and IRObj will be valid with a
// binary that has embedded bitcode.
@@ -497,72 +497,72 @@ static void thinSlice(ArrayRef<OwningBinary<Binary>> InputBinaries,
else
B = Ar->get();
- Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError =
- FileOutputBuffer::create(OutputFileName,
- B->getMemoryBufferRef().getBufferSize(),
- sys::fs::can_execute(UO->getFileName())
- ? FileOutputBuffer::F_executable
- : 0);
- if (!OutFileOrError)
- reportError(OutputFileName, OutFileOrError.takeError());
- std::copy(B->getMemoryBufferRef().getBufferStart(),
- B->getMemoryBufferRef().getBufferEnd(),
- OutFileOrError.get()->getBufferStart());
- if (Error E = OutFileOrError.get()->commit())
- reportError(OutputFileName, std::move(E));
- exit(EXIT_SUCCESS);
-}
-
-static void checkArchDuplicates(ArrayRef<Slice> Slices) {
- DenseMap<uint64_t, const Binary *> CPUIds;
- for (const auto &S : Slices) {
- auto Entry = CPUIds.try_emplace(S.getCPUID(), S.getBinary());
- if (!Entry.second)
- reportError(Entry.first->second->getFileName() + " and " +
- S.getBinary()->getFileName() +
- " have the same architecture " + S.getArchString() +
- " and therefore cannot be in the same universal binary");
- }
-}
-
-template <typename Range>
-static void updateAlignments(Range &Slices,
- const StringMap<const uint32_t> &Alignments) {
- for (auto &Slice : Slices) {
- auto Alignment = Alignments.find(Slice.getArchString());
- if (Alignment != Alignments.end())
- Slice.setP2Alignment(Alignment->second);
- }
-}
-
-static void checkUnusedAlignments(ArrayRef<Slice> Slices,
- const StringMap<const uint32_t> &Alignments) {
- auto HasArch = [&](StringRef Arch) {
+ Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError =
+ FileOutputBuffer::create(OutputFileName,
+ B->getMemoryBufferRef().getBufferSize(),
+ sys::fs::can_execute(UO->getFileName())
+ ? FileOutputBuffer::F_executable
+ : 0);
+ if (!OutFileOrError)
+ reportError(OutputFileName, OutFileOrError.takeError());
+ std::copy(B->getMemoryBufferRef().getBufferStart(),
+ B->getMemoryBufferRef().getBufferEnd(),
+ OutFileOrError.get()->getBufferStart());
+ if (Error E = OutFileOrError.get()->commit())
+ reportError(OutputFileName, std::move(E));
+ exit(EXIT_SUCCESS);
+}
+
+static void checkArchDuplicates(ArrayRef<Slice> Slices) {
+ DenseMap<uint64_t, const Binary *> CPUIds;
+ for (const auto &S : Slices) {
+ auto Entry = CPUIds.try_emplace(S.getCPUID(), S.getBinary());
+ if (!Entry.second)
+ reportError(Entry.first->second->getFileName() + " and " +
+ S.getBinary()->getFileName() +
+ " have the same architecture " + S.getArchString() +
+ " and therefore cannot be in the same universal binary");
+ }
+}
+
+template <typename Range>
+static void updateAlignments(Range &Slices,
+ const StringMap<const uint32_t> &Alignments) {
+ for (auto &Slice : Slices) {
+ auto Alignment = Alignments.find(Slice.getArchString());
+ if (Alignment != Alignments.end())
+ Slice.setP2Alignment(Alignment->second);
+ }
+}
+
+static void checkUnusedAlignments(ArrayRef<Slice> Slices,
+ const StringMap<const uint32_t> &Alignments) {
+ auto HasArch = [&](StringRef Arch) {
return llvm::any_of(Slices,
[Arch](Slice S) { return S.getArchString() == Arch; });
- };
- for (StringRef Arch : Alignments.keys())
- if (!HasArch(Arch))
- reportError("-segalign " + Arch +
- " <value> specified but resulting fat file does not contain "
- "that architecture ");
-}
-
-// Updates vector ExtractedObjects with the MachOObjectFiles extracted from
-// Universal Binary files to transfer ownership.
+ };
+ for (StringRef Arch : Alignments.keys())
+ if (!HasArch(Arch))
+ reportError("-segalign " + Arch +
+ " <value> specified but resulting fat file does not contain "
+ "that architecture ");
+}
+
+// Updates vector ExtractedObjects with the MachOObjectFiles extracted from
+// Universal Binary files to transfer ownership.
static SmallVector<Slice, 2>
buildSlices(ArrayRef<OwningBinary<Binary>> InputBinaries,
const StringMap<const uint32_t> &Alignments,
SmallVectorImpl<std::unique_ptr<SymbolicFile>> &ExtractedObjects) {
- SmallVector<Slice, 2> Slices;
- for (auto &IB : InputBinaries) {
- const Binary *InputBinary = IB.getBinary();
- if (auto UO = dyn_cast<MachOUniversalBinary>(InputBinary)) {
- for (const auto &O : UO->objects()) {
+ SmallVector<Slice, 2> Slices;
+ for (auto &IB : InputBinaries) {
+ const Binary *InputBinary = IB.getBinary();
+ if (auto UO = dyn_cast<MachOUniversalBinary>(InputBinary)) {
+ for (const auto &O : UO->objects()) {
// Order here is important, because both MachOObjectFile and
// IRObjectFile can be created with a binary that has embedded bitcode.
- Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError =
- O.getAsObjectFile();
+ Expected<std::unique_ptr<MachOObjectFile>> BinaryOrError =
+ O.getAsObjectFile();
if (BinaryOrError) {
Slices.emplace_back(*(BinaryOrError.get()), O.getAlign());
ExtractedObjects.push_back(std::move(BinaryOrError.get()));
@@ -578,7 +578,7 @@ buildSlices(ArrayRef<OwningBinary<Binary>> InputBinaries,
continue;
}
reportError(InputBinary->getFileName(), BinaryOrError.takeError());
- }
+ }
} else if (const auto *O = dyn_cast<MachOObjectFile>(InputBinary)) {
Slices.emplace_back(*O);
} else if (const auto *A = dyn_cast<Archive>(InputBinary)) {
@@ -591,166 +591,166 @@ buildSlices(ArrayRef<OwningBinary<Binary>> InputBinaries,
continue;
}
Slices.emplace_back(std::move(SliceOrErr.get()));
- } else {
- llvm_unreachable("Unexpected binary format");
- }
- }
- updateAlignments(Slices, Alignments);
- return Slices;
-}
-
-LLVM_ATTRIBUTE_NORETURN
-static void createUniversalBinary(ArrayRef<OwningBinary<Binary>> InputBinaries,
- const StringMap<const uint32_t> &Alignments,
- StringRef OutputFileName) {
- assert(InputBinaries.size() >= 1 && "Incorrect number of input binaries");
- assert(!OutputFileName.empty() && "Create expects a single output file");
-
+ } else {
+ llvm_unreachable("Unexpected binary format");
+ }
+ }
+ updateAlignments(Slices, Alignments);
+ return Slices;
+}
+
+LLVM_ATTRIBUTE_NORETURN
+static void createUniversalBinary(ArrayRef<OwningBinary<Binary>> InputBinaries,
+ const StringMap<const uint32_t> &Alignments,
+ StringRef OutputFileName) {
+ assert(InputBinaries.size() >= 1 && "Incorrect number of input binaries");
+ assert(!OutputFileName.empty() && "Create expects a single output file");
+
SmallVector<std::unique_ptr<SymbolicFile>, 1> ExtractedObjects;
- SmallVector<Slice, 1> Slices =
- buildSlices(InputBinaries, Alignments, ExtractedObjects);
- checkArchDuplicates(Slices);
- checkUnusedAlignments(Slices, Alignments);
-
+ SmallVector<Slice, 1> Slices =
+ buildSlices(InputBinaries, Alignments, ExtractedObjects);
+ checkArchDuplicates(Slices);
+ checkUnusedAlignments(Slices, Alignments);
+
llvm::stable_sort(Slices);
if (Error E = writeUniversalBinary(Slices, OutputFileName))
reportError(std::move(E));
- exit(EXIT_SUCCESS);
-}
-
-LLVM_ATTRIBUTE_NORETURN
-static void extractSlice(ArrayRef<OwningBinary<Binary>> InputBinaries,
- const StringMap<const uint32_t> &Alignments,
- StringRef ArchType, StringRef OutputFileName) {
- assert(!ArchType.empty() &&
- "The architecture type should be non-empty");
- assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
- assert(!OutputFileName.empty() && "Thin expects a single output file");
-
- if (InputBinaries.front().getBinary()->isMachO()) {
- reportError("input file " +
- InputBinaries.front().getBinary()->getFileName() +
- " must be a fat file when the -extract option is specified");
- }
-
+ exit(EXIT_SUCCESS);
+}
+
+LLVM_ATTRIBUTE_NORETURN
+static void extractSlice(ArrayRef<OwningBinary<Binary>> InputBinaries,
+ const StringMap<const uint32_t> &Alignments,
+ StringRef ArchType, StringRef OutputFileName) {
+ assert(!ArchType.empty() &&
+ "The architecture type should be non-empty");
+ assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
+ assert(!OutputFileName.empty() && "Thin expects a single output file");
+
+ if (InputBinaries.front().getBinary()->isMachO()) {
+ reportError("input file " +
+ InputBinaries.front().getBinary()->getFileName() +
+ " must be a fat file when the -extract option is specified");
+ }
+
SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects;
- SmallVector<Slice, 2> Slices =
- buildSlices(InputBinaries, Alignments, ExtractedObjects);
- erase_if(Slices, [ArchType](const Slice &S) {
- return ArchType != S.getArchString();
- });
-
- if (Slices.empty())
- reportError(
- "fat input file " + InputBinaries.front().getBinary()->getFileName() +
- " does not contain the specified architecture " + ArchType);
+ SmallVector<Slice, 2> Slices =
+ buildSlices(InputBinaries, Alignments, ExtractedObjects);
+ erase_if(Slices, [ArchType](const Slice &S) {
+ return ArchType != S.getArchString();
+ });
+
+ if (Slices.empty())
+ reportError(
+ "fat input file " + InputBinaries.front().getBinary()->getFileName() +
+ " does not contain the specified architecture " + ArchType);
llvm::stable_sort(Slices);
if (Error E = writeUniversalBinary(Slices, OutputFileName))
reportError(std::move(E));
- exit(EXIT_SUCCESS);
-}
-
-static StringMap<Slice>
-buildReplacementSlices(ArrayRef<OwningBinary<Binary>> ReplacementBinaries,
- const StringMap<const uint32_t> &Alignments) {
- StringMap<Slice> Slices;
- // populates StringMap of slices to replace with; error checks for mismatched
- // replace flag args, fat files, and duplicate arch_types
- for (const auto &OB : ReplacementBinaries) {
- const Binary *ReplacementBinary = OB.getBinary();
- auto O = dyn_cast<MachOObjectFile>(ReplacementBinary);
- if (!O)
- reportError("replacement file: " + ReplacementBinary->getFileName() +
- " is a fat file (must be a thin file)");
+ exit(EXIT_SUCCESS);
+}
+
+static StringMap<Slice>
+buildReplacementSlices(ArrayRef<OwningBinary<Binary>> ReplacementBinaries,
+ const StringMap<const uint32_t> &Alignments) {
+ StringMap<Slice> Slices;
+ // populates StringMap of slices to replace with; error checks for mismatched
+ // replace flag args, fat files, and duplicate arch_types
+ for (const auto &OB : ReplacementBinaries) {
+ const Binary *ReplacementBinary = OB.getBinary();
+ auto O = dyn_cast<MachOObjectFile>(ReplacementBinary);
+ if (!O)
+ reportError("replacement file: " + ReplacementBinary->getFileName() +
+ " is a fat file (must be a thin file)");
Slice S(*O);
- auto Entry = Slices.try_emplace(S.getArchString(), S);
- if (!Entry.second)
- reportError("-replace " + S.getArchString() +
- " <file_name> specified multiple times: " +
- Entry.first->second.getBinary()->getFileName() + ", " +
- O->getFileName());
- }
- auto SlicesMapRange = map_range(
- Slices, [](StringMapEntry<Slice> &E) -> Slice & { return E.getValue(); });
- updateAlignments(SlicesMapRange, Alignments);
- return Slices;
-}
-
-LLVM_ATTRIBUTE_NORETURN
-static void replaceSlices(ArrayRef<OwningBinary<Binary>> InputBinaries,
- const StringMap<const uint32_t> &Alignments,
- StringRef OutputFileName,
- ArrayRef<InputFile> ReplacementFiles) {
- assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
- assert(!OutputFileName.empty() && "Replace expects a single output file");
-
- if (InputBinaries.front().getBinary()->isMachO())
- reportError("input file " +
- InputBinaries.front().getBinary()->getFileName() +
- " must be a fat file when the -replace option is specified");
-
- SmallVector<OwningBinary<Binary>, 1> ReplacementBinaries =
- readInputBinaries(ReplacementFiles);
-
- StringMap<Slice> ReplacementSlices =
- buildReplacementSlices(ReplacementBinaries, Alignments);
+ auto Entry = Slices.try_emplace(S.getArchString(), S);
+ if (!Entry.second)
+ reportError("-replace " + S.getArchString() +
+ " <file_name> specified multiple times: " +
+ Entry.first->second.getBinary()->getFileName() + ", " +
+ O->getFileName());
+ }
+ auto SlicesMapRange = map_range(
+ Slices, [](StringMapEntry<Slice> &E) -> Slice & { return E.getValue(); });
+ updateAlignments(SlicesMapRange, Alignments);
+ return Slices;
+}
+
+LLVM_ATTRIBUTE_NORETURN
+static void replaceSlices(ArrayRef<OwningBinary<Binary>> InputBinaries,
+ const StringMap<const uint32_t> &Alignments,
+ StringRef OutputFileName,
+ ArrayRef<InputFile> ReplacementFiles) {
+ assert(InputBinaries.size() == 1 && "Incorrect number of input binaries");
+ assert(!OutputFileName.empty() && "Replace expects a single output file");
+
+ if (InputBinaries.front().getBinary()->isMachO())
+ reportError("input file " +
+ InputBinaries.front().getBinary()->getFileName() +
+ " must be a fat file when the -replace option is specified");
+
+ SmallVector<OwningBinary<Binary>, 1> ReplacementBinaries =
+ readInputBinaries(ReplacementFiles);
+
+ StringMap<Slice> ReplacementSlices =
+ buildReplacementSlices(ReplacementBinaries, Alignments);
SmallVector<std::unique_ptr<SymbolicFile>, 2> ExtractedObjects;
- SmallVector<Slice, 2> Slices =
- buildSlices(InputBinaries, Alignments, ExtractedObjects);
-
- for (auto &Slice : Slices) {
- auto It = ReplacementSlices.find(Slice.getArchString());
- if (It != ReplacementSlices.end()) {
- Slice = It->second;
- ReplacementSlices.erase(It); // only keep remaining replacing arch_types
- }
- }
-
- if (!ReplacementSlices.empty())
- reportError("-replace " + ReplacementSlices.begin()->first() +
- " <file_name> specified but fat file: " +
- InputBinaries.front().getBinary()->getFileName() +
- " does not contain that architecture");
-
- checkUnusedAlignments(Slices, Alignments);
+ SmallVector<Slice, 2> Slices =
+ buildSlices(InputBinaries, Alignments, ExtractedObjects);
+
+ for (auto &Slice : Slices) {
+ auto It = ReplacementSlices.find(Slice.getArchString());
+ if (It != ReplacementSlices.end()) {
+ Slice = It->second;
+ ReplacementSlices.erase(It); // only keep remaining replacing arch_types
+ }
+ }
+
+ if (!ReplacementSlices.empty())
+ reportError("-replace " + ReplacementSlices.begin()->first() +
+ " <file_name> specified but fat file: " +
+ InputBinaries.front().getBinary()->getFileName() +
+ " does not contain that architecture");
+
+ checkUnusedAlignments(Slices, Alignments);
llvm::stable_sort(Slices);
if (Error E = writeUniversalBinary(Slices, OutputFileName))
reportError(std::move(E));
- exit(EXIT_SUCCESS);
-}
-
-int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
- Config C = parseLipoOptions(makeArrayRef(argv + 1, argc));
- SmallVector<OwningBinary<Binary>, 1> InputBinaries =
- readInputBinaries(C.InputFiles);
-
- switch (C.ActionToPerform) {
- case LipoAction::VerifyArch:
- verifyArch(InputBinaries, C.VerifyArchList);
- break;
- case LipoAction::PrintArchs:
- printArchs(InputBinaries);
- break;
- case LipoAction::PrintInfo:
- printInfo(InputBinaries);
- break;
- case LipoAction::ThinArch:
- thinSlice(InputBinaries, C.ArchType, C.OutputFile);
- break;
- case LipoAction::ExtractArch:
- extractSlice(InputBinaries, C.SegmentAlignments, C.ArchType, C.OutputFile);
- break;
- case LipoAction::CreateUniversal:
- createUniversalBinary(InputBinaries, C.SegmentAlignments, C.OutputFile);
- break;
- case LipoAction::ReplaceArch:
- replaceSlices(InputBinaries, C.SegmentAlignments, C.OutputFile,
- C.ReplacementFiles);
- break;
- }
- return EXIT_SUCCESS;
-}
+ exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char **argv) {
+ InitLLVM X(argc, argv);
+ Config C = parseLipoOptions(makeArrayRef(argv + 1, argc));
+ SmallVector<OwningBinary<Binary>, 1> InputBinaries =
+ readInputBinaries(C.InputFiles);
+
+ switch (C.ActionToPerform) {
+ case LipoAction::VerifyArch:
+ verifyArch(InputBinaries, C.VerifyArchList);
+ break;
+ case LipoAction::PrintArchs:
+ printArchs(InputBinaries);
+ break;
+ case LipoAction::PrintInfo:
+ printInfo(InputBinaries);
+ break;
+ case LipoAction::ThinArch:
+ thinSlice(InputBinaries, C.ArchType, C.OutputFile);
+ break;
+ case LipoAction::ExtractArch:
+ extractSlice(InputBinaries, C.SegmentAlignments, C.ArchType, C.OutputFile);
+ break;
+ case LipoAction::CreateUniversal:
+ createUniversalBinary(InputBinaries, C.SegmentAlignments, C.OutputFile);
+ break;
+ case LipoAction::ReplaceArch:
+ replaceSlices(InputBinaries, C.SegmentAlignments, C.OutputFile,
+ C.ReplacementFiles);
+ break;
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/contrib/libs/llvm12/tools/llvm-lipo/ya.make b/contrib/libs/llvm12/tools/llvm-lipo/ya.make
index afb28b31ce..157bfe611e 100644
--- a/contrib/libs/llvm12/tools/llvm-lipo/ya.make
+++ b/contrib/libs/llvm12/tools/llvm-lipo/ya.make
@@ -1,17 +1,17 @@
-# Generated by devtools/yamaker.
-
-PROGRAM()
-
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
-
+
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/BinaryFormat
@@ -56,19 +56,19 @@ PEERDIR(
contrib/libs/llvm12/lib/Target/X86/MCTargetDesc
contrib/libs/llvm12/lib/Target/X86/TargetInfo
contrib/libs/llvm12/lib/TextAPI/MachO
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/llvm-lipo
contrib/libs/llvm12/tools/llvm-lipo
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- llvm-lipo.cpp
-)
-
-END()
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ llvm-lipo.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm12/tools/llvm-ml/Disassembler.cpp b/contrib/libs/llvm12/tools/llvm-ml/Disassembler.cpp
index 8eeddb7179..a7fec3c35d 100644
--- a/contrib/libs/llvm12/tools/llvm-ml/Disassembler.cpp
+++ b/contrib/libs/llvm12/tools/llvm-ml/Disassembler.cpp
@@ -1,203 +1,203 @@
-//===- Disassembler.cpp - Disassembler for hex strings --------------------===//
-//
-// 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 class implements the disassembler of strings of bytes written in
-// hexadecimal, from standard input or from a file.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Disassembler.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCDisassembler/MCDisassembler.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-
-typedef std::pair<std::vector<unsigned char>, std::vector<const char *>>
- ByteArrayTy;
-
-static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
- SourceMgr &SM, raw_ostream &Out, MCStreamer &Streamer,
- bool InAtomicBlock, const MCSubtargetInfo &STI) {
- ArrayRef<uint8_t> Data(Bytes.first.data(), Bytes.first.size());
-
- // Disassemble it to strings.
- uint64_t Size;
- uint64_t Index;
-
- for (Index = 0; Index < Bytes.first.size(); Index += Size) {
- MCInst Inst;
-
- MCDisassembler::DecodeStatus S;
- S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls());
- switch (S) {
- case MCDisassembler::Fail:
- SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
- SourceMgr::DK_Warning, "invalid instruction encoding");
- // Don't try to resynchronise the stream in a block
- if (InAtomicBlock)
- return true;
-
- if (Size == 0)
- Size = 1; // skip illegible bytes
-
- break;
-
- case MCDisassembler::SoftFail:
- SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
- SourceMgr::DK_Warning,
- "potentially undefined instruction encoding");
- LLVM_FALLTHROUGH;
-
- case MCDisassembler::Success:
- Streamer.emitInstruction(Inst, STI);
- break;
- }
- }
-
- return false;
-}
-
-static bool SkipToToken(StringRef &Str) {
- for (;;) {
- if (Str.empty())
- return false;
-
- // Strip horizontal whitespace and commas.
- if (size_t Pos = Str.find_first_not_of(" \t\r\n,")) {
- Str = Str.substr(Pos);
- continue;
- }
-
- // If this is the start of a comment, remove the rest of the line.
- if (Str[0] == '#') {
- Str = Str.substr(Str.find_first_of('\n'));
- continue;
- }
- return true;
- }
-}
-
-static bool ByteArrayFromString(ByteArrayTy &ByteArray, StringRef &Str,
- SourceMgr &SM) {
- while (SkipToToken(Str)) {
- // Handled by higher level
- if (Str[0] == '[' || Str[0] == ']')
- return false;
-
- // Get the current token.
- size_t Next = Str.find_first_of(" \t\n\r,#[]");
- StringRef Value = Str.substr(0, Next);
-
- // Convert to a byte and add to the byte vector.
- unsigned ByteVal;
- if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) {
- // If we have an error, print it and skip to the end of line.
- SM.PrintMessage(SMLoc::getFromPointer(Value.data()), SourceMgr::DK_Error,
- "invalid input token");
- Str = Str.substr(Str.find('\n'));
- ByteArray.first.clear();
- ByteArray.second.clear();
- continue;
- }
-
- ByteArray.first.push_back(ByteVal);
- ByteArray.second.push_back(Value.data());
- Str = Str.substr(Next);
- }
-
- return false;
-}
-
-int Disassembler::disassemble(const Target &T, const std::string &Triple,
- MCSubtargetInfo &STI, MCStreamer &Streamer,
- MemoryBuffer &Buffer, SourceMgr &SM,
- raw_ostream &Out) {
- std::unique_ptr<const MCRegisterInfo> MRI(T.createMCRegInfo(Triple));
- if (!MRI) {
- errs() << "error: no register info for target " << Triple << "\n";
- return -1;
- }
-
- MCTargetOptions MCOptions;
- std::unique_ptr<const MCAsmInfo> MAI(
- T.createMCAsmInfo(*MRI, Triple, MCOptions));
- if (!MAI) {
- errs() << "error: no assembly info for target " << Triple << "\n";
- return -1;
- }
-
- // Set up the MCContext for creating symbols and MCExpr's.
- MCContext Ctx(MAI.get(), MRI.get(), nullptr);
-
- std::unique_ptr<const MCDisassembler> DisAsm(
- T.createMCDisassembler(STI, Ctx));
- if (!DisAsm) {
- errs() << "error: no disassembler for target " << Triple << "\n";
- return -1;
- }
-
- // Set up initial section manually here
- Streamer.InitSections(false);
-
- bool ErrorOccurred = false;
-
- // Convert the input to a vector for disassembly.
- ByteArrayTy ByteArray;
- StringRef Str = Buffer.getBuffer();
- bool InAtomicBlock = false;
-
- while (SkipToToken(Str)) {
- ByteArray.first.clear();
- ByteArray.second.clear();
-
- if (Str[0] == '[') {
- if (InAtomicBlock) {
- SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
- "nested atomic blocks make no sense");
- ErrorOccurred = true;
- }
- InAtomicBlock = true;
- Str = Str.drop_front();
- continue;
- } else if (Str[0] == ']') {
- if (!InAtomicBlock) {
- SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
- "attempt to close atomic block without opening");
- ErrorOccurred = true;
- }
- InAtomicBlock = false;
- Str = Str.drop_front();
- continue;
- }
-
- // It's a real token, get the bytes and emit them
- ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM);
-
- if (!ByteArray.first.empty())
- ErrorOccurred |=
- PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer, InAtomicBlock, STI);
- }
-
- if (InAtomicBlock) {
- SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
- "unclosed atomic block");
- ErrorOccurred = true;
- }
-
- return ErrorOccurred;
-}
+//===- Disassembler.cpp - Disassembler for hex strings --------------------===//
+//
+// 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 class implements the disassembler of strings of bytes written in
+// hexadecimal, from standard input or from a file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Disassembler.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+typedef std::pair<std::vector<unsigned char>, std::vector<const char *>>
+ ByteArrayTy;
+
+static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
+ SourceMgr &SM, raw_ostream &Out, MCStreamer &Streamer,
+ bool InAtomicBlock, const MCSubtargetInfo &STI) {
+ ArrayRef<uint8_t> Data(Bytes.first.data(), Bytes.first.size());
+
+ // Disassemble it to strings.
+ uint64_t Size;
+ uint64_t Index;
+
+ for (Index = 0; Index < Bytes.first.size(); Index += Size) {
+ MCInst Inst;
+
+ MCDisassembler::DecodeStatus S;
+ S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls());
+ switch (S) {
+ case MCDisassembler::Fail:
+ SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
+ SourceMgr::DK_Warning, "invalid instruction encoding");
+ // Don't try to resynchronise the stream in a block
+ if (InAtomicBlock)
+ return true;
+
+ if (Size == 0)
+ Size = 1; // skip illegible bytes
+
+ break;
+
+ case MCDisassembler::SoftFail:
+ SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
+ SourceMgr::DK_Warning,
+ "potentially undefined instruction encoding");
+ LLVM_FALLTHROUGH;
+
+ case MCDisassembler::Success:
+ Streamer.emitInstruction(Inst, STI);
+ break;
+ }
+ }
+
+ return false;
+}
+
+static bool SkipToToken(StringRef &Str) {
+ for (;;) {
+ if (Str.empty())
+ return false;
+
+ // Strip horizontal whitespace and commas.
+ if (size_t Pos = Str.find_first_not_of(" \t\r\n,")) {
+ Str = Str.substr(Pos);
+ continue;
+ }
+
+ // If this is the start of a comment, remove the rest of the line.
+ if (Str[0] == '#') {
+ Str = Str.substr(Str.find_first_of('\n'));
+ continue;
+ }
+ return true;
+ }
+}
+
+static bool ByteArrayFromString(ByteArrayTy &ByteArray, StringRef &Str,
+ SourceMgr &SM) {
+ while (SkipToToken(Str)) {
+ // Handled by higher level
+ if (Str[0] == '[' || Str[0] == ']')
+ return false;
+
+ // Get the current token.
+ size_t Next = Str.find_first_of(" \t\n\r,#[]");
+ StringRef Value = Str.substr(0, Next);
+
+ // Convert to a byte and add to the byte vector.
+ unsigned ByteVal;
+ if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) {
+ // If we have an error, print it and skip to the end of line.
+ SM.PrintMessage(SMLoc::getFromPointer(Value.data()), SourceMgr::DK_Error,
+ "invalid input token");
+ Str = Str.substr(Str.find('\n'));
+ ByteArray.first.clear();
+ ByteArray.second.clear();
+ continue;
+ }
+
+ ByteArray.first.push_back(ByteVal);
+ ByteArray.second.push_back(Value.data());
+ Str = Str.substr(Next);
+ }
+
+ return false;
+}
+
+int Disassembler::disassemble(const Target &T, const std::string &Triple,
+ MCSubtargetInfo &STI, MCStreamer &Streamer,
+ MemoryBuffer &Buffer, SourceMgr &SM,
+ raw_ostream &Out) {
+ std::unique_ptr<const MCRegisterInfo> MRI(T.createMCRegInfo(Triple));
+ if (!MRI) {
+ errs() << "error: no register info for target " << Triple << "\n";
+ return -1;
+ }
+
+ MCTargetOptions MCOptions;
+ std::unique_ptr<const MCAsmInfo> MAI(
+ T.createMCAsmInfo(*MRI, Triple, MCOptions));
+ if (!MAI) {
+ errs() << "error: no assembly info for target " << Triple << "\n";
+ return -1;
+ }
+
+ // Set up the MCContext for creating symbols and MCExpr's.
+ MCContext Ctx(MAI.get(), MRI.get(), nullptr);
+
+ std::unique_ptr<const MCDisassembler> DisAsm(
+ T.createMCDisassembler(STI, Ctx));
+ if (!DisAsm) {
+ errs() << "error: no disassembler for target " << Triple << "\n";
+ return -1;
+ }
+
+ // Set up initial section manually here
+ Streamer.InitSections(false);
+
+ bool ErrorOccurred = false;
+
+ // Convert the input to a vector for disassembly.
+ ByteArrayTy ByteArray;
+ StringRef Str = Buffer.getBuffer();
+ bool InAtomicBlock = false;
+
+ while (SkipToToken(Str)) {
+ ByteArray.first.clear();
+ ByteArray.second.clear();
+
+ if (Str[0] == '[') {
+ if (InAtomicBlock) {
+ SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
+ "nested atomic blocks make no sense");
+ ErrorOccurred = true;
+ }
+ InAtomicBlock = true;
+ Str = Str.drop_front();
+ continue;
+ } else if (Str[0] == ']') {
+ if (!InAtomicBlock) {
+ SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
+ "attempt to close atomic block without opening");
+ ErrorOccurred = true;
+ }
+ InAtomicBlock = false;
+ Str = Str.drop_front();
+ continue;
+ }
+
+ // It's a real token, get the bytes and emit them
+ ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM);
+
+ if (!ByteArray.first.empty())
+ ErrorOccurred |=
+ PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer, InAtomicBlock, STI);
+ }
+
+ if (InAtomicBlock) {
+ SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
+ "unclosed atomic block");
+ ErrorOccurred = true;
+ }
+
+ return ErrorOccurred;
+}
diff --git a/contrib/libs/llvm12/tools/llvm-ml/Disassembler.h b/contrib/libs/llvm12/tools/llvm-ml/Disassembler.h
index d3565089e2..f54bab3239 100644
--- a/contrib/libs/llvm12/tools/llvm-ml/Disassembler.h
+++ b/contrib/libs/llvm12/tools/llvm-ml/Disassembler.h
@@ -1,37 +1,37 @@
-//===- Disassembler.h - Text File Disassembler ----------------------------===//
-//
-// 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 class implements the disassembler of strings of bytes written in
-// hexadecimal, from standard input or from a file.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVM_MC_DISASSEMBLER_H
-#define LLVM_TOOLS_LLVM_MC_DISASSEMBLER_H
-
-#include <string>
-
-namespace llvm {
-
-class MemoryBuffer;
-class Target;
-class raw_ostream;
-class SourceMgr;
-class MCSubtargetInfo;
-class MCStreamer;
-
-class Disassembler {
-public:
- static int disassemble(const Target &T, const std::string &Triple,
- MCSubtargetInfo &STI, MCStreamer &Streamer,
- MemoryBuffer &Buffer, SourceMgr &SM, raw_ostream &Out);
-};
-
-} // namespace llvm
-
-#endif
+//===- Disassembler.h - Text File Disassembler ----------------------------===//
+//
+// 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 class implements the disassembler of strings of bytes written in
+// hexadecimal, from standard input or from a file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_MC_DISASSEMBLER_H
+#define LLVM_TOOLS_LLVM_MC_DISASSEMBLER_H
+
+#include <string>
+
+namespace llvm {
+
+class MemoryBuffer;
+class Target;
+class raw_ostream;
+class SourceMgr;
+class MCSubtargetInfo;
+class MCStreamer;
+
+class Disassembler {
+public:
+ static int disassemble(const Target &T, const std::string &Triple,
+ MCSubtargetInfo &STI, MCStreamer &Streamer,
+ MemoryBuffer &Buffer, SourceMgr &SM, raw_ostream &Out);
+};
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-ml/llvm-ml.cpp b/contrib/libs/llvm12/tools/llvm-ml/llvm-ml.cpp
index 1733dcd472..8ac253723e 100644
--- a/contrib/libs/llvm12/tools/llvm-ml/llvm-ml.cpp
+++ b/contrib/libs/llvm12/tools/llvm-ml/llvm-ml.cpp
@@ -1,52 +1,52 @@
-//===-- llvm-ml.cpp - masm-compatible assembler -----------------*- 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
-//
-//===----------------------------------------------------------------------===//
-//
-// A simple driver around MasmParser; based on llvm-mc.
-//
-//===----------------------------------------------------------------------===//
-
+//===-- llvm-ml.cpp - masm-compatible assembler -----------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// A simple driver around MasmParser; based on llvm-mc.
+//
+//===----------------------------------------------------------------------===//
+
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/MC/MCAsmBackend.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCCodeEmitter.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCObjectWriter.h"
-#include "llvm/MC/MCParser/AsmLexer.h"
-#include "llvm/MC/MCParser/MCTargetAsmParser.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCParser/AsmLexer.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
-#include "llvm/Support/Compression.h"
-#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/FormattedStream.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/TargetSelect.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/WithColor.h"
-
-using namespace llvm;
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+
+using namespace llvm;
using namespace llvm::opt;
-
+
namespace {
-
+
enum ID {
OPT_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
@@ -54,12 +54,12 @@ enum ID {
OPT_##ID,
#include "Opts.inc"
#undef OPTION
-};
-
+};
+
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Opts.inc"
#undef PREFIX
-
+
static const opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
@@ -70,83 +70,83 @@ static const opt::OptTable::Info InfoTable[] = {
OPT_##ALIAS, ALIASARGS, VALUES},
#include "Opts.inc"
#undef OPTION
-};
-
+};
+
class MLOptTable : public opt::OptTable {
public:
MLOptTable() : OptTable(InfoTable, /*IgnoreCase=*/false) {}
-};
+};
} // namespace
-
+
static Triple GetTriple(StringRef ProgName, opt::InputArgList &Args) {
- // Figure out the target triple.
+ // Figure out the target triple.
StringRef DefaultBitness = "32";
SmallString<255> Program = ProgName;
sys::path::replace_extension(Program, "");
if (Program.endswith("ml64"))
DefaultBitness = "64";
-
+
StringRef TripleName =
StringSwitch<StringRef>(Args.getLastArgValue(OPT_bitness, DefaultBitness))
.Case("32", "i386-pc-windows")
.Case("64", "x86_64-pc-windows")
.Default("");
return Triple(Triple::normalize(TripleName));
-}
-
-static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path) {
- std::error_code EC;
- auto Out = std::make_unique<ToolOutputFile>(Path, EC, sys::fs::F_None);
- if (EC) {
- WithColor::error() << EC.message() << '\n';
- return nullptr;
- }
-
- return Out;
-}
-
-static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) {
- AsmLexer Lexer(MAI);
- Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer());
+}
+
+static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path) {
+ std::error_code EC;
+ auto Out = std::make_unique<ToolOutputFile>(Path, EC, sys::fs::F_None);
+ if (EC) {
+ WithColor::error() << EC.message() << '\n';
+ return nullptr;
+ }
+
+ return Out;
+}
+
+static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, raw_ostream &OS) {
+ AsmLexer Lexer(MAI);
+ Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer());
Lexer.setLexMasmIntegers(true);
Lexer.useMasmDefaultRadix(true);
Lexer.setLexMasmHexFloats(true);
Lexer.setLexMasmStrings(true);
-
- bool Error = false;
- while (Lexer.Lex().isNot(AsmToken::Eof)) {
- Lexer.getTok().dump(OS);
- OS << "\n";
- if (Lexer.getTok().getKind() == AsmToken::Error)
- Error = true;
- }
-
- return Error;
-}
-
+
+ bool Error = false;
+ while (Lexer.Lex().isNot(AsmToken::Eof)) {
+ Lexer.getTok().dump(OS);
+ OS << "\n";
+ if (Lexer.getTok().getKind() == AsmToken::Error)
+ Error = true;
+ }
+
+ return Error;
+}
+
static int AssembleInput(StringRef ProgName, const Target *TheTarget,
- SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,
- MCAsmInfo &MAI, MCSubtargetInfo &STI,
+ SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,
+ MCAsmInfo &MAI, MCSubtargetInfo &STI,
MCInstrInfo &MCII, MCTargetOptions &MCOptions,
const opt::ArgList &InputArgs) {
- std::unique_ptr<MCAsmParser> Parser(
+ std::unique_ptr<MCAsmParser> Parser(
createMCMasmParser(SrcMgr, Ctx, Str, MAI, 0));
- std::unique_ptr<MCTargetAsmParser> TAP(
- TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
-
- if (!TAP) {
- WithColor::error(errs(), ProgName)
- << "this target does not support assembly parsing.\n";
- return 1;
- }
-
+ std::unique_ptr<MCTargetAsmParser> TAP(
+ TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
+
+ if (!TAP) {
+ WithColor::error(errs(), ProgName)
+ << "this target does not support assembly parsing.\n";
+ return 1;
+ }
+
Parser->setShowParsedOperands(InputArgs.hasArg(OPT_show_inst_operands));
- Parser->setTargetParser(*TAP);
- Parser->getLexer().setLexMasmIntegers(true);
+ Parser->setTargetParser(*TAP);
+ Parser->getLexer().setLexMasmIntegers(true);
Parser->getLexer().useMasmDefaultRadix(true);
Parser->getLexer().setLexMasmHexFloats(true);
Parser->getLexer().setLexMasmStrings(true);
-
+
auto Defines = InputArgs.getAllArgValues(OPT_define);
for (StringRef Define : Defines) {
const auto NameValue = Define.split('=');
@@ -158,27 +158,27 @@ static int AssembleInput(StringRef ProgName, const Target *TheTarget,
}
}
- int Res = Parser->Run(/*NoInitialTextSection=*/true);
-
- return Res;
-}
-
+ int Res = Parser->Run(/*NoInitialTextSection=*/true);
+
+ return Res;
+}
+
int main(int Argc, char **Argv) {
InitLLVM X(Argc, Argv);
StringRef ProgName = sys::path::filename(Argv[0]);
-
- // Initialize targets and assembly printers/parsers.
- llvm::InitializeAllTargetInfos();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllAsmParsers();
- llvm::InitializeAllDisassemblers();
-
+
+ // Initialize targets and assembly printers/parsers.
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+ llvm::InitializeAllDisassemblers();
+
MLOptTable T;
unsigned MissingArgIndex, MissingArgCount;
ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
opt::InputArgList InputArgs =
T.ParseArgs(ArgsArr, MissingArgIndex, MissingArgCount);
-
+
std::string InputFilename;
for (auto *Arg : InputArgs.filtered(OPT_INPUT)) {
std::string ArgString = Arg->getAsString(InputArgs);
@@ -230,17 +230,17 @@ int main(int Argc, char **Argv) {
}
MCTargetOptions MCOptions;
- MCOptions.AssemblyLanguage = "masm";
-
+ MCOptions.AssemblyLanguage = "masm";
+
Triple TheTriple = GetTriple(ProgName, InputArgs);
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget("", TheTriple, Error);
if (!TheTarget) {
WithColor::error(errs(), ProgName) << Error;
- return 1;
+ return 1;
}
const std::string &TripleName = TheTriple.getTriple();
-
+
bool SafeSEH = InputArgs.hasArg(OPT_safeseh);
if (SafeSEH && !(TheTriple.isArch32Bit() && TheTriple.isX86())) {
WithColor::warning()
@@ -248,42 +248,42 @@ int main(int Argc, char **Argv) {
SafeSEH = false;
}
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr =
- MemoryBuffer::getFileOrSTDIN(InputFilename);
- if (std::error_code EC = BufferPtr.getError()) {
- WithColor::error(errs(), ProgName)
- << InputFilename << ": " << EC.message() << '\n';
- return 1;
- }
-
- SourceMgr SrcMgr;
-
- // Tell SrcMgr about this buffer, which is what the parser will pick up.
- SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc());
-
- // Record the location of the include directories so that the lexer can find
- // it later.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr =
+ MemoryBuffer::getFileOrSTDIN(InputFilename);
+ if (std::error_code EC = BufferPtr.getError()) {
+ WithColor::error(errs(), ProgName)
+ << InputFilename << ": " << EC.message() << '\n';
+ return 1;
+ }
+
+ SourceMgr SrcMgr;
+
+ // Tell SrcMgr about this buffer, which is what the parser will pick up.
+ SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc());
+
+ // Record the location of the include directories so that the lexer can find
+ // it later.
SrcMgr.setIncludeDirs(InputArgs.getAllArgValues(OPT_include_path));
-
- std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
- assert(MRI && "Unable to create target register info!");
-
- std::unique_ptr<MCAsmInfo> MAI(
- TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
- assert(MAI && "Unable to create target asm info!");
-
+
+ std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
+ assert(MRI && "Unable to create target register info!");
+
+ std::unique_ptr<MCAsmInfo> MAI(
+ TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
+ assert(MAI && "Unable to create target asm info!");
+
MAI->setPreserveAsmComments(InputArgs.hasArg(OPT_preserve_comments));
-
- // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
- // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
- MCObjectFileInfo MOFI;
- MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr);
- MOFI.InitMCObjectFileInfo(TheTriple, /*PIC=*/false, Ctx,
- /*LargeCodeModel=*/true);
-
+
+ // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
+ // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
+ MCObjectFileInfo MOFI;
+ MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr);
+ MOFI.InitMCObjectFileInfo(TheTriple, /*PIC=*/false, Ctx,
+ /*LargeCodeModel=*/true);
+
if (InputArgs.hasArg(OPT_save_temp_labels))
- Ctx.setAllowTemporaryLabels(false);
-
+ Ctx.setAllowTemporaryLabels(false);
+
// Set compilation information.
SmallString<128> CWD;
if (!sys::fs::current_path(CWD))
@@ -294,78 +294,78 @@ int main(int Argc, char **Argv) {
SmallString<255> DefaultOutputFilename;
if (InputArgs.hasArg(OPT_as_lex)) {
DefaultOutputFilename = "-";
- } else {
+ } else {
DefaultOutputFilename = InputFilename;
sys::path::replace_extension(DefaultOutputFilename, FileType);
- }
+ }
const StringRef OutputFilename =
InputArgs.getLastArgValue(OPT_output_file, DefaultOutputFilename);
- std::unique_ptr<ToolOutputFile> Out = GetOutputStream(OutputFilename);
- if (!Out)
- return 1;
-
- std::unique_ptr<buffer_ostream> BOS;
- raw_pwrite_stream *OS = &Out->os();
- std::unique_ptr<MCStreamer> Str;
-
- std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
+ std::unique_ptr<ToolOutputFile> Out = GetOutputStream(OutputFilename);
+ if (!Out)
+ return 1;
+
+ std::unique_ptr<buffer_ostream> BOS;
+ raw_pwrite_stream *OS = &Out->os();
+ std::unique_ptr<MCStreamer> Str;
+
+ std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
assert(MCII && "Unable to create instruction info!");
- std::unique_ptr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(
- TripleName, /*CPU=*/"", /*Features=*/""));
+ std::unique_ptr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(
+ TripleName, /*CPU=*/"", /*Features=*/""));
assert(STI && "Unable to create subtarget info!");
-
- MCInstPrinter *IP = nullptr;
+
+ MCInstPrinter *IP = nullptr;
if (FileType == "s") {
const bool OutputATTAsm = InputArgs.hasArg(OPT_output_att_asm);
- const unsigned OutputAsmVariant = OutputATTAsm ? 0U // ATT dialect
- : 1U; // Intel dialect
+ const unsigned OutputAsmVariant = OutputATTAsm ? 0U // ATT dialect
+ : 1U; // Intel dialect
IP = TheTarget->createMCInstPrinter(TheTriple, OutputAsmVariant, *MAI,
*MCII, *MRI);
-
- if (!IP) {
- WithColor::error()
- << "unable to create instruction printer for target triple '"
- << TheTriple.normalize() << "' with "
- << (OutputATTAsm ? "ATT" : "Intel") << " assembly variant.\n";
- return 1;
- }
-
- // Set the display preference for hex vs. decimal immediates.
+
+ if (!IP) {
+ WithColor::error()
+ << "unable to create instruction printer for target triple '"
+ << TheTriple.normalize() << "' with "
+ << (OutputATTAsm ? "ATT" : "Intel") << " assembly variant.\n";
+ return 1;
+ }
+
+ // Set the display preference for hex vs. decimal immediates.
IP->setPrintImmHex(InputArgs.hasArg(OPT_print_imm_hex));
-
- // Set up the AsmStreamer.
- std::unique_ptr<MCCodeEmitter> CE;
+
+ // Set up the AsmStreamer.
+ std::unique_ptr<MCCodeEmitter> CE;
if (InputArgs.hasArg(OPT_show_encoding))
- CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
-
- std::unique_ptr<MCAsmBackend> MAB(
- TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
- auto FOut = std::make_unique<formatted_raw_ostream>(*OS);
+ CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+
+ std::unique_ptr<MCAsmBackend> MAB(
+ TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
+ auto FOut = std::make_unique<formatted_raw_ostream>(*OS);
Str.reset(TheTarget->createAsmStreamer(
Ctx, std::move(FOut), /*asmverbose*/ true,
/*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
InputArgs.hasArg(OPT_show_inst)));
-
+
} else if (FileType == "null") {
- Str.reset(TheTarget->createNullStreamer(Ctx));
+ Str.reset(TheTarget->createNullStreamer(Ctx));
} else if (FileType == "obj") {
- if (!Out->os().supportsSeeking()) {
- BOS = std::make_unique<buffer_ostream>(Out->os());
- OS = BOS.get();
- }
-
- MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
- MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions);
- Str.reset(TheTarget->createMCObjectStreamer(
- TheTriple, Ctx, std::unique_ptr<MCAsmBackend>(MAB),
- MAB->createObjectWriter(*OS), std::unique_ptr<MCCodeEmitter>(CE), *STI,
- MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible,
- /*DWARFMustBeAtTheEnd*/ false));
+ if (!Out->os().supportsSeeking()) {
+ BOS = std::make_unique<buffer_ostream>(Out->os());
+ OS = BOS.get();
+ }
+
+ MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
+ MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions);
+ Str.reset(TheTarget->createMCObjectStreamer(
+ TheTriple, Ctx, std::unique_ptr<MCAsmBackend>(MAB),
+ MAB->createObjectWriter(*OS), std::unique_ptr<MCCodeEmitter>(CE), *STI,
+ MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible,
+ /*DWARFMustBeAtTheEnd*/ false));
} else {
llvm_unreachable("Invalid file type!");
- }
-
+ }
+
if (TheTriple.isOSBinFormatCOFF()) {
// Emit an absolute @feat.00 symbol. This is a features bitfield read by
// link.exe.
@@ -383,20 +383,20 @@ int main(int Argc, char **Argv) {
Str->emitAssignment(Feat00Sym, MCConstantExpr::create(Feat00Flags, Ctx));
}
- // Use Assembler information for parsing.
- Str->setUseAssemblerInfoForParsing(true);
-
- int Res = 1;
+ // Use Assembler information for parsing.
+ Str->setUseAssemblerInfoForParsing(true);
+
+ int Res = 1;
if (InputArgs.hasArg(OPT_as_lex)) {
// -as-lex; Lex only, and output a stream of tokens
- Res = AsLexInput(SrcMgr, *MAI, Out->os());
+ Res = AsLexInput(SrcMgr, *MAI, Out->os());
} else {
- Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI,
+ Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI,
*MCII, MCOptions, InputArgs);
- }
-
- // Keep output if no errors.
- if (Res == 0)
- Out->keep();
- return Res;
-}
+ }
+
+ // Keep output if no errors.
+ if (Res == 0)
+ Out->keep();
+ return Res;
+}
diff --git a/contrib/libs/llvm12/tools/llvm-ml/ya.make b/contrib/libs/llvm12/tools/llvm-ml/ya.make
index 5371cfd851..8566abf283 100644
--- a/contrib/libs/llvm12/tools/llvm-ml/ya.make
+++ b/contrib/libs/llvm12/tools/llvm-ml/ya.make
@@ -1,17 +1,17 @@
-# Generated by devtools/yamaker.
-
-PROGRAM()
-
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
-
+
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/BinaryFormat
@@ -45,20 +45,20 @@ PEERDIR(
contrib/libs/llvm12/lib/Target/X86/Disassembler
contrib/libs/llvm12/lib/Target/X86/MCTargetDesc
contrib/libs/llvm12/lib/Target/X86/TargetInfo
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/llvm-ml
contrib/libs/llvm12/tools/llvm-ml
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- Disassembler.cpp
- llvm-ml.cpp
-)
-
-END()
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ Disassembler.cpp
+ llvm-ml.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm12/tools/llvm-mt/Opts.td b/contrib/libs/llvm12/tools/llvm-mt/Opts.td
index da5b2c992e..4c9b5def88 100644
--- a/contrib/libs/llvm12/tools/llvm-mt/Opts.td
+++ b/contrib/libs/llvm12/tools/llvm-mt/Opts.td
@@ -1,30 +1,30 @@
-include "llvm/Option/OptParser.td"
-
-def unsupported : OptionGroup<"unsupported">;
-def manifest : Separate<["/", "-"], "manifest">, HelpText<"Used to specify each manifest that need to be processed">, MetaVarName<"manifest">;
-def identity : Joined<["/", "-"], "identity:">, HelpText<"Not supported">, MetaVarName<"identity">, Group<unsupported>;
-def rgs : Joined<["/", "-"], "rgs:">, HelpText<"Not supported">, MetaVarName<"script">, Group<unsupported>;
-def tlb : Joined<["/", "-"], "tlb:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
-def dll : Joined<["/", "-"], "dll:">, HelpText<"Not supported">, MetaVarName<"dll">, Group<unsupported>;
-def replacements : Joined<["/", "-"], "replacements:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
-def managed_assembly_name : Joined<["/", "-"], "managedassemblyname:">, HelpText<"Not supported">, MetaVarName<"assembly">, Group<unsupported>;
-def no_dependency : Flag<["/", "-"], "nodependency">, HelpText<"Not supported">, Group<unsupported>;
-def category : Flag<["/", "-"], "category">, HelpText<"Not supported">, Group<unsupported>;
-def no_logo : Flag<["/", "-"], "nologo">, HelpText<"No effect as this tool never writes copyright data. Included for parity">;
-def out : Joined<["/", "-"], "out:">, HelpText<"Name of the output manifest. If this is skipped and only one manifest is being operated upon by the tool, that manifest is modified in place">, MetaVarName<"manifest">;
-def input_resource : Joined<["/", "-"], "inputresource:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
-def output_resource : Joined<["/", "-"], "outputresource:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
-def output_resource_flag : Flag<["/", "-"], "outputresource">, Alias<output_resource>, HelpText<"Not supported">, Group<unsupported>;
-def update_resource : Joined<["/", "-"], "updateresource:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
-def hash_update : Joined<["/", "-"], "hashupdate:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
-def hash_update_flag : Flag<["/", "-"], "hashupdate">, Alias<hash_update>, HelpText<"Not supported">, Group<unsupported>;
-def validate_manifest : Flag<["/", "-"], "validate_manifest">, HelpText<"Not supported">, Group<unsupported>;
-def validate_file_hashes : Joined<["/", "-"], "validate_file_hashes:">, HelpText<"Not supported">, MetaVarName<"">, Group<unsupported>;
-def canonicalize : Flag<["/", "-"], "canonicalize:">, HelpText<"Not supported">, Group<unsupported>;
-def check_for_duplicates : Flag<["/", "-"], "check_for_duplicates:">, HelpText<"Not supported">, Group<unsupported>;
-def make_cdfs : Flag<["/", "-"], "makecdfs:">, HelpText<"Not supported">, Group<unsupported>;
-def notify_update : Flag<["/", "-"], "notify_update">, HelpText<"Not supported">, Group<unsupported>;
-def verbose : Flag<["/", "-"], "verbose">, HelpText<"Not supported">, Group<unsupported>;
-def help : Flag<["/", "-"], "?">;
-def help_long : Flag<["/", "-"], "help">, Alias<help>;
-def h : Flag<["/", "-"], "h">, Alias<help>;
+include "llvm/Option/OptParser.td"
+
+def unsupported : OptionGroup<"unsupported">;
+def manifest : Separate<["/", "-"], "manifest">, HelpText<"Used to specify each manifest that need to be processed">, MetaVarName<"manifest">;
+def identity : Joined<["/", "-"], "identity:">, HelpText<"Not supported">, MetaVarName<"identity">, Group<unsupported>;
+def rgs : Joined<["/", "-"], "rgs:">, HelpText<"Not supported">, MetaVarName<"script">, Group<unsupported>;
+def tlb : Joined<["/", "-"], "tlb:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
+def dll : Joined<["/", "-"], "dll:">, HelpText<"Not supported">, MetaVarName<"dll">, Group<unsupported>;
+def replacements : Joined<["/", "-"], "replacements:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
+def managed_assembly_name : Joined<["/", "-"], "managedassemblyname:">, HelpText<"Not supported">, MetaVarName<"assembly">, Group<unsupported>;
+def no_dependency : Flag<["/", "-"], "nodependency">, HelpText<"Not supported">, Group<unsupported>;
+def category : Flag<["/", "-"], "category">, HelpText<"Not supported">, Group<unsupported>;
+def no_logo : Flag<["/", "-"], "nologo">, HelpText<"No effect as this tool never writes copyright data. Included for parity">;
+def out : Joined<["/", "-"], "out:">, HelpText<"Name of the output manifest. If this is skipped and only one manifest is being operated upon by the tool, that manifest is modified in place">, MetaVarName<"manifest">;
+def input_resource : Joined<["/", "-"], "inputresource:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
+def output_resource : Joined<["/", "-"], "outputresource:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
+def output_resource_flag : Flag<["/", "-"], "outputresource">, Alias<output_resource>, HelpText<"Not supported">, Group<unsupported>;
+def update_resource : Joined<["/", "-"], "updateresource:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
+def hash_update : Joined<["/", "-"], "hashupdate:">, HelpText<"Not supported">, MetaVarName<"file">, Group<unsupported>;
+def hash_update_flag : Flag<["/", "-"], "hashupdate">, Alias<hash_update>, HelpText<"Not supported">, Group<unsupported>;
+def validate_manifest : Flag<["/", "-"], "validate_manifest">, HelpText<"Not supported">, Group<unsupported>;
+def validate_file_hashes : Joined<["/", "-"], "validate_file_hashes:">, HelpText<"Not supported">, MetaVarName<"">, Group<unsupported>;
+def canonicalize : Flag<["/", "-"], "canonicalize:">, HelpText<"Not supported">, Group<unsupported>;
+def check_for_duplicates : Flag<["/", "-"], "check_for_duplicates:">, HelpText<"Not supported">, Group<unsupported>;
+def make_cdfs : Flag<["/", "-"], "makecdfs:">, HelpText<"Not supported">, Group<unsupported>;
+def notify_update : Flag<["/", "-"], "notify_update">, HelpText<"Not supported">, Group<unsupported>;
+def verbose : Flag<["/", "-"], "verbose">, HelpText<"Not supported">, Group<unsupported>;
+def help : Flag<["/", "-"], "?">;
+def help_long : Flag<["/", "-"], "help">, Alias<help>;
+def h : Flag<["/", "-"], "h">, Alias<help>;
diff --git a/contrib/libs/llvm12/tools/llvm-mt/llvm-mt.cpp b/contrib/libs/llvm12/tools/llvm-mt/llvm-mt.cpp
index 997e5acbe2..59458ae8c3 100644
--- a/contrib/libs/llvm12/tools/llvm-mt/llvm-mt.cpp
+++ b/contrib/libs/llvm12/tools/llvm-mt/llvm-mt.cpp
@@ -1,154 +1,154 @@
-//===- llvm-mt.cpp - Merge .manifest files ---------------------*- 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
-//
-//===---------------------------------------------------------------------===//
-//
-// Merge .manifest files. This is intended to be a platform-independent port
-// of Microsoft's mt.exe.
-//
-//===---------------------------------------------------------------------===//
-
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/WindowsManifest/WindowsManifestMerger.h"
-
-#include <system_error>
-
-using namespace llvm;
-
-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 "Opts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#include "Opts.inc"
-#undef PREFIX
-
-static 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 "Opts.inc"
-#undef OPTION
-};
-
-class CvtResOptTable : public opt::OptTable {
-public:
- CvtResOptTable() : OptTable(InfoTable, true) {}
-};
-} // namespace
-
+//===- llvm-mt.cpp - Merge .manifest files ---------------------*- 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
+//
+//===---------------------------------------------------------------------===//
+//
+// Merge .manifest files. This is intended to be a platform-independent port
+// of Microsoft's mt.exe.
+//
+//===---------------------------------------------------------------------===//
+
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/WindowsManifest/WindowsManifestMerger.h"
+
+#include <system_error>
+
+using namespace llvm;
+
+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 "Opts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Opts.inc"
+#undef PREFIX
+
+static 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 "Opts.inc"
+#undef OPTION
+};
+
+class CvtResOptTable : public opt::OptTable {
+public:
+ CvtResOptTable() : OptTable(InfoTable, true) {}
+};
+} // namespace
+
LLVM_ATTRIBUTE_NORETURN static void reportError(Twine Msg) {
- WithColor::error(errs(), "llvm-mt") << Msg << '\n';
- exit(1);
-}
-
-static void reportError(StringRef Input, std::error_code EC) {
- reportError(Twine(Input) + ": " + EC.message());
-}
-
+ WithColor::error(errs(), "llvm-mt") << Msg << '\n';
+ exit(1);
+}
+
+static void reportError(StringRef Input, std::error_code EC) {
+ reportError(Twine(Input) + ": " + EC.message());
+}
+
static void error(Error EC) {
- if (EC)
- handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
- reportError(EI.message());
- });
-}
-
-int main(int Argc, const char **Argv) {
- InitLLVM X(Argc, Argv);
-
- CvtResOptTable T;
- unsigned MAI, MAC;
- ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
- opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
-
- for (auto *Arg : InputArgs.filtered(OPT_INPUT)) {
- auto ArgString = Arg->getAsString(InputArgs);
- std::string Diag;
- raw_string_ostream OS(Diag);
- OS << "invalid option '" << ArgString << "'";
-
- std::string Nearest;
- if (T.findNearest(ArgString, Nearest) < 2)
- OS << ", did you mean '" << Nearest << "'?";
-
- reportError(OS.str());
- }
-
- for (auto &Arg : InputArgs) {
- if (Arg->getOption().matches(OPT_unsupported)) {
- outs() << "llvm-mt: ignoring unsupported '" << Arg->getOption().getName()
- << "' option\n";
- }
- }
-
- if (InputArgs.hasArg(OPT_help)) {
- T.PrintHelp(outs(), "llvm-mt [options] file...", "Manifest Tool", false);
- return 0;
- }
-
- std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_manifest);
-
- if (InputFiles.size() == 0) {
- reportError("no input file specified");
- }
-
- StringRef OutputFile;
- if (InputArgs.hasArg(OPT_out)) {
- OutputFile = InputArgs.getLastArgValue(OPT_out);
- } else if (InputFiles.size() == 1) {
- OutputFile = InputFiles[0];
- } else {
- reportError("no output file specified");
- }
-
- windows_manifest::WindowsManifestMerger Merger;
-
- for (const auto &File : InputFiles) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> ManifestOrErr =
- MemoryBuffer::getFile(File);
- if (!ManifestOrErr)
- reportError(File, ManifestOrErr.getError());
- MemoryBuffer &Manifest = *ManifestOrErr.get();
- error(Merger.merge(Manifest));
- }
-
- std::unique_ptr<MemoryBuffer> OutputBuffer = Merger.getMergedManifest();
- if (!OutputBuffer)
- reportError("empty manifest not written");
- Expected<std::unique_ptr<FileOutputBuffer>> FileOrErr =
- FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
- if (!FileOrErr)
- reportError(OutputFile, errorToErrorCode(FileOrErr.takeError()));
- std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
- std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
- FileBuffer->getBufferStart());
- error(FileBuffer->commit());
- return 0;
-}
+ if (EC)
+ handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
+ reportError(EI.message());
+ });
+}
+
+int main(int Argc, const char **Argv) {
+ InitLLVM X(Argc, Argv);
+
+ CvtResOptTable T;
+ unsigned MAI, MAC;
+ ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
+ opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
+
+ for (auto *Arg : InputArgs.filtered(OPT_INPUT)) {
+ auto ArgString = Arg->getAsString(InputArgs);
+ std::string Diag;
+ raw_string_ostream OS(Diag);
+ OS << "invalid option '" << ArgString << "'";
+
+ std::string Nearest;
+ if (T.findNearest(ArgString, Nearest) < 2)
+ OS << ", did you mean '" << Nearest << "'?";
+
+ reportError(OS.str());
+ }
+
+ for (auto &Arg : InputArgs) {
+ if (Arg->getOption().matches(OPT_unsupported)) {
+ outs() << "llvm-mt: ignoring unsupported '" << Arg->getOption().getName()
+ << "' option\n";
+ }
+ }
+
+ if (InputArgs.hasArg(OPT_help)) {
+ T.PrintHelp(outs(), "llvm-mt [options] file...", "Manifest Tool", false);
+ return 0;
+ }
+
+ std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_manifest);
+
+ if (InputFiles.size() == 0) {
+ reportError("no input file specified");
+ }
+
+ StringRef OutputFile;
+ if (InputArgs.hasArg(OPT_out)) {
+ OutputFile = InputArgs.getLastArgValue(OPT_out);
+ } else if (InputFiles.size() == 1) {
+ OutputFile = InputFiles[0];
+ } else {
+ reportError("no output file specified");
+ }
+
+ windows_manifest::WindowsManifestMerger Merger;
+
+ for (const auto &File : InputFiles) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ManifestOrErr =
+ MemoryBuffer::getFile(File);
+ if (!ManifestOrErr)
+ reportError(File, ManifestOrErr.getError());
+ MemoryBuffer &Manifest = *ManifestOrErr.get();
+ error(Merger.merge(Manifest));
+ }
+
+ std::unique_ptr<MemoryBuffer> OutputBuffer = Merger.getMergedManifest();
+ if (!OutputBuffer)
+ reportError("empty manifest not written");
+ Expected<std::unique_ptr<FileOutputBuffer>> FileOrErr =
+ FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
+ if (!FileOrErr)
+ reportError(OutputFile, errorToErrorCode(FileOrErr.takeError()));
+ std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
+ std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
+ FileBuffer->getBufferStart());
+ error(FileBuffer->commit());
+ return 0;
+}
diff --git a/contrib/libs/llvm12/tools/llvm-mt/ya.make b/contrib/libs/llvm12/tools/llvm-mt/ya.make
index 83a363a067..4bea81adf1 100644
--- a/contrib/libs/llvm12/tools/llvm-mt/ya.make
+++ b/contrib/libs/llvm12/tools/llvm-mt/ya.make
@@ -1,36 +1,36 @@
-# Generated by devtools/yamaker.
-
-PROGRAM()
-
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
-
+
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/Demangle
contrib/libs/llvm12/lib/Option
contrib/libs/llvm12/lib/Support
contrib/libs/llvm12/lib/WindowsManifest
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/llvm-mt
contrib/libs/llvm12/tools/llvm-mt
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- llvm-mt.cpp
-)
-
-END()
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ llvm-mt.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/Buffer.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/Buffer.cpp
index 06b2a20a76..f71d1bfacb 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/Buffer.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/Buffer.cpp
@@ -1,79 +1,79 @@
-//===- Buffer.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 "Buffer.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Process.h"
-#include <memory>
-
-namespace llvm {
-namespace objcopy {
-
-Buffer::~Buffer() {}
-
-static Error createEmptyFile(StringRef FileName) {
- // Create an empty tempfile and atomically swap it in place with the desired
- // output file.
- Expected<sys::fs::TempFile> Temp =
- sys::fs::TempFile::create(FileName + ".temp-empty-%%%%%%%");
- return Temp ? Temp->keep(FileName) : Temp.takeError();
-}
-
-Error FileBuffer::allocate(size_t Size) {
- // When a 0-sized file is requested, skip allocation but defer file
- // creation/truncation until commit() to avoid side effects if something
- // happens between allocate() and commit().
- if (Size == 0) {
- EmptyFile = true;
- return Error::success();
- }
-
- Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
- FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable);
- // FileOutputBuffer::create() returns an Error that is just a wrapper around
- // std::error_code. Wrap it in FileError to include the actual filename.
- if (!BufferOrErr)
- return createFileError(getName(), BufferOrErr.takeError());
- Buf = std::move(*BufferOrErr);
- return Error::success();
-}
-
-Error FileBuffer::commit() {
- if (EmptyFile)
- return createEmptyFile(getName());
-
- assert(Buf && "allocate() not called before commit()!");
- Error Err = Buf->commit();
- // FileOutputBuffer::commit() returns an Error that is just a wrapper around
- // std::error_code. Wrap it in FileError to include the actual filename.
- return Err ? createFileError(getName(), std::move(Err)) : std::move(Err);
-}
-
-uint8_t *FileBuffer::getBufferStart() {
- return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
-}
-
-Error MemBuffer::allocate(size_t Size) {
- Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
- return Error::success();
-}
-
-Error MemBuffer::commit() { return Error::success(); }
-
-uint8_t *MemBuffer::getBufferStart() {
- return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
-}
-
-std::unique_ptr<WritableMemoryBuffer> MemBuffer::releaseMemoryBuffer() {
- return std::move(Buf);
-}
-
-} // end namespace objcopy
-} // end namespace llvm
+//===- Buffer.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 "Buffer.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Process.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+
+Buffer::~Buffer() {}
+
+static Error createEmptyFile(StringRef FileName) {
+ // Create an empty tempfile and atomically swap it in place with the desired
+ // output file.
+ Expected<sys::fs::TempFile> Temp =
+ sys::fs::TempFile::create(FileName + ".temp-empty-%%%%%%%");
+ return Temp ? Temp->keep(FileName) : Temp.takeError();
+}
+
+Error FileBuffer::allocate(size_t Size) {
+ // When a 0-sized file is requested, skip allocation but defer file
+ // creation/truncation until commit() to avoid side effects if something
+ // happens between allocate() and commit().
+ if (Size == 0) {
+ EmptyFile = true;
+ return Error::success();
+ }
+
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable);
+ // FileOutputBuffer::create() returns an Error that is just a wrapper around
+ // std::error_code. Wrap it in FileError to include the actual filename.
+ if (!BufferOrErr)
+ return createFileError(getName(), BufferOrErr.takeError());
+ Buf = std::move(*BufferOrErr);
+ return Error::success();
+}
+
+Error FileBuffer::commit() {
+ if (EmptyFile)
+ return createEmptyFile(getName());
+
+ assert(Buf && "allocate() not called before commit()!");
+ Error Err = Buf->commit();
+ // FileOutputBuffer::commit() returns an Error that is just a wrapper around
+ // std::error_code. Wrap it in FileError to include the actual filename.
+ return Err ? createFileError(getName(), std::move(Err)) : std::move(Err);
+}
+
+uint8_t *FileBuffer::getBufferStart() {
+ return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
+}
+
+Error MemBuffer::allocate(size_t Size) {
+ Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
+ return Error::success();
+}
+
+Error MemBuffer::commit() { return Error::success(); }
+
+uint8_t *MemBuffer::getBufferStart() {
+ return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
+}
+
+std::unique_ptr<WritableMemoryBuffer> MemBuffer::releaseMemoryBuffer() {
+ return std::move(Buf);
+}
+
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/Buffer.h b/contrib/libs/llvm12/tools/llvm-objcopy/Buffer.h
index 487d5585c3..7782463ac5 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/Buffer.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/Buffer.h
@@ -1,68 +1,68 @@
-//===- Buffer.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_OBJCOPY_BUFFER_H
-#define LLVM_TOOLS_OBJCOPY_BUFFER_H
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include <memory>
-
-namespace llvm {
-namespace objcopy {
-
-// The class Buffer abstracts out the common interface of FileOutputBuffer and
-// WritableMemoryBuffer so that the hierarchy of Writers depends on this
-// abstract interface and doesn't depend on a particular implementation.
-// TODO: refactor the buffer classes in LLVM to enable us to use them here
-// directly.
-class Buffer {
- StringRef Name;
-
-public:
- virtual ~Buffer();
- virtual Error allocate(size_t Size) = 0;
- virtual uint8_t *getBufferStart() = 0;
- virtual Error commit() = 0;
-
- explicit Buffer(StringRef Name) : Name(Name) {}
- StringRef getName() const { return Name; }
-};
-
-class FileBuffer : public Buffer {
- std::unique_ptr<FileOutputBuffer> Buf;
- // Indicates that allocate(0) was called, and commit() should create or
- // truncate a file instead of using a FileOutputBuffer.
- bool EmptyFile = false;
-
-public:
- Error allocate(size_t Size) override;
- uint8_t *getBufferStart() override;
- Error commit() override;
-
- explicit FileBuffer(StringRef FileName) : Buffer(FileName) {}
-};
-
-class MemBuffer : public Buffer {
- std::unique_ptr<WritableMemoryBuffer> Buf;
-
-public:
- Error allocate(size_t Size) override;
- uint8_t *getBufferStart() override;
- Error commit() override;
-
- explicit MemBuffer(StringRef Name) : Buffer(Name) {}
-
- std::unique_ptr<WritableMemoryBuffer> releaseMemoryBuffer();
-};
-
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_OBJCOPY_BUFFER_H
+//===- Buffer.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_OBJCOPY_BUFFER_H
+#define LLVM_TOOLS_OBJCOPY_BUFFER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+
+// The class Buffer abstracts out the common interface of FileOutputBuffer and
+// WritableMemoryBuffer so that the hierarchy of Writers depends on this
+// abstract interface and doesn't depend on a particular implementation.
+// TODO: refactor the buffer classes in LLVM to enable us to use them here
+// directly.
+class Buffer {
+ StringRef Name;
+
+public:
+ virtual ~Buffer();
+ virtual Error allocate(size_t Size) = 0;
+ virtual uint8_t *getBufferStart() = 0;
+ virtual Error commit() = 0;
+
+ explicit Buffer(StringRef Name) : Name(Name) {}
+ StringRef getName() const { return Name; }
+};
+
+class FileBuffer : public Buffer {
+ std::unique_ptr<FileOutputBuffer> Buf;
+ // Indicates that allocate(0) was called, and commit() should create or
+ // truncate a file instead of using a FileOutputBuffer.
+ bool EmptyFile = false;
+
+public:
+ Error allocate(size_t Size) override;
+ uint8_t *getBufferStart() override;
+ Error commit() override;
+
+ explicit FileBuffer(StringRef FileName) : Buffer(FileName) {}
+};
+
+class MemBuffer : public Buffer {
+ std::unique_ptr<WritableMemoryBuffer> Buf;
+
+public:
+ Error allocate(size_t Size) override;
+ uint8_t *getBufferStart() override;
+ Error commit() override;
+
+ explicit MemBuffer(StringRef Name) : Buffer(Name) {}
+
+ std::unique_ptr<WritableMemoryBuffer> releaseMemoryBuffer();
+};
+
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_BUFFER_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
index b5de8a45a8..3c058e4785 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
@@ -1,292 +1,292 @@
-//===- COFFObjcopy.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 "COFFObjcopy.h"
-#include "Buffer.h"
-#include "CopyConfig.h"
-#include "Object.h"
-#include "Reader.h"
-#include "Writer.h"
-
-#include "llvm/Object/Binary.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/CRC.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/Path.h"
-#include <cassert>
-
-namespace llvm {
-namespace objcopy {
-namespace coff {
-
-using namespace object;
-using namespace COFF;
-
-static bool isDebugSection(const Section &Sec) {
- return Sec.Name.startswith(".debug");
-}
-
-static uint64_t getNextRVA(const Object &Obj) {
- if (Obj.getSections().empty())
- return 0;
- const Section &Last = Obj.getSections().back();
- return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize,
- Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1);
-}
-
+//===- COFFObjcopy.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 "COFFObjcopy.h"
+#include "Buffer.h"
+#include "CopyConfig.h"
+#include "Object.h"
+#include "Reader.h"
+#include "Writer.h"
+
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/CRC.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Path.h"
+#include <cassert>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+using namespace object;
+using namespace COFF;
+
+static bool isDebugSection(const Section &Sec) {
+ return Sec.Name.startswith(".debug");
+}
+
+static uint64_t getNextRVA(const Object &Obj) {
+ if (Obj.getSections().empty())
+ return 0;
+ const Section &Last = Obj.getSections().back();
+ return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize,
+ Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1);
+}
+
static Expected<std::vector<uint8_t>>
createGnuDebugLinkSectionContents(StringRef File) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =
- MemoryBuffer::getFile(File);
- if (!LinkTargetOrErr)
+ ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =
+ MemoryBuffer::getFile(File);
+ if (!LinkTargetOrErr)
return createFileError(File, LinkTargetOrErr.getError());
- auto LinkTarget = std::move(*LinkTargetOrErr);
- uint32_t CRC32 = llvm::crc32(arrayRefFromStringRef(LinkTarget->getBuffer()));
-
- StringRef FileName = sys::path::filename(File);
- size_t CRCPos = alignTo(FileName.size() + 1, 4);
- std::vector<uint8_t> Data(CRCPos + 4);
- memcpy(Data.data(), FileName.data(), FileName.size());
- support::endian::write32le(Data.data() + CRCPos, CRC32);
- return Data;
-}
-
-// Adds named section with given contents to the object.
-static void addSection(Object &Obj, StringRef Name, ArrayRef<uint8_t> Contents,
- uint32_t Characteristics) {
- bool NeedVA = Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
- IMAGE_SCN_MEM_WRITE);
-
- Section Sec;
- Sec.setOwnedContents(Contents);
- Sec.Name = Name;
- Sec.Header.VirtualSize = NeedVA ? Sec.getContents().size() : 0u;
- Sec.Header.VirtualAddress = NeedVA ? getNextRVA(Obj) : 0u;
- Sec.Header.SizeOfRawData =
- NeedVA ? alignTo(Sec.Header.VirtualSize,
- Obj.IsPE ? Obj.PeHeader.FileAlignment : 1)
- : Sec.getContents().size();
- // Sec.Header.PointerToRawData is filled in by the writer.
- Sec.Header.PointerToRelocations = 0;
- Sec.Header.PointerToLinenumbers = 0;
- // Sec.Header.NumberOfRelocations is filled in by the writer.
- Sec.Header.NumberOfLinenumbers = 0;
- Sec.Header.Characteristics = Characteristics;
-
- Obj.addSections(Sec);
-}
-
+ auto LinkTarget = std::move(*LinkTargetOrErr);
+ uint32_t CRC32 = llvm::crc32(arrayRefFromStringRef(LinkTarget->getBuffer()));
+
+ StringRef FileName = sys::path::filename(File);
+ size_t CRCPos = alignTo(FileName.size() + 1, 4);
+ std::vector<uint8_t> Data(CRCPos + 4);
+ memcpy(Data.data(), FileName.data(), FileName.size());
+ support::endian::write32le(Data.data() + CRCPos, CRC32);
+ return Data;
+}
+
+// Adds named section with given contents to the object.
+static void addSection(Object &Obj, StringRef Name, ArrayRef<uint8_t> Contents,
+ uint32_t Characteristics) {
+ bool NeedVA = Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
+ IMAGE_SCN_MEM_WRITE);
+
+ Section Sec;
+ Sec.setOwnedContents(Contents);
+ Sec.Name = Name;
+ Sec.Header.VirtualSize = NeedVA ? Sec.getContents().size() : 0u;
+ Sec.Header.VirtualAddress = NeedVA ? getNextRVA(Obj) : 0u;
+ Sec.Header.SizeOfRawData =
+ NeedVA ? alignTo(Sec.Header.VirtualSize,
+ Obj.IsPE ? Obj.PeHeader.FileAlignment : 1)
+ : Sec.getContents().size();
+ // Sec.Header.PointerToRawData is filled in by the writer.
+ Sec.Header.PointerToRelocations = 0;
+ Sec.Header.PointerToLinenumbers = 0;
+ // Sec.Header.NumberOfRelocations is filled in by the writer.
+ Sec.Header.NumberOfLinenumbers = 0;
+ Sec.Header.Characteristics = Characteristics;
+
+ Obj.addSections(Sec);
+}
+
static Error addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
Expected<std::vector<uint8_t>> Contents =
- createGnuDebugLinkSectionContents(DebugLinkFile);
+ createGnuDebugLinkSectionContents(DebugLinkFile);
if (!Contents)
return Contents.takeError();
addSection(Obj, ".gnu_debuglink", *Contents,
- IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
- IMAGE_SCN_MEM_DISCARDABLE);
+ IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
+ IMAGE_SCN_MEM_DISCARDABLE);
return Error::success();
-}
-
-static void setSectionFlags(Section &Sec, SectionFlag AllFlags) {
- // Need to preserve alignment flags.
- const uint32_t PreserveMask =
- IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_ALIGN_4BYTES |
- IMAGE_SCN_ALIGN_8BYTES | IMAGE_SCN_ALIGN_16BYTES |
- IMAGE_SCN_ALIGN_32BYTES | IMAGE_SCN_ALIGN_64BYTES |
- IMAGE_SCN_ALIGN_128BYTES | IMAGE_SCN_ALIGN_256BYTES |
- IMAGE_SCN_ALIGN_512BYTES | IMAGE_SCN_ALIGN_1024BYTES |
- IMAGE_SCN_ALIGN_2048BYTES | IMAGE_SCN_ALIGN_4096BYTES |
- IMAGE_SCN_ALIGN_8192BYTES;
-
- // Setup new section characteristics based on the flags provided in command
- // line.
- uint32_t NewCharacteristics =
- (Sec.Header.Characteristics & PreserveMask) | IMAGE_SCN_MEM_READ;
-
- if ((AllFlags & SectionFlag::SecAlloc) && !(AllFlags & SectionFlag::SecLoad))
- NewCharacteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
- if (AllFlags & SectionFlag::SecNoload)
- NewCharacteristics |= IMAGE_SCN_LNK_REMOVE;
- if (!(AllFlags & SectionFlag::SecReadonly))
- NewCharacteristics |= IMAGE_SCN_MEM_WRITE;
- if (AllFlags & SectionFlag::SecDebug)
- NewCharacteristics |=
- IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
- if (AllFlags & SectionFlag::SecCode)
- NewCharacteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
- if (AllFlags & SectionFlag::SecData)
- NewCharacteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
- if (AllFlags & SectionFlag::SecShare)
- NewCharacteristics |= IMAGE_SCN_MEM_SHARED;
- if (AllFlags & SectionFlag::SecExclude)
- NewCharacteristics |= IMAGE_SCN_LNK_REMOVE;
-
- Sec.Header.Characteristics = NewCharacteristics;
-}
-
-static Error handleArgs(const CopyConfig &Config, Object &Obj) {
- // Perform the actual section removals.
- Obj.removeSections([&Config](const Section &Sec) {
- // Contrary to --only-keep-debug, --only-section fully removes sections that
- // aren't mentioned.
- if (!Config.OnlySection.empty() && !Config.OnlySection.matches(Sec.Name))
- return true;
-
- if (Config.StripDebug || Config.StripAll || Config.StripAllGNU ||
- Config.DiscardMode == DiscardType::All || Config.StripUnneeded) {
- if (isDebugSection(Sec) &&
- (Sec.Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
- return true;
- }
-
- if (Config.ToRemove.matches(Sec.Name))
- return true;
-
- return false;
- });
-
- if (Config.OnlyKeepDebug) {
- // For --only-keep-debug, we keep all other sections, but remove their
- // content. The VirtualSize field in the section header is kept intact.
- Obj.truncateSections([](const Section &Sec) {
- return !isDebugSection(Sec) && Sec.Name != ".buildid" &&
- ((Sec.Header.Characteristics &
- (IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA)) != 0);
- });
- }
-
- // StripAll removes all symbols and thus also removes all relocations.
- if (Config.StripAll || Config.StripAllGNU)
- for (Section &Sec : Obj.getMutableSections())
- Sec.Relocs.clear();
-
- // If we need to do per-symbol removals, initialize the Referenced field.
- if (Config.StripUnneeded || Config.DiscardMode == DiscardType::All ||
- !Config.SymbolsToRemove.empty())
- if (Error E = Obj.markSymbols())
- return E;
-
- for (Symbol &Sym : Obj.getMutableSymbols()) {
- auto I = Config.SymbolsToRename.find(Sym.Name);
- if (I != Config.SymbolsToRename.end())
- Sym.Name = I->getValue();
- }
-
+}
+
+static void setSectionFlags(Section &Sec, SectionFlag AllFlags) {
+ // Need to preserve alignment flags.
+ const uint32_t PreserveMask =
+ IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_ALIGN_4BYTES |
+ IMAGE_SCN_ALIGN_8BYTES | IMAGE_SCN_ALIGN_16BYTES |
+ IMAGE_SCN_ALIGN_32BYTES | IMAGE_SCN_ALIGN_64BYTES |
+ IMAGE_SCN_ALIGN_128BYTES | IMAGE_SCN_ALIGN_256BYTES |
+ IMAGE_SCN_ALIGN_512BYTES | IMAGE_SCN_ALIGN_1024BYTES |
+ IMAGE_SCN_ALIGN_2048BYTES | IMAGE_SCN_ALIGN_4096BYTES |
+ IMAGE_SCN_ALIGN_8192BYTES;
+
+ // Setup new section characteristics based on the flags provided in command
+ // line.
+ uint32_t NewCharacteristics =
+ (Sec.Header.Characteristics & PreserveMask) | IMAGE_SCN_MEM_READ;
+
+ if ((AllFlags & SectionFlag::SecAlloc) && !(AllFlags & SectionFlag::SecLoad))
+ NewCharacteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ if (AllFlags & SectionFlag::SecNoload)
+ NewCharacteristics |= IMAGE_SCN_LNK_REMOVE;
+ if (!(AllFlags & SectionFlag::SecReadonly))
+ NewCharacteristics |= IMAGE_SCN_MEM_WRITE;
+ if (AllFlags & SectionFlag::SecDebug)
+ NewCharacteristics |=
+ IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
+ if (AllFlags & SectionFlag::SecCode)
+ NewCharacteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
+ if (AllFlags & SectionFlag::SecData)
+ NewCharacteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
+ if (AllFlags & SectionFlag::SecShare)
+ NewCharacteristics |= IMAGE_SCN_MEM_SHARED;
+ if (AllFlags & SectionFlag::SecExclude)
+ NewCharacteristics |= IMAGE_SCN_LNK_REMOVE;
+
+ Sec.Header.Characteristics = NewCharacteristics;
+}
+
+static Error handleArgs(const CopyConfig &Config, Object &Obj) {
+ // Perform the actual section removals.
+ Obj.removeSections([&Config](const Section &Sec) {
+ // Contrary to --only-keep-debug, --only-section fully removes sections that
+ // aren't mentioned.
+ if (!Config.OnlySection.empty() && !Config.OnlySection.matches(Sec.Name))
+ return true;
+
+ if (Config.StripDebug || Config.StripAll || Config.StripAllGNU ||
+ Config.DiscardMode == DiscardType::All || Config.StripUnneeded) {
+ if (isDebugSection(Sec) &&
+ (Sec.Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
+ return true;
+ }
+
+ if (Config.ToRemove.matches(Sec.Name))
+ return true;
+
+ return false;
+ });
+
+ if (Config.OnlyKeepDebug) {
+ // For --only-keep-debug, we keep all other sections, but remove their
+ // content. The VirtualSize field in the section header is kept intact.
+ Obj.truncateSections([](const Section &Sec) {
+ return !isDebugSection(Sec) && Sec.Name != ".buildid" &&
+ ((Sec.Header.Characteristics &
+ (IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA)) != 0);
+ });
+ }
+
+ // StripAll removes all symbols and thus also removes all relocations.
+ if (Config.StripAll || Config.StripAllGNU)
+ for (Section &Sec : Obj.getMutableSections())
+ Sec.Relocs.clear();
+
+ // If we need to do per-symbol removals, initialize the Referenced field.
+ if (Config.StripUnneeded || Config.DiscardMode == DiscardType::All ||
+ !Config.SymbolsToRemove.empty())
+ if (Error E = Obj.markSymbols())
+ return E;
+
+ for (Symbol &Sym : Obj.getMutableSymbols()) {
+ auto I = Config.SymbolsToRename.find(Sym.Name);
+ if (I != Config.SymbolsToRename.end())
+ Sym.Name = I->getValue();
+ }
+
auto ToRemove = [&](const Symbol &Sym) -> Expected<bool> {
- // For StripAll, all relocations have been stripped and we remove all
- // symbols.
- if (Config.StripAll || Config.StripAllGNU)
- return true;
-
- if (Config.SymbolsToRemove.matches(Sym.Name)) {
- // Explicitly removing a referenced symbol is an error.
- if (Sym.Referenced)
+ // For StripAll, all relocations have been stripped and we remove all
+ // symbols.
+ if (Config.StripAll || Config.StripAllGNU)
+ return true;
+
+ if (Config.SymbolsToRemove.matches(Sym.Name)) {
+ // Explicitly removing a referenced symbol is an error.
+ if (Sym.Referenced)
return createStringError(
llvm::errc::invalid_argument,
"'" + Config.OutputFilename + "': not stripping symbol '" +
Sym.Name.str() + "' because it is named in a relocation");
- return true;
- }
-
- if (!Sym.Referenced) {
- // With --strip-unneeded, GNU objcopy removes all unreferenced local
- // symbols, and any unreferenced undefined external.
- // With --strip-unneeded-symbol we strip only specific unreferenced
- // local symbol instead of removing all of such.
- if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
- Sym.Sym.SectionNumber == 0)
- if (Config.StripUnneeded ||
- Config.UnneededSymbolsToRemove.matches(Sym.Name))
- return true;
-
- // GNU objcopy keeps referenced local symbols and external symbols
- // if --discard-all is set, similar to what --strip-unneeded does,
- // but undefined local symbols are kept when --discard-all is set.
- if (Config.DiscardMode == DiscardType::All &&
- Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
- Sym.Sym.SectionNumber != 0)
- return true;
- }
-
- return false;
+ return true;
+ }
+
+ if (!Sym.Referenced) {
+ // With --strip-unneeded, GNU objcopy removes all unreferenced local
+ // symbols, and any unreferenced undefined external.
+ // With --strip-unneeded-symbol we strip only specific unreferenced
+ // local symbol instead of removing all of such.
+ if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
+ Sym.Sym.SectionNumber == 0)
+ if (Config.StripUnneeded ||
+ Config.UnneededSymbolsToRemove.matches(Sym.Name))
+ return true;
+
+ // GNU objcopy keeps referenced local symbols and external symbols
+ // if --discard-all is set, similar to what --strip-unneeded does,
+ // but undefined local symbols are kept when --discard-all is set.
+ if (Config.DiscardMode == DiscardType::All &&
+ Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
+ Sym.Sym.SectionNumber != 0)
+ return true;
+ }
+
+ return false;
};
-
+
// Actually do removals of symbols.
if (Error Err = Obj.removeSymbols(ToRemove))
return Err;
- if (!Config.SetSectionFlags.empty())
- for (Section &Sec : Obj.getMutableSections()) {
- const auto It = Config.SetSectionFlags.find(Sec.Name);
- if (It != Config.SetSectionFlags.end())
- setSectionFlags(Sec, It->second.NewFlags);
- }
-
- for (const auto &Flag : Config.AddSection) {
- StringRef SecName, FileName;
- std::tie(SecName, FileName) = Flag.split("=");
-
- auto BufOrErr = MemoryBuffer::getFile(FileName);
- if (!BufOrErr)
- return createFileError(FileName, errorCodeToError(BufOrErr.getError()));
- auto Buf = std::move(*BufOrErr);
-
- addSection(
- Obj, SecName,
- makeArrayRef(reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
- Buf->getBufferSize()),
- IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES);
- }
-
- if (!Config.AddGnuDebugLink.empty())
+ if (!Config.SetSectionFlags.empty())
+ for (Section &Sec : Obj.getMutableSections()) {
+ const auto It = Config.SetSectionFlags.find(Sec.Name);
+ if (It != Config.SetSectionFlags.end())
+ setSectionFlags(Sec, It->second.NewFlags);
+ }
+
+ for (const auto &Flag : Config.AddSection) {
+ StringRef SecName, FileName;
+ std::tie(SecName, FileName) = Flag.split("=");
+
+ auto BufOrErr = MemoryBuffer::getFile(FileName);
+ if (!BufOrErr)
+ return createFileError(FileName, errorCodeToError(BufOrErr.getError()));
+ auto Buf = std::move(*BufOrErr);
+
+ addSection(
+ Obj, SecName,
+ makeArrayRef(reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
+ Buf->getBufferSize()),
+ IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES);
+ }
+
+ if (!Config.AddGnuDebugLink.empty())
if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink))
return E;
-
- if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
- Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
- !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
- !Config.AllocSectionsPrefix.empty() || !Config.DumpSection.empty() ||
- !Config.KeepSection.empty() || Config.NewSymbolVisibility ||
- !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
- !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
- !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
- !Config.SetSectionAlignment.empty() || Config.ExtractDWO ||
- Config.LocalizeHidden || Config.PreserveDates || Config.StripDWO ||
- Config.StripNonAlloc || Config.StripSections ||
- Config.StripSwiftSymbols || Config.Weaken ||
- Config.DecompressDebugSections ||
- Config.DiscardMode == DiscardType::Locals ||
- !Config.SymbolsToAdd.empty() || Config.EntryExpr) {
- return createStringError(llvm::errc::invalid_argument,
- "option not supported by llvm-objcopy for COFF");
- }
-
- return Error::success();
-}
-
-Error executeObjcopyOnBinary(const CopyConfig &Config, COFFObjectFile &In,
- Buffer &Out) {
- COFFReader Reader(In);
- Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
- if (!ObjOrErr)
- return createFileError(Config.InputFilename, ObjOrErr.takeError());
- Object *Obj = ObjOrErr->get();
- assert(Obj && "Unable to deserialize COFF object");
- if (Error E = handleArgs(Config, *Obj))
- return createFileError(Config.InputFilename, std::move(E));
- COFFWriter Writer(*Obj, Out);
- if (Error E = Writer.write())
- return createFileError(Config.OutputFilename, std::move(E));
- return Error::success();
-}
-
-} // end namespace coff
-} // end namespace objcopy
-} // end namespace llvm
+
+ if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
+ Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
+ !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
+ !Config.AllocSectionsPrefix.empty() || !Config.DumpSection.empty() ||
+ !Config.KeepSection.empty() || Config.NewSymbolVisibility ||
+ !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
+ !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
+ !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
+ !Config.SetSectionAlignment.empty() || Config.ExtractDWO ||
+ Config.LocalizeHidden || Config.PreserveDates || Config.StripDWO ||
+ Config.StripNonAlloc || Config.StripSections ||
+ Config.StripSwiftSymbols || Config.Weaken ||
+ Config.DecompressDebugSections ||
+ Config.DiscardMode == DiscardType::Locals ||
+ !Config.SymbolsToAdd.empty() || Config.EntryExpr) {
+ return createStringError(llvm::errc::invalid_argument,
+ "option not supported by llvm-objcopy for COFF");
+ }
+
+ return Error::success();
+}
+
+Error executeObjcopyOnBinary(const CopyConfig &Config, COFFObjectFile &In,
+ Buffer &Out) {
+ COFFReader Reader(In);
+ Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
+ if (!ObjOrErr)
+ return createFileError(Config.InputFilename, ObjOrErr.takeError());
+ Object *Obj = ObjOrErr->get();
+ assert(Obj && "Unable to deserialize COFF object");
+ if (Error E = handleArgs(Config, *Obj))
+ return createFileError(Config.InputFilename, std::move(E));
+ COFFWriter Writer(*Obj, Out);
+ if (Error E = Writer.write())
+ return createFileError(Config.OutputFilename, std::move(E));
+ return Error::success();
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.h b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.h
index 858759e52c..6b59f44946 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/COFFObjcopy.h
@@ -1,31 +1,31 @@
-//===- COFFObjcopy.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_OBJCOPY_COFFOBJCOPY_H
-#define LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H
-
-namespace llvm {
-class Error;
-
-namespace object {
-class COFFObjectFile;
-} // end namespace object
-
-namespace objcopy {
-struct CopyConfig;
-class Buffer;
-
-namespace coff {
-Error executeObjcopyOnBinary(const CopyConfig &Config,
- object::COFFObjectFile &In, Buffer &Out);
-
-} // end namespace coff
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H
+//===- COFFObjcopy.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_OBJCOPY_COFFOBJCOPY_H
+#define LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H
+
+namespace llvm {
+class Error;
+
+namespace object {
+class COFFObjectFile;
+} // end namespace object
+
+namespace objcopy {
+struct CopyConfig;
+class Buffer;
+
+namespace coff {
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::COFFObjectFile &In, Buffer &Out);
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.cpp
index 1c17b8408e..fc67f1cb4d 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.cpp
@@ -1,39 +1,39 @@
-//===- Object.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 "Object.h"
-#include "llvm/ADT/DenseSet.h"
-#include <algorithm>
-
-namespace llvm {
-namespace objcopy {
-namespace coff {
-
-using namespace object;
-
-void Object::addSymbols(ArrayRef<Symbol> NewSymbols) {
- for (Symbol S : NewSymbols) {
- S.UniqueId = NextSymbolUniqueId++;
- Symbols.emplace_back(S);
- }
- updateSymbols();
-}
-
-void Object::updateSymbols() {
- SymbolMap = DenseMap<size_t, Symbol *>(Symbols.size());
- for (Symbol &Sym : Symbols)
- SymbolMap[Sym.UniqueId] = &Sym;
-}
-
-const Symbol *Object::findSymbol(size_t UniqueId) const {
+//===- Object.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 "Object.h"
+#include "llvm/ADT/DenseSet.h"
+#include <algorithm>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+using namespace object;
+
+void Object::addSymbols(ArrayRef<Symbol> NewSymbols) {
+ for (Symbol S : NewSymbols) {
+ S.UniqueId = NextSymbolUniqueId++;
+ Symbols.emplace_back(S);
+ }
+ updateSymbols();
+}
+
+void Object::updateSymbols() {
+ SymbolMap = DenseMap<size_t, Symbol *>(Symbols.size());
+ for (Symbol &Sym : Symbols)
+ SymbolMap[Sym.UniqueId] = &Sym;
+}
+
+const Symbol *Object::findSymbol(size_t UniqueId) const {
return SymbolMap.lookup(UniqueId);
-}
-
+}
+
Error Object::removeSymbols(
function_ref<Expected<bool>(const Symbol &)> ToRemove) {
Error Errs = Error::success();
@@ -46,61 +46,61 @@ Error Object::removeSymbols(
return *ShouldRemove;
});
- updateSymbols();
+ updateSymbols();
return Errs;
-}
-
-Error Object::markSymbols() {
- for (Symbol &Sym : Symbols)
- Sym.Referenced = false;
- for (const Section &Sec : Sections) {
- for (const Relocation &R : Sec.Relocs) {
- auto It = SymbolMap.find(R.Target);
- if (It == SymbolMap.end())
- return createStringError(object_error::invalid_symbol_index,
- "relocation target %zu not found", R.Target);
- It->second->Referenced = true;
- }
- }
- return Error::success();
-}
-
-void Object::addSections(ArrayRef<Section> NewSections) {
- for (Section S : NewSections) {
- S.UniqueId = NextSectionUniqueId++;
- Sections.emplace_back(S);
- }
- updateSections();
-}
-
-void Object::updateSections() {
- SectionMap = DenseMap<ssize_t, Section *>(Sections.size());
- size_t Index = 1;
- for (Section &S : Sections) {
- SectionMap[S.UniqueId] = &S;
- S.Index = Index++;
- }
-}
-
-const Section *Object::findSection(ssize_t UniqueId) const {
+}
+
+Error Object::markSymbols() {
+ for (Symbol &Sym : Symbols)
+ Sym.Referenced = false;
+ for (const Section &Sec : Sections) {
+ for (const Relocation &R : Sec.Relocs) {
+ auto It = SymbolMap.find(R.Target);
+ if (It == SymbolMap.end())
+ return createStringError(object_error::invalid_symbol_index,
+ "relocation target %zu not found", R.Target);
+ It->second->Referenced = true;
+ }
+ }
+ return Error::success();
+}
+
+void Object::addSections(ArrayRef<Section> NewSections) {
+ for (Section S : NewSections) {
+ S.UniqueId = NextSectionUniqueId++;
+ Sections.emplace_back(S);
+ }
+ updateSections();
+}
+
+void Object::updateSections() {
+ SectionMap = DenseMap<ssize_t, Section *>(Sections.size());
+ size_t Index = 1;
+ for (Section &S : Sections) {
+ SectionMap[S.UniqueId] = &S;
+ S.Index = Index++;
+ }
+}
+
+const Section *Object::findSection(ssize_t UniqueId) const {
return SectionMap.lookup(UniqueId);
-}
-
-void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
- DenseSet<ssize_t> AssociatedSections;
- auto RemoveAssociated = [&AssociatedSections](const Section &Sec) {
+}
+
+void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
+ DenseSet<ssize_t> AssociatedSections;
+ auto RemoveAssociated = [&AssociatedSections](const Section &Sec) {
return AssociatedSections.contains(Sec.UniqueId);
- };
- do {
- DenseSet<ssize_t> RemovedSections;
+ };
+ do {
+ DenseSet<ssize_t> RemovedSections;
llvm::erase_if(Sections, [ToRemove, &RemovedSections](const Section &Sec) {
bool Remove = ToRemove(Sec);
if (Remove)
RemovedSections.insert(Sec.UniqueId);
return Remove;
});
- // Remove all symbols referring to the removed sections.
- AssociatedSections.clear();
+ // Remove all symbols referring to the removed sections.
+ AssociatedSections.clear();
llvm::erase_if(
Symbols, [&RemovedSections, &AssociatedSections](const Symbol &Sym) {
// If there are sections that are associative to a removed
@@ -111,22 +111,22 @@ void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
AssociatedSections.insert(Sym.TargetSectionId);
return RemovedSections.contains(Sym.TargetSectionId);
});
- ToRemove = RemoveAssociated;
- } while (!AssociatedSections.empty());
- updateSections();
- updateSymbols();
-}
-
-void Object::truncateSections(function_ref<bool(const Section &)> ToTruncate) {
- for (Section &Sec : Sections) {
- if (ToTruncate(Sec)) {
- Sec.clearContents();
- Sec.Relocs.clear();
- Sec.Header.SizeOfRawData = 0;
- }
- }
-}
-
-} // end namespace coff
-} // end namespace objcopy
-} // end namespace llvm
+ ToRemove = RemoveAssociated;
+ } while (!AssociatedSections.empty());
+ updateSections();
+ updateSymbols();
+}
+
+void Object::truncateSections(function_ref<bool(const Section &)> ToTruncate) {
+ for (Section &Sec : Sections) {
+ if (ToTruncate(Sec)) {
+ Sec.clearContents();
+ Sec.Relocs.clear();
+ Sec.Header.SizeOfRawData = 0;
+ }
+ }
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.h b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.h
index 0e854b58cb..9602f56e63 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Object.h
@@ -1,211 +1,211 @@
-//===- Object.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_OBJCOPY_COFF_OBJECT_H
-#define LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/BinaryFormat/COFF.h"
-#include "llvm/Object/COFF.h"
-#include <cstddef>
-#include <cstdint>
-#include <vector>
-
-namespace llvm {
-namespace objcopy {
-namespace coff {
-
-struct Relocation {
- Relocation() = default;
+//===- Object.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_OBJCOPY_COFF_OBJECT_H
+#define LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+struct Relocation {
+ Relocation() = default;
Relocation(const object::coff_relocation &R) : Reloc(R) {}
-
- object::coff_relocation Reloc;
- size_t Target = 0;
- StringRef TargetName; // Used for diagnostics only
-};
-
-struct Section {
- object::coff_section Header;
- std::vector<Relocation> Relocs;
- StringRef Name;
- ssize_t UniqueId;
- size_t Index;
-
- ArrayRef<uint8_t> getContents() const {
- if (!OwnedContents.empty())
- return OwnedContents;
- return ContentsRef;
- }
-
- void setContentsRef(ArrayRef<uint8_t> Data) {
- OwnedContents.clear();
- ContentsRef = Data;
- }
-
- void setOwnedContents(std::vector<uint8_t> &&Data) {
- ContentsRef = ArrayRef<uint8_t>();
- OwnedContents = std::move(Data);
- }
-
- void clearContents() {
- ContentsRef = ArrayRef<uint8_t>();
- OwnedContents.clear();
- }
-
-private:
- ArrayRef<uint8_t> ContentsRef;
- std::vector<uint8_t> OwnedContents;
-};
-
-struct AuxSymbol {
- AuxSymbol(ArrayRef<uint8_t> In) {
- assert(In.size() == sizeof(Opaque));
- std::copy(In.begin(), In.end(), Opaque);
- }
-
- ArrayRef<uint8_t> getRef() const {
- return ArrayRef<uint8_t>(Opaque, sizeof(Opaque));
- }
-
- uint8_t Opaque[sizeof(object::coff_symbol16)];
-};
-
-struct Symbol {
- object::coff_symbol32 Sym;
- StringRef Name;
- std::vector<AuxSymbol> AuxData;
- StringRef AuxFile;
- ssize_t TargetSectionId;
- ssize_t AssociativeComdatTargetSectionId = 0;
- Optional<size_t> WeakTargetSymbolId;
- size_t UniqueId;
- size_t RawIndex;
- bool Referenced;
-};
-
-struct Object {
- bool IsPE = false;
-
- object::dos_header DosHeader;
- ArrayRef<uint8_t> DosStub;
-
- object::coff_file_header CoffFileHeader;
-
- bool Is64 = false;
- object::pe32plus_header PeHeader;
- uint32_t BaseOfData = 0; // pe32plus_header lacks this field.
-
- std::vector<object::data_directory> DataDirectories;
-
- ArrayRef<Symbol> getSymbols() const { return Symbols; }
- // This allows mutating individual Symbols, but not mutating the list
- // of symbols itself.
- iterator_range<std::vector<Symbol>::iterator> getMutableSymbols() {
- return make_range(Symbols.begin(), Symbols.end());
- }
-
- const Symbol *findSymbol(size_t UniqueId) const;
-
- void addSymbols(ArrayRef<Symbol> NewSymbols);
+
+ object::coff_relocation Reloc;
+ size_t Target = 0;
+ StringRef TargetName; // Used for diagnostics only
+};
+
+struct Section {
+ object::coff_section Header;
+ std::vector<Relocation> Relocs;
+ StringRef Name;
+ ssize_t UniqueId;
+ size_t Index;
+
+ ArrayRef<uint8_t> getContents() const {
+ if (!OwnedContents.empty())
+ return OwnedContents;
+ return ContentsRef;
+ }
+
+ void setContentsRef(ArrayRef<uint8_t> Data) {
+ OwnedContents.clear();
+ ContentsRef = Data;
+ }
+
+ void setOwnedContents(std::vector<uint8_t> &&Data) {
+ ContentsRef = ArrayRef<uint8_t>();
+ OwnedContents = std::move(Data);
+ }
+
+ void clearContents() {
+ ContentsRef = ArrayRef<uint8_t>();
+ OwnedContents.clear();
+ }
+
+private:
+ ArrayRef<uint8_t> ContentsRef;
+ std::vector<uint8_t> OwnedContents;
+};
+
+struct AuxSymbol {
+ AuxSymbol(ArrayRef<uint8_t> In) {
+ assert(In.size() == sizeof(Opaque));
+ std::copy(In.begin(), In.end(), Opaque);
+ }
+
+ ArrayRef<uint8_t> getRef() const {
+ return ArrayRef<uint8_t>(Opaque, sizeof(Opaque));
+ }
+
+ uint8_t Opaque[sizeof(object::coff_symbol16)];
+};
+
+struct Symbol {
+ object::coff_symbol32 Sym;
+ StringRef Name;
+ std::vector<AuxSymbol> AuxData;
+ StringRef AuxFile;
+ ssize_t TargetSectionId;
+ ssize_t AssociativeComdatTargetSectionId = 0;
+ Optional<size_t> WeakTargetSymbolId;
+ size_t UniqueId;
+ size_t RawIndex;
+ bool Referenced;
+};
+
+struct Object {
+ bool IsPE = false;
+
+ object::dos_header DosHeader;
+ ArrayRef<uint8_t> DosStub;
+
+ object::coff_file_header CoffFileHeader;
+
+ bool Is64 = false;
+ object::pe32plus_header PeHeader;
+ uint32_t BaseOfData = 0; // pe32plus_header lacks this field.
+
+ std::vector<object::data_directory> DataDirectories;
+
+ ArrayRef<Symbol> getSymbols() const { return Symbols; }
+ // This allows mutating individual Symbols, but not mutating the list
+ // of symbols itself.
+ iterator_range<std::vector<Symbol>::iterator> getMutableSymbols() {
+ return make_range(Symbols.begin(), Symbols.end());
+ }
+
+ const Symbol *findSymbol(size_t UniqueId) const;
+
+ void addSymbols(ArrayRef<Symbol> NewSymbols);
Error removeSymbols(function_ref<Expected<bool>(const Symbol &)> ToRemove);
-
- // Set the Referenced field on all Symbols, based on relocations in
- // all sections.
- Error markSymbols();
-
- ArrayRef<Section> getSections() const { return Sections; }
- // This allows mutating individual Sections, but not mutating the list
- // of sections itself.
- iterator_range<std::vector<Section>::iterator> getMutableSections() {
- return make_range(Sections.begin(), Sections.end());
- }
-
- const Section *findSection(ssize_t UniqueId) const;
-
- void addSections(ArrayRef<Section> NewSections);
- void removeSections(function_ref<bool(const Section &)> ToRemove);
- void truncateSections(function_ref<bool(const Section &)> ToTruncate);
-
-private:
- std::vector<Symbol> Symbols;
- DenseMap<size_t, Symbol *> SymbolMap;
-
- size_t NextSymbolUniqueId = 0;
-
- std::vector<Section> Sections;
- DenseMap<ssize_t, Section *> SectionMap;
-
- ssize_t NextSectionUniqueId = 1; // Allow a UniqueId 0 to mean undefined.
-
- // Update SymbolMap.
- void updateSymbols();
-
- // Update SectionMap and Index in each Section.
- void updateSections();
-};
-
-// Copy between coff_symbol16 and coff_symbol32.
-// The source and destination files can use either coff_symbol16 or
-// coff_symbol32, while we always store them as coff_symbol32 in the
-// intermediate data structure.
-template <class Symbol1Ty, class Symbol2Ty>
-void copySymbol(Symbol1Ty &Dest, const Symbol2Ty &Src) {
- static_assert(sizeof(Dest.Name.ShortName) == sizeof(Src.Name.ShortName),
- "Mismatched name sizes");
- memcpy(Dest.Name.ShortName, Src.Name.ShortName, sizeof(Dest.Name.ShortName));
- Dest.Value = Src.Value;
- Dest.SectionNumber = Src.SectionNumber;
- Dest.Type = Src.Type;
- Dest.StorageClass = Src.StorageClass;
- Dest.NumberOfAuxSymbols = Src.NumberOfAuxSymbols;
-}
-
-// Copy between pe32_header and pe32plus_header.
-// We store the intermediate state in a pe32plus_header.
-template <class PeHeader1Ty, class PeHeader2Ty>
-void copyPeHeader(PeHeader1Ty &Dest, const PeHeader2Ty &Src) {
- Dest.Magic = Src.Magic;
- Dest.MajorLinkerVersion = Src.MajorLinkerVersion;
- Dest.MinorLinkerVersion = Src.MinorLinkerVersion;
- Dest.SizeOfCode = Src.SizeOfCode;
- Dest.SizeOfInitializedData = Src.SizeOfInitializedData;
- Dest.SizeOfUninitializedData = Src.SizeOfUninitializedData;
- Dest.AddressOfEntryPoint = Src.AddressOfEntryPoint;
- Dest.BaseOfCode = Src.BaseOfCode;
- Dest.ImageBase = Src.ImageBase;
- Dest.SectionAlignment = Src.SectionAlignment;
- Dest.FileAlignment = Src.FileAlignment;
- Dest.MajorOperatingSystemVersion = Src.MajorOperatingSystemVersion;
- Dest.MinorOperatingSystemVersion = Src.MinorOperatingSystemVersion;
- Dest.MajorImageVersion = Src.MajorImageVersion;
- Dest.MinorImageVersion = Src.MinorImageVersion;
- Dest.MajorSubsystemVersion = Src.MajorSubsystemVersion;
- Dest.MinorSubsystemVersion = Src.MinorSubsystemVersion;
- Dest.Win32VersionValue = Src.Win32VersionValue;
- Dest.SizeOfImage = Src.SizeOfImage;
- Dest.SizeOfHeaders = Src.SizeOfHeaders;
- Dest.CheckSum = Src.CheckSum;
- Dest.Subsystem = Src.Subsystem;
- Dest.DLLCharacteristics = Src.DLLCharacteristics;
- Dest.SizeOfStackReserve = Src.SizeOfStackReserve;
- Dest.SizeOfStackCommit = Src.SizeOfStackCommit;
- Dest.SizeOfHeapReserve = Src.SizeOfHeapReserve;
- Dest.SizeOfHeapCommit = Src.SizeOfHeapCommit;
- Dest.LoaderFlags = Src.LoaderFlags;
- Dest.NumberOfRvaAndSize = Src.NumberOfRvaAndSize;
-}
-
-} // end namespace coff
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H
+
+ // Set the Referenced field on all Symbols, based on relocations in
+ // all sections.
+ Error markSymbols();
+
+ ArrayRef<Section> getSections() const { return Sections; }
+ // This allows mutating individual Sections, but not mutating the list
+ // of sections itself.
+ iterator_range<std::vector<Section>::iterator> getMutableSections() {
+ return make_range(Sections.begin(), Sections.end());
+ }
+
+ const Section *findSection(ssize_t UniqueId) const;
+
+ void addSections(ArrayRef<Section> NewSections);
+ void removeSections(function_ref<bool(const Section &)> ToRemove);
+ void truncateSections(function_ref<bool(const Section &)> ToTruncate);
+
+private:
+ std::vector<Symbol> Symbols;
+ DenseMap<size_t, Symbol *> SymbolMap;
+
+ size_t NextSymbolUniqueId = 0;
+
+ std::vector<Section> Sections;
+ DenseMap<ssize_t, Section *> SectionMap;
+
+ ssize_t NextSectionUniqueId = 1; // Allow a UniqueId 0 to mean undefined.
+
+ // Update SymbolMap.
+ void updateSymbols();
+
+ // Update SectionMap and Index in each Section.
+ void updateSections();
+};
+
+// Copy between coff_symbol16 and coff_symbol32.
+// The source and destination files can use either coff_symbol16 or
+// coff_symbol32, while we always store them as coff_symbol32 in the
+// intermediate data structure.
+template <class Symbol1Ty, class Symbol2Ty>
+void copySymbol(Symbol1Ty &Dest, const Symbol2Ty &Src) {
+ static_assert(sizeof(Dest.Name.ShortName) == sizeof(Src.Name.ShortName),
+ "Mismatched name sizes");
+ memcpy(Dest.Name.ShortName, Src.Name.ShortName, sizeof(Dest.Name.ShortName));
+ Dest.Value = Src.Value;
+ Dest.SectionNumber = Src.SectionNumber;
+ Dest.Type = Src.Type;
+ Dest.StorageClass = Src.StorageClass;
+ Dest.NumberOfAuxSymbols = Src.NumberOfAuxSymbols;
+}
+
+// Copy between pe32_header and pe32plus_header.
+// We store the intermediate state in a pe32plus_header.
+template <class PeHeader1Ty, class PeHeader2Ty>
+void copyPeHeader(PeHeader1Ty &Dest, const PeHeader2Ty &Src) {
+ Dest.Magic = Src.Magic;
+ Dest.MajorLinkerVersion = Src.MajorLinkerVersion;
+ Dest.MinorLinkerVersion = Src.MinorLinkerVersion;
+ Dest.SizeOfCode = Src.SizeOfCode;
+ Dest.SizeOfInitializedData = Src.SizeOfInitializedData;
+ Dest.SizeOfUninitializedData = Src.SizeOfUninitializedData;
+ Dest.AddressOfEntryPoint = Src.AddressOfEntryPoint;
+ Dest.BaseOfCode = Src.BaseOfCode;
+ Dest.ImageBase = Src.ImageBase;
+ Dest.SectionAlignment = Src.SectionAlignment;
+ Dest.FileAlignment = Src.FileAlignment;
+ Dest.MajorOperatingSystemVersion = Src.MajorOperatingSystemVersion;
+ Dest.MinorOperatingSystemVersion = Src.MinorOperatingSystemVersion;
+ Dest.MajorImageVersion = Src.MajorImageVersion;
+ Dest.MinorImageVersion = Src.MinorImageVersion;
+ Dest.MajorSubsystemVersion = Src.MajorSubsystemVersion;
+ Dest.MinorSubsystemVersion = Src.MinorSubsystemVersion;
+ Dest.Win32VersionValue = Src.Win32VersionValue;
+ Dest.SizeOfImage = Src.SizeOfImage;
+ Dest.SizeOfHeaders = Src.SizeOfHeaders;
+ Dest.CheckSum = Src.CheckSum;
+ Dest.Subsystem = Src.Subsystem;
+ Dest.DLLCharacteristics = Src.DLLCharacteristics;
+ Dest.SizeOfStackReserve = Src.SizeOfStackReserve;
+ Dest.SizeOfStackCommit = Src.SizeOfStackCommit;
+ Dest.SizeOfHeapReserve = Src.SizeOfHeapReserve;
+ Dest.SizeOfHeapCommit = Src.SizeOfHeapCommit;
+ Dest.LoaderFlags = Src.LoaderFlags;
+ Dest.NumberOfRvaAndSize = Src.NumberOfRvaAndSize;
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.cpp
index d1beacb3bd..aafdc0f728 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.cpp
@@ -1,226 +1,226 @@
-//===- Reader.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 "Reader.h"
-#include "Object.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/BinaryFormat/COFF.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/ErrorHandling.h"
-#include <cstddef>
-#include <cstdint>
-
-namespace llvm {
-namespace objcopy {
-namespace coff {
-
-using namespace object;
-using namespace COFF;
-
-Error COFFReader::readExecutableHeaders(Object &Obj) const {
- const dos_header *DH = COFFObj.getDOSHeader();
- Obj.Is64 = COFFObj.is64();
- if (!DH)
- return Error::success();
-
- Obj.IsPE = true;
- Obj.DosHeader = *DH;
- if (DH->AddressOfNewExeHeader > sizeof(*DH))
- Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),
- DH->AddressOfNewExeHeader - sizeof(*DH));
-
- if (COFFObj.is64()) {
- Obj.PeHeader = *COFFObj.getPE32PlusHeader();
- } else {
- const pe32_header *PE32 = COFFObj.getPE32Header();
- copyPeHeader(Obj.PeHeader, *PE32);
- // The pe32plus_header (stored in Object) lacks the BaseOfData field.
- Obj.BaseOfData = PE32->BaseOfData;
- }
-
- for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {
- const data_directory *Dir = COFFObj.getDataDirectory(I);
- if (!Dir)
- return errorCodeToError(object_error::parse_failed);
- Obj.DataDirectories.emplace_back(*Dir);
- }
- return Error::success();
-}
-
-Error COFFReader::readSections(Object &Obj) const {
- std::vector<Section> Sections;
- // Section indexing starts from 1.
- for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
- Expected<const coff_section *> SecOrErr = COFFObj.getSection(I);
- if (!SecOrErr)
- return SecOrErr.takeError();
- const coff_section *Sec = *SecOrErr;
- Sections.push_back(Section());
- Section &S = Sections.back();
- S.Header = *Sec;
- S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
- ArrayRef<uint8_t> Contents;
- if (Error E = COFFObj.getSectionContents(Sec, Contents))
- return E;
- S.setContentsRef(Contents);
- ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
- for (const coff_relocation &R : Relocs)
- S.Relocs.push_back(R);
- if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))
- S.Name = *NameOrErr;
- else
- return NameOrErr.takeError();
- }
- Obj.addSections(Sections);
- return Error::success();
-}
-
-Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
- std::vector<Symbol> Symbols;
- Symbols.reserve(COFFObj.getRawNumberOfSymbols());
- ArrayRef<Section> Sections = Obj.getSections();
- for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
- Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
- if (!SymOrErr)
- return SymOrErr.takeError();
- COFFSymbolRef SymRef = *SymOrErr;
-
- Symbols.push_back(Symbol());
- Symbol &Sym = Symbols.back();
- // Copy symbols from the original form into an intermediate coff_symbol32.
- if (IsBigObj)
- copySymbol(Sym.Sym,
- *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));
- else
- copySymbol(Sym.Sym,
- *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
- auto NameOrErr = COFFObj.getSymbolName(SymRef);
- if (!NameOrErr)
- return NameOrErr.takeError();
- Sym.Name = *NameOrErr;
-
- ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
- size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
- assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
- // The auxillary symbols are structs of sizeof(coff_symbol16) each.
- // In the big object format (where symbols are coff_symbol32), each
- // auxillary symbol is padded with 2 bytes at the end. Copy each
- // auxillary symbol to the Sym.AuxData vector. For file symbols,
- // the whole range of aux symbols are interpreted as one null padded
- // string instead.
- if (SymRef.isFileRecord())
- Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
- AuxData.size())
- .rtrim('\0');
- else
- for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
- Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
-
- // Find the unique id of the section
- if (SymRef.getSectionNumber() <=
- 0) // Special symbol (undefined/absolute/debug)
- Sym.TargetSectionId = SymRef.getSectionNumber();
- else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
- Sections.size())
- Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
- else
- return createStringError(object_error::parse_failed,
- "section number out of range");
- // For section definitions, check if it is comdat associative, and if
- // it is, find the target section unique id.
- const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
- const coff_aux_weak_external *WE = SymRef.getWeakExternal();
- if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
- int32_t Index = SD->getNumber(IsBigObj);
- if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
- return createStringError(object_error::parse_failed,
- "unexpected associative section index");
- Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
- } else if (WE) {
- // This is a raw symbol index for now, but store it in the Symbol
- // until we've added them to the Object, which assigns the final
- // unique ids.
- Sym.WeakTargetSymbolId = WE->TagIndex;
- }
- I += 1 + SymRef.getNumberOfAuxSymbols();
- }
- Obj.addSymbols(Symbols);
- return Error::success();
-}
-
-Error COFFReader::setSymbolTargets(Object &Obj) const {
- std::vector<const Symbol *> RawSymbolTable;
- for (const Symbol &Sym : Obj.getSymbols()) {
- RawSymbolTable.push_back(&Sym);
- for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
- RawSymbolTable.push_back(nullptr);
- }
- for (Symbol &Sym : Obj.getMutableSymbols()) {
- // Convert WeakTargetSymbolId from the original raw symbol index to
- // a proper unique id.
- if (Sym.WeakTargetSymbolId) {
- if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
- return createStringError(object_error::parse_failed,
- "weak external reference out of range");
- const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
- if (Target == nullptr)
- return createStringError(object_error::parse_failed,
- "invalid SymbolTableIndex");
- Sym.WeakTargetSymbolId = Target->UniqueId;
- }
- }
- for (Section &Sec : Obj.getMutableSections()) {
- for (Relocation &R : Sec.Relocs) {
- if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
- return createStringError(object_error::parse_failed,
- "SymbolTableIndex out of range");
- const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
- if (Sym == nullptr)
- return createStringError(object_error::parse_failed,
- "invalid SymbolTableIndex");
- R.Target = Sym->UniqueId;
- R.TargetName = Sym->Name;
- }
- }
- return Error::success();
-}
-
-Expected<std::unique_ptr<Object>> COFFReader::create() const {
- auto Obj = std::make_unique<Object>();
-
- bool IsBigObj = false;
- if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) {
- Obj->CoffFileHeader = *CFH;
- } else {
- const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader();
- if (!CBFH)
- return createStringError(object_error::parse_failed,
- "no COFF file header returned");
- // Only copying the few fields from the bigobj header that we need
- // and won't recreate in the end.
- Obj->CoffFileHeader.Machine = CBFH->Machine;
- Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;
- IsBigObj = true;
- }
-
- if (Error E = readExecutableHeaders(*Obj))
- return std::move(E);
- if (Error E = readSections(*Obj))
- return std::move(E);
- if (Error E = readSymbols(*Obj, IsBigObj))
- return std::move(E);
- if (Error E = setSymbolTargets(*Obj))
- return std::move(E);
-
- return std::move(Obj);
-}
-
-} // end namespace coff
-} // end namespace objcopy
-} // end namespace llvm
+//===- Reader.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 "Reader.h"
+#include "Object.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+using namespace object;
+using namespace COFF;
+
+Error COFFReader::readExecutableHeaders(Object &Obj) const {
+ const dos_header *DH = COFFObj.getDOSHeader();
+ Obj.Is64 = COFFObj.is64();
+ if (!DH)
+ return Error::success();
+
+ Obj.IsPE = true;
+ Obj.DosHeader = *DH;
+ if (DH->AddressOfNewExeHeader > sizeof(*DH))
+ Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),
+ DH->AddressOfNewExeHeader - sizeof(*DH));
+
+ if (COFFObj.is64()) {
+ Obj.PeHeader = *COFFObj.getPE32PlusHeader();
+ } else {
+ const pe32_header *PE32 = COFFObj.getPE32Header();
+ copyPeHeader(Obj.PeHeader, *PE32);
+ // The pe32plus_header (stored in Object) lacks the BaseOfData field.
+ Obj.BaseOfData = PE32->BaseOfData;
+ }
+
+ for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {
+ const data_directory *Dir = COFFObj.getDataDirectory(I);
+ if (!Dir)
+ return errorCodeToError(object_error::parse_failed);
+ Obj.DataDirectories.emplace_back(*Dir);
+ }
+ return Error::success();
+}
+
+Error COFFReader::readSections(Object &Obj) const {
+ std::vector<Section> Sections;
+ // Section indexing starts from 1.
+ for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
+ Expected<const coff_section *> SecOrErr = COFFObj.getSection(I);
+ if (!SecOrErr)
+ return SecOrErr.takeError();
+ const coff_section *Sec = *SecOrErr;
+ Sections.push_back(Section());
+ Section &S = Sections.back();
+ S.Header = *Sec;
+ S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
+ ArrayRef<uint8_t> Contents;
+ if (Error E = COFFObj.getSectionContents(Sec, Contents))
+ return E;
+ S.setContentsRef(Contents);
+ ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
+ for (const coff_relocation &R : Relocs)
+ S.Relocs.push_back(R);
+ if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))
+ S.Name = *NameOrErr;
+ else
+ return NameOrErr.takeError();
+ }
+ Obj.addSections(Sections);
+ return Error::success();
+}
+
+Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
+ std::vector<Symbol> Symbols;
+ Symbols.reserve(COFFObj.getRawNumberOfSymbols());
+ ArrayRef<Section> Sections = Obj.getSections();
+ for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
+ Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
+ if (!SymOrErr)
+ return SymOrErr.takeError();
+ COFFSymbolRef SymRef = *SymOrErr;
+
+ Symbols.push_back(Symbol());
+ Symbol &Sym = Symbols.back();
+ // Copy symbols from the original form into an intermediate coff_symbol32.
+ if (IsBigObj)
+ copySymbol(Sym.Sym,
+ *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));
+ else
+ copySymbol(Sym.Sym,
+ *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
+ auto NameOrErr = COFFObj.getSymbolName(SymRef);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ Sym.Name = *NameOrErr;
+
+ ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
+ size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
+ assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
+ // The auxillary symbols are structs of sizeof(coff_symbol16) each.
+ // In the big object format (where symbols are coff_symbol32), each
+ // auxillary symbol is padded with 2 bytes at the end. Copy each
+ // auxillary symbol to the Sym.AuxData vector. For file symbols,
+ // the whole range of aux symbols are interpreted as one null padded
+ // string instead.
+ if (SymRef.isFileRecord())
+ Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
+ AuxData.size())
+ .rtrim('\0');
+ else
+ for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
+ Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
+
+ // Find the unique id of the section
+ if (SymRef.getSectionNumber() <=
+ 0) // Special symbol (undefined/absolute/debug)
+ Sym.TargetSectionId = SymRef.getSectionNumber();
+ else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
+ Sections.size())
+ Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
+ else
+ return createStringError(object_error::parse_failed,
+ "section number out of range");
+ // For section definitions, check if it is comdat associative, and if
+ // it is, find the target section unique id.
+ const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
+ const coff_aux_weak_external *WE = SymRef.getWeakExternal();
+ if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ int32_t Index = SD->getNumber(IsBigObj);
+ if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
+ return createStringError(object_error::parse_failed,
+ "unexpected associative section index");
+ Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
+ } else if (WE) {
+ // This is a raw symbol index for now, but store it in the Symbol
+ // until we've added them to the Object, which assigns the final
+ // unique ids.
+ Sym.WeakTargetSymbolId = WE->TagIndex;
+ }
+ I += 1 + SymRef.getNumberOfAuxSymbols();
+ }
+ Obj.addSymbols(Symbols);
+ return Error::success();
+}
+
+Error COFFReader::setSymbolTargets(Object &Obj) const {
+ std::vector<const Symbol *> RawSymbolTable;
+ for (const Symbol &Sym : Obj.getSymbols()) {
+ RawSymbolTable.push_back(&Sym);
+ for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
+ RawSymbolTable.push_back(nullptr);
+ }
+ for (Symbol &Sym : Obj.getMutableSymbols()) {
+ // Convert WeakTargetSymbolId from the original raw symbol index to
+ // a proper unique id.
+ if (Sym.WeakTargetSymbolId) {
+ if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
+ return createStringError(object_error::parse_failed,
+ "weak external reference out of range");
+ const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
+ if (Target == nullptr)
+ return createStringError(object_error::parse_failed,
+ "invalid SymbolTableIndex");
+ Sym.WeakTargetSymbolId = Target->UniqueId;
+ }
+ }
+ for (Section &Sec : Obj.getMutableSections()) {
+ for (Relocation &R : Sec.Relocs) {
+ if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
+ return createStringError(object_error::parse_failed,
+ "SymbolTableIndex out of range");
+ const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
+ if (Sym == nullptr)
+ return createStringError(object_error::parse_failed,
+ "invalid SymbolTableIndex");
+ R.Target = Sym->UniqueId;
+ R.TargetName = Sym->Name;
+ }
+ }
+ return Error::success();
+}
+
+Expected<std::unique_ptr<Object>> COFFReader::create() const {
+ auto Obj = std::make_unique<Object>();
+
+ bool IsBigObj = false;
+ if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) {
+ Obj->CoffFileHeader = *CFH;
+ } else {
+ const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader();
+ if (!CBFH)
+ return createStringError(object_error::parse_failed,
+ "no COFF file header returned");
+ // Only copying the few fields from the bigobj header that we need
+ // and won't recreate in the end.
+ Obj->CoffFileHeader.Machine = CBFH->Machine;
+ Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;
+ IsBigObj = true;
+ }
+
+ if (Error E = readExecutableHeaders(*Obj))
+ return std::move(E);
+ if (Error E = readSections(*Obj))
+ return std::move(E);
+ if (Error E = readSymbols(*Obj, IsBigObj))
+ return std::move(E);
+ if (Error E = setSymbolTargets(*Obj))
+ return std::move(E);
+
+ return std::move(Obj);
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.h b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.h
index ec15369db0..573b768c06 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Reader.h
@@ -1,42 +1,42 @@
-//===- Reader.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_OBJCOPY_COFF_READER_H
-#define LLVM_TOOLS_OBJCOPY_COFF_READER_H
-
-#include "Buffer.h"
-#include "llvm/BinaryFormat/COFF.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-namespace objcopy {
-namespace coff {
-
-struct Object;
-
-using object::COFFObjectFile;
-
-class COFFReader {
- const COFFObjectFile &COFFObj;
-
- Error readExecutableHeaders(Object &Obj) const;
- Error readSections(Object &Obj) const;
- Error readSymbols(Object &Obj, bool IsBigObj) const;
- Error setSymbolTargets(Object &Obj) const;
-
-public:
- explicit COFFReader(const COFFObjectFile &O) : COFFObj(O) {}
- Expected<std::unique_ptr<Object>> create() const;
-};
-
-} // end namespace coff
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_OBJCOPY_COFF_READER_H
+//===- Reader.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_OBJCOPY_COFF_READER_H
+#define LLVM_TOOLS_OBJCOPY_COFF_READER_H
+
+#include "Buffer.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+struct Object;
+
+using object::COFFObjectFile;
+
+class COFFReader {
+ const COFFObjectFile &COFFObj;
+
+ Error readExecutableHeaders(Object &Obj) const;
+ Error readSections(Object &Obj) const;
+ Error readSymbols(Object &Obj, bool IsBigObj) const;
+ Error setSymbolTargets(Object &Obj) const;
+
+public:
+ explicit COFFReader(const COFFObjectFile &O) : COFFObj(O) {}
+ Expected<std::unique_ptr<Object>> create() const;
+};
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_COFF_READER_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.cpp
index 6b560890a4..3fff721dcb 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.cpp
@@ -1,449 +1,449 @@
-//===- Writer.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 "Writer.h"
-#include "Object.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/BinaryFormat/COFF.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/ErrorHandling.h"
-#include <cstddef>
-#include <cstdint>
-
-namespace llvm {
-namespace objcopy {
-namespace coff {
-
-using namespace object;
-using namespace COFF;
-
-Error COFFWriter::finalizeRelocTargets() {
- for (Section &Sec : Obj.getMutableSections()) {
- for (Relocation &R : Sec.Relocs) {
- const Symbol *Sym = Obj.findSymbol(R.Target);
- if (Sym == nullptr)
- return createStringError(object_error::invalid_symbol_index,
- "relocation target '%s' (%zu) not found",
- R.TargetName.str().c_str(), R.Target);
- R.Reloc.SymbolTableIndex = Sym->RawIndex;
- }
- }
- return Error::success();
-}
-
-Error COFFWriter::finalizeSymbolContents() {
- for (Symbol &Sym : Obj.getMutableSymbols()) {
- if (Sym.TargetSectionId <= 0) {
- // Undefined, or a special kind of symbol. These negative values
- // are stored in the SectionNumber field which is unsigned.
- Sym.Sym.SectionNumber = static_cast<uint32_t>(Sym.TargetSectionId);
- } else {
- const Section *Sec = Obj.findSection(Sym.TargetSectionId);
- if (Sec == nullptr)
- return createStringError(object_error::invalid_symbol_index,
- "symbol '%s' points to a removed section",
- Sym.Name.str().c_str());
- Sym.Sym.SectionNumber = Sec->Index;
-
- if (Sym.Sym.NumberOfAuxSymbols == 1 &&
- Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) {
- coff_aux_section_definition *SD =
- reinterpret_cast<coff_aux_section_definition *>(
- Sym.AuxData[0].Opaque);
- uint32_t SDSectionNumber;
- if (Sym.AssociativeComdatTargetSectionId == 0) {
- // Not a comdat associative section; just set the Number field to
- // the number of the section itself.
- SDSectionNumber = Sec->Index;
- } else {
- Sec = Obj.findSection(Sym.AssociativeComdatTargetSectionId);
- if (Sec == nullptr)
- return createStringError(
- object_error::invalid_symbol_index,
- "symbol '%s' is associative to a removed section",
- Sym.Name.str().c_str());
- SDSectionNumber = Sec->Index;
- }
- // Update the section definition with the new section number.
- SD->NumberLowPart = static_cast<uint16_t>(SDSectionNumber);
- SD->NumberHighPart = static_cast<uint16_t>(SDSectionNumber >> 16);
- }
- }
- // Check that we actually have got AuxData to match the weak symbol target
- // we want to set. Only >= 1 would be required, but only == 1 makes sense.
- if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) {
- coff_aux_weak_external *WE =
- reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData[0].Opaque);
- const Symbol *Target = Obj.findSymbol(*Sym.WeakTargetSymbolId);
- if (Target == nullptr)
- return createStringError(object_error::invalid_symbol_index,
- "symbol '%s' is missing its weak target",
- Sym.Name.str().c_str());
- WE->TagIndex = Target->RawIndex;
- }
- }
- return Error::success();
-}
-
-void COFFWriter::layoutSections() {
- for (auto &S : Obj.getMutableSections()) {
- if (S.Header.SizeOfRawData > 0)
- S.Header.PointerToRawData = FileSize;
- FileSize += S.Header.SizeOfRawData; // For executables, this is already
- // aligned to FileAlignment.
- if (S.Relocs.size() >= 0xffff) {
- S.Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
- S.Header.NumberOfRelocations = 0xffff;
- S.Header.PointerToRelocations = FileSize;
- FileSize += sizeof(coff_relocation);
- } else {
- S.Header.NumberOfRelocations = S.Relocs.size();
- S.Header.PointerToRelocations = S.Relocs.size() ? FileSize : 0;
- }
-
- FileSize += S.Relocs.size() * sizeof(coff_relocation);
- FileSize = alignTo(FileSize, FileAlignment);
-
- if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
- SizeOfInitializedData += S.Header.SizeOfRawData;
- }
-}
-
-size_t COFFWriter::finalizeStringTable() {
- for (const auto &S : Obj.getSections())
- if (S.Name.size() > COFF::NameSize)
- StrTabBuilder.add(S.Name);
-
- for (const auto &S : Obj.getSymbols())
- if (S.Name.size() > COFF::NameSize)
- StrTabBuilder.add(S.Name);
-
- StrTabBuilder.finalize();
-
- for (auto &S : Obj.getMutableSections()) {
- memset(S.Header.Name, 0, sizeof(S.Header.Name));
- if (S.Name.size() > COFF::NameSize) {
- snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d",
- (int)StrTabBuilder.getOffset(S.Name));
- } else {
- memcpy(S.Header.Name, S.Name.data(), S.Name.size());
- }
- }
- for (auto &S : Obj.getMutableSymbols()) {
- if (S.Name.size() > COFF::NameSize) {
- S.Sym.Name.Offset.Zeroes = 0;
- S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name);
- } else {
- strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize);
- }
- }
- return StrTabBuilder.getSize();
-}
-
-template <class SymbolTy>
-std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
- size_t RawSymIndex = 0;
- for (auto &S : Obj.getMutableSymbols()) {
- // Symbols normally have NumberOfAuxSymbols set correctly all the time.
- // For file symbols, we need to know the output file's symbol size to be
- // able to calculate the number of slots it occupies.
- if (!S.AuxFile.empty())
- S.Sym.NumberOfAuxSymbols =
- alignTo(S.AuxFile.size(), sizeof(SymbolTy)) / sizeof(SymbolTy);
- S.RawIndex = RawSymIndex;
- RawSymIndex += 1 + S.Sym.NumberOfAuxSymbols;
- }
- return std::make_pair(RawSymIndex * sizeof(SymbolTy), sizeof(SymbolTy));
-}
-
-Error COFFWriter::finalize(bool IsBigObj) {
- size_t SymTabSize, SymbolSize;
- std::tie(SymTabSize, SymbolSize) = IsBigObj
- ? finalizeSymbolTable<coff_symbol32>()
- : finalizeSymbolTable<coff_symbol16>();
-
- if (Error E = finalizeRelocTargets())
- return E;
- if (Error E = finalizeSymbolContents())
- return E;
-
- size_t SizeOfHeaders = 0;
- FileAlignment = 1;
- size_t PeHeaderSize = 0;
- if (Obj.IsPE) {
- Obj.DosHeader.AddressOfNewExeHeader =
- sizeof(Obj.DosHeader) + Obj.DosStub.size();
- SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic);
-
- FileAlignment = Obj.PeHeader.FileAlignment;
- Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size();
-
- PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header);
- SizeOfHeaders +=
- PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
- }
- Obj.CoffFileHeader.NumberOfSections = Obj.getSections().size();
- SizeOfHeaders +=
- IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
- SizeOfHeaders += sizeof(coff_section) * Obj.getSections().size();
- SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
-
- Obj.CoffFileHeader.SizeOfOptionalHeader =
- PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
-
- FileSize = SizeOfHeaders;
- SizeOfInitializedData = 0;
-
- layoutSections();
-
- if (Obj.IsPE) {
- Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
- Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
-
- if (!Obj.getSections().empty()) {
- const Section &S = Obj.getSections().back();
- Obj.PeHeader.SizeOfImage =
- alignTo(S.Header.VirtualAddress + S.Header.VirtualSize,
- Obj.PeHeader.SectionAlignment);
- }
-
- // If the PE header had a checksum, clear it, since it isn't valid
- // any longer. (We don't calculate a new one.)
- Obj.PeHeader.CheckSum = 0;
- }
-
- size_t StrTabSize = finalizeStringTable();
-
- size_t PointerToSymbolTable = FileSize;
- // StrTabSize <= 4 is the size of an empty string table, only consisting
- // of the length field.
- if (SymTabSize == 0 && StrTabSize <= 4 && Obj.IsPE) {
- // For executables, don't point to the symbol table and skip writing
- // the length field, if both the symbol and string tables are empty.
- PointerToSymbolTable = 0;
- StrTabSize = 0;
- }
-
- size_t NumRawSymbols = SymTabSize / SymbolSize;
- Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable;
- Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols;
- FileSize += SymTabSize + StrTabSize;
- FileSize = alignTo(FileSize, FileAlignment);
-
- return Error::success();
-}
-
-void COFFWriter::writeHeaders(bool IsBigObj) {
- uint8_t *Ptr = Buf.getBufferStart();
- if (Obj.IsPE) {
- memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader));
- Ptr += sizeof(Obj.DosHeader);
- memcpy(Ptr, Obj.DosStub.data(), Obj.DosStub.size());
- Ptr += Obj.DosStub.size();
- memcpy(Ptr, PEMagic, sizeof(PEMagic));
- Ptr += sizeof(PEMagic);
- }
- if (!IsBigObj) {
- memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader));
- Ptr += sizeof(Obj.CoffFileHeader);
- } else {
- // Generate a coff_bigobj_file_header, filling it in with the values
- // from Obj.CoffFileHeader. All extra fields that don't exist in
- // coff_file_header can be set to hardcoded values.
- coff_bigobj_file_header BigObjHeader;
- BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN;
- BigObjHeader.Sig2 = 0xffff;
- BigObjHeader.Version = BigObjHeader::MinBigObjectVersion;
- BigObjHeader.Machine = Obj.CoffFileHeader.Machine;
- BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp;
- memcpy(BigObjHeader.UUID, BigObjMagic, sizeof(BigObjMagic));
- BigObjHeader.unused1 = 0;
- BigObjHeader.unused2 = 0;
- BigObjHeader.unused3 = 0;
- BigObjHeader.unused4 = 0;
- // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
- // get the original one instead.
- BigObjHeader.NumberOfSections = Obj.getSections().size();
- BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable;
- BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols;
-
- memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader));
- Ptr += sizeof(BigObjHeader);
- }
- if (Obj.IsPE) {
- if (Obj.Is64) {
- memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader));
- Ptr += sizeof(Obj.PeHeader);
- } else {
- pe32_header PeHeader;
- copyPeHeader(PeHeader, Obj.PeHeader);
- // The pe32plus_header (stored in Object) lacks the BaseOfData field.
- PeHeader.BaseOfData = Obj.BaseOfData;
-
- memcpy(Ptr, &PeHeader, sizeof(PeHeader));
- Ptr += sizeof(PeHeader);
- }
- for (const auto &DD : Obj.DataDirectories) {
- memcpy(Ptr, &DD, sizeof(DD));
- Ptr += sizeof(DD);
- }
- }
- for (const auto &S : Obj.getSections()) {
- memcpy(Ptr, &S.Header, sizeof(S.Header));
- Ptr += sizeof(S.Header);
- }
-}
-
-void COFFWriter::writeSections() {
- for (const auto &S : Obj.getSections()) {
- uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
- ArrayRef<uint8_t> Contents = S.getContents();
- std::copy(Contents.begin(), Contents.end(), Ptr);
-
- // For executable sections, pad the remainder of the raw data size with
- // 0xcc, which is int3 on x86.
- if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
- S.Header.SizeOfRawData > Contents.size())
- memset(Ptr + Contents.size(), 0xcc,
- S.Header.SizeOfRawData - Contents.size());
-
- Ptr += S.Header.SizeOfRawData;
-
- if (S.Relocs.size() >= 0xffff) {
- object::coff_relocation R;
- R.VirtualAddress = S.Relocs.size() + 1;
- R.SymbolTableIndex = 0;
- R.Type = 0;
- memcpy(Ptr, &R, sizeof(R));
- Ptr += sizeof(R);
- }
- for (const auto &R : S.Relocs) {
- memcpy(Ptr, &R.Reloc, sizeof(R.Reloc));
- Ptr += sizeof(R.Reloc);
- }
- }
-}
-
-template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
- uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable;
- for (const auto &S : Obj.getSymbols()) {
- // Convert symbols back to the right size, from coff_symbol32.
- copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
- S.Sym);
- Ptr += sizeof(SymbolTy);
- if (!S.AuxFile.empty()) {
- // For file symbols, just write the string into the aux symbol slots,
- // assuming that the unwritten parts are initialized to zero in the memory
- // mapped file.
- std::copy(S.AuxFile.begin(), S.AuxFile.end(), Ptr);
- Ptr += S.Sym.NumberOfAuxSymbols * sizeof(SymbolTy);
- } else {
- // For other auxillary symbols, write their opaque payload into one symbol
- // table slot each. For big object files, the symbols are larger than the
- // opaque auxillary symbol struct and we leave padding at the end of each
- // entry.
- for (const AuxSymbol &AuxSym : S.AuxData) {
- ArrayRef<uint8_t> Ref = AuxSym.getRef();
- std::copy(Ref.begin(), Ref.end(), Ptr);
- Ptr += sizeof(SymbolTy);
- }
- }
- }
- if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) {
- // Always write a string table in object files, even an empty one.
- StrTabBuilder.write(Ptr);
- Ptr += StrTabBuilder.getSize();
- }
-}
-
-Error COFFWriter::write(bool IsBigObj) {
- if (Error E = finalize(IsBigObj))
- return E;
-
- if (Error E = Buf.allocate(FileSize))
- return E;
-
- writeHeaders(IsBigObj);
- writeSections();
- if (IsBigObj)
- writeSymbolStringTables<coff_symbol32>();
- else
- writeSymbolStringTables<coff_symbol16>();
-
- if (Obj.IsPE)
- if (Error E = patchDebugDirectory())
- return E;
-
- return Buf.commit();
-}
-
-Expected<uint32_t> COFFWriter::virtualAddressToFileAddress(uint32_t RVA) {
- for (const auto &S : Obj.getSections()) {
- if (RVA >= S.Header.VirtualAddress &&
- RVA < S.Header.VirtualAddress + S.Header.SizeOfRawData)
- return S.Header.PointerToRawData + RVA - S.Header.VirtualAddress;
- }
- return createStringError(object_error::parse_failed,
- "debug directory payload not found");
-}
-
-// Locate which sections contain the debug directories, iterate over all
-// the debug_directory structs in there, and set the PointerToRawData field
-// in all of them, according to their new physical location in the file.
-Error COFFWriter::patchDebugDirectory() {
- if (Obj.DataDirectories.size() < DEBUG_DIRECTORY)
- return Error::success();
- const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
- if (Dir->Size <= 0)
- return Error::success();
- for (const auto &S : Obj.getSections()) {
- if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress &&
- Dir->RelativeVirtualAddress <
- S.Header.VirtualAddress + S.Header.SizeOfRawData) {
- if (Dir->RelativeVirtualAddress + Dir->Size >
- S.Header.VirtualAddress + S.Header.SizeOfRawData)
- return createStringError(object_error::parse_failed,
- "debug directory extends past end of section");
-
- size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
- uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset;
- uint8_t *End = Ptr + Dir->Size;
- while (Ptr < End) {
- debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr);
- if (!Debug->AddressOfRawData)
- return createStringError(object_error::parse_failed,
- "debug directory payload outside of "
- "mapped sections not supported");
- if (Expected<uint32_t> FilePosOrErr =
- virtualAddressToFileAddress(Debug->AddressOfRawData))
- Debug->PointerToRawData = *FilePosOrErr;
- else
- return FilePosOrErr.takeError();
- Ptr += sizeof(debug_directory);
- Offset += sizeof(debug_directory);
- }
- // Debug directory found and patched, all done.
- return Error::success();
- }
- }
- return createStringError(object_error::parse_failed,
- "debug directory not found");
-}
-
-Error COFFWriter::write() {
- bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16;
- if (IsBigObj && Obj.IsPE)
- return createStringError(object_error::parse_failed,
- "too many sections for executable");
- return write(IsBigObj);
-}
-
-} // end namespace coff
-} // end namespace objcopy
-} // end namespace llvm
+//===- Writer.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 "Writer.h"
+#include "Object.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+using namespace object;
+using namespace COFF;
+
+Error COFFWriter::finalizeRelocTargets() {
+ for (Section &Sec : Obj.getMutableSections()) {
+ for (Relocation &R : Sec.Relocs) {
+ const Symbol *Sym = Obj.findSymbol(R.Target);
+ if (Sym == nullptr)
+ return createStringError(object_error::invalid_symbol_index,
+ "relocation target '%s' (%zu) not found",
+ R.TargetName.str().c_str(), R.Target);
+ R.Reloc.SymbolTableIndex = Sym->RawIndex;
+ }
+ }
+ return Error::success();
+}
+
+Error COFFWriter::finalizeSymbolContents() {
+ for (Symbol &Sym : Obj.getMutableSymbols()) {
+ if (Sym.TargetSectionId <= 0) {
+ // Undefined, or a special kind of symbol. These negative values
+ // are stored in the SectionNumber field which is unsigned.
+ Sym.Sym.SectionNumber = static_cast<uint32_t>(Sym.TargetSectionId);
+ } else {
+ const Section *Sec = Obj.findSection(Sym.TargetSectionId);
+ if (Sec == nullptr)
+ return createStringError(object_error::invalid_symbol_index,
+ "symbol '%s' points to a removed section",
+ Sym.Name.str().c_str());
+ Sym.Sym.SectionNumber = Sec->Index;
+
+ if (Sym.Sym.NumberOfAuxSymbols == 1 &&
+ Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) {
+ coff_aux_section_definition *SD =
+ reinterpret_cast<coff_aux_section_definition *>(
+ Sym.AuxData[0].Opaque);
+ uint32_t SDSectionNumber;
+ if (Sym.AssociativeComdatTargetSectionId == 0) {
+ // Not a comdat associative section; just set the Number field to
+ // the number of the section itself.
+ SDSectionNumber = Sec->Index;
+ } else {
+ Sec = Obj.findSection(Sym.AssociativeComdatTargetSectionId);
+ if (Sec == nullptr)
+ return createStringError(
+ object_error::invalid_symbol_index,
+ "symbol '%s' is associative to a removed section",
+ Sym.Name.str().c_str());
+ SDSectionNumber = Sec->Index;
+ }
+ // Update the section definition with the new section number.
+ SD->NumberLowPart = static_cast<uint16_t>(SDSectionNumber);
+ SD->NumberHighPart = static_cast<uint16_t>(SDSectionNumber >> 16);
+ }
+ }
+ // Check that we actually have got AuxData to match the weak symbol target
+ // we want to set. Only >= 1 would be required, but only == 1 makes sense.
+ if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) {
+ coff_aux_weak_external *WE =
+ reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData[0].Opaque);
+ const Symbol *Target = Obj.findSymbol(*Sym.WeakTargetSymbolId);
+ if (Target == nullptr)
+ return createStringError(object_error::invalid_symbol_index,
+ "symbol '%s' is missing its weak target",
+ Sym.Name.str().c_str());
+ WE->TagIndex = Target->RawIndex;
+ }
+ }
+ return Error::success();
+}
+
+void COFFWriter::layoutSections() {
+ for (auto &S : Obj.getMutableSections()) {
+ if (S.Header.SizeOfRawData > 0)
+ S.Header.PointerToRawData = FileSize;
+ FileSize += S.Header.SizeOfRawData; // For executables, this is already
+ // aligned to FileAlignment.
+ if (S.Relocs.size() >= 0xffff) {
+ S.Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
+ S.Header.NumberOfRelocations = 0xffff;
+ S.Header.PointerToRelocations = FileSize;
+ FileSize += sizeof(coff_relocation);
+ } else {
+ S.Header.NumberOfRelocations = S.Relocs.size();
+ S.Header.PointerToRelocations = S.Relocs.size() ? FileSize : 0;
+ }
+
+ FileSize += S.Relocs.size() * sizeof(coff_relocation);
+ FileSize = alignTo(FileSize, FileAlignment);
+
+ if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
+ SizeOfInitializedData += S.Header.SizeOfRawData;
+ }
+}
+
+size_t COFFWriter::finalizeStringTable() {
+ for (const auto &S : Obj.getSections())
+ if (S.Name.size() > COFF::NameSize)
+ StrTabBuilder.add(S.Name);
+
+ for (const auto &S : Obj.getSymbols())
+ if (S.Name.size() > COFF::NameSize)
+ StrTabBuilder.add(S.Name);
+
+ StrTabBuilder.finalize();
+
+ for (auto &S : Obj.getMutableSections()) {
+ memset(S.Header.Name, 0, sizeof(S.Header.Name));
+ if (S.Name.size() > COFF::NameSize) {
+ snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d",
+ (int)StrTabBuilder.getOffset(S.Name));
+ } else {
+ memcpy(S.Header.Name, S.Name.data(), S.Name.size());
+ }
+ }
+ for (auto &S : Obj.getMutableSymbols()) {
+ if (S.Name.size() > COFF::NameSize) {
+ S.Sym.Name.Offset.Zeroes = 0;
+ S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name);
+ } else {
+ strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize);
+ }
+ }
+ return StrTabBuilder.getSize();
+}
+
+template <class SymbolTy>
+std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
+ size_t RawSymIndex = 0;
+ for (auto &S : Obj.getMutableSymbols()) {
+ // Symbols normally have NumberOfAuxSymbols set correctly all the time.
+ // For file symbols, we need to know the output file's symbol size to be
+ // able to calculate the number of slots it occupies.
+ if (!S.AuxFile.empty())
+ S.Sym.NumberOfAuxSymbols =
+ alignTo(S.AuxFile.size(), sizeof(SymbolTy)) / sizeof(SymbolTy);
+ S.RawIndex = RawSymIndex;
+ RawSymIndex += 1 + S.Sym.NumberOfAuxSymbols;
+ }
+ return std::make_pair(RawSymIndex * sizeof(SymbolTy), sizeof(SymbolTy));
+}
+
+Error COFFWriter::finalize(bool IsBigObj) {
+ size_t SymTabSize, SymbolSize;
+ std::tie(SymTabSize, SymbolSize) = IsBigObj
+ ? finalizeSymbolTable<coff_symbol32>()
+ : finalizeSymbolTable<coff_symbol16>();
+
+ if (Error E = finalizeRelocTargets())
+ return E;
+ if (Error E = finalizeSymbolContents())
+ return E;
+
+ size_t SizeOfHeaders = 0;
+ FileAlignment = 1;
+ size_t PeHeaderSize = 0;
+ if (Obj.IsPE) {
+ Obj.DosHeader.AddressOfNewExeHeader =
+ sizeof(Obj.DosHeader) + Obj.DosStub.size();
+ SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic);
+
+ FileAlignment = Obj.PeHeader.FileAlignment;
+ Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size();
+
+ PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header);
+ SizeOfHeaders +=
+ PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
+ }
+ Obj.CoffFileHeader.NumberOfSections = Obj.getSections().size();
+ SizeOfHeaders +=
+ IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
+ SizeOfHeaders += sizeof(coff_section) * Obj.getSections().size();
+ SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
+
+ Obj.CoffFileHeader.SizeOfOptionalHeader =
+ PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
+
+ FileSize = SizeOfHeaders;
+ SizeOfInitializedData = 0;
+
+ layoutSections();
+
+ if (Obj.IsPE) {
+ Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
+ Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
+
+ if (!Obj.getSections().empty()) {
+ const Section &S = Obj.getSections().back();
+ Obj.PeHeader.SizeOfImage =
+ alignTo(S.Header.VirtualAddress + S.Header.VirtualSize,
+ Obj.PeHeader.SectionAlignment);
+ }
+
+ // If the PE header had a checksum, clear it, since it isn't valid
+ // any longer. (We don't calculate a new one.)
+ Obj.PeHeader.CheckSum = 0;
+ }
+
+ size_t StrTabSize = finalizeStringTable();
+
+ size_t PointerToSymbolTable = FileSize;
+ // StrTabSize <= 4 is the size of an empty string table, only consisting
+ // of the length field.
+ if (SymTabSize == 0 && StrTabSize <= 4 && Obj.IsPE) {
+ // For executables, don't point to the symbol table and skip writing
+ // the length field, if both the symbol and string tables are empty.
+ PointerToSymbolTable = 0;
+ StrTabSize = 0;
+ }
+
+ size_t NumRawSymbols = SymTabSize / SymbolSize;
+ Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable;
+ Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols;
+ FileSize += SymTabSize + StrTabSize;
+ FileSize = alignTo(FileSize, FileAlignment);
+
+ return Error::success();
+}
+
+void COFFWriter::writeHeaders(bool IsBigObj) {
+ uint8_t *Ptr = Buf.getBufferStart();
+ if (Obj.IsPE) {
+ memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader));
+ Ptr += sizeof(Obj.DosHeader);
+ memcpy(Ptr, Obj.DosStub.data(), Obj.DosStub.size());
+ Ptr += Obj.DosStub.size();
+ memcpy(Ptr, PEMagic, sizeof(PEMagic));
+ Ptr += sizeof(PEMagic);
+ }
+ if (!IsBigObj) {
+ memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader));
+ Ptr += sizeof(Obj.CoffFileHeader);
+ } else {
+ // Generate a coff_bigobj_file_header, filling it in with the values
+ // from Obj.CoffFileHeader. All extra fields that don't exist in
+ // coff_file_header can be set to hardcoded values.
+ coff_bigobj_file_header BigObjHeader;
+ BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN;
+ BigObjHeader.Sig2 = 0xffff;
+ BigObjHeader.Version = BigObjHeader::MinBigObjectVersion;
+ BigObjHeader.Machine = Obj.CoffFileHeader.Machine;
+ BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp;
+ memcpy(BigObjHeader.UUID, BigObjMagic, sizeof(BigObjMagic));
+ BigObjHeader.unused1 = 0;
+ BigObjHeader.unused2 = 0;
+ BigObjHeader.unused3 = 0;
+ BigObjHeader.unused4 = 0;
+ // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
+ // get the original one instead.
+ BigObjHeader.NumberOfSections = Obj.getSections().size();
+ BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable;
+ BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols;
+
+ memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader));
+ Ptr += sizeof(BigObjHeader);
+ }
+ if (Obj.IsPE) {
+ if (Obj.Is64) {
+ memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader));
+ Ptr += sizeof(Obj.PeHeader);
+ } else {
+ pe32_header PeHeader;
+ copyPeHeader(PeHeader, Obj.PeHeader);
+ // The pe32plus_header (stored in Object) lacks the BaseOfData field.
+ PeHeader.BaseOfData = Obj.BaseOfData;
+
+ memcpy(Ptr, &PeHeader, sizeof(PeHeader));
+ Ptr += sizeof(PeHeader);
+ }
+ for (const auto &DD : Obj.DataDirectories) {
+ memcpy(Ptr, &DD, sizeof(DD));
+ Ptr += sizeof(DD);
+ }
+ }
+ for (const auto &S : Obj.getSections()) {
+ memcpy(Ptr, &S.Header, sizeof(S.Header));
+ Ptr += sizeof(S.Header);
+ }
+}
+
+void COFFWriter::writeSections() {
+ for (const auto &S : Obj.getSections()) {
+ uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
+ ArrayRef<uint8_t> Contents = S.getContents();
+ std::copy(Contents.begin(), Contents.end(), Ptr);
+
+ // For executable sections, pad the remainder of the raw data size with
+ // 0xcc, which is int3 on x86.
+ if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
+ S.Header.SizeOfRawData > Contents.size())
+ memset(Ptr + Contents.size(), 0xcc,
+ S.Header.SizeOfRawData - Contents.size());
+
+ Ptr += S.Header.SizeOfRawData;
+
+ if (S.Relocs.size() >= 0xffff) {
+ object::coff_relocation R;
+ R.VirtualAddress = S.Relocs.size() + 1;
+ R.SymbolTableIndex = 0;
+ R.Type = 0;
+ memcpy(Ptr, &R, sizeof(R));
+ Ptr += sizeof(R);
+ }
+ for (const auto &R : S.Relocs) {
+ memcpy(Ptr, &R.Reloc, sizeof(R.Reloc));
+ Ptr += sizeof(R.Reloc);
+ }
+ }
+}
+
+template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
+ uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable;
+ for (const auto &S : Obj.getSymbols()) {
+ // Convert symbols back to the right size, from coff_symbol32.
+ copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
+ S.Sym);
+ Ptr += sizeof(SymbolTy);
+ if (!S.AuxFile.empty()) {
+ // For file symbols, just write the string into the aux symbol slots,
+ // assuming that the unwritten parts are initialized to zero in the memory
+ // mapped file.
+ std::copy(S.AuxFile.begin(), S.AuxFile.end(), Ptr);
+ Ptr += S.Sym.NumberOfAuxSymbols * sizeof(SymbolTy);
+ } else {
+ // For other auxillary symbols, write their opaque payload into one symbol
+ // table slot each. For big object files, the symbols are larger than the
+ // opaque auxillary symbol struct and we leave padding at the end of each
+ // entry.
+ for (const AuxSymbol &AuxSym : S.AuxData) {
+ ArrayRef<uint8_t> Ref = AuxSym.getRef();
+ std::copy(Ref.begin(), Ref.end(), Ptr);
+ Ptr += sizeof(SymbolTy);
+ }
+ }
+ }
+ if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) {
+ // Always write a string table in object files, even an empty one.
+ StrTabBuilder.write(Ptr);
+ Ptr += StrTabBuilder.getSize();
+ }
+}
+
+Error COFFWriter::write(bool IsBigObj) {
+ if (Error E = finalize(IsBigObj))
+ return E;
+
+ if (Error E = Buf.allocate(FileSize))
+ return E;
+
+ writeHeaders(IsBigObj);
+ writeSections();
+ if (IsBigObj)
+ writeSymbolStringTables<coff_symbol32>();
+ else
+ writeSymbolStringTables<coff_symbol16>();
+
+ if (Obj.IsPE)
+ if (Error E = patchDebugDirectory())
+ return E;
+
+ return Buf.commit();
+}
+
+Expected<uint32_t> COFFWriter::virtualAddressToFileAddress(uint32_t RVA) {
+ for (const auto &S : Obj.getSections()) {
+ if (RVA >= S.Header.VirtualAddress &&
+ RVA < S.Header.VirtualAddress + S.Header.SizeOfRawData)
+ return S.Header.PointerToRawData + RVA - S.Header.VirtualAddress;
+ }
+ return createStringError(object_error::parse_failed,
+ "debug directory payload not found");
+}
+
+// Locate which sections contain the debug directories, iterate over all
+// the debug_directory structs in there, and set the PointerToRawData field
+// in all of them, according to their new physical location in the file.
+Error COFFWriter::patchDebugDirectory() {
+ if (Obj.DataDirectories.size() < DEBUG_DIRECTORY)
+ return Error::success();
+ const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
+ if (Dir->Size <= 0)
+ return Error::success();
+ for (const auto &S : Obj.getSections()) {
+ if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress &&
+ Dir->RelativeVirtualAddress <
+ S.Header.VirtualAddress + S.Header.SizeOfRawData) {
+ if (Dir->RelativeVirtualAddress + Dir->Size >
+ S.Header.VirtualAddress + S.Header.SizeOfRawData)
+ return createStringError(object_error::parse_failed,
+ "debug directory extends past end of section");
+
+ size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
+ uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset;
+ uint8_t *End = Ptr + Dir->Size;
+ while (Ptr < End) {
+ debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr);
+ if (!Debug->AddressOfRawData)
+ return createStringError(object_error::parse_failed,
+ "debug directory payload outside of "
+ "mapped sections not supported");
+ if (Expected<uint32_t> FilePosOrErr =
+ virtualAddressToFileAddress(Debug->AddressOfRawData))
+ Debug->PointerToRawData = *FilePosOrErr;
+ else
+ return FilePosOrErr.takeError();
+ Ptr += sizeof(debug_directory);
+ Offset += sizeof(debug_directory);
+ }
+ // Debug directory found and patched, all done.
+ return Error::success();
+ }
+ }
+ return createStringError(object_error::parse_failed,
+ "debug directory not found");
+}
+
+Error COFFWriter::write() {
+ bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16;
+ if (IsBigObj && Obj.IsPE)
+ return createStringError(object_error::parse_failed,
+ "too many sections for executable");
+ return write(IsBigObj);
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.h b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.h
index 3c0bdcbd5d..cd6a17984c 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/COFF/Writer.h
@@ -1,62 +1,62 @@
-//===- Writer.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_OBJCOPY_COFF_WRITER_H
-#define LLVM_TOOLS_OBJCOPY_COFF_WRITER_H
-
-#include "Buffer.h"
-#include "llvm/MC/StringTableBuilder.h"
-#include "llvm/Support/Error.h"
-#include <cstddef>
-#include <utility>
-
-namespace llvm {
-namespace objcopy {
-namespace coff {
-
-struct Object;
-
-class COFFWriter {
- Object &Obj;
- Buffer &Buf;
-
- size_t FileSize;
- size_t FileAlignment;
- size_t SizeOfInitializedData;
- StringTableBuilder StrTabBuilder;
-
- template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
- Error finalizeRelocTargets();
- Error finalizeSymbolContents();
- void layoutSections();
- size_t finalizeStringTable();
-
- Error finalize(bool IsBigObj);
-
- void writeHeaders(bool IsBigObj);
- void writeSections();
- template <class SymbolTy> void writeSymbolStringTables();
-
- Error write(bool IsBigObj);
-
- Error patchDebugDirectory();
- Expected<uint32_t> virtualAddressToFileAddress(uint32_t RVA);
-
-public:
- virtual ~COFFWriter() {}
- Error write();
-
- COFFWriter(Object &Obj, Buffer &Buf)
- : Obj(Obj), Buf(Buf), StrTabBuilder(StringTableBuilder::WinCOFF) {}
-};
-
-} // end namespace coff
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_OBJCOPY_COFF_WRITER_H
+//===- Writer.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_OBJCOPY_COFF_WRITER_H
+#define LLVM_TOOLS_OBJCOPY_COFF_WRITER_H
+
+#include "Buffer.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+#include <utility>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+struct Object;
+
+class COFFWriter {
+ Object &Obj;
+ Buffer &Buf;
+
+ size_t FileSize;
+ size_t FileAlignment;
+ size_t SizeOfInitializedData;
+ StringTableBuilder StrTabBuilder;
+
+ template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
+ Error finalizeRelocTargets();
+ Error finalizeSymbolContents();
+ void layoutSections();
+ size_t finalizeStringTable();
+
+ Error finalize(bool IsBigObj);
+
+ void writeHeaders(bool IsBigObj);
+ void writeSections();
+ template <class SymbolTy> void writeSymbolStringTables();
+
+ Error write(bool IsBigObj);
+
+ Error patchDebugDirectory();
+ Expected<uint32_t> virtualAddressToFileAddress(uint32_t RVA);
+
+public:
+ virtual ~COFFWriter() {}
+ Error write();
+
+ COFFWriter(Object &Obj, Buffer &Buf)
+ : Obj(Obj), Buf(Buf), StrTabBuilder(StringTableBuilder::WinCOFF) {}
+};
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_COFF_WRITER_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/CommonOpts.td b/contrib/libs/llvm12/tools/llvm-objcopy/CommonOpts.td
index 6481d1d1df..8f29e1346d 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/CommonOpts.td
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/CommonOpts.td
@@ -1,125 +1,125 @@
-include "llvm/Option/OptParser.td"
-
-multiclass Eq<string name, string help> {
- def NAME : Separate<["--"], name>;
- def NAME #_eq : Joined<["--"], name #"=">,
- Alias<!cast<Separate>(NAME)>,
- HelpText<help>;
-}
-
-def help : Flag<["--"], "help">;
-def h : Flag<["-"], "h">, Alias<help>;
-
-def allow_broken_links
- : Flag<["--"], "allow-broken-links">,
- HelpText<"Allow the tool to remove sections even if it would leave "
- "invalid section references. The appropriate sh_link fields "
- "will be set to zero.">;
-
-def enable_deterministic_archives
- : Flag<["--"], "enable-deterministic-archives">,
- HelpText<"Enable deterministic mode when operating on archives (use "
- "zero for UIDs, GIDs, and timestamps).">;
-def D : Flag<["-"], "D">,
- Alias<enable_deterministic_archives>,
- HelpText<"Alias for --enable-deterministic-archives">;
-
-def disable_deterministic_archives
- : Flag<["--"], "disable-deterministic-archives">,
- HelpText<"Disable deterministic mode when operating on archives (use "
- "real values for UIDs, GIDs, and timestamps).">;
-def U : Flag<["-"], "U">,
- Alias<disable_deterministic_archives>,
- HelpText<"Alias for --disable-deterministic-archives">;
-
-def preserve_dates : Flag<["--"], "preserve-dates">,
- HelpText<"Preserve access and modification timestamps">;
-def p : Flag<["-"], "p">,
- Alias<preserve_dates>,
- HelpText<"Alias for --preserve-dates">;
-
-def strip_all : Flag<["--"], "strip-all">,
- HelpText<"Remove non-allocated sections outside segments. "
- ".gnu.warning* and .ARM.attribute sections are not "
- "removed">;
-
-def strip_all_gnu
- : Flag<["--"], "strip-all-gnu">,
- HelpText<"Compatible with GNU's --strip-all">;
-
-def strip_debug : Flag<["--"], "strip-debug">,
- HelpText<"Remove all debug sections">;
-def g : Flag<["-"], "g">,
- Alias<strip_debug>,
- HelpText<"Alias for --strip-debug">;
-
-def strip_unneeded : Flag<["--"], "strip-unneeded">,
- HelpText<"Remove all symbols not needed by relocations">;
-
-defm remove_section : Eq<"remove-section", "Remove <section>">,
- MetaVarName<"section">;
-def R : JoinedOrSeparate<["-"], "R">,
- Alias<remove_section>,
- HelpText<"Alias for --remove-section">;
-
-def strip_sections
- : Flag<["--"], "strip-sections">,
- HelpText<"Remove all section headers and all sections not in segments">;
-
-defm strip_symbol : Eq<"strip-symbol", "Strip <symbol>">,
- MetaVarName<"symbol">;
-def N : JoinedOrSeparate<["-"], "N">,
- Alias<strip_symbol>,
- HelpText<"Alias for --strip-symbol">;
-
-defm keep_section : Eq<"keep-section", "Keep <section>">,
- MetaVarName<"section">;
-
-defm keep_symbol : Eq<"keep-symbol", "Do not remove symbol <symbol>">,
- MetaVarName<"symbol">;
-def K : JoinedOrSeparate<["-"], "K">,
- Alias<keep_symbol>,
- HelpText<"Alias for --keep-symbol">;
-
-def keep_file_symbols : Flag<["--"], "keep-file-symbols">,
- HelpText<"Do not remove file symbols">;
-
-def only_keep_debug
- : Flag<["--"], "only-keep-debug">,
- HelpText<
- "Produce a debug file as the output that only preserves contents of "
- "sections useful for debugging purposes">;
-
-def discard_locals : Flag<["--"], "discard-locals">,
- HelpText<"Remove compiler-generated local symbols, (e.g. "
- "symbols starting with .L)">;
-def X : Flag<["-"], "X">,
- Alias<discard_locals>,
- HelpText<"Alias for --discard-locals">;
-
-def discard_all
- : Flag<["--"], "discard-all">,
- HelpText<"Remove all local symbols except file and section symbols">;
-def x : Flag<["-"], "x">,
- Alias<discard_all>,
- HelpText<"Alias for --discard-all">;
-
-def regex
- : Flag<["--"], "regex">,
- HelpText<"Permit regular expressions in name comparison">;
-
-def version : Flag<["--"], "version">,
- HelpText<"Print the version and exit.">;
-def V : Flag<["-"], "V">,
- Alias<version>,
- HelpText<"Alias for --version">;
-
-def wildcard
- : Flag<["--"], "wildcard">,
- HelpText<"Allow wildcard syntax for symbol-related flags. Incompatible "
- "with --regex. Allows using '*' to match any number of "
- "characters, '?' to match any single character, '\' to escape "
- "special characters, and '[]' to define character classes. "
- "Wildcards beginning with '!' will prevent a match, for example "
- "\"-N '*' -N '!x'\" will strip all symbols except for \"x\".">;
-def w : Flag<["-"], "w">, Alias<wildcard>, HelpText<"Alias for --wildcard">;
+include "llvm/Option/OptParser.td"
+
+multiclass Eq<string name, string help> {
+ def NAME : Separate<["--"], name>;
+ def NAME #_eq : Joined<["--"], name #"=">,
+ Alias<!cast<Separate>(NAME)>,
+ HelpText<help>;
+}
+
+def help : Flag<["--"], "help">;
+def h : Flag<["-"], "h">, Alias<help>;
+
+def allow_broken_links
+ : Flag<["--"], "allow-broken-links">,
+ HelpText<"Allow the tool to remove sections even if it would leave "
+ "invalid section references. The appropriate sh_link fields "
+ "will be set to zero.">;
+
+def enable_deterministic_archives
+ : Flag<["--"], "enable-deterministic-archives">,
+ HelpText<"Enable deterministic mode when operating on archives (use "
+ "zero for UIDs, GIDs, and timestamps).">;
+def D : Flag<["-"], "D">,
+ Alias<enable_deterministic_archives>,
+ HelpText<"Alias for --enable-deterministic-archives">;
+
+def disable_deterministic_archives
+ : Flag<["--"], "disable-deterministic-archives">,
+ HelpText<"Disable deterministic mode when operating on archives (use "
+ "real values for UIDs, GIDs, and timestamps).">;
+def U : Flag<["-"], "U">,
+ Alias<disable_deterministic_archives>,
+ HelpText<"Alias for --disable-deterministic-archives">;
+
+def preserve_dates : Flag<["--"], "preserve-dates">,
+ HelpText<"Preserve access and modification timestamps">;
+def p : Flag<["-"], "p">,
+ Alias<preserve_dates>,
+ HelpText<"Alias for --preserve-dates">;
+
+def strip_all : Flag<["--"], "strip-all">,
+ HelpText<"Remove non-allocated sections outside segments. "
+ ".gnu.warning* and .ARM.attribute sections are not "
+ "removed">;
+
+def strip_all_gnu
+ : Flag<["--"], "strip-all-gnu">,
+ HelpText<"Compatible with GNU's --strip-all">;
+
+def strip_debug : Flag<["--"], "strip-debug">,
+ HelpText<"Remove all debug sections">;
+def g : Flag<["-"], "g">,
+ Alias<strip_debug>,
+ HelpText<"Alias for --strip-debug">;
+
+def strip_unneeded : Flag<["--"], "strip-unneeded">,
+ HelpText<"Remove all symbols not needed by relocations">;
+
+defm remove_section : Eq<"remove-section", "Remove <section>">,
+ MetaVarName<"section">;
+def R : JoinedOrSeparate<["-"], "R">,
+ Alias<remove_section>,
+ HelpText<"Alias for --remove-section">;
+
+def strip_sections
+ : Flag<["--"], "strip-sections">,
+ HelpText<"Remove all section headers and all sections not in segments">;
+
+defm strip_symbol : Eq<"strip-symbol", "Strip <symbol>">,
+ MetaVarName<"symbol">;
+def N : JoinedOrSeparate<["-"], "N">,
+ Alias<strip_symbol>,
+ HelpText<"Alias for --strip-symbol">;
+
+defm keep_section : Eq<"keep-section", "Keep <section>">,
+ MetaVarName<"section">;
+
+defm keep_symbol : Eq<"keep-symbol", "Do not remove symbol <symbol>">,
+ MetaVarName<"symbol">;
+def K : JoinedOrSeparate<["-"], "K">,
+ Alias<keep_symbol>,
+ HelpText<"Alias for --keep-symbol">;
+
+def keep_file_symbols : Flag<["--"], "keep-file-symbols">,
+ HelpText<"Do not remove file symbols">;
+
+def only_keep_debug
+ : Flag<["--"], "only-keep-debug">,
+ HelpText<
+ "Produce a debug file as the output that only preserves contents of "
+ "sections useful for debugging purposes">;
+
+def discard_locals : Flag<["--"], "discard-locals">,
+ HelpText<"Remove compiler-generated local symbols, (e.g. "
+ "symbols starting with .L)">;
+def X : Flag<["-"], "X">,
+ Alias<discard_locals>,
+ HelpText<"Alias for --discard-locals">;
+
+def discard_all
+ : Flag<["--"], "discard-all">,
+ HelpText<"Remove all local symbols except file and section symbols">;
+def x : Flag<["-"], "x">,
+ Alias<discard_all>,
+ HelpText<"Alias for --discard-all">;
+
+def regex
+ : Flag<["--"], "regex">,
+ HelpText<"Permit regular expressions in name comparison">;
+
+def version : Flag<["--"], "version">,
+ HelpText<"Print the version and exit.">;
+def V : Flag<["-"], "V">,
+ Alias<version>,
+ HelpText<"Alias for --version">;
+
+def wildcard
+ : Flag<["--"], "wildcard">,
+ HelpText<"Allow wildcard syntax for symbol-related flags. Incompatible "
+ "with --regex. Allows using '*' to match any number of "
+ "characters, '?' to match any single character, '\' to escape "
+ "special characters, and '[]' to define character classes. "
+ "Wildcards beginning with '!' will prevent a match, for example "
+ "\"-N '*' -N '!x'\" will strip all symbols except for \"x\".">;
+def w : Flag<["-"], "w">, Alias<wildcard>, HelpText<"Alias for --wildcard">;
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.cpp
index ba74759a34..8fca9b62cd 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.cpp
@@ -1,106 +1,106 @@
-//===- CopyConfig.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 "CopyConfig.h"
-
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/CRC.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Compression.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/StringSaver.h"
-#include <memory>
-
-namespace llvm {
-namespace objcopy {
-
-namespace {
-enum ObjcopyID {
- OBJCOPY_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OBJCOPY_##ID,
-#include "ObjcopyOpts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
-#include "ObjcopyOpts.inc"
-#undef PREFIX
-
-static const opt::OptTable::Info ObjcopyInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {OBJCOPY_##PREFIX, \
- NAME, \
- HELPTEXT, \
- METAVAR, \
- OBJCOPY_##ID, \
- opt::Option::KIND##Class, \
- PARAM, \
- FLAGS, \
- OBJCOPY_##GROUP, \
- OBJCOPY_##ALIAS, \
- ALIASARGS, \
- VALUES},
-#include "ObjcopyOpts.inc"
-#undef OPTION
-};
-
-class ObjcopyOptTable : public opt::OptTable {
-public:
- ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {}
-};
-
-enum InstallNameToolID {
- INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- INSTALL_NAME_TOOL_##ID,
-#include "InstallNameToolOpts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) \
- const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE;
-#include "InstallNameToolOpts.inc"
-#undef PREFIX
-
-static const opt::OptTable::Info InstallNameToolInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {INSTALL_NAME_TOOL_##PREFIX, \
- NAME, \
- HELPTEXT, \
- METAVAR, \
- INSTALL_NAME_TOOL_##ID, \
- opt::Option::KIND##Class, \
- PARAM, \
- FLAGS, \
- INSTALL_NAME_TOOL_##GROUP, \
- INSTALL_NAME_TOOL_##ALIAS, \
- ALIASARGS, \
- VALUES},
-#include "InstallNameToolOpts.inc"
-#undef OPTION
-};
-
-class InstallNameToolOptTable : public opt::OptTable {
-public:
- InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {}
-};
-
+//===- CopyConfig.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 "CopyConfig.h"
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/CRC.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/StringSaver.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+
+namespace {
+enum ObjcopyID {
+ OBJCOPY_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OBJCOPY_##ID,
+#include "ObjcopyOpts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
+#include "ObjcopyOpts.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info ObjcopyInfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {OBJCOPY_##PREFIX, \
+ NAME, \
+ HELPTEXT, \
+ METAVAR, \
+ OBJCOPY_##ID, \
+ opt::Option::KIND##Class, \
+ PARAM, \
+ FLAGS, \
+ OBJCOPY_##GROUP, \
+ OBJCOPY_##ALIAS, \
+ ALIASARGS, \
+ VALUES},
+#include "ObjcopyOpts.inc"
+#undef OPTION
+};
+
+class ObjcopyOptTable : public opt::OptTable {
+public:
+ ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {}
+};
+
+enum InstallNameToolID {
+ INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ INSTALL_NAME_TOOL_##ID,
+#include "InstallNameToolOpts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) \
+ const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE;
+#include "InstallNameToolOpts.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info InstallNameToolInfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {INSTALL_NAME_TOOL_##PREFIX, \
+ NAME, \
+ HELPTEXT, \
+ METAVAR, \
+ INSTALL_NAME_TOOL_##ID, \
+ opt::Option::KIND##Class, \
+ PARAM, \
+ FLAGS, \
+ INSTALL_NAME_TOOL_##GROUP, \
+ INSTALL_NAME_TOOL_##ALIAS, \
+ ALIASARGS, \
+ VALUES},
+#include "InstallNameToolOpts.inc"
+#undef OPTION
+};
+
+class InstallNameToolOptTable : public opt::OptTable {
+public:
+ InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {}
+};
+
enum BitcodeStripID {
BITCODE_STRIP_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
@@ -138,816 +138,816 @@ public:
BitcodeStripOptTable() : OptTable(BitcodeStripInfoTable) {}
};
-enum StripID {
- STRIP_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- STRIP_##ID,
-#include "StripOpts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
-#include "StripOpts.inc"
-#undef PREFIX
-
-static const opt::OptTable::Info StripInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {STRIP_##PREFIX, NAME, HELPTEXT, \
- METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, STRIP_##GROUP, \
- STRIP_##ALIAS, ALIASARGS, VALUES},
-#include "StripOpts.inc"
-#undef OPTION
-};
-
-class StripOptTable : public opt::OptTable {
-public:
- StripOptTable() : OptTable(StripInfoTable) {}
-};
-
-} // namespace
-
-static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
- return llvm::StringSwitch<SectionFlag>(SectionName)
- .CaseLower("alloc", SectionFlag::SecAlloc)
- .CaseLower("load", SectionFlag::SecLoad)
- .CaseLower("noload", SectionFlag::SecNoload)
- .CaseLower("readonly", SectionFlag::SecReadonly)
- .CaseLower("debug", SectionFlag::SecDebug)
- .CaseLower("code", SectionFlag::SecCode)
- .CaseLower("data", SectionFlag::SecData)
- .CaseLower("rom", SectionFlag::SecRom)
- .CaseLower("merge", SectionFlag::SecMerge)
- .CaseLower("strings", SectionFlag::SecStrings)
- .CaseLower("contents", SectionFlag::SecContents)
- .CaseLower("share", SectionFlag::SecShare)
- .CaseLower("exclude", SectionFlag::SecExclude)
- .Default(SectionFlag::SecNone);
-}
-
-static Expected<SectionFlag>
-parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
- SectionFlag ParsedFlags = SectionFlag::SecNone;
- for (StringRef Flag : SectionFlags) {
- SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);
- if (ParsedFlag == SectionFlag::SecNone)
- return createStringError(
- errc::invalid_argument,
- "unrecognized section flag '%s'. Flags supported for GNU "
- "compatibility: alloc, load, noload, readonly, exclude, debug, "
- "code, data, rom, share, contents, merge, strings",
- Flag.str().c_str());
- ParsedFlags |= ParsedFlag;
- }
-
- return ParsedFlags;
-}
-
-static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {
- if (!FlagValue.contains('='))
- return createStringError(errc::invalid_argument,
- "bad format for --rename-section: missing '='");
-
- // Initial split: ".foo" = ".bar,f1,f2,..."
- auto Old2New = FlagValue.split('=');
- SectionRename SR;
- SR.OriginalName = Old2New.first;
-
- // Flags split: ".bar" "f1" "f2" ...
- SmallVector<StringRef, 6> NameAndFlags;
- Old2New.second.split(NameAndFlags, ',');
- SR.NewName = NameAndFlags[0];
-
- if (NameAndFlags.size() > 1) {
- Expected<SectionFlag> ParsedFlagSet =
- parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
- if (!ParsedFlagSet)
- return ParsedFlagSet.takeError();
- SR.NewFlags = *ParsedFlagSet;
- }
-
- return SR;
-}
-
-static Expected<std::pair<StringRef, uint64_t>>
-parseSetSectionAlignment(StringRef FlagValue) {
- if (!FlagValue.contains('='))
- return createStringError(
- errc::invalid_argument,
- "bad format for --set-section-alignment: missing '='");
- auto Split = StringRef(FlagValue).split('=');
- if (Split.first.empty())
- return createStringError(
- errc::invalid_argument,
- "bad format for --set-section-alignment: missing section name");
- uint64_t NewAlign;
- if (Split.second.getAsInteger(0, NewAlign))
- return createStringError(errc::invalid_argument,
- "invalid alignment for --set-section-alignment: '%s'",
- Split.second.str().c_str());
- return std::make_pair(Split.first, NewAlign);
-}
-
-static Expected<SectionFlagsUpdate>
-parseSetSectionFlagValue(StringRef FlagValue) {
- if (!StringRef(FlagValue).contains('='))
- return createStringError(errc::invalid_argument,
- "bad format for --set-section-flags: missing '='");
-
- // Initial split: ".foo" = "f1,f2,..."
- auto Section2Flags = StringRef(FlagValue).split('=');
- SectionFlagsUpdate SFU;
- SFU.Name = Section2Flags.first;
-
- // Flags split: "f1" "f2" ...
- SmallVector<StringRef, 6> SectionFlags;
- Section2Flags.second.split(SectionFlags, ',');
- Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags);
- if (!ParsedFlagSet)
- return ParsedFlagSet.takeError();
- SFU.NewFlags = *ParsedFlagSet;
-
- return SFU;
-}
-
-struct TargetInfo {
- FileFormat Format;
- MachineInfo Machine;
-};
-
-// FIXME: consolidate with the bfd parsing used by lld.
-static const StringMap<MachineInfo> TargetMap{
- // Name, {EMachine, 64bit, LittleEndian}
- // x86
- {"elf32-i386", {ELF::EM_386, false, true}},
- {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
- {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
- // Intel MCU
- {"elf32-iamcu", {ELF::EM_IAMCU, false, true}},
- // ARM
- {"elf32-littlearm", {ELF::EM_ARM, false, true}},
- // ARM AArch64
- {"elf64-aarch64", {ELF::EM_AARCH64, true, true}},
- {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}},
- // RISC-V
- {"elf32-littleriscv", {ELF::EM_RISCV, false, true}},
- {"elf64-littleriscv", {ELF::EM_RISCV, true, true}},
- // PowerPC
- {"elf32-powerpc", {ELF::EM_PPC, false, false}},
- {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
- {"elf64-powerpc", {ELF::EM_PPC64, true, false}},
- {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
- // MIPS
- {"elf32-bigmips", {ELF::EM_MIPS, false, false}},
- {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}},
- {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}},
- {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}},
- {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}},
- {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}},
- {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}},
- // SPARC
- {"elf32-sparc", {ELF::EM_SPARC, false, false}},
- {"elf32-sparcel", {ELF::EM_SPARC, false, true}},
- {"elf32-hexagon", {ELF::EM_HEXAGON, false, true}},
-};
-
-static Expected<TargetInfo>
-getOutputTargetInfoByTargetName(StringRef TargetName) {
- StringRef OriginalTargetName = TargetName;
- bool IsFreeBSD = TargetName.consume_back("-freebsd");
- auto Iter = TargetMap.find(TargetName);
- if (Iter == std::end(TargetMap))
- return createStringError(errc::invalid_argument,
- "invalid output format: '%s'",
- OriginalTargetName.str().c_str());
- MachineInfo MI = Iter->getValue();
- if (IsFreeBSD)
- MI.OSABI = ELF::ELFOSABI_FREEBSD;
-
- FileFormat Format;
- if (TargetName.startswith("elf"))
- Format = FileFormat::ELF;
- else
- // This should never happen because `TargetName` is valid (it certainly
- // exists in the TargetMap).
- llvm_unreachable("unknown target prefix");
-
- return {TargetInfo{Format, MI}};
-}
-
-static Error
-addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,
- StringRef Filename, MatchStyle MS,
- llvm::function_ref<Error(Error)> ErrorCallback) {
- StringSaver Saver(Alloc);
- SmallVector<StringRef, 16> Lines;
- auto BufOrErr = MemoryBuffer::getFile(Filename);
- if (!BufOrErr)
- return createFileError(Filename, BufOrErr.getError());
-
- BufOrErr.get()->getBuffer().split(Lines, '\n');
- for (StringRef Line : Lines) {
- // Ignore everything after '#', trim whitespace, and only add the symbol if
- // it's not empty.
- auto TrimmedLine = Line.split('#').first.trim();
- if (!TrimmedLine.empty())
- if (Error E = Symbols.addMatcher(NameOrPattern::create(
- Saver.save(TrimmedLine), MS, ErrorCallback)))
- return E;
- }
-
- return Error::success();
-}
-
-Expected<NameOrPattern>
-NameOrPattern::create(StringRef Pattern, MatchStyle MS,
- llvm::function_ref<Error(Error)> ErrorCallback) {
- switch (MS) {
- case MatchStyle::Literal:
- return NameOrPattern(Pattern);
- case MatchStyle::Wildcard: {
- SmallVector<char, 32> Data;
- bool IsPositiveMatch = true;
- if (Pattern[0] == '!') {
- IsPositiveMatch = false;
- Pattern = Pattern.drop_front();
- }
- Expected<GlobPattern> GlobOrErr = GlobPattern::create(Pattern);
-
- // If we couldn't create it as a glob, report the error, but try again with
- // a literal if the error reporting is non-fatal.
- if (!GlobOrErr) {
- if (Error E = ErrorCallback(GlobOrErr.takeError()))
- return std::move(E);
- return create(Pattern, MatchStyle::Literal, ErrorCallback);
- }
-
- return NameOrPattern(std::make_shared<GlobPattern>(*GlobOrErr),
- IsPositiveMatch);
- }
- case MatchStyle::Regex: {
- SmallVector<char, 32> Data;
- return NameOrPattern(std::make_shared<Regex>(
- ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data)));
- }
- }
- llvm_unreachable("Unhandled llvm.objcopy.MatchStyle enum");
-}
-
-static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
- BumpPtrAllocator &Alloc,
- StringRef Filename) {
- StringSaver Saver(Alloc);
- SmallVector<StringRef, 16> Lines;
- auto BufOrErr = MemoryBuffer::getFile(Filename);
- if (!BufOrErr)
- return createFileError(Filename, BufOrErr.getError());
-
- BufOrErr.get()->getBuffer().split(Lines, '\n');
- size_t NumLines = Lines.size();
- for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {
- StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
- if (TrimmedLine.empty())
- continue;
-
- std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
- StringRef NewName = Pair.second.trim();
- if (NewName.empty())
- return createStringError(errc::invalid_argument,
- "%s:%zu: missing new symbol name",
- Filename.str().c_str(), LineNo + 1);
- SymbolsToRename.insert({Pair.first, NewName});
- }
- return Error::success();
-}
-
-template <class T> static ErrorOr<T> getAsInteger(StringRef Val) {
- T Result;
- if (Val.getAsInteger(0, Result))
- return errc::invalid_argument;
- return Result;
-}
-
-namespace {
-
+enum StripID {
+ STRIP_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ STRIP_##ID,
+#include "StripOpts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
+#include "StripOpts.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info StripInfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {STRIP_##PREFIX, NAME, HELPTEXT, \
+ METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, STRIP_##GROUP, \
+ STRIP_##ALIAS, ALIASARGS, VALUES},
+#include "StripOpts.inc"
+#undef OPTION
+};
+
+class StripOptTable : public opt::OptTable {
+public:
+ StripOptTable() : OptTable(StripInfoTable) {}
+};
+
+} // namespace
+
+static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
+ return llvm::StringSwitch<SectionFlag>(SectionName)
+ .CaseLower("alloc", SectionFlag::SecAlloc)
+ .CaseLower("load", SectionFlag::SecLoad)
+ .CaseLower("noload", SectionFlag::SecNoload)
+ .CaseLower("readonly", SectionFlag::SecReadonly)
+ .CaseLower("debug", SectionFlag::SecDebug)
+ .CaseLower("code", SectionFlag::SecCode)
+ .CaseLower("data", SectionFlag::SecData)
+ .CaseLower("rom", SectionFlag::SecRom)
+ .CaseLower("merge", SectionFlag::SecMerge)
+ .CaseLower("strings", SectionFlag::SecStrings)
+ .CaseLower("contents", SectionFlag::SecContents)
+ .CaseLower("share", SectionFlag::SecShare)
+ .CaseLower("exclude", SectionFlag::SecExclude)
+ .Default(SectionFlag::SecNone);
+}
+
+static Expected<SectionFlag>
+parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
+ SectionFlag ParsedFlags = SectionFlag::SecNone;
+ for (StringRef Flag : SectionFlags) {
+ SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);
+ if (ParsedFlag == SectionFlag::SecNone)
+ return createStringError(
+ errc::invalid_argument,
+ "unrecognized section flag '%s'. Flags supported for GNU "
+ "compatibility: alloc, load, noload, readonly, exclude, debug, "
+ "code, data, rom, share, contents, merge, strings",
+ Flag.str().c_str());
+ ParsedFlags |= ParsedFlag;
+ }
+
+ return ParsedFlags;
+}
+
+static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {
+ if (!FlagValue.contains('='))
+ return createStringError(errc::invalid_argument,
+ "bad format for --rename-section: missing '='");
+
+ // Initial split: ".foo" = ".bar,f1,f2,..."
+ auto Old2New = FlagValue.split('=');
+ SectionRename SR;
+ SR.OriginalName = Old2New.first;
+
+ // Flags split: ".bar" "f1" "f2" ...
+ SmallVector<StringRef, 6> NameAndFlags;
+ Old2New.second.split(NameAndFlags, ',');
+ SR.NewName = NameAndFlags[0];
+
+ if (NameAndFlags.size() > 1) {
+ Expected<SectionFlag> ParsedFlagSet =
+ parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
+ if (!ParsedFlagSet)
+ return ParsedFlagSet.takeError();
+ SR.NewFlags = *ParsedFlagSet;
+ }
+
+ return SR;
+}
+
+static Expected<std::pair<StringRef, uint64_t>>
+parseSetSectionAlignment(StringRef FlagValue) {
+ if (!FlagValue.contains('='))
+ return createStringError(
+ errc::invalid_argument,
+ "bad format for --set-section-alignment: missing '='");
+ auto Split = StringRef(FlagValue).split('=');
+ if (Split.first.empty())
+ return createStringError(
+ errc::invalid_argument,
+ "bad format for --set-section-alignment: missing section name");
+ uint64_t NewAlign;
+ if (Split.second.getAsInteger(0, NewAlign))
+ return createStringError(errc::invalid_argument,
+ "invalid alignment for --set-section-alignment: '%s'",
+ Split.second.str().c_str());
+ return std::make_pair(Split.first, NewAlign);
+}
+
+static Expected<SectionFlagsUpdate>
+parseSetSectionFlagValue(StringRef FlagValue) {
+ if (!StringRef(FlagValue).contains('='))
+ return createStringError(errc::invalid_argument,
+ "bad format for --set-section-flags: missing '='");
+
+ // Initial split: ".foo" = "f1,f2,..."
+ auto Section2Flags = StringRef(FlagValue).split('=');
+ SectionFlagsUpdate SFU;
+ SFU.Name = Section2Flags.first;
+
+ // Flags split: "f1" "f2" ...
+ SmallVector<StringRef, 6> SectionFlags;
+ Section2Flags.second.split(SectionFlags, ',');
+ Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags);
+ if (!ParsedFlagSet)
+ return ParsedFlagSet.takeError();
+ SFU.NewFlags = *ParsedFlagSet;
+
+ return SFU;
+}
+
+struct TargetInfo {
+ FileFormat Format;
+ MachineInfo Machine;
+};
+
+// FIXME: consolidate with the bfd parsing used by lld.
+static const StringMap<MachineInfo> TargetMap{
+ // Name, {EMachine, 64bit, LittleEndian}
+ // x86
+ {"elf32-i386", {ELF::EM_386, false, true}},
+ {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
+ {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
+ // Intel MCU
+ {"elf32-iamcu", {ELF::EM_IAMCU, false, true}},
+ // ARM
+ {"elf32-littlearm", {ELF::EM_ARM, false, true}},
+ // ARM AArch64
+ {"elf64-aarch64", {ELF::EM_AARCH64, true, true}},
+ {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}},
+ // RISC-V
+ {"elf32-littleriscv", {ELF::EM_RISCV, false, true}},
+ {"elf64-littleriscv", {ELF::EM_RISCV, true, true}},
+ // PowerPC
+ {"elf32-powerpc", {ELF::EM_PPC, false, false}},
+ {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
+ {"elf64-powerpc", {ELF::EM_PPC64, true, false}},
+ {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
+ // MIPS
+ {"elf32-bigmips", {ELF::EM_MIPS, false, false}},
+ {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}},
+ {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}},
+ {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}},
+ {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}},
+ {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}},
+ {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}},
+ // SPARC
+ {"elf32-sparc", {ELF::EM_SPARC, false, false}},
+ {"elf32-sparcel", {ELF::EM_SPARC, false, true}},
+ {"elf32-hexagon", {ELF::EM_HEXAGON, false, true}},
+};
+
+static Expected<TargetInfo>
+getOutputTargetInfoByTargetName(StringRef TargetName) {
+ StringRef OriginalTargetName = TargetName;
+ bool IsFreeBSD = TargetName.consume_back("-freebsd");
+ auto Iter = TargetMap.find(TargetName);
+ if (Iter == std::end(TargetMap))
+ return createStringError(errc::invalid_argument,
+ "invalid output format: '%s'",
+ OriginalTargetName.str().c_str());
+ MachineInfo MI = Iter->getValue();
+ if (IsFreeBSD)
+ MI.OSABI = ELF::ELFOSABI_FREEBSD;
+
+ FileFormat Format;
+ if (TargetName.startswith("elf"))
+ Format = FileFormat::ELF;
+ else
+ // This should never happen because `TargetName` is valid (it certainly
+ // exists in the TargetMap).
+ llvm_unreachable("unknown target prefix");
+
+ return {TargetInfo{Format, MI}};
+}
+
+static Error
+addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,
+ StringRef Filename, MatchStyle MS,
+ llvm::function_ref<Error(Error)> ErrorCallback) {
+ StringSaver Saver(Alloc);
+ SmallVector<StringRef, 16> Lines;
+ auto BufOrErr = MemoryBuffer::getFile(Filename);
+ if (!BufOrErr)
+ return createFileError(Filename, BufOrErr.getError());
+
+ BufOrErr.get()->getBuffer().split(Lines, '\n');
+ for (StringRef Line : Lines) {
+ // Ignore everything after '#', trim whitespace, and only add the symbol if
+ // it's not empty.
+ auto TrimmedLine = Line.split('#').first.trim();
+ if (!TrimmedLine.empty())
+ if (Error E = Symbols.addMatcher(NameOrPattern::create(
+ Saver.save(TrimmedLine), MS, ErrorCallback)))
+ return E;
+ }
+
+ return Error::success();
+}
+
+Expected<NameOrPattern>
+NameOrPattern::create(StringRef Pattern, MatchStyle MS,
+ llvm::function_ref<Error(Error)> ErrorCallback) {
+ switch (MS) {
+ case MatchStyle::Literal:
+ return NameOrPattern(Pattern);
+ case MatchStyle::Wildcard: {
+ SmallVector<char, 32> Data;
+ bool IsPositiveMatch = true;
+ if (Pattern[0] == '!') {
+ IsPositiveMatch = false;
+ Pattern = Pattern.drop_front();
+ }
+ Expected<GlobPattern> GlobOrErr = GlobPattern::create(Pattern);
+
+ // If we couldn't create it as a glob, report the error, but try again with
+ // a literal if the error reporting is non-fatal.
+ if (!GlobOrErr) {
+ if (Error E = ErrorCallback(GlobOrErr.takeError()))
+ return std::move(E);
+ return create(Pattern, MatchStyle::Literal, ErrorCallback);
+ }
+
+ return NameOrPattern(std::make_shared<GlobPattern>(*GlobOrErr),
+ IsPositiveMatch);
+ }
+ case MatchStyle::Regex: {
+ SmallVector<char, 32> Data;
+ return NameOrPattern(std::make_shared<Regex>(
+ ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data)));
+ }
+ }
+ llvm_unreachable("Unhandled llvm.objcopy.MatchStyle enum");
+}
+
+static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
+ BumpPtrAllocator &Alloc,
+ StringRef Filename) {
+ StringSaver Saver(Alloc);
+ SmallVector<StringRef, 16> Lines;
+ auto BufOrErr = MemoryBuffer::getFile(Filename);
+ if (!BufOrErr)
+ return createFileError(Filename, BufOrErr.getError());
+
+ BufOrErr.get()->getBuffer().split(Lines, '\n');
+ size_t NumLines = Lines.size();
+ for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {
+ StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
+ if (TrimmedLine.empty())
+ continue;
+
+ std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
+ StringRef NewName = Pair.second.trim();
+ if (NewName.empty())
+ return createStringError(errc::invalid_argument,
+ "%s:%zu: missing new symbol name",
+ Filename.str().c_str(), LineNo + 1);
+ SymbolsToRename.insert({Pair.first, NewName});
+ }
+ return Error::success();
+}
+
+template <class T> static ErrorOr<T> getAsInteger(StringRef Val) {
+ T Result;
+ if (Val.getAsInteger(0, Result))
+ return errc::invalid_argument;
+ return Result;
+}
+
+namespace {
+
enum class ToolType { Objcopy, Strip, InstallNameTool, BitcodeStrip };
-
-} // anonymous namespace
-
-static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS,
- ToolType Tool) {
- StringRef HelpText, ToolName;
- switch (Tool) {
- case ToolType::Objcopy:
- ToolName = "llvm-objcopy";
- HelpText = " [options] input [output]";
- break;
- case ToolType::Strip:
- ToolName = "llvm-strip";
- HelpText = " [options] inputs...";
- break;
- case ToolType::InstallNameTool:
- ToolName = "llvm-install-name-tool";
- HelpText = " [options] input";
- break;
+
+} // anonymous namespace
+
+static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS,
+ ToolType Tool) {
+ StringRef HelpText, ToolName;
+ switch (Tool) {
+ case ToolType::Objcopy:
+ ToolName = "llvm-objcopy";
+ HelpText = " [options] input [output]";
+ break;
+ case ToolType::Strip:
+ ToolName = "llvm-strip";
+ HelpText = " [options] inputs...";
+ break;
+ case ToolType::InstallNameTool:
+ ToolName = "llvm-install-name-tool";
+ HelpText = " [options] input";
+ break;
case ToolType::BitcodeStrip:
ToolName = "llvm-bitcode-strip";
HelpText = " [options] input";
break;
- }
- OptTable.PrintHelp(OS, (ToolName + HelpText).str().c_str(),
- (ToolName + " tool").str().c_str());
- // TODO: Replace this with libOption call once it adds extrahelp support.
- // The CommandLine library has a cl::extrahelp class to support this,
- // but libOption does not have that yet.
- OS << "\nPass @FILE as argument to read options from FILE.\n";
-}
-
-// ParseObjcopyOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseObjcopyOptions will print the help messege and
-// exit.
-Expected<DriverConfig>
-parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
- llvm::function_ref<Error(Error)> ErrorCallback) {
- DriverConfig DC;
- ObjcopyOptTable T;
- unsigned MissingArgumentIndex, MissingArgumentCount;
- llvm::opt::InputArgList InputArgs =
- T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
-
- if (InputArgs.size() == 0) {
- printHelp(T, errs(), ToolType::Objcopy);
- exit(1);
- }
-
- if (InputArgs.hasArg(OBJCOPY_help)) {
- printHelp(T, outs(), ToolType::Objcopy);
- exit(0);
- }
-
- if (InputArgs.hasArg(OBJCOPY_version)) {
- outs() << "llvm-objcopy, compatible with GNU objcopy\n";
- cl::PrintVersionMessage();
- exit(0);
- }
-
- SmallVector<const char *, 2> Positional;
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
- return createStringError(errc::invalid_argument, "unknown argument '%s'",
- Arg->getAsString(InputArgs).c_str());
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
- Positional.push_back(Arg->getValue());
-
- if (Positional.empty())
- return createStringError(errc::invalid_argument, "no input file specified");
-
- if (Positional.size() > 2)
- return createStringError(errc::invalid_argument,
- "too many positional arguments");
-
- CopyConfig Config;
- Config.InputFilename = Positional[0];
- Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
- if (InputArgs.hasArg(OBJCOPY_target) &&
- (InputArgs.hasArg(OBJCOPY_input_target) ||
- InputArgs.hasArg(OBJCOPY_output_target)))
- return createStringError(
- errc::invalid_argument,
- "--target cannot be used with --input-target or --output-target");
-
- if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard))
- return createStringError(errc::invalid_argument,
- "--regex and --wildcard are incompatible");
-
- MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
- ? MatchStyle::Regex
- : MatchStyle::Wildcard;
- MatchStyle SymbolMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
- ? MatchStyle::Regex
- : InputArgs.hasArg(OBJCOPY_wildcard)
- ? MatchStyle::Wildcard
- : MatchStyle::Literal;
- StringRef InputFormat, OutputFormat;
- if (InputArgs.hasArg(OBJCOPY_target)) {
- InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
- OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
- } else {
- InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
- OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
- }
-
- // FIXME: Currently, we ignore the target for non-binary/ihex formats
- // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the
- // format by llvm::object::createBinary regardless of the option value.
- Config.InputFormat = StringSwitch<FileFormat>(InputFormat)
- .Case("binary", FileFormat::Binary)
- .Case("ihex", FileFormat::IHex)
- .Default(FileFormat::Unspecified);
-
- if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility))
- Config.NewSymbolVisibility =
- InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);
-
- Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
- .Case("binary", FileFormat::Binary)
- .Case("ihex", FileFormat::IHex)
- .Default(FileFormat::Unspecified);
- if (Config.OutputFormat == FileFormat::Unspecified) {
- if (OutputFormat.empty()) {
- Config.OutputFormat = Config.InputFormat;
- } else {
- Expected<TargetInfo> Target =
- getOutputTargetInfoByTargetName(OutputFormat);
- if (!Target)
- return Target.takeError();
- Config.OutputFormat = Target->Format;
- Config.OutputArch = Target->Machine;
- }
- }
-
- if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
- OBJCOPY_compress_debug_sections_eq)) {
- Config.CompressionType = DebugCompressionType::Z;
-
- if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
- Config.CompressionType =
- StringSwitch<DebugCompressionType>(
- InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
- .Case("zlib-gnu", DebugCompressionType::GNU)
- .Case("zlib", DebugCompressionType::Z)
- .Default(DebugCompressionType::None);
- if (Config.CompressionType == DebugCompressionType::None)
- return createStringError(
- errc::invalid_argument,
- "invalid or unsupported --compress-debug-sections format: %s",
- InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)
- .str()
- .c_str());
- }
- if (!zlib::isAvailable())
- return createStringError(
- errc::invalid_argument,
- "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress");
- }
-
- Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
- // The gnu_debuglink's target is expected to not change or else its CRC would
- // become invalidated and get rejected. We can avoid recalculating the
- // checksum for every target file inside an archive by precomputing the CRC
- // here. This prevents a significant amount of I/O.
- if (!Config.AddGnuDebugLink.empty()) {
- auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink);
- if (!DebugOrErr)
- return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError());
- auto Debug = std::move(*DebugOrErr);
- Config.GnuDebugLinkCRC32 =
- llvm::crc32(arrayRefFromStringRef(Debug->getBuffer()));
- }
- Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
- if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
- Config.BuildIdLinkInput =
- InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
- if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
- Config.BuildIdLinkOutput =
- InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
- Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
- Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
- Config.AllocSectionsPrefix =
- InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections);
- if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
- Config.ExtractPartition = Arg->getValue();
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
- if (!StringRef(Arg->getValue()).contains('='))
- return createStringError(errc::invalid_argument,
- "bad format for --redefine-sym");
- auto Old2New = StringRef(Arg->getValue()).split('=');
- if (!Config.SymbolsToRename.insert(Old2New).second)
- return createStringError(errc::invalid_argument,
- "multiple redefinition of symbol '%s'",
- Old2New.first.str().c_str());
- }
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
- if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
- Arg->getValue()))
- return std::move(E);
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
- Expected<SectionRename> SR =
- parseRenameSectionValue(StringRef(Arg->getValue()));
- if (!SR)
- return SR.takeError();
- if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second)
- return createStringError(errc::invalid_argument,
- "multiple renames of section '%s'",
- SR->OriginalName.str().c_str());
- }
- for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {
- Expected<std::pair<StringRef, uint64_t>> NameAndAlign =
- parseSetSectionAlignment(Arg->getValue());
- if (!NameAndAlign)
- return NameAndAlign.takeError();
- Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;
- }
- for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
- Expected<SectionFlagsUpdate> SFU =
- parseSetSectionFlagValue(Arg->getValue());
- if (!SFU)
- return SFU.takeError();
- if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second)
- return createStringError(
- errc::invalid_argument,
- "--set-section-flags set multiple times for section '%s'",
- SFU->Name.str().c_str());
- }
- // Prohibit combinations of --set-section-flags when the section name is used
- // by --rename-section, either as a source or a destination.
- for (const auto &E : Config.SectionsToRename) {
- const SectionRename &SR = E.second;
- if (Config.SetSectionFlags.count(SR.OriginalName))
- return createStringError(
- errc::invalid_argument,
- "--set-section-flags=%s conflicts with --rename-section=%s=%s",
- SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(),
- SR.NewName.str().c_str());
- if (Config.SetSectionFlags.count(SR.NewName))
- return createStringError(
- errc::invalid_argument,
- "--set-section-flags=%s conflicts with --rename-section=%s=%s",
- SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),
- SR.NewName.str().c_str());
- }
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
- if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
- Arg->getValue(), SectionMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
- if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
- Arg->getValue(), SectionMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
- if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create(
- Arg->getValue(), SectionMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) {
- StringRef ArgValue(Arg->getValue());
- if (!ArgValue.contains('='))
- return createStringError(errc::invalid_argument,
- "bad format for --add-section: missing '='");
- if (ArgValue.split("=").second.empty())
- return createStringError(
- errc::invalid_argument,
- "bad format for --add-section: missing file name");
- Config.AddSection.push_back(ArgValue);
- }
- for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
- Config.DumpSection.push_back(Arg->getValue());
- Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
- Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
- Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
- Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
- Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
- Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
- Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
- Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
- Config.ExtractMainPartition =
- InputArgs.hasArg(OBJCOPY_extract_main_partition);
- Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
- Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
- if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals))
- Config.DiscardMode =
- InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals)
- ? DiscardType::All
- : DiscardType::Locals;
- Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
- Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
- Config.DecompressDebugSections =
- InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
- if (Config.DiscardMode == DiscardType::All) {
- Config.StripDebug = true;
- Config.KeepFileSymbols = true;
- }
- for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
- if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create(
- Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
- if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,
- Arg->getValue(), SymbolMatchStyle,
- ErrorCallback))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
- if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create(
- Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
- if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
- Arg->getValue(), SymbolMatchStyle,
- ErrorCallback))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
- if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create(
- Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
- if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,
- Arg->getValue(), SymbolMatchStyle,
- ErrorCallback))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
- if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create(
- Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
- if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,
- Arg->getValue(), SymbolMatchStyle,
- ErrorCallback))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
- if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
- Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
- if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,
- Arg->getValue(), SymbolMatchStyle,
- ErrorCallback))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
- if (Error E =
- Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create(
- Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
- if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
- Arg->getValue(), SymbolMatchStyle,
- ErrorCallback))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
- if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
- Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols))
- if (Error E =
- addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),
- SymbolMatchStyle, ErrorCallback))
- return std::move(E);
- for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol))
- Config.SymbolsToAdd.push_back(Arg->getValue());
-
- Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);
-
- Config.DeterministicArchives = InputArgs.hasFlag(
- OBJCOPY_enable_deterministic_archives,
- OBJCOPY_disable_deterministic_archives, /*default=*/true);
-
- Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
-
- if (Config.PreserveDates &&
- (Config.OutputFilename == "-" || Config.InputFilename == "-"))
- return createStringError(errc::invalid_argument,
- "--preserve-dates requires a file");
-
- for (auto Arg : InputArgs)
- if (Arg->getOption().matches(OBJCOPY_set_start)) {
- auto EAddr = getAsInteger<uint64_t>(Arg->getValue());
- if (!EAddr)
- return createStringError(
- EAddr.getError(), "bad entry point address: '%s'", Arg->getValue());
-
- Config.EntryExpr = [EAddr](uint64_t) { return *EAddr; };
- } else if (Arg->getOption().matches(OBJCOPY_change_start)) {
- auto EIncr = getAsInteger<int64_t>(Arg->getValue());
- if (!EIncr)
- return createStringError(EIncr.getError(),
- "bad entry point increment: '%s'",
- Arg->getValue());
- auto Expr = Config.EntryExpr ? std::move(Config.EntryExpr)
- : [](uint64_t A) { return A; };
- Config.EntryExpr = [Expr, EIncr](uint64_t EAddr) {
- return Expr(EAddr) + *EIncr;
- };
- }
-
- if (Config.DecompressDebugSections &&
- Config.CompressionType != DebugCompressionType::None) {
- return createStringError(
- errc::invalid_argument,
- "cannot specify both --compress-debug-sections and "
- "--decompress-debug-sections");
- }
-
- if (Config.DecompressDebugSections && !zlib::isAvailable())
- return createStringError(
- errc::invalid_argument,
- "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");
-
- if (Config.ExtractPartition && Config.ExtractMainPartition)
- return createStringError(errc::invalid_argument,
- "cannot specify --extract-partition together with "
- "--extract-main-partition");
-
- DC.CopyConfigs.push_back(std::move(Config));
- return std::move(DC);
-}
-
-// ParseInstallNameToolOptions returns the config and sets the input arguments.
-// If a help flag is set then ParseInstallNameToolOptions will print the help
-// messege and exit.
-Expected<DriverConfig>
-parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
- DriverConfig DC;
- CopyConfig Config;
- InstallNameToolOptTable T;
- unsigned MissingArgumentIndex, MissingArgumentCount;
- llvm::opt::InputArgList InputArgs =
- T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
-
- if (MissingArgumentCount)
- return createStringError(
- errc::invalid_argument,
- "missing argument to " +
- StringRef(InputArgs.getArgString(MissingArgumentIndex)) +
- " option");
-
- if (InputArgs.size() == 0) {
- printHelp(T, errs(), ToolType::InstallNameTool);
- exit(1);
- }
-
- if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) {
- printHelp(T, outs(), ToolType::InstallNameTool);
- exit(0);
- }
-
- if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) {
- outs() << "llvm-install-name-tool, compatible with cctools "
- "install_name_tool\n";
- cl::PrintVersionMessage();
- exit(0);
- }
-
- for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))
- Config.RPathToAdd.push_back(Arg->getValue());
-
+ }
+ OptTable.PrintHelp(OS, (ToolName + HelpText).str().c_str(),
+ (ToolName + " tool").str().c_str());
+ // TODO: Replace this with libOption call once it adds extrahelp support.
+ // The CommandLine library has a cl::extrahelp class to support this,
+ // but libOption does not have that yet.
+ OS << "\nPass @FILE as argument to read options from FILE.\n";
+}
+
+// ParseObjcopyOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseObjcopyOptions will print the help messege and
+// exit.
+Expected<DriverConfig>
+parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
+ llvm::function_ref<Error(Error)> ErrorCallback) {
+ DriverConfig DC;
+ ObjcopyOptTable T;
+ unsigned MissingArgumentIndex, MissingArgumentCount;
+ llvm::opt::InputArgList InputArgs =
+ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
+
+ if (InputArgs.size() == 0) {
+ printHelp(T, errs(), ToolType::Objcopy);
+ exit(1);
+ }
+
+ if (InputArgs.hasArg(OBJCOPY_help)) {
+ printHelp(T, outs(), ToolType::Objcopy);
+ exit(0);
+ }
+
+ if (InputArgs.hasArg(OBJCOPY_version)) {
+ outs() << "llvm-objcopy, compatible with GNU objcopy\n";
+ cl::PrintVersionMessage();
+ exit(0);
+ }
+
+ SmallVector<const char *, 2> Positional;
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
+ return createStringError(errc::invalid_argument, "unknown argument '%s'",
+ Arg->getAsString(InputArgs).c_str());
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
+ Positional.push_back(Arg->getValue());
+
+ if (Positional.empty())
+ return createStringError(errc::invalid_argument, "no input file specified");
+
+ if (Positional.size() > 2)
+ return createStringError(errc::invalid_argument,
+ "too many positional arguments");
+
+ CopyConfig Config;
+ Config.InputFilename = Positional[0];
+ Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
+ if (InputArgs.hasArg(OBJCOPY_target) &&
+ (InputArgs.hasArg(OBJCOPY_input_target) ||
+ InputArgs.hasArg(OBJCOPY_output_target)))
+ return createStringError(
+ errc::invalid_argument,
+ "--target cannot be used with --input-target or --output-target");
+
+ if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard))
+ return createStringError(errc::invalid_argument,
+ "--regex and --wildcard are incompatible");
+
+ MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
+ ? MatchStyle::Regex
+ : MatchStyle::Wildcard;
+ MatchStyle SymbolMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
+ ? MatchStyle::Regex
+ : InputArgs.hasArg(OBJCOPY_wildcard)
+ ? MatchStyle::Wildcard
+ : MatchStyle::Literal;
+ StringRef InputFormat, OutputFormat;
+ if (InputArgs.hasArg(OBJCOPY_target)) {
+ InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
+ OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
+ } else {
+ InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
+ OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
+ }
+
+ // FIXME: Currently, we ignore the target for non-binary/ihex formats
+ // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the
+ // format by llvm::object::createBinary regardless of the option value.
+ Config.InputFormat = StringSwitch<FileFormat>(InputFormat)
+ .Case("binary", FileFormat::Binary)
+ .Case("ihex", FileFormat::IHex)
+ .Default(FileFormat::Unspecified);
+
+ if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility))
+ Config.NewSymbolVisibility =
+ InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);
+
+ Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
+ .Case("binary", FileFormat::Binary)
+ .Case("ihex", FileFormat::IHex)
+ .Default(FileFormat::Unspecified);
+ if (Config.OutputFormat == FileFormat::Unspecified) {
+ if (OutputFormat.empty()) {
+ Config.OutputFormat = Config.InputFormat;
+ } else {
+ Expected<TargetInfo> Target =
+ getOutputTargetInfoByTargetName(OutputFormat);
+ if (!Target)
+ return Target.takeError();
+ Config.OutputFormat = Target->Format;
+ Config.OutputArch = Target->Machine;
+ }
+ }
+
+ if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
+ OBJCOPY_compress_debug_sections_eq)) {
+ Config.CompressionType = DebugCompressionType::Z;
+
+ if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
+ Config.CompressionType =
+ StringSwitch<DebugCompressionType>(
+ InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
+ .Case("zlib-gnu", DebugCompressionType::GNU)
+ .Case("zlib", DebugCompressionType::Z)
+ .Default(DebugCompressionType::None);
+ if (Config.CompressionType == DebugCompressionType::None)
+ return createStringError(
+ errc::invalid_argument,
+ "invalid or unsupported --compress-debug-sections format: %s",
+ InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)
+ .str()
+ .c_str());
+ }
+ if (!zlib::isAvailable())
+ return createStringError(
+ errc::invalid_argument,
+ "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress");
+ }
+
+ Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
+ // The gnu_debuglink's target is expected to not change or else its CRC would
+ // become invalidated and get rejected. We can avoid recalculating the
+ // checksum for every target file inside an archive by precomputing the CRC
+ // here. This prevents a significant amount of I/O.
+ if (!Config.AddGnuDebugLink.empty()) {
+ auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink);
+ if (!DebugOrErr)
+ return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError());
+ auto Debug = std::move(*DebugOrErr);
+ Config.GnuDebugLinkCRC32 =
+ llvm::crc32(arrayRefFromStringRef(Debug->getBuffer()));
+ }
+ Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
+ if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
+ Config.BuildIdLinkInput =
+ InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
+ if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
+ Config.BuildIdLinkOutput =
+ InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
+ Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
+ Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
+ Config.AllocSectionsPrefix =
+ InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections);
+ if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
+ Config.ExtractPartition = Arg->getValue();
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
+ if (!StringRef(Arg->getValue()).contains('='))
+ return createStringError(errc::invalid_argument,
+ "bad format for --redefine-sym");
+ auto Old2New = StringRef(Arg->getValue()).split('=');
+ if (!Config.SymbolsToRename.insert(Old2New).second)
+ return createStringError(errc::invalid_argument,
+ "multiple redefinition of symbol '%s'",
+ Old2New.first.str().c_str());
+ }
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
+ if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
+ Arg->getValue()))
+ return std::move(E);
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
+ Expected<SectionRename> SR =
+ parseRenameSectionValue(StringRef(Arg->getValue()));
+ if (!SR)
+ return SR.takeError();
+ if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second)
+ return createStringError(errc::invalid_argument,
+ "multiple renames of section '%s'",
+ SR->OriginalName.str().c_str());
+ }
+ for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {
+ Expected<std::pair<StringRef, uint64_t>> NameAndAlign =
+ parseSetSectionAlignment(Arg->getValue());
+ if (!NameAndAlign)
+ return NameAndAlign.takeError();
+ Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;
+ }
+ for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
+ Expected<SectionFlagsUpdate> SFU =
+ parseSetSectionFlagValue(Arg->getValue());
+ if (!SFU)
+ return SFU.takeError();
+ if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second)
+ return createStringError(
+ errc::invalid_argument,
+ "--set-section-flags set multiple times for section '%s'",
+ SFU->Name.str().c_str());
+ }
+ // Prohibit combinations of --set-section-flags when the section name is used
+ // by --rename-section, either as a source or a destination.
+ for (const auto &E : Config.SectionsToRename) {
+ const SectionRename &SR = E.second;
+ if (Config.SetSectionFlags.count(SR.OriginalName))
+ return createStringError(
+ errc::invalid_argument,
+ "--set-section-flags=%s conflicts with --rename-section=%s=%s",
+ SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(),
+ SR.NewName.str().c_str());
+ if (Config.SetSectionFlags.count(SR.NewName))
+ return createStringError(
+ errc::invalid_argument,
+ "--set-section-flags=%s conflicts with --rename-section=%s=%s",
+ SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),
+ SR.NewName.str().c_str());
+ }
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
+ if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
+ if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
+ if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) {
+ StringRef ArgValue(Arg->getValue());
+ if (!ArgValue.contains('='))
+ return createStringError(errc::invalid_argument,
+ "bad format for --add-section: missing '='");
+ if (ArgValue.split("=").second.empty())
+ return createStringError(
+ errc::invalid_argument,
+ "bad format for --add-section: missing file name");
+ Config.AddSection.push_back(ArgValue);
+ }
+ for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
+ Config.DumpSection.push_back(Arg->getValue());
+ Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
+ Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
+ Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
+ Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
+ Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
+ Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
+ Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
+ Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
+ Config.ExtractMainPartition =
+ InputArgs.hasArg(OBJCOPY_extract_main_partition);
+ Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
+ Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
+ if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals))
+ Config.DiscardMode =
+ InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals)
+ ? DiscardType::All
+ : DiscardType::Locals;
+ Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
+ Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
+ Config.DecompressDebugSections =
+ InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
+ if (Config.DiscardMode == DiscardType::All) {
+ Config.StripDebug = true;
+ Config.KeepFileSymbols = true;
+ }
+ for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
+ if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
+ if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
+ if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
+ if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
+ if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
+ if (Error E =
+ Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
+ if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
+ if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols))
+ if (Error E =
+ addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),
+ SymbolMatchStyle, ErrorCallback))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol))
+ Config.SymbolsToAdd.push_back(Arg->getValue());
+
+ Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);
+
+ Config.DeterministicArchives = InputArgs.hasFlag(
+ OBJCOPY_enable_deterministic_archives,
+ OBJCOPY_disable_deterministic_archives, /*default=*/true);
+
+ Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
+
+ if (Config.PreserveDates &&
+ (Config.OutputFilename == "-" || Config.InputFilename == "-"))
+ return createStringError(errc::invalid_argument,
+ "--preserve-dates requires a file");
+
+ for (auto Arg : InputArgs)
+ if (Arg->getOption().matches(OBJCOPY_set_start)) {
+ auto EAddr = getAsInteger<uint64_t>(Arg->getValue());
+ if (!EAddr)
+ return createStringError(
+ EAddr.getError(), "bad entry point address: '%s'", Arg->getValue());
+
+ Config.EntryExpr = [EAddr](uint64_t) { return *EAddr; };
+ } else if (Arg->getOption().matches(OBJCOPY_change_start)) {
+ auto EIncr = getAsInteger<int64_t>(Arg->getValue());
+ if (!EIncr)
+ return createStringError(EIncr.getError(),
+ "bad entry point increment: '%s'",
+ Arg->getValue());
+ auto Expr = Config.EntryExpr ? std::move(Config.EntryExpr)
+ : [](uint64_t A) { return A; };
+ Config.EntryExpr = [Expr, EIncr](uint64_t EAddr) {
+ return Expr(EAddr) + *EIncr;
+ };
+ }
+
+ if (Config.DecompressDebugSections &&
+ Config.CompressionType != DebugCompressionType::None) {
+ return createStringError(
+ errc::invalid_argument,
+ "cannot specify both --compress-debug-sections and "
+ "--decompress-debug-sections");
+ }
+
+ if (Config.DecompressDebugSections && !zlib::isAvailable())
+ return createStringError(
+ errc::invalid_argument,
+ "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");
+
+ if (Config.ExtractPartition && Config.ExtractMainPartition)
+ return createStringError(errc::invalid_argument,
+ "cannot specify --extract-partition together with "
+ "--extract-main-partition");
+
+ DC.CopyConfigs.push_back(std::move(Config));
+ return std::move(DC);
+}
+
+// ParseInstallNameToolOptions returns the config and sets the input arguments.
+// If a help flag is set then ParseInstallNameToolOptions will print the help
+// messege and exit.
+Expected<DriverConfig>
+parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
+ DriverConfig DC;
+ CopyConfig Config;
+ InstallNameToolOptTable T;
+ unsigned MissingArgumentIndex, MissingArgumentCount;
+ llvm::opt::InputArgList InputArgs =
+ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
+
+ if (MissingArgumentCount)
+ return createStringError(
+ errc::invalid_argument,
+ "missing argument to " +
+ StringRef(InputArgs.getArgString(MissingArgumentIndex)) +
+ " option");
+
+ if (InputArgs.size() == 0) {
+ printHelp(T, errs(), ToolType::InstallNameTool);
+ exit(1);
+ }
+
+ if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) {
+ printHelp(T, outs(), ToolType::InstallNameTool);
+ exit(0);
+ }
+
+ if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) {
+ outs() << "llvm-install-name-tool, compatible with cctools "
+ "install_name_tool\n";
+ cl::PrintVersionMessage();
+ exit(0);
+ }
+
+ for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))
+ Config.RPathToAdd.push_back(Arg->getValue());
+
for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath))
Config.RPathToPrepend.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {
- StringRef RPath = Arg->getValue();
-
- // Cannot add and delete the same rpath at the same time.
- if (is_contained(Config.RPathToAdd, RPath))
- return createStringError(
- errc::invalid_argument,
+ for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {
+ StringRef RPath = Arg->getValue();
+
+ // Cannot add and delete the same rpath at the same time.
+ if (is_contained(Config.RPathToAdd, RPath))
+ return createStringError(
+ errc::invalid_argument,
"cannot specify both -add_rpath '%s' and -delete_rpath '%s'",
- RPath.str().c_str(), RPath.str().c_str());
+ RPath.str().c_str(), RPath.str().c_str());
if (is_contained(Config.RPathToPrepend, RPath))
return createStringError(
errc::invalid_argument,
"cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'",
RPath.str().c_str(), RPath.str().c_str());
-
- Config.RPathsToRemove.insert(RPath);
- }
-
- for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) {
- StringRef Old = Arg->getValue(0);
- StringRef New = Arg->getValue(1);
-
- auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; };
-
- // Cannot specify duplicate -rpath entries
- auto It1 = find_if(
- Config.RPathsToUpdate,
- [&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) {
- return Match(OldNew.getFirst()) || Match(OldNew.getSecond());
- });
- if (It1 != Config.RPathsToUpdate.end())
- return createStringError(errc::invalid_argument,
+
+ Config.RPathsToRemove.insert(RPath);
+ }
+
+ for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) {
+ StringRef Old = Arg->getValue(0);
+ StringRef New = Arg->getValue(1);
+
+ auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; };
+
+ // Cannot specify duplicate -rpath entries
+ auto It1 = find_if(
+ Config.RPathsToUpdate,
+ [&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) {
+ return Match(OldNew.getFirst()) || Match(OldNew.getSecond());
+ });
+ if (It1 != Config.RPathsToUpdate.end())
+ return createStringError(errc::invalid_argument,
"cannot specify both -rpath '" +
It1->getFirst() + "' '" + It1->getSecond() +
"' and -rpath '" + Old + "' '" + New + "'");
-
- // Cannot specify the same rpath under both -delete_rpath and -rpath
- auto It2 = find_if(Config.RPathsToRemove, Match);
- if (It2 != Config.RPathsToRemove.end())
- return createStringError(errc::invalid_argument,
+
+ // Cannot specify the same rpath under both -delete_rpath and -rpath
+ auto It2 = find_if(Config.RPathsToRemove, Match);
+ if (It2 != Config.RPathsToRemove.end())
+ return createStringError(errc::invalid_argument,
"cannot specify both -delete_rpath '" + *It2 +
"' and -rpath '" + Old + "' '" + New + "'");
-
- // Cannot specify the same rpath under both -add_rpath and -rpath
- auto It3 = find_if(Config.RPathToAdd, Match);
- if (It3 != Config.RPathToAdd.end())
- return createStringError(errc::invalid_argument,
+
+ // Cannot specify the same rpath under both -add_rpath and -rpath
+ auto It3 = find_if(Config.RPathToAdd, Match);
+ if (It3 != Config.RPathToAdd.end())
+ return createStringError(errc::invalid_argument,
"cannot specify both -add_rpath '" + *It3 +
"' and -rpath '" + Old + "' '" + New + "'");
-
+
// Cannot specify the same rpath under both -prepend_rpath and -rpath.
auto It4 = find_if(Config.RPathToPrepend, Match);
if (It4 != Config.RPathToPrepend.end())
@@ -955,41 +955,41 @@ parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
"cannot specify both -prepend_rpath '" + *It4 +
"' and -rpath '" + Old + "' '" + New + "'");
- Config.RPathsToUpdate.insert({Old, New});
- }
-
+ Config.RPathsToUpdate.insert({Old, New});
+ }
+
if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) {
- Config.SharedLibId = Arg->getValue();
+ Config.SharedLibId = Arg->getValue();
if (Config.SharedLibId->empty())
return createStringError(errc::invalid_argument,
"cannot specify an empty id");
}
-
+
for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change))
- Config.InstallNamesToUpdate.insert({Arg->getValue(0), Arg->getValue(1)});
-
+ Config.InstallNamesToUpdate.insert({Arg->getValue(0), Arg->getValue(1)});
+
Config.RemoveAllRpaths =
InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths);
- SmallVector<StringRef, 2> Positional;
- for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))
- return createStringError(errc::invalid_argument, "unknown argument '%s'",
- Arg->getAsString(InputArgs).c_str());
- for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT))
- Positional.push_back(Arg->getValue());
- if (Positional.empty())
- return createStringError(errc::invalid_argument, "no input file specified");
- if (Positional.size() > 1)
- return createStringError(
- errc::invalid_argument,
- "llvm-install-name-tool expects a single input file");
- Config.InputFilename = Positional[0];
- Config.OutputFilename = Positional[0];
-
- DC.CopyConfigs.push_back(std::move(Config));
- return std::move(DC);
-}
-
+ SmallVector<StringRef, 2> Positional;
+ for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))
+ return createStringError(errc::invalid_argument, "unknown argument '%s'",
+ Arg->getAsString(InputArgs).c_str());
+ for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT))
+ Positional.push_back(Arg->getValue());
+ if (Positional.empty())
+ return createStringError(errc::invalid_argument, "no input file specified");
+ if (Positional.size() > 1)
+ return createStringError(
+ errc::invalid_argument,
+ "llvm-install-name-tool expects a single input file");
+ Config.InputFilename = Positional[0];
+ Config.OutputFilename = Positional[0];
+
+ DC.CopyConfigs.push_back(std::move(Config));
+ return std::move(DC);
+}
+
Expected<DriverConfig>
parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr) {
DriverConfig DC;
@@ -1034,147 +1034,147 @@ parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr) {
return std::move(DC);
}
-// ParseStripOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseStripOptions will print the help messege and
-// exit.
-Expected<DriverConfig>
-parseStripOptions(ArrayRef<const char *> ArgsArr,
- llvm::function_ref<Error(Error)> ErrorCallback) {
- StripOptTable T;
- unsigned MissingArgumentIndex, MissingArgumentCount;
- llvm::opt::InputArgList InputArgs =
- T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
-
- if (InputArgs.size() == 0) {
- printHelp(T, errs(), ToolType::Strip);
- exit(1);
- }
-
- if (InputArgs.hasArg(STRIP_help)) {
- printHelp(T, outs(), ToolType::Strip);
- exit(0);
- }
-
- if (InputArgs.hasArg(STRIP_version)) {
- outs() << "llvm-strip, compatible with GNU strip\n";
- cl::PrintVersionMessage();
- exit(0);
- }
-
- SmallVector<StringRef, 2> Positional;
- for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
- return createStringError(errc::invalid_argument, "unknown argument '%s'",
- Arg->getAsString(InputArgs).c_str());
- for (auto Arg : InputArgs.filtered(STRIP_INPUT))
- Positional.push_back(Arg->getValue());
-
- if (Positional.empty())
- return createStringError(errc::invalid_argument, "no input file specified");
-
- if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
- return createStringError(
- errc::invalid_argument,
- "multiple input files cannot be used in combination with -o");
-
- CopyConfig Config;
-
- if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))
- return createStringError(errc::invalid_argument,
- "--regex and --wildcard are incompatible");
- MatchStyle SectionMatchStyle =
- InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard;
- MatchStyle SymbolMatchStyle = InputArgs.hasArg(STRIP_regex)
- ? MatchStyle::Regex
- : InputArgs.hasArg(STRIP_wildcard)
- ? MatchStyle::Wildcard
- : MatchStyle::Literal;
- Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);
- Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
-
- if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals))
- Config.DiscardMode =
- InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals)
- ? DiscardType::All
- : DiscardType::Locals;
- Config.StripSections = InputArgs.hasArg(STRIP_strip_sections);
- Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
- if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all))
- Config.StripAll = Arg->getOption().getID() == STRIP_strip_all;
- Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
- Config.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols);
- Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);
- Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
-
- for (auto Arg : InputArgs.filtered(STRIP_keep_section))
- if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
- Arg->getValue(), SectionMatchStyle, ErrorCallback)))
- return std::move(E);
-
- for (auto Arg : InputArgs.filtered(STRIP_remove_section))
- if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
- Arg->getValue(), SectionMatchStyle, ErrorCallback)))
- return std::move(E);
-
- for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
- if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
- Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
- return std::move(E);
-
- for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
- if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
- Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
- return std::move(E);
-
- if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&
- !Config.StripUnneeded && Config.DiscardMode == DiscardType::None &&
- !Config.StripAllGNU && Config.SymbolsToRemove.empty())
- Config.StripAll = true;
-
- if (Config.DiscardMode == DiscardType::All) {
- Config.StripDebug = true;
- Config.KeepFileSymbols = true;
- }
-
- Config.DeterministicArchives =
- InputArgs.hasFlag(STRIP_enable_deterministic_archives,
- STRIP_disable_deterministic_archives, /*default=*/true);
-
- Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
- Config.InputFormat = FileFormat::Unspecified;
- Config.OutputFormat = FileFormat::Unspecified;
-
- DriverConfig DC;
- if (Positional.size() == 1) {
- Config.InputFilename = Positional[0];
- Config.OutputFilename =
- InputArgs.getLastArgValue(STRIP_output, Positional[0]);
- DC.CopyConfigs.push_back(std::move(Config));
- } else {
- StringMap<unsigned> InputFiles;
- for (StringRef Filename : Positional) {
- if (InputFiles[Filename]++ == 1) {
- if (Filename == "-")
- return createStringError(
- errc::invalid_argument,
- "cannot specify '-' as an input file more than once");
- if (Error E = ErrorCallback(createStringError(
- errc::invalid_argument, "'%s' was already specified",
- Filename.str().c_str())))
- return std::move(E);
- }
- Config.InputFilename = Filename;
- Config.OutputFilename = Filename;
- DC.CopyConfigs.push_back(Config);
- }
- }
-
- if (Config.PreserveDates && (is_contained(Positional, "-") ||
- InputArgs.getLastArgValue(STRIP_output) == "-"))
- return createStringError(errc::invalid_argument,
- "--preserve-dates requires a file");
-
- return std::move(DC);
-}
-
-} // namespace objcopy
-} // namespace llvm
+// ParseStripOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseStripOptions will print the help messege and
+// exit.
+Expected<DriverConfig>
+parseStripOptions(ArrayRef<const char *> ArgsArr,
+ llvm::function_ref<Error(Error)> ErrorCallback) {
+ StripOptTable T;
+ unsigned MissingArgumentIndex, MissingArgumentCount;
+ llvm::opt::InputArgList InputArgs =
+ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
+
+ if (InputArgs.size() == 0) {
+ printHelp(T, errs(), ToolType::Strip);
+ exit(1);
+ }
+
+ if (InputArgs.hasArg(STRIP_help)) {
+ printHelp(T, outs(), ToolType::Strip);
+ exit(0);
+ }
+
+ if (InputArgs.hasArg(STRIP_version)) {
+ outs() << "llvm-strip, compatible with GNU strip\n";
+ cl::PrintVersionMessage();
+ exit(0);
+ }
+
+ SmallVector<StringRef, 2> Positional;
+ for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
+ return createStringError(errc::invalid_argument, "unknown argument '%s'",
+ Arg->getAsString(InputArgs).c_str());
+ for (auto Arg : InputArgs.filtered(STRIP_INPUT))
+ Positional.push_back(Arg->getValue());
+
+ if (Positional.empty())
+ return createStringError(errc::invalid_argument, "no input file specified");
+
+ if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
+ return createStringError(
+ errc::invalid_argument,
+ "multiple input files cannot be used in combination with -o");
+
+ CopyConfig Config;
+
+ if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))
+ return createStringError(errc::invalid_argument,
+ "--regex and --wildcard are incompatible");
+ MatchStyle SectionMatchStyle =
+ InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard;
+ MatchStyle SymbolMatchStyle = InputArgs.hasArg(STRIP_regex)
+ ? MatchStyle::Regex
+ : InputArgs.hasArg(STRIP_wildcard)
+ ? MatchStyle::Wildcard
+ : MatchStyle::Literal;
+ Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);
+ Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
+
+ if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals))
+ Config.DiscardMode =
+ InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals)
+ ? DiscardType::All
+ : DiscardType::Locals;
+ Config.StripSections = InputArgs.hasArg(STRIP_strip_sections);
+ Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
+ if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all))
+ Config.StripAll = Arg->getOption().getID() == STRIP_strip_all;
+ Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
+ Config.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols);
+ Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);
+ Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
+
+ for (auto Arg : InputArgs.filtered(STRIP_keep_section))
+ if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
+
+ for (auto Arg : InputArgs.filtered(STRIP_remove_section))
+ if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
+
+ for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
+ if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
+
+ for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
+ if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
+
+ if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&
+ !Config.StripUnneeded && Config.DiscardMode == DiscardType::None &&
+ !Config.StripAllGNU && Config.SymbolsToRemove.empty())
+ Config.StripAll = true;
+
+ if (Config.DiscardMode == DiscardType::All) {
+ Config.StripDebug = true;
+ Config.KeepFileSymbols = true;
+ }
+
+ Config.DeterministicArchives =
+ InputArgs.hasFlag(STRIP_enable_deterministic_archives,
+ STRIP_disable_deterministic_archives, /*default=*/true);
+
+ Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
+ Config.InputFormat = FileFormat::Unspecified;
+ Config.OutputFormat = FileFormat::Unspecified;
+
+ DriverConfig DC;
+ if (Positional.size() == 1) {
+ Config.InputFilename = Positional[0];
+ Config.OutputFilename =
+ InputArgs.getLastArgValue(STRIP_output, Positional[0]);
+ DC.CopyConfigs.push_back(std::move(Config));
+ } else {
+ StringMap<unsigned> InputFiles;
+ for (StringRef Filename : Positional) {
+ if (InputFiles[Filename]++ == 1) {
+ if (Filename == "-")
+ return createStringError(
+ errc::invalid_argument,
+ "cannot specify '-' as an input file more than once");
+ if (Error E = ErrorCallback(createStringError(
+ errc::invalid_argument, "'%s' was already specified",
+ Filename.str().c_str())))
+ return std::move(E);
+ }
+ Config.InputFilename = Filename;
+ Config.OutputFilename = Filename;
+ DC.CopyConfigs.push_back(Config);
+ }
+ }
+
+ if (Config.PreserveDates && (is_contained(Positional, "-") ||
+ InputArgs.getLastArgValue(STRIP_output) == "-"))
+ return createStringError(errc::invalid_argument,
+ "--preserve-dates requires a file");
+
+ return std::move(DC);
+}
+
+} // namespace objcopy
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.h b/contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.h
index 07eac9d2bb..008a138de7 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/CopyConfig.h
@@ -1,289 +1,289 @@
-//===- CopyConfig.h -------------------------------------------------------===//
-//
-// 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_LLVM_OBJCOPY_COPY_CONFIG_H
-#define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
-
-#include "ELF/ELFConfig.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitmaskEnum.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Object/ELFTypes.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/GlobPattern.h"
-#include "llvm/Support/Regex.h"
-// Necessary for llvm::DebugCompressionType::None
-#include "llvm/Target/TargetOptions.h"
-#include <vector>
-
-namespace llvm {
-namespace objcopy {
-
-enum class FileFormat {
- Unspecified,
- ELF,
- Binary,
- IHex,
-};
-
-// This type keeps track of the machine info for various architectures. This
-// lets us map architecture names to ELF types and the e_machine value of the
-// ELF file.
-struct MachineInfo {
- MachineInfo(uint16_t EM, uint8_t ABI, bool Is64, bool IsLittle)
- : EMachine(EM), OSABI(ABI), Is64Bit(Is64), IsLittleEndian(IsLittle) {}
- // Alternative constructor that defaults to NONE for OSABI.
- MachineInfo(uint16_t EM, bool Is64, bool IsLittle)
- : MachineInfo(EM, ELF::ELFOSABI_NONE, Is64, IsLittle) {}
- // Default constructor for unset fields.
- MachineInfo() : MachineInfo(0, 0, false, false) {}
- uint16_t EMachine;
- uint8_t OSABI;
- bool Is64Bit;
- bool IsLittleEndian;
-};
-
-// Flags set by --set-section-flags or --rename-section. Interpretation of these
-// is format-specific and not all flags are meaningful for all object file
-// formats. This is a bitmask; many section flags may be set.
-enum SectionFlag {
- SecNone = 0,
- SecAlloc = 1 << 0,
- SecLoad = 1 << 1,
- SecNoload = 1 << 2,
- SecReadonly = 1 << 3,
- SecDebug = 1 << 4,
- SecCode = 1 << 5,
- SecData = 1 << 6,
- SecRom = 1 << 7,
- SecMerge = 1 << 8,
- SecStrings = 1 << 9,
- SecContents = 1 << 10,
- SecShare = 1 << 11,
- SecExclude = 1 << 12,
- LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/SecExclude)
-};
-
-struct SectionRename {
- StringRef OriginalName;
- StringRef NewName;
- Optional<SectionFlag> NewFlags;
-};
-
-struct SectionFlagsUpdate {
- StringRef Name;
- SectionFlag NewFlags;
-};
-
-enum class DiscardType {
- None, // Default
- All, // --discard-all (-x)
- Locals, // --discard-locals (-X)
-};
-
-enum class MatchStyle {
- Literal, // Default for symbols.
- Wildcard, // Default for sections, or enabled with --wildcard (-w).
- Regex, // Enabled with --regex.
-};
-
-class NameOrPattern {
- StringRef Name;
- // Regex is shared between multiple CopyConfig instances.
- std::shared_ptr<Regex> R;
- std::shared_ptr<GlobPattern> G;
- bool IsPositiveMatch = true;
-
- NameOrPattern(StringRef N) : Name(N) {}
- NameOrPattern(std::shared_ptr<Regex> R) : R(R) {}
- NameOrPattern(std::shared_ptr<GlobPattern> G, bool IsPositiveMatch)
- : G(G), IsPositiveMatch(IsPositiveMatch) {}
-
-public:
- // ErrorCallback is used to handle recoverable errors. An Error returned
- // by the callback aborts the parsing and is then returned by this function.
- static Expected<NameOrPattern>
- create(StringRef Pattern, MatchStyle MS,
- llvm::function_ref<Error(Error)> ErrorCallback);
-
- bool isPositiveMatch() const { return IsPositiveMatch; }
- bool operator==(StringRef S) const {
- return R ? R->match(S) : G ? G->match(S) : Name == S;
- }
- bool operator!=(StringRef S) const { return !operator==(S); }
-};
-
-// Matcher that checks symbol or section names against the command line flags
-// provided for that option.
-class NameMatcher {
- std::vector<NameOrPattern> PosMatchers;
- std::vector<NameOrPattern> NegMatchers;
-
-public:
- Error addMatcher(Expected<NameOrPattern> Matcher) {
- if (!Matcher)
- return Matcher.takeError();
- if (Matcher->isPositiveMatch())
- PosMatchers.push_back(std::move(*Matcher));
- else
- NegMatchers.push_back(std::move(*Matcher));
- return Error::success();
- }
- bool matches(StringRef S) const {
- return is_contained(PosMatchers, S) && !is_contained(NegMatchers, S);
- }
- bool empty() const { return PosMatchers.empty() && NegMatchers.empty(); }
-};
-
-// Configuration for copying/stripping a single file.
-struct CopyConfig {
- // Format-specific options to be initialized lazily when needed.
- Optional<elf::ELFCopyConfig> ELF;
-
- // Main input/output options
- StringRef InputFilename;
- FileFormat InputFormat = FileFormat::Unspecified;
- StringRef OutputFilename;
- FileFormat OutputFormat = FileFormat::Unspecified;
-
- // Only applicable when --output-format!=binary (e.g. elf64-x86-64).
- Optional<MachineInfo> OutputArch;
-
- // Advanced options
- StringRef AddGnuDebugLink;
- // Cached gnu_debuglink's target CRC
- uint32_t GnuDebugLinkCRC32;
- StringRef BuildIdLinkDir;
- Optional<StringRef> BuildIdLinkInput;
- Optional<StringRef> BuildIdLinkOutput;
- Optional<StringRef> ExtractPartition;
- StringRef SplitDWO;
- StringRef SymbolsPrefix;
- StringRef AllocSectionsPrefix;
- DiscardType DiscardMode = DiscardType::None;
- Optional<StringRef> NewSymbolVisibility;
-
- // Repeated options
- std::vector<StringRef> AddSection;
- std::vector<StringRef> DumpSection;
- std::vector<StringRef> SymbolsToAdd;
- std::vector<StringRef> RPathToAdd;
+//===- CopyConfig.h -------------------------------------------------------===//
+//
+// 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_LLVM_OBJCOPY_COPY_CONFIG_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
+
+#include "ELF/ELFConfig.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/GlobPattern.h"
+#include "llvm/Support/Regex.h"
+// Necessary for llvm::DebugCompressionType::None
+#include "llvm/Target/TargetOptions.h"
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+
+enum class FileFormat {
+ Unspecified,
+ ELF,
+ Binary,
+ IHex,
+};
+
+// This type keeps track of the machine info for various architectures. This
+// lets us map architecture names to ELF types and the e_machine value of the
+// ELF file.
+struct MachineInfo {
+ MachineInfo(uint16_t EM, uint8_t ABI, bool Is64, bool IsLittle)
+ : EMachine(EM), OSABI(ABI), Is64Bit(Is64), IsLittleEndian(IsLittle) {}
+ // Alternative constructor that defaults to NONE for OSABI.
+ MachineInfo(uint16_t EM, bool Is64, bool IsLittle)
+ : MachineInfo(EM, ELF::ELFOSABI_NONE, Is64, IsLittle) {}
+ // Default constructor for unset fields.
+ MachineInfo() : MachineInfo(0, 0, false, false) {}
+ uint16_t EMachine;
+ uint8_t OSABI;
+ bool Is64Bit;
+ bool IsLittleEndian;
+};
+
+// Flags set by --set-section-flags or --rename-section. Interpretation of these
+// is format-specific and not all flags are meaningful for all object file
+// formats. This is a bitmask; many section flags may be set.
+enum SectionFlag {
+ SecNone = 0,
+ SecAlloc = 1 << 0,
+ SecLoad = 1 << 1,
+ SecNoload = 1 << 2,
+ SecReadonly = 1 << 3,
+ SecDebug = 1 << 4,
+ SecCode = 1 << 5,
+ SecData = 1 << 6,
+ SecRom = 1 << 7,
+ SecMerge = 1 << 8,
+ SecStrings = 1 << 9,
+ SecContents = 1 << 10,
+ SecShare = 1 << 11,
+ SecExclude = 1 << 12,
+ LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/SecExclude)
+};
+
+struct SectionRename {
+ StringRef OriginalName;
+ StringRef NewName;
+ Optional<SectionFlag> NewFlags;
+};
+
+struct SectionFlagsUpdate {
+ StringRef Name;
+ SectionFlag NewFlags;
+};
+
+enum class DiscardType {
+ None, // Default
+ All, // --discard-all (-x)
+ Locals, // --discard-locals (-X)
+};
+
+enum class MatchStyle {
+ Literal, // Default for symbols.
+ Wildcard, // Default for sections, or enabled with --wildcard (-w).
+ Regex, // Enabled with --regex.
+};
+
+class NameOrPattern {
+ StringRef Name;
+ // Regex is shared between multiple CopyConfig instances.
+ std::shared_ptr<Regex> R;
+ std::shared_ptr<GlobPattern> G;
+ bool IsPositiveMatch = true;
+
+ NameOrPattern(StringRef N) : Name(N) {}
+ NameOrPattern(std::shared_ptr<Regex> R) : R(R) {}
+ NameOrPattern(std::shared_ptr<GlobPattern> G, bool IsPositiveMatch)
+ : G(G), IsPositiveMatch(IsPositiveMatch) {}
+
+public:
+ // ErrorCallback is used to handle recoverable errors. An Error returned
+ // by the callback aborts the parsing and is then returned by this function.
+ static Expected<NameOrPattern>
+ create(StringRef Pattern, MatchStyle MS,
+ llvm::function_ref<Error(Error)> ErrorCallback);
+
+ bool isPositiveMatch() const { return IsPositiveMatch; }
+ bool operator==(StringRef S) const {
+ return R ? R->match(S) : G ? G->match(S) : Name == S;
+ }
+ bool operator!=(StringRef S) const { return !operator==(S); }
+};
+
+// Matcher that checks symbol or section names against the command line flags
+// provided for that option.
+class NameMatcher {
+ std::vector<NameOrPattern> PosMatchers;
+ std::vector<NameOrPattern> NegMatchers;
+
+public:
+ Error addMatcher(Expected<NameOrPattern> Matcher) {
+ if (!Matcher)
+ return Matcher.takeError();
+ if (Matcher->isPositiveMatch())
+ PosMatchers.push_back(std::move(*Matcher));
+ else
+ NegMatchers.push_back(std::move(*Matcher));
+ return Error::success();
+ }
+ bool matches(StringRef S) const {
+ return is_contained(PosMatchers, S) && !is_contained(NegMatchers, S);
+ }
+ bool empty() const { return PosMatchers.empty() && NegMatchers.empty(); }
+};
+
+// Configuration for copying/stripping a single file.
+struct CopyConfig {
+ // Format-specific options to be initialized lazily when needed.
+ Optional<elf::ELFCopyConfig> ELF;
+
+ // Main input/output options
+ StringRef InputFilename;
+ FileFormat InputFormat = FileFormat::Unspecified;
+ StringRef OutputFilename;
+ FileFormat OutputFormat = FileFormat::Unspecified;
+
+ // Only applicable when --output-format!=binary (e.g. elf64-x86-64).
+ Optional<MachineInfo> OutputArch;
+
+ // Advanced options
+ StringRef AddGnuDebugLink;
+ // Cached gnu_debuglink's target CRC
+ uint32_t GnuDebugLinkCRC32;
+ StringRef BuildIdLinkDir;
+ Optional<StringRef> BuildIdLinkInput;
+ Optional<StringRef> BuildIdLinkOutput;
+ Optional<StringRef> ExtractPartition;
+ StringRef SplitDWO;
+ StringRef SymbolsPrefix;
+ StringRef AllocSectionsPrefix;
+ DiscardType DiscardMode = DiscardType::None;
+ Optional<StringRef> NewSymbolVisibility;
+
+ // Repeated options
+ std::vector<StringRef> AddSection;
+ std::vector<StringRef> DumpSection;
+ std::vector<StringRef> SymbolsToAdd;
+ std::vector<StringRef> RPathToAdd;
std::vector<StringRef> RPathToPrepend;
- DenseMap<StringRef, StringRef> RPathsToUpdate;
- DenseMap<StringRef, StringRef> InstallNamesToUpdate;
- DenseSet<StringRef> RPathsToRemove;
-
- // install-name-tool's id option
- Optional<StringRef> SharedLibId;
-
- // Section matchers
- NameMatcher KeepSection;
- NameMatcher OnlySection;
- NameMatcher ToRemove;
-
- // Symbol matchers
- NameMatcher SymbolsToGlobalize;
- NameMatcher SymbolsToKeep;
- NameMatcher SymbolsToLocalize;
- NameMatcher SymbolsToRemove;
- NameMatcher UnneededSymbolsToRemove;
- NameMatcher SymbolsToWeaken;
- NameMatcher SymbolsToKeepGlobal;
-
- // Map options
- StringMap<SectionRename> SectionsToRename;
- StringMap<uint64_t> SetSectionAlignment;
- StringMap<SectionFlagsUpdate> SetSectionFlags;
- StringMap<StringRef> SymbolsToRename;
-
- // ELF entry point address expression. The input parameter is an entry point
- // address in the input ELF file. The entry address in the output file is
- // calculated with EntryExpr(input_address), when either --set-start or
- // --change-start is used.
- std::function<uint64_t(uint64_t)> EntryExpr;
-
- // Boolean options
- bool AllowBrokenLinks = false;
- bool DeterministicArchives = true;
- bool ExtractDWO = false;
- bool ExtractMainPartition = false;
- bool KeepFileSymbols = false;
- bool LocalizeHidden = false;
- bool OnlyKeepDebug = false;
- bool PreserveDates = false;
- bool StripAll = false;
- bool StripAllGNU = false;
- bool StripDWO = false;
- bool StripDebug = false;
- bool StripNonAlloc = false;
- bool StripSections = false;
- bool StripSwiftSymbols = false;
- bool StripUnneeded = false;
- bool Weaken = false;
- bool DecompressDebugSections = false;
+ DenseMap<StringRef, StringRef> RPathsToUpdate;
+ DenseMap<StringRef, StringRef> InstallNamesToUpdate;
+ DenseSet<StringRef> RPathsToRemove;
+
+ // install-name-tool's id option
+ Optional<StringRef> SharedLibId;
+
+ // Section matchers
+ NameMatcher KeepSection;
+ NameMatcher OnlySection;
+ NameMatcher ToRemove;
+
+ // Symbol matchers
+ NameMatcher SymbolsToGlobalize;
+ NameMatcher SymbolsToKeep;
+ NameMatcher SymbolsToLocalize;
+ NameMatcher SymbolsToRemove;
+ NameMatcher UnneededSymbolsToRemove;
+ NameMatcher SymbolsToWeaken;
+ NameMatcher SymbolsToKeepGlobal;
+
+ // Map options
+ StringMap<SectionRename> SectionsToRename;
+ StringMap<uint64_t> SetSectionAlignment;
+ StringMap<SectionFlagsUpdate> SetSectionFlags;
+ StringMap<StringRef> SymbolsToRename;
+
+ // ELF entry point address expression. The input parameter is an entry point
+ // address in the input ELF file. The entry address in the output file is
+ // calculated with EntryExpr(input_address), when either --set-start or
+ // --change-start is used.
+ std::function<uint64_t(uint64_t)> EntryExpr;
+
+ // Boolean options
+ bool AllowBrokenLinks = false;
+ bool DeterministicArchives = true;
+ bool ExtractDWO = false;
+ bool ExtractMainPartition = false;
+ bool KeepFileSymbols = false;
+ bool LocalizeHidden = false;
+ bool OnlyKeepDebug = false;
+ bool PreserveDates = false;
+ bool StripAll = false;
+ bool StripAllGNU = false;
+ bool StripDWO = false;
+ bool StripDebug = false;
+ bool StripNonAlloc = false;
+ bool StripSections = false;
+ bool StripSwiftSymbols = false;
+ bool StripUnneeded = false;
+ bool Weaken = false;
+ bool DecompressDebugSections = false;
// install-name-tool's --delete_all_rpaths
bool RemoveAllRpaths = false;
- DebugCompressionType CompressionType = DebugCompressionType::None;
-
- // parseELFConfig performs ELF-specific command-line parsing. Fills `ELF` on
- // success or returns an Error otherwise.
- Error parseELFConfig() {
- if (!ELF) {
- Expected<elf::ELFCopyConfig> ELFConfig = elf::parseConfig(*this);
- if (!ELFConfig)
- return ELFConfig.takeError();
- ELF = *ELFConfig;
- }
- return Error::success();
- }
-};
-
-// Configuration for the overall invocation of this tool. When invoked as
-// objcopy, will always contain exactly one CopyConfig. When invoked as strip,
-// will contain one or more CopyConfigs.
-struct DriverConfig {
- SmallVector<CopyConfig, 1> CopyConfigs;
- BumpPtrAllocator Alloc;
-};
-
-// ParseObjcopyOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseObjcopyOptions will print the help messege and
-// exit. ErrorCallback is used to handle recoverable errors. An Error returned
-// by the callback aborts the parsing and is then returned by this function.
-Expected<DriverConfig>
-parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
- llvm::function_ref<Error(Error)> ErrorCallback);
-
-// ParseInstallNameToolOptions returns the config and sets the input arguments.
-// If a help flag is set then ParseInstallNameToolOptions will print the help
-// messege and exit.
-Expected<DriverConfig>
-parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr);
-
+ DebugCompressionType CompressionType = DebugCompressionType::None;
+
+ // parseELFConfig performs ELF-specific command-line parsing. Fills `ELF` on
+ // success or returns an Error otherwise.
+ Error parseELFConfig() {
+ if (!ELF) {
+ Expected<elf::ELFCopyConfig> ELFConfig = elf::parseConfig(*this);
+ if (!ELFConfig)
+ return ELFConfig.takeError();
+ ELF = *ELFConfig;
+ }
+ return Error::success();
+ }
+};
+
+// Configuration for the overall invocation of this tool. When invoked as
+// objcopy, will always contain exactly one CopyConfig. When invoked as strip,
+// will contain one or more CopyConfigs.
+struct DriverConfig {
+ SmallVector<CopyConfig, 1> CopyConfigs;
+ BumpPtrAllocator Alloc;
+};
+
+// ParseObjcopyOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseObjcopyOptions will print the help messege and
+// exit. ErrorCallback is used to handle recoverable errors. An Error returned
+// by the callback aborts the parsing and is then returned by this function.
+Expected<DriverConfig>
+parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
+ llvm::function_ref<Error(Error)> ErrorCallback);
+
+// ParseInstallNameToolOptions returns the config and sets the input arguments.
+// If a help flag is set then ParseInstallNameToolOptions will print the help
+// messege and exit.
+Expected<DriverConfig>
+parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr);
+
// ParseBitcodeStripOptions returns the config and sets the input arguments.
// If a help flag is set then ParseBitcodeStripOptions will print the help
// messege and exit.
Expected<DriverConfig> parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr);
-// ParseStripOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseStripOptions will print the help messege and
-// exit. ErrorCallback is used to handle recoverable errors. An Error returned
-// by the callback aborts the parsing and is then returned by this function.
-Expected<DriverConfig>
-parseStripOptions(ArrayRef<const char *> ArgsArr,
- llvm::function_ref<Error(Error)> ErrorCallback);
-} // namespace objcopy
-} // namespace llvm
-
-#endif
+// ParseStripOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseStripOptions will print the help messege and
+// exit. ErrorCallback is used to handle recoverable errors. An Error returned
+// by the callback aborts the parsing and is then returned by this function.
+Expected<DriverConfig>
+parseStripOptions(ArrayRef<const char *> ArgsArr,
+ llvm::function_ref<Error(Error)> ErrorCallback);
+} // namespace objcopy
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp
index 40993760ad..fcedf8ee11 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.cpp
@@ -1,133 +1,133 @@
-//===- ELFConfig.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 "CopyConfig.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-namespace objcopy {
-namespace elf {
-
-static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue,
- uint8_t DefaultVisibility) {
- // Parse value given with --add-symbol option and create the
- // new symbol if possible. The value format for --add-symbol is:
- //
- // <name>=[<section>:]<value>[,<flags>]
- //
- // where:
- // <name> - symbol name, can be empty string
- // <section> - optional section name. If not given ABS symbol is created
- // <value> - symbol value, can be decimal or hexadecimal number prefixed
- // with 0x.
- // <flags> - optional flags affecting symbol type, binding or visibility:
- // The following are currently supported:
- //
- // global, local, weak, default, hidden, file, section, object,
- // indirect-function.
- //
- // The following flags are ignored and provided for GNU
- // compatibility only:
- //
- // warning, debug, constructor, indirect, synthetic,
- // unique-object, before=<symbol>.
- NewSymbolInfo SI;
- StringRef Value;
- std::tie(SI.SymbolName, Value) = FlagValue.split('=');
- if (Value.empty())
- return createStringError(
- errc::invalid_argument,
- "bad format for --add-symbol, missing '=' after '%s'",
- SI.SymbolName.str().c_str());
-
- if (Value.contains(':')) {
- std::tie(SI.SectionName, Value) = Value.split(':');
- if (SI.SectionName.empty() || Value.empty())
- return createStringError(
- errc::invalid_argument,
- "bad format for --add-symbol, missing section name or symbol value");
- }
-
- SmallVector<StringRef, 6> Flags;
- Value.split(Flags, ',');
- if (Flags[0].getAsInteger(0, SI.Value))
- return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
- Flags[0].str().c_str());
-
- SI.Visibility = DefaultVisibility;
-
- using Functor = std::function<void(void)>;
- SmallVector<StringRef, 6> UnsupportedFlags;
- for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
- static_cast<Functor>(
- StringSwitch<Functor>(Flags[I])
- .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
- .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
- .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
- .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
- .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
- .CaseLower("protected",
- [&SI] { SI.Visibility = ELF::STV_PROTECTED; })
- .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
- .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
- .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
- .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
- .CaseLower("indirect-function",
- [&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
- .CaseLower("debug", [] {})
- .CaseLower("constructor", [] {})
- .CaseLower("warning", [] {})
- .CaseLower("indirect", [] {})
- .CaseLower("synthetic", [] {})
- .CaseLower("unique-object", [] {})
- .StartsWithLower("before", [] {})
- .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
- if (!UnsupportedFlags.empty())
- return createStringError(errc::invalid_argument,
- "unsupported flag%s for --add-symbol: '%s'",
- UnsupportedFlags.size() > 1 ? "s" : "",
- join(UnsupportedFlags, "', '").c_str());
- return SI;
-}
-
-Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config) {
- ELFCopyConfig ELFConfig;
- if (Config.NewSymbolVisibility) {
- const uint8_t Invalid = 0xff;
- ELFConfig.NewSymbolVisibility =
- StringSwitch<uint8_t>(*Config.NewSymbolVisibility)
- .Case("default", ELF::STV_DEFAULT)
- .Case("hidden", ELF::STV_HIDDEN)
- .Case("internal", ELF::STV_INTERNAL)
- .Case("protected", ELF::STV_PROTECTED)
- .Default(Invalid);
-
- if (ELFConfig.NewSymbolVisibility == Invalid)
- return createStringError(errc::invalid_argument,
- "'%s' is not a valid symbol visibility",
- Config.NewSymbolVisibility->str().c_str());
- }
-
- for (StringRef Arg : Config.SymbolsToAdd) {
- Expected<elf::NewSymbolInfo> NSI = parseNewSymbolInfo(
- Arg,
- ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT));
- if (!NSI)
- return NSI.takeError();
- ELFConfig.SymbolsToAdd.push_back(*NSI);
- }
-
- return ELFConfig;
-}
-
-} // end namespace elf
-} // end namespace objcopy
-} // end namespace llvm
+//===- ELFConfig.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 "CopyConfig.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace objcopy {
+namespace elf {
+
+static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue,
+ uint8_t DefaultVisibility) {
+ // Parse value given with --add-symbol option and create the
+ // new symbol if possible. The value format for --add-symbol is:
+ //
+ // <name>=[<section>:]<value>[,<flags>]
+ //
+ // where:
+ // <name> - symbol name, can be empty string
+ // <section> - optional section name. If not given ABS symbol is created
+ // <value> - symbol value, can be decimal or hexadecimal number prefixed
+ // with 0x.
+ // <flags> - optional flags affecting symbol type, binding or visibility:
+ // The following are currently supported:
+ //
+ // global, local, weak, default, hidden, file, section, object,
+ // indirect-function.
+ //
+ // The following flags are ignored and provided for GNU
+ // compatibility only:
+ //
+ // warning, debug, constructor, indirect, synthetic,
+ // unique-object, before=<symbol>.
+ NewSymbolInfo SI;
+ StringRef Value;
+ std::tie(SI.SymbolName, Value) = FlagValue.split('=');
+ if (Value.empty())
+ return createStringError(
+ errc::invalid_argument,
+ "bad format for --add-symbol, missing '=' after '%s'",
+ SI.SymbolName.str().c_str());
+
+ if (Value.contains(':')) {
+ std::tie(SI.SectionName, Value) = Value.split(':');
+ if (SI.SectionName.empty() || Value.empty())
+ return createStringError(
+ errc::invalid_argument,
+ "bad format for --add-symbol, missing section name or symbol value");
+ }
+
+ SmallVector<StringRef, 6> Flags;
+ Value.split(Flags, ',');
+ if (Flags[0].getAsInteger(0, SI.Value))
+ return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
+ Flags[0].str().c_str());
+
+ SI.Visibility = DefaultVisibility;
+
+ using Functor = std::function<void(void)>;
+ SmallVector<StringRef, 6> UnsupportedFlags;
+ for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
+ static_cast<Functor>(
+ StringSwitch<Functor>(Flags[I])
+ .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
+ .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
+ .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
+ .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
+ .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
+ .CaseLower("protected",
+ [&SI] { SI.Visibility = ELF::STV_PROTECTED; })
+ .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
+ .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
+ .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
+ .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
+ .CaseLower("indirect-function",
+ [&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
+ .CaseLower("debug", [] {})
+ .CaseLower("constructor", [] {})
+ .CaseLower("warning", [] {})
+ .CaseLower("indirect", [] {})
+ .CaseLower("synthetic", [] {})
+ .CaseLower("unique-object", [] {})
+ .StartsWithLower("before", [] {})
+ .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
+ if (!UnsupportedFlags.empty())
+ return createStringError(errc::invalid_argument,
+ "unsupported flag%s for --add-symbol: '%s'",
+ UnsupportedFlags.size() > 1 ? "s" : "",
+ join(UnsupportedFlags, "', '").c_str());
+ return SI;
+}
+
+Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config) {
+ ELFCopyConfig ELFConfig;
+ if (Config.NewSymbolVisibility) {
+ const uint8_t Invalid = 0xff;
+ ELFConfig.NewSymbolVisibility =
+ StringSwitch<uint8_t>(*Config.NewSymbolVisibility)
+ .Case("default", ELF::STV_DEFAULT)
+ .Case("hidden", ELF::STV_HIDDEN)
+ .Case("internal", ELF::STV_INTERNAL)
+ .Case("protected", ELF::STV_PROTECTED)
+ .Default(Invalid);
+
+ if (ELFConfig.NewSymbolVisibility == Invalid)
+ return createStringError(errc::invalid_argument,
+ "'%s' is not a valid symbol visibility",
+ Config.NewSymbolVisibility->str().c_str());
+ }
+
+ for (StringRef Arg : Config.SymbolsToAdd) {
+ Expected<elf::NewSymbolInfo> NSI = parseNewSymbolInfo(
+ Arg,
+ ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT));
+ if (!NSI)
+ return NSI.takeError();
+ ELFConfig.SymbolsToAdd.push_back(*NSI);
+ }
+
+ return ELFConfig;
+}
+
+} // end namespace elf
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h
index 977efbc416..a51ac07546 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFConfig.h
@@ -1,44 +1,44 @@
-//===- ELFConfig.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_OBJCOPY_ELFCONFIG_H
-#define LLVM_TOOLS_OBJCOPY_ELFCONFIG_H
-
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Object/ELFTypes.h"
-#include "llvm/Support/Error.h"
-#include <vector>
-
-namespace llvm {
-namespace objcopy {
-struct CopyConfig;
-
-namespace elf {
-
-struct NewSymbolInfo {
- StringRef SymbolName;
- StringRef SectionName;
- uint64_t Value = 0;
- uint8_t Type = ELF::STT_NOTYPE;
- uint8_t Bind = ELF::STB_GLOBAL;
- uint8_t Visibility = ELF::STV_DEFAULT;
-};
-
-struct ELFCopyConfig {
- Optional<uint8_t> NewSymbolVisibility;
- std::vector<NewSymbolInfo> SymbolsToAdd;
-};
-
-Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config);
-
-} // namespace elf
-} // namespace objcopy
-} // namespace llvm
-
-#endif
+//===- ELFConfig.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_OBJCOPY_ELFCONFIG_H
+#define LLVM_TOOLS_OBJCOPY_ELFCONFIG_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Support/Error.h"
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+struct CopyConfig;
+
+namespace elf {
+
+struct NewSymbolInfo {
+ StringRef SymbolName;
+ StringRef SectionName;
+ uint64_t Value = 0;
+ uint8_t Type = ELF::STT_NOTYPE;
+ uint8_t Bind = ELF::STB_GLOBAL;
+ uint8_t Visibility = ELF::STV_DEFAULT;
+};
+
+struct ELFCopyConfig {
+ Optional<uint8_t> NewSymbolVisibility;
+ std::vector<NewSymbolInfo> SymbolsToAdd;
+};
+
+Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config);
+
+} // namespace elf
+} // namespace objcopy
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
index c53a34bc46..6067ed6d26 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
@@ -1,592 +1,592 @@
-//===- ELFObjcopy.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 "ELFObjcopy.h"
-#include "Buffer.h"
-#include "CopyConfig.h"
-#include "Object.h"
-#include "llvm/ADT/BitmaskEnum.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/MC/MCTargetOptions.h"
-#include "llvm/Object/Binary.h"
-#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/Object/ELFTypes.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Compression.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Memory.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cassert>
-#include <cstdlib>
-#include <functional>
-#include <iterator>
-#include <memory>
-#include <string>
-#include <system_error>
-#include <utility>
-
-namespace llvm {
-namespace objcopy {
-namespace elf {
-
-using namespace object;
-using namespace ELF;
-using SectionPred = std::function<bool(const SectionBase &Sec)>;
-
-static bool isDebugSection(const SectionBase &Sec) {
- return StringRef(Sec.Name).startswith(".debug") ||
- StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
-}
-
-static bool isDWOSection(const SectionBase &Sec) {
- return StringRef(Sec.Name).endswith(".dwo");
-}
-
-static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
- // We can't remove the section header string table.
- if (&Sec == Obj.SectionNames)
- return false;
- // Short of keeping the string table we want to keep everything that is a DWO
- // section and remove everything else.
- return !isDWOSection(Sec);
-}
-
-uint64_t getNewShfFlags(SectionFlag AllFlags) {
- uint64_t NewFlags = 0;
- if (AllFlags & SectionFlag::SecAlloc)
- NewFlags |= ELF::SHF_ALLOC;
- if (!(AllFlags & SectionFlag::SecReadonly))
- NewFlags |= ELF::SHF_WRITE;
- if (AllFlags & SectionFlag::SecCode)
- NewFlags |= ELF::SHF_EXECINSTR;
- if (AllFlags & SectionFlag::SecMerge)
- NewFlags |= ELF::SHF_MERGE;
- if (AllFlags & SectionFlag::SecStrings)
- NewFlags |= ELF::SHF_STRINGS;
- if (AllFlags & SectionFlag::SecExclude)
- NewFlags |= ELF::SHF_EXCLUDE;
- return NewFlags;
-}
-
-static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
- uint64_t NewFlags) {
- // Preserve some flags which should not be dropped when setting flags.
- // Also, preserve anything OS/processor dependant.
- const uint64_t PreserveMask =
- (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
- ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS |
- ELF::SHF_INFO_LINK) &
- ~ELF::SHF_EXCLUDE;
- return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
-}
-
-static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) {
- Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags));
-
- // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule
- // may promote more non-ALLOC sections than GNU objcopy, but it is fine as
- // non-ALLOC SHT_NOBITS sections do not make much sense.
- if (Sec.Type == SHT_NOBITS &&
- (!(Sec.Flags & ELF::SHF_ALLOC) ||
- Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))
- Sec.Type = SHT_PROGBITS;
-}
-
-static ElfType getOutputElfType(const Binary &Bin) {
- // Infer output ELF type from the input ELF object
- if (isa<ELFObjectFile<ELF32LE>>(Bin))
- return ELFT_ELF32LE;
- if (isa<ELFObjectFile<ELF64LE>>(Bin))
- return ELFT_ELF64LE;
- if (isa<ELFObjectFile<ELF32BE>>(Bin))
- return ELFT_ELF32BE;
- if (isa<ELFObjectFile<ELF64BE>>(Bin))
- return ELFT_ELF64BE;
- llvm_unreachable("Invalid ELFType");
-}
-
-static ElfType getOutputElfType(const MachineInfo &MI) {
- // Infer output ELF type from the binary arch specified
- if (MI.Is64Bit)
- return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
- else
- return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
-}
-
-static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,
- Object &Obj, Buffer &Buf,
- ElfType OutputElfType) {
- // Depending on the initial ELFT and OutputFormat we need a different Writer.
- switch (OutputElfType) {
- case ELFT_ELF32LE:
- return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections,
- Config.OnlyKeepDebug);
- case ELFT_ELF64LE:
- return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections,
- Config.OnlyKeepDebug);
- case ELFT_ELF32BE:
- return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections,
- Config.OnlyKeepDebug);
- case ELFT_ELF64BE:
- return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections,
- Config.OnlyKeepDebug);
- }
- llvm_unreachable("Invalid output format");
-}
-
-static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
- Object &Obj, Buffer &Buf,
- ElfType OutputElfType) {
- switch (Config.OutputFormat) {
- case FileFormat::Binary:
- return std::make_unique<BinaryWriter>(Obj, Buf);
- case FileFormat::IHex:
- return std::make_unique<IHexWriter>(Obj, Buf);
- default:
- return createELFWriter(Config, Obj, Buf, OutputElfType);
- }
-}
-
-template <class ELFT>
-static Expected<ArrayRef<uint8_t>>
-findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) {
- auto PhdrsOrErr = In.program_headers();
- if (auto Err = PhdrsOrErr.takeError())
- return createFileError(Config.InputFilename, std::move(Err));
-
- for (const auto &Phdr : *PhdrsOrErr) {
- if (Phdr.p_type != PT_NOTE)
- continue;
- Error Err = Error::success();
- for (auto Note : In.notes(Phdr, Err))
- if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU)
- return Note.getDesc();
- if (Err)
- return createFileError(Config.InputFilename, std::move(Err));
- }
-
+//===- ELFObjcopy.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 "ELFObjcopy.h"
+#include "Buffer.h"
+#include "CopyConfig.h"
+#include "Object.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
+namespace llvm {
+namespace objcopy {
+namespace elf {
+
+using namespace object;
+using namespace ELF;
+using SectionPred = std::function<bool(const SectionBase &Sec)>;
+
+static bool isDebugSection(const SectionBase &Sec) {
+ return StringRef(Sec.Name).startswith(".debug") ||
+ StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
+}
+
+static bool isDWOSection(const SectionBase &Sec) {
+ return StringRef(Sec.Name).endswith(".dwo");
+}
+
+static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
+ // We can't remove the section header string table.
+ if (&Sec == Obj.SectionNames)
+ return false;
+ // Short of keeping the string table we want to keep everything that is a DWO
+ // section and remove everything else.
+ return !isDWOSection(Sec);
+}
+
+uint64_t getNewShfFlags(SectionFlag AllFlags) {
+ uint64_t NewFlags = 0;
+ if (AllFlags & SectionFlag::SecAlloc)
+ NewFlags |= ELF::SHF_ALLOC;
+ if (!(AllFlags & SectionFlag::SecReadonly))
+ NewFlags |= ELF::SHF_WRITE;
+ if (AllFlags & SectionFlag::SecCode)
+ NewFlags |= ELF::SHF_EXECINSTR;
+ if (AllFlags & SectionFlag::SecMerge)
+ NewFlags |= ELF::SHF_MERGE;
+ if (AllFlags & SectionFlag::SecStrings)
+ NewFlags |= ELF::SHF_STRINGS;
+ if (AllFlags & SectionFlag::SecExclude)
+ NewFlags |= ELF::SHF_EXCLUDE;
+ return NewFlags;
+}
+
+static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
+ uint64_t NewFlags) {
+ // Preserve some flags which should not be dropped when setting flags.
+ // Also, preserve anything OS/processor dependant.
+ const uint64_t PreserveMask =
+ (ELF::SHF_COMPRESSED | ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
+ ELF::SHF_MASKOS | ELF::SHF_MASKPROC | ELF::SHF_TLS |
+ ELF::SHF_INFO_LINK) &
+ ~ELF::SHF_EXCLUDE;
+ return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
+}
+
+static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) {
+ Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags));
+
+ // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule
+ // may promote more non-ALLOC sections than GNU objcopy, but it is fine as
+ // non-ALLOC SHT_NOBITS sections do not make much sense.
+ if (Sec.Type == SHT_NOBITS &&
+ (!(Sec.Flags & ELF::SHF_ALLOC) ||
+ Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))
+ Sec.Type = SHT_PROGBITS;
+}
+
+static ElfType getOutputElfType(const Binary &Bin) {
+ // Infer output ELF type from the input ELF object
+ if (isa<ELFObjectFile<ELF32LE>>(Bin))
+ return ELFT_ELF32LE;
+ if (isa<ELFObjectFile<ELF64LE>>(Bin))
+ return ELFT_ELF64LE;
+ if (isa<ELFObjectFile<ELF32BE>>(Bin))
+ return ELFT_ELF32BE;
+ if (isa<ELFObjectFile<ELF64BE>>(Bin))
+ return ELFT_ELF64BE;
+ llvm_unreachable("Invalid ELFType");
+}
+
+static ElfType getOutputElfType(const MachineInfo &MI) {
+ // Infer output ELF type from the binary arch specified
+ if (MI.Is64Bit)
+ return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
+ else
+ return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
+}
+
+static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,
+ Object &Obj, Buffer &Buf,
+ ElfType OutputElfType) {
+ // Depending on the initial ELFT and OutputFormat we need a different Writer.
+ switch (OutputElfType) {
+ case ELFT_ELF32LE:
+ return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections,
+ Config.OnlyKeepDebug);
+ case ELFT_ELF64LE:
+ return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections,
+ Config.OnlyKeepDebug);
+ case ELFT_ELF32BE:
+ return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections,
+ Config.OnlyKeepDebug);
+ case ELFT_ELF64BE:
+ return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections,
+ Config.OnlyKeepDebug);
+ }
+ llvm_unreachable("Invalid output format");
+}
+
+static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
+ Object &Obj, Buffer &Buf,
+ ElfType OutputElfType) {
+ switch (Config.OutputFormat) {
+ case FileFormat::Binary:
+ return std::make_unique<BinaryWriter>(Obj, Buf);
+ case FileFormat::IHex:
+ return std::make_unique<IHexWriter>(Obj, Buf);
+ default:
+ return createELFWriter(Config, Obj, Buf, OutputElfType);
+ }
+}
+
+template <class ELFT>
+static Expected<ArrayRef<uint8_t>>
+findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) {
+ auto PhdrsOrErr = In.program_headers();
+ if (auto Err = PhdrsOrErr.takeError())
+ return createFileError(Config.InputFilename, std::move(Err));
+
+ for (const auto &Phdr : *PhdrsOrErr) {
+ if (Phdr.p_type != PT_NOTE)
+ continue;
+ Error Err = Error::success();
+ for (auto Note : In.notes(Phdr, Err))
+ if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU)
+ return Note.getDesc();
+ if (Err)
+ return createFileError(Config.InputFilename, std::move(Err));
+ }
+
return createFileError(Config.InputFilename,
createStringError(llvm::errc::invalid_argument,
"could not find build ID"));
-}
-
-static Expected<ArrayRef<uint8_t>>
-findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) {
- if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In))
+}
+
+static Expected<ArrayRef<uint8_t>>
+findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) {
+ if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In))
return findBuildID(Config, O->getELFFile());
- else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In))
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In))
return findBuildID(Config, O->getELFFile());
- else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In))
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In))
return findBuildID(Config, O->getELFFile());
- else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In))
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In))
return findBuildID(Config, O->getELFFile());
-
- llvm_unreachable("Bad file format");
-}
-
-template <class... Ts>
+
+ llvm_unreachable("Bad file format");
+}
+
+template <class... Ts>
static Error makeStringError(std::error_code EC, const Twine &Msg,
Ts &&... Args) {
- std::string FullMsg = (EC.message() + ": " + Msg).str();
- return createStringError(EC, FullMsg.c_str(), std::forward<Ts>(Args)...);
-}
-
-#define MODEL_8 "%%%%%%%%"
-#define MODEL_16 MODEL_8 MODEL_8
-#define MODEL_32 (MODEL_16 MODEL_16)
-
-static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink,
- StringRef Suffix,
- ArrayRef<uint8_t> BuildIdBytes) {
- SmallString<128> Path = Config.BuildIdLinkDir;
- sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true));
- if (auto EC = sys::fs::create_directories(Path))
- return createFileError(
- Path.str(),
- makeStringError(EC, "cannot create build ID link directory"));
-
- sys::path::append(Path,
- llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true));
- Path += Suffix;
- SmallString<128> TmpPath;
- // create_hard_link races so we need to link to a temporary path but
- // we want to make sure that we choose a filename that does not exist.
- // By using 32 model characters we get 128-bits of entropy. It is
- // unlikely that this string has ever existed before much less exists
- // on this disk or in the current working directory.
- // Additionally we prepend the original Path for debugging but also
- // because it ensures that we're linking within a directory on the same
- // partition on the same device which is critical. It has the added
- // win of yet further decreasing the odds of a conflict.
- sys::fs::createUniquePath(Twine(Path) + "-" + MODEL_32 + ".tmp", TmpPath,
- /*MakeAbsolute*/ false);
- if (auto EC = sys::fs::create_hard_link(ToLink, TmpPath)) {
- Path.push_back('\0');
- return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
- Path.data());
- }
- // We then atomically rename the link into place which will just move the
- // link. If rename fails something is more seriously wrong so just return
- // an error.
- if (auto EC = sys::fs::rename(TmpPath, Path)) {
- Path.push_back('\0');
- return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
- Path.data());
- }
- // If `Path` was already a hard-link to the same underlying file then the
- // temp file will be left so we need to remove it. Remove will not cause
- // an error by default if the file is already gone so just blindly remove
- // it rather than checking.
- if (auto EC = sys::fs::remove(TmpPath)) {
- TmpPath.push_back('\0');
- return makeStringError(EC, "could not remove '%s'", TmpPath.data());
- }
- return Error::success();
-}
-
-static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
- StringRef File, ElfType OutputElfType) {
+ std::string FullMsg = (EC.message() + ": " + Msg).str();
+ return createStringError(EC, FullMsg.c_str(), std::forward<Ts>(Args)...);
+}
+
+#define MODEL_8 "%%%%%%%%"
+#define MODEL_16 MODEL_8 MODEL_8
+#define MODEL_32 (MODEL_16 MODEL_16)
+
+static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink,
+ StringRef Suffix,
+ ArrayRef<uint8_t> BuildIdBytes) {
+ SmallString<128> Path = Config.BuildIdLinkDir;
+ sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true));
+ if (auto EC = sys::fs::create_directories(Path))
+ return createFileError(
+ Path.str(),
+ makeStringError(EC, "cannot create build ID link directory"));
+
+ sys::path::append(Path,
+ llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true));
+ Path += Suffix;
+ SmallString<128> TmpPath;
+ // create_hard_link races so we need to link to a temporary path but
+ // we want to make sure that we choose a filename that does not exist.
+ // By using 32 model characters we get 128-bits of entropy. It is
+ // unlikely that this string has ever existed before much less exists
+ // on this disk or in the current working directory.
+ // Additionally we prepend the original Path for debugging but also
+ // because it ensures that we're linking within a directory on the same
+ // partition on the same device which is critical. It has the added
+ // win of yet further decreasing the odds of a conflict.
+ sys::fs::createUniquePath(Twine(Path) + "-" + MODEL_32 + ".tmp", TmpPath,
+ /*MakeAbsolute*/ false);
+ if (auto EC = sys::fs::create_hard_link(ToLink, TmpPath)) {
+ Path.push_back('\0');
+ return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
+ Path.data());
+ }
+ // We then atomically rename the link into place which will just move the
+ // link. If rename fails something is more seriously wrong so just return
+ // an error.
+ if (auto EC = sys::fs::rename(TmpPath, Path)) {
+ Path.push_back('\0');
+ return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
+ Path.data());
+ }
+ // If `Path` was already a hard-link to the same underlying file then the
+ // temp file will be left so we need to remove it. Remove will not cause
+ // an error by default if the file is already gone so just blindly remove
+ // it rather than checking.
+ if (auto EC = sys::fs::remove(TmpPath)) {
+ TmpPath.push_back('\0');
+ return makeStringError(EC, "could not remove '%s'", TmpPath.data());
+ }
+ return Error::success();
+}
+
+static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
+ StringRef File, ElfType OutputElfType) {
Expected<std::unique_ptr<Object>> DWOFile = Reader.create(false);
if (!DWOFile)
return DWOFile.takeError();
- auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) {
+ auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) {
return onlyKeepDWOPred(**DWOFile, Sec);
- };
+ };
if (Error E =
(*DWOFile)->removeSections(Config.AllowBrokenLinks, OnlyKeepDWOPred))
- return E;
- if (Config.OutputArch) {
+ return E;
+ if (Config.OutputArch) {
(*DWOFile)->Machine = Config.OutputArch.getValue().EMachine;
(*DWOFile)->OSABI = Config.OutputArch.getValue().OSABI;
- }
- FileBuffer FB(File);
+ }
+ FileBuffer FB(File);
std::unique_ptr<Writer> Writer =
createWriter(Config, **DWOFile, FB, OutputElfType);
- if (Error E = Writer->finalize())
- return E;
- return Writer->write();
-}
-
-static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
- Object &Obj) {
- for (auto &Sec : Obj.sections()) {
- if (Sec.Name == SecName) {
- if (Sec.Type == SHT_NOBITS)
- return createStringError(object_error::parse_failed,
- "cannot dump section '%s': it has no contents",
- SecName.str().c_str());
- Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
- FileOutputBuffer::create(Filename, Sec.OriginalData.size());
- if (!BufferOrErr)
- return BufferOrErr.takeError();
- std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
- std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
- Buf->getBufferStart());
- if (Error E = Buf->commit())
- return E;
- return Error::success();
- }
- }
- return createStringError(object_error::parse_failed, "section '%s' not found",
- SecName.str().c_str());
-}
-
-static bool isCompressable(const SectionBase &Sec) {
- return !(Sec.Flags & ELF::SHF_COMPRESSED) &&
- StringRef(Sec.Name).startswith(".debug");
-}
-
+ if (Error E = Writer->finalize())
+ return E;
+ return Writer->write();
+}
+
+static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
+ Object &Obj) {
+ for (auto &Sec : Obj.sections()) {
+ if (Sec.Name == SecName) {
+ if (Sec.Type == SHT_NOBITS)
+ return createStringError(object_error::parse_failed,
+ "cannot dump section '%s': it has no contents",
+ SecName.str().c_str());
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(Filename, Sec.OriginalData.size());
+ if (!BufferOrErr)
+ return BufferOrErr.takeError();
+ std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
+ std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
+ Buf->getBufferStart());
+ if (Error E = Buf->commit())
+ return E;
+ return Error::success();
+ }
+ }
+ return createStringError(object_error::parse_failed, "section '%s' not found",
+ SecName.str().c_str());
+}
+
+static bool isCompressable(const SectionBase &Sec) {
+ return !(Sec.Flags & ELF::SHF_COMPRESSED) &&
+ StringRef(Sec.Name).startswith(".debug");
+}
+
static Error replaceDebugSections(
- Object &Obj, SectionPred &RemovePred,
+ Object &Obj, SectionPred &RemovePred,
function_ref<bool(const SectionBase &)> ShouldReplace,
function_ref<Expected<SectionBase *>(const SectionBase *)> AddSection) {
- // Build a list of the debug sections we are going to replace.
+ // Build a list of the debug sections we are going to replace.
// We can't call `AddSection` while iterating over sections,
- // because it would mutate the sections array.
- SmallVector<SectionBase *, 13> ToReplace;
- for (auto &Sec : Obj.sections())
+ // because it would mutate the sections array.
+ SmallVector<SectionBase *, 13> ToReplace;
+ for (auto &Sec : Obj.sections())
if (ShouldReplace(Sec))
- ToReplace.push_back(&Sec);
-
- // Build a mapping from original section to a new one.
- DenseMap<SectionBase *, SectionBase *> FromTo;
+ ToReplace.push_back(&Sec);
+
+ // Build a mapping from original section to a new one.
+ DenseMap<SectionBase *, SectionBase *> FromTo;
for (SectionBase *S : ToReplace) {
Expected<SectionBase *> NewSection = AddSection(S);
if (!NewSection)
return NewSection.takeError();
-
+
FromTo[S] = *NewSection;
}
- // Now we want to update the target sections of relocation
- // sections. Also we will update the relocations themselves
- // to update the symbol references.
- for (auto &Sec : Obj.sections())
- Sec.replaceSectionReferences(FromTo);
-
+ // Now we want to update the target sections of relocation
+ // sections. Also we will update the relocations themselves
+ // to update the symbol references.
+ for (auto &Sec : Obj.sections())
+ Sec.replaceSectionReferences(FromTo);
+
RemovePred = [ShouldReplace, RemovePred](const SectionBase &Sec) {
return ShouldReplace(Sec) || RemovePred(Sec);
- };
+ };
return Error::success();
-}
-
-static bool isUnneededSymbol(const Symbol &Sym) {
- return !Sym.Referenced &&
- (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
- Sym.Type != STT_SECTION;
-}
-
-static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
- // TODO: update or remove symbols only if there is an option that affects
- // them.
- if (!Obj.SymbolTable)
- return Error::success();
-
- Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
- // Common and undefined symbols don't make sense as local symbols, and can
- // even cause crashes if we localize those, so skip them.
- if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&
- ((Config.LocalizeHidden &&
- (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
- Config.SymbolsToLocalize.matches(Sym.Name)))
- Sym.Binding = STB_LOCAL;
-
- // Note: these two globalize flags have very similar names but different
- // meanings:
- //
- // --globalize-symbol: promote a symbol to global
- // --keep-global-symbol: all symbols except for these should be made local
- //
- // If --globalize-symbol is specified for a given symbol, it will be
- // global in the output file even if it is not included via
- // --keep-global-symbol. Because of that, make sure to check
- // --globalize-symbol second.
- if (!Config.SymbolsToKeepGlobal.empty() &&
- !Config.SymbolsToKeepGlobal.matches(Sym.Name) &&
- Sym.getShndx() != SHN_UNDEF)
- Sym.Binding = STB_LOCAL;
-
- if (Config.SymbolsToGlobalize.matches(Sym.Name) &&
- Sym.getShndx() != SHN_UNDEF)
- Sym.Binding = STB_GLOBAL;
-
- if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding == STB_GLOBAL)
- Sym.Binding = STB_WEAK;
-
- if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
- Sym.getShndx() != SHN_UNDEF)
- Sym.Binding = STB_WEAK;
-
- const auto I = Config.SymbolsToRename.find(Sym.Name);
- if (I != Config.SymbolsToRename.end())
- Sym.Name = std::string(I->getValue());
-
- if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
- Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
- });
-
- // The purpose of this loop is to mark symbols referenced by sections
- // (like GroupSection or RelocationSection). This way, we know which
- // symbols are still 'needed' and which are not.
- if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() ||
- !Config.OnlySection.empty()) {
- for (SectionBase &Sec : Obj.sections())
- Sec.markSymbols();
- }
-
- auto RemoveSymbolsPred = [&](const Symbol &Sym) {
- if (Config.SymbolsToKeep.matches(Sym.Name) ||
- (Config.KeepFileSymbols && Sym.Type == STT_FILE))
- return false;
-
- if ((Config.DiscardMode == DiscardType::All ||
- (Config.DiscardMode == DiscardType::Locals &&
- StringRef(Sym.Name).startswith(".L"))) &&
- Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF &&
- Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
- return true;
-
- if (Config.StripAll || Config.StripAllGNU)
- return true;
-
- if (Config.StripDebug && Sym.Type == STT_FILE)
- return true;
-
- if (Config.SymbolsToRemove.matches(Sym.Name))
- return true;
-
- if ((Config.StripUnneeded ||
- Config.UnneededSymbolsToRemove.matches(Sym.Name)) &&
- (!Obj.isRelocatable() || isUnneededSymbol(Sym)))
- return true;
-
- // We want to remove undefined symbols if all references have been stripped.
- if (!Config.OnlySection.empty() && !Sym.Referenced &&
- Sym.getShndx() == SHN_UNDEF)
- return true;
-
- return false;
- };
-
- return Obj.removeSymbols(RemoveSymbolsPred);
-}
-
-static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {
- SectionPred RemovePred = [](const SectionBase &) { return false; };
-
- // Removes:
- if (!Config.ToRemove.empty()) {
- RemovePred = [&Config](const SectionBase &Sec) {
- return Config.ToRemove.matches(Sec.Name);
- };
- }
-
- if (Config.StripDWO || !Config.SplitDWO.empty())
- RemovePred = [RemovePred](const SectionBase &Sec) {
- return isDWOSection(Sec) || RemovePred(Sec);
- };
-
- if (Config.ExtractDWO)
- RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
- return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
- };
-
- if (Config.StripAllGNU)
- RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
- if (RemovePred(Sec))
- return true;
- if ((Sec.Flags & SHF_ALLOC) != 0)
- return false;
- if (&Sec == Obj.SectionNames)
- return false;
- switch (Sec.Type) {
- case SHT_SYMTAB:
- case SHT_REL:
- case SHT_RELA:
- case SHT_STRTAB:
- return true;
- }
- return isDebugSection(Sec);
- };
-
- if (Config.StripSections) {
- RemovePred = [RemovePred](const SectionBase &Sec) {
- return RemovePred(Sec) || Sec.ParentSegment == nullptr;
- };
- }
-
- if (Config.StripDebug || Config.StripUnneeded) {
- RemovePred = [RemovePred](const SectionBase &Sec) {
- return RemovePred(Sec) || isDebugSection(Sec);
- };
- }
-
- if (Config.StripNonAlloc)
- RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
- if (RemovePred(Sec))
- return true;
- if (&Sec == Obj.SectionNames)
- return false;
- return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr;
- };
-
- if (Config.StripAll)
- RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
- if (RemovePred(Sec))
- return true;
- if (&Sec == Obj.SectionNames)
- return false;
- if (StringRef(Sec.Name).startswith(".gnu.warning"))
- return false;
- // We keep the .ARM.attribute section to maintain compatibility
- // with Debian derived distributions. This is a bug in their
- // patchset as documented here:
- // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798
- if (Sec.Type == SHT_ARM_ATTRIBUTES)
- return false;
- if (Sec.ParentSegment != nullptr)
- return false;
- return (Sec.Flags & SHF_ALLOC) == 0;
- };
-
- if (Config.ExtractPartition || Config.ExtractMainPartition) {
- RemovePred = [RemovePred](const SectionBase &Sec) {
- if (RemovePred(Sec))
- return true;
- if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR)
- return true;
- return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment;
- };
- }
-
- // Explicit copies:
- if (!Config.OnlySection.empty()) {
- RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
- // Explicitly keep these sections regardless of previous removes.
- if (Config.OnlySection.matches(Sec.Name))
- return false;
-
- // Allow all implicit removes.
- if (RemovePred(Sec))
- return true;
-
- // Keep special sections.
- if (Obj.SectionNames == &Sec)
- return false;
- if (Obj.SymbolTable == &Sec ||
- (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
- return false;
-
- // Remove everything else.
- return true;
- };
- }
-
- if (!Config.KeepSection.empty()) {
- RemovePred = [&Config, RemovePred](const SectionBase &Sec) {
- // Explicitly keep these sections regardless of previous removes.
- if (Config.KeepSection.matches(Sec.Name))
- return false;
- // Otherwise defer to RemovePred.
- return RemovePred(Sec);
- };
- }
-
- // This has to be the last predicate assignment.
- // If the option --keep-symbol has been specified
- // and at least one of those symbols is present
- // (equivalently, the updated symbol table is not empty)
- // the symbol table and the string table should not be removed.
- if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
- Obj.SymbolTable && !Obj.SymbolTable->empty()) {
- RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
- if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
- return false;
- return RemovePred(Sec);
- };
- }
-
+}
+
+static bool isUnneededSymbol(const Symbol &Sym) {
+ return !Sym.Referenced &&
+ (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
+ Sym.Type != STT_SECTION;
+}
+
+static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
+ // TODO: update or remove symbols only if there is an option that affects
+ // them.
+ if (!Obj.SymbolTable)
+ return Error::success();
+
+ Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
+ // Common and undefined symbols don't make sense as local symbols, and can
+ // even cause crashes if we localize those, so skip them.
+ if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&
+ ((Config.LocalizeHidden &&
+ (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
+ Config.SymbolsToLocalize.matches(Sym.Name)))
+ Sym.Binding = STB_LOCAL;
+
+ // Note: these two globalize flags have very similar names but different
+ // meanings:
+ //
+ // --globalize-symbol: promote a symbol to global
+ // --keep-global-symbol: all symbols except for these should be made local
+ //
+ // If --globalize-symbol is specified for a given symbol, it will be
+ // global in the output file even if it is not included via
+ // --keep-global-symbol. Because of that, make sure to check
+ // --globalize-symbol second.
+ if (!Config.SymbolsToKeepGlobal.empty() &&
+ !Config.SymbolsToKeepGlobal.matches(Sym.Name) &&
+ Sym.getShndx() != SHN_UNDEF)
+ Sym.Binding = STB_LOCAL;
+
+ if (Config.SymbolsToGlobalize.matches(Sym.Name) &&
+ Sym.getShndx() != SHN_UNDEF)
+ Sym.Binding = STB_GLOBAL;
+
+ if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding == STB_GLOBAL)
+ Sym.Binding = STB_WEAK;
+
+ if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
+ Sym.getShndx() != SHN_UNDEF)
+ Sym.Binding = STB_WEAK;
+
+ const auto I = Config.SymbolsToRename.find(Sym.Name);
+ if (I != Config.SymbolsToRename.end())
+ Sym.Name = std::string(I->getValue());
+
+ if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
+ Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
+ });
+
+ // The purpose of this loop is to mark symbols referenced by sections
+ // (like GroupSection or RelocationSection). This way, we know which
+ // symbols are still 'needed' and which are not.
+ if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() ||
+ !Config.OnlySection.empty()) {
+ for (SectionBase &Sec : Obj.sections())
+ Sec.markSymbols();
+ }
+
+ auto RemoveSymbolsPred = [&](const Symbol &Sym) {
+ if (Config.SymbolsToKeep.matches(Sym.Name) ||
+ (Config.KeepFileSymbols && Sym.Type == STT_FILE))
+ return false;
+
+ if ((Config.DiscardMode == DiscardType::All ||
+ (Config.DiscardMode == DiscardType::Locals &&
+ StringRef(Sym.Name).startswith(".L"))) &&
+ Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF &&
+ Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
+ return true;
+
+ if (Config.StripAll || Config.StripAllGNU)
+ return true;
+
+ if (Config.StripDebug && Sym.Type == STT_FILE)
+ return true;
+
+ if (Config.SymbolsToRemove.matches(Sym.Name))
+ return true;
+
+ if ((Config.StripUnneeded ||
+ Config.UnneededSymbolsToRemove.matches(Sym.Name)) &&
+ (!Obj.isRelocatable() || isUnneededSymbol(Sym)))
+ return true;
+
+ // We want to remove undefined symbols if all references have been stripped.
+ if (!Config.OnlySection.empty() && !Sym.Referenced &&
+ Sym.getShndx() == SHN_UNDEF)
+ return true;
+
+ return false;
+ };
+
+ return Obj.removeSymbols(RemoveSymbolsPred);
+}
+
+static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {
+ SectionPred RemovePred = [](const SectionBase &) { return false; };
+
+ // Removes:
+ if (!Config.ToRemove.empty()) {
+ RemovePred = [&Config](const SectionBase &Sec) {
+ return Config.ToRemove.matches(Sec.Name);
+ };
+ }
+
+ if (Config.StripDWO || !Config.SplitDWO.empty())
+ RemovePred = [RemovePred](const SectionBase &Sec) {
+ return isDWOSection(Sec) || RemovePred(Sec);
+ };
+
+ if (Config.ExtractDWO)
+ RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
+ return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
+ };
+
+ if (Config.StripAllGNU)
+ RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
+ if (RemovePred(Sec))
+ return true;
+ if ((Sec.Flags & SHF_ALLOC) != 0)
+ return false;
+ if (&Sec == Obj.SectionNames)
+ return false;
+ switch (Sec.Type) {
+ case SHT_SYMTAB:
+ case SHT_REL:
+ case SHT_RELA:
+ case SHT_STRTAB:
+ return true;
+ }
+ return isDebugSection(Sec);
+ };
+
+ if (Config.StripSections) {
+ RemovePred = [RemovePred](const SectionBase &Sec) {
+ return RemovePred(Sec) || Sec.ParentSegment == nullptr;
+ };
+ }
+
+ if (Config.StripDebug || Config.StripUnneeded) {
+ RemovePred = [RemovePred](const SectionBase &Sec) {
+ return RemovePred(Sec) || isDebugSection(Sec);
+ };
+ }
+
+ if (Config.StripNonAlloc)
+ RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
+ if (RemovePred(Sec))
+ return true;
+ if (&Sec == Obj.SectionNames)
+ return false;
+ return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr;
+ };
+
+ if (Config.StripAll)
+ RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
+ if (RemovePred(Sec))
+ return true;
+ if (&Sec == Obj.SectionNames)
+ return false;
+ if (StringRef(Sec.Name).startswith(".gnu.warning"))
+ return false;
+ // We keep the .ARM.attribute section to maintain compatibility
+ // with Debian derived distributions. This is a bug in their
+ // patchset as documented here:
+ // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798
+ if (Sec.Type == SHT_ARM_ATTRIBUTES)
+ return false;
+ if (Sec.ParentSegment != nullptr)
+ return false;
+ return (Sec.Flags & SHF_ALLOC) == 0;
+ };
+
+ if (Config.ExtractPartition || Config.ExtractMainPartition) {
+ RemovePred = [RemovePred](const SectionBase &Sec) {
+ if (RemovePred(Sec))
+ return true;
+ if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR)
+ return true;
+ return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment;
+ };
+ }
+
+ // Explicit copies:
+ if (!Config.OnlySection.empty()) {
+ RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
+ // Explicitly keep these sections regardless of previous removes.
+ if (Config.OnlySection.matches(Sec.Name))
+ return false;
+
+ // Allow all implicit removes.
+ if (RemovePred(Sec))
+ return true;
+
+ // Keep special sections.
+ if (Obj.SectionNames == &Sec)
+ return false;
+ if (Obj.SymbolTable == &Sec ||
+ (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
+ return false;
+
+ // Remove everything else.
+ return true;
+ };
+ }
+
+ if (!Config.KeepSection.empty()) {
+ RemovePred = [&Config, RemovePred](const SectionBase &Sec) {
+ // Explicitly keep these sections regardless of previous removes.
+ if (Config.KeepSection.matches(Sec.Name))
+ return false;
+ // Otherwise defer to RemovePred.
+ return RemovePred(Sec);
+ };
+ }
+
+ // This has to be the last predicate assignment.
+ // If the option --keep-symbol has been specified
+ // and at least one of those symbols is present
+ // (equivalently, the updated symbol table is not empty)
+ // the symbol table and the string table should not be removed.
+ if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
+ Obj.SymbolTable && !Obj.SymbolTable->empty()) {
+ RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
+ if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
+ return false;
+ return RemovePred(Sec);
+ };
+ }
+
if (Config.CompressionType != DebugCompressionType::None) {
if (Error Err = replaceDebugSections(
Obj, RemovePred, isCompressable,
@@ -595,7 +595,7 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {
CompressedSection::create(*S, Config.CompressionType);
if (!NewSection)
return NewSection.takeError();
-
+
return &Obj.addSection<CompressedSection>(std::move(*NewSection));
}))
return Err;
@@ -610,156 +610,156 @@ static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {
return Err;
}
- return Obj.removeSections(Config.AllowBrokenLinks, RemovePred);
-}
-
-// This function handles the high level operations of GNU objcopy including
-// handling command line options. It's important to outline certain properties
-// we expect to hold of the command line operations. Any operation that "keeps"
-// should keep regardless of a remove. Additionally any removal should respect
-// any previous removals. Lastly whether or not something is removed shouldn't
-// depend a) on the order the options occur in or b) on some opaque priority
-// system. The only priority is that keeps/copies overrule removes.
-static Error handleArgs(const CopyConfig &Config, Object &Obj,
- const Reader &Reader, ElfType OutputElfType) {
- if (Config.StripSwiftSymbols)
- return createStringError(llvm::errc::invalid_argument,
- "option not supported by llvm-objcopy for ELF");
- if (!Config.SplitDWO.empty())
- if (Error E =
- splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType))
- return E;
-
- if (Config.OutputArch) {
- Obj.Machine = Config.OutputArch.getValue().EMachine;
- Obj.OSABI = Config.OutputArch.getValue().OSABI;
- }
-
- // Dump sections before add/remove for compatibility with GNU objcopy.
- for (StringRef Flag : Config.DumpSection) {
- StringRef SectionName;
- StringRef FileName;
- std::tie(SectionName, FileName) = Flag.split('=');
- if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
- return E;
- }
-
- // It is important to remove the sections first. For example, we want to
- // remove the relocation sections before removing the symbols. That allows
- // us to avoid reporting the inappropriate errors about removing symbols
- // named in relocations.
- if (Error E = replaceAndRemoveSections(Config, Obj))
- return E;
-
- if (Error E = updateAndRemoveSymbols(Config, Obj))
- return E;
-
- if (!Config.SectionsToRename.empty()) {
- for (SectionBase &Sec : Obj.sections()) {
- const auto Iter = Config.SectionsToRename.find(Sec.Name);
- if (Iter != Config.SectionsToRename.end()) {
- const SectionRename &SR = Iter->second;
- Sec.Name = std::string(SR.NewName);
- if (SR.NewFlags.hasValue())
- setSectionFlagsAndType(Sec, SR.NewFlags.getValue());
- }
- }
- }
-
- // Add a prefix to allocated sections and their relocation sections. This
- // should be done after renaming the section by Config.SectionToRename to
- // imitate the GNU objcopy behavior.
- if (!Config.AllocSectionsPrefix.empty()) {
- DenseSet<SectionBase *> PrefixedSections;
- for (SectionBase &Sec : Obj.sections()) {
- if (Sec.Flags & SHF_ALLOC) {
- Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str();
- PrefixedSections.insert(&Sec);
- } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) {
- // Rename relocation sections associated to the allocated sections.
- // For example, if we rename .text to .prefix.text, we also rename
- // .rel.text to .rel.prefix.text.
- //
- // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled
- // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not
- // .rela.prefix.plt since GNU objcopy does so.
- const SectionBase *TargetSec = RelocSec->getSection();
- if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) {
- StringRef prefix;
- switch (Sec.Type) {
- case SHT_REL:
- prefix = ".rel";
- break;
- case SHT_RELA:
- prefix = ".rela";
- break;
- default:
- llvm_unreachable("not a relocation section");
- }
-
- // If the relocation section comes *after* the target section, we
- // don't add Config.AllocSectionsPrefix because we've already added
- // the prefix to TargetSec->Name. Otherwise, if the relocation
- // section comes *before* the target section, we add the prefix.
- if (PrefixedSections.count(TargetSec))
- Sec.Name = (prefix + TargetSec->Name).str();
- else
- Sec.Name =
- (prefix + Config.AllocSectionsPrefix + TargetSec->Name).str();
- }
- }
- }
- }
-
- if (!Config.SetSectionAlignment.empty()) {
- for (SectionBase &Sec : Obj.sections()) {
- auto I = Config.SetSectionAlignment.find(Sec.Name);
- if (I != Config.SetSectionAlignment.end())
- Sec.Align = I->second;
- }
- }
-
- if (Config.OnlyKeepDebug)
- for (auto &Sec : Obj.sections())
- if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
- Sec.Type = SHT_NOBITS;
-
- for (const auto &Flag : Config.AddSection) {
- std::pair<StringRef, StringRef> SecPair = Flag.split("=");
- StringRef SecName = SecPair.first;
- StringRef File = SecPair.second;
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFile(File);
- if (!BufOrErr)
- return createFileError(File, errorCodeToError(BufOrErr.getError()));
- std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
- ArrayRef<uint8_t> Data(
- reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
- Buf->getBufferSize());
- OwnedDataSection &NewSection =
- Obj.addSection<OwnedDataSection>(SecName, Data);
- if (SecName.startswith(".note") && SecName != ".note.GNU-stack")
- NewSection.Type = SHT_NOTE;
- }
-
- if (!Config.AddGnuDebugLink.empty())
- Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,
- Config.GnuDebugLinkCRC32);
-
- // If the symbol table was previously removed, we need to create a new one
- // before adding new symbols.
+ return Obj.removeSections(Config.AllowBrokenLinks, RemovePred);
+}
+
+// This function handles the high level operations of GNU objcopy including
+// handling command line options. It's important to outline certain properties
+// we expect to hold of the command line operations. Any operation that "keeps"
+// should keep regardless of a remove. Additionally any removal should respect
+// any previous removals. Lastly whether or not something is removed shouldn't
+// depend a) on the order the options occur in or b) on some opaque priority
+// system. The only priority is that keeps/copies overrule removes.
+static Error handleArgs(const CopyConfig &Config, Object &Obj,
+ const Reader &Reader, ElfType OutputElfType) {
+ if (Config.StripSwiftSymbols)
+ return createStringError(llvm::errc::invalid_argument,
+ "option not supported by llvm-objcopy for ELF");
+ if (!Config.SplitDWO.empty())
+ if (Error E =
+ splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType))
+ return E;
+
+ if (Config.OutputArch) {
+ Obj.Machine = Config.OutputArch.getValue().EMachine;
+ Obj.OSABI = Config.OutputArch.getValue().OSABI;
+ }
+
+ // Dump sections before add/remove for compatibility with GNU objcopy.
+ for (StringRef Flag : Config.DumpSection) {
+ StringRef SectionName;
+ StringRef FileName;
+ std::tie(SectionName, FileName) = Flag.split('=');
+ if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
+ return E;
+ }
+
+ // It is important to remove the sections first. For example, we want to
+ // remove the relocation sections before removing the symbols. That allows
+ // us to avoid reporting the inappropriate errors about removing symbols
+ // named in relocations.
+ if (Error E = replaceAndRemoveSections(Config, Obj))
+ return E;
+
+ if (Error E = updateAndRemoveSymbols(Config, Obj))
+ return E;
+
+ if (!Config.SectionsToRename.empty()) {
+ for (SectionBase &Sec : Obj.sections()) {
+ const auto Iter = Config.SectionsToRename.find(Sec.Name);
+ if (Iter != Config.SectionsToRename.end()) {
+ const SectionRename &SR = Iter->second;
+ Sec.Name = std::string(SR.NewName);
+ if (SR.NewFlags.hasValue())
+ setSectionFlagsAndType(Sec, SR.NewFlags.getValue());
+ }
+ }
+ }
+
+ // Add a prefix to allocated sections and their relocation sections. This
+ // should be done after renaming the section by Config.SectionToRename to
+ // imitate the GNU objcopy behavior.
+ if (!Config.AllocSectionsPrefix.empty()) {
+ DenseSet<SectionBase *> PrefixedSections;
+ for (SectionBase &Sec : Obj.sections()) {
+ if (Sec.Flags & SHF_ALLOC) {
+ Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str();
+ PrefixedSections.insert(&Sec);
+ } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) {
+ // Rename relocation sections associated to the allocated sections.
+ // For example, if we rename .text to .prefix.text, we also rename
+ // .rel.text to .rel.prefix.text.
+ //
+ // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled
+ // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not
+ // .rela.prefix.plt since GNU objcopy does so.
+ const SectionBase *TargetSec = RelocSec->getSection();
+ if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) {
+ StringRef prefix;
+ switch (Sec.Type) {
+ case SHT_REL:
+ prefix = ".rel";
+ break;
+ case SHT_RELA:
+ prefix = ".rela";
+ break;
+ default:
+ llvm_unreachable("not a relocation section");
+ }
+
+ // If the relocation section comes *after* the target section, we
+ // don't add Config.AllocSectionsPrefix because we've already added
+ // the prefix to TargetSec->Name. Otherwise, if the relocation
+ // section comes *before* the target section, we add the prefix.
+ if (PrefixedSections.count(TargetSec))
+ Sec.Name = (prefix + TargetSec->Name).str();
+ else
+ Sec.Name =
+ (prefix + Config.AllocSectionsPrefix + TargetSec->Name).str();
+ }
+ }
+ }
+ }
+
+ if (!Config.SetSectionAlignment.empty()) {
+ for (SectionBase &Sec : Obj.sections()) {
+ auto I = Config.SetSectionAlignment.find(Sec.Name);
+ if (I != Config.SetSectionAlignment.end())
+ Sec.Align = I->second;
+ }
+ }
+
+ if (Config.OnlyKeepDebug)
+ for (auto &Sec : Obj.sections())
+ if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
+ Sec.Type = SHT_NOBITS;
+
+ for (const auto &Flag : Config.AddSection) {
+ std::pair<StringRef, StringRef> SecPair = Flag.split("=");
+ StringRef SecName = SecPair.first;
+ StringRef File = SecPair.second;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFile(File);
+ if (!BufOrErr)
+ return createFileError(File, errorCodeToError(BufOrErr.getError()));
+ std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
+ ArrayRef<uint8_t> Data(
+ reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
+ Buf->getBufferSize());
+ OwnedDataSection &NewSection =
+ Obj.addSection<OwnedDataSection>(SecName, Data);
+ if (SecName.startswith(".note") && SecName != ".note.GNU-stack")
+ NewSection.Type = SHT_NOTE;
+ }
+
+ if (!Config.AddGnuDebugLink.empty())
+ Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,
+ Config.GnuDebugLinkCRC32);
+
+ // If the symbol table was previously removed, we need to create a new one
+ // before adding new symbols.
if (!Obj.SymbolTable && !Config.ELF->SymbolsToAdd.empty())
if (Error E = Obj.addNewSymbolTable())
return E;
-
- for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) {
- SectionBase *Sec = Obj.findSection(SI.SectionName);
- uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value;
- Obj.SymbolTable->addSymbol(
- SI.SymbolName, SI.Bind, SI.Type, Sec, Value, SI.Visibility,
- Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
- }
-
+
+ for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) {
+ SectionBase *Sec = Obj.findSection(SI.SectionName);
+ uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value;
+ Obj.SymbolTable->addSymbol(
+ SI.SymbolName, SI.Bind, SI.Type, Sec, Value, SI.Visibility,
+ Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
+ }
+
// --set-section-flags works with sections added by --add-section.
if (!Config.SetSectionFlags.empty()) {
for (auto &Sec : Obj.sections()) {
@@ -771,98 +771,98 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj,
}
}
- if (Config.EntryExpr)
- Obj.Entry = Config.EntryExpr(Obj.Entry);
- return Error::success();
-}
-
-static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,
- ElfType OutputElfType) {
- std::unique_ptr<Writer> Writer =
- createWriter(Config, Obj, Out, OutputElfType);
- if (Error E = Writer->finalize())
- return E;
- return Writer->write();
-}
-
-Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
- Buffer &Out) {
- IHexReader Reader(&In);
+ if (Config.EntryExpr)
+ Obj.Entry = Config.EntryExpr(Obj.Entry);
+ return Error::success();
+}
+
+static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,
+ ElfType OutputElfType) {
+ std::unique_ptr<Writer> Writer =
+ createWriter(Config, Obj, Out, OutputElfType);
+ if (Error E = Writer->finalize())
+ return E;
+ return Writer->write();
+}
+
+Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out) {
+ IHexReader Reader(&In);
Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
if (!Obj)
return Obj.takeError();
- const ElfType OutputElfType =
+ const ElfType OutputElfType =
getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));
if (Error E = handleArgs(Config, **Obj, Reader, OutputElfType))
- return E;
+ return E;
return writeOutput(Config, **Obj, Out, OutputElfType);
-}
-
-Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
- Buffer &Out) {
- uint8_t NewSymbolVisibility =
- Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT);
- BinaryReader Reader(&In, NewSymbolVisibility);
+}
+
+Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out) {
+ uint8_t NewSymbolVisibility =
+ Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT);
+ BinaryReader Reader(&In, NewSymbolVisibility);
Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
if (!Obj)
return Obj.takeError();
-
- // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
- // (-B<arch>).
- const ElfType OutputElfType =
- getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));
+
+ // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
+ // (-B<arch>).
+ const ElfType OutputElfType =
+ getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));
if (Error E = handleArgs(Config, **Obj, Reader, OutputElfType))
- return E;
+ return E;
return writeOutput(Config, **Obj, Out, OutputElfType);
-}
-
-Error executeObjcopyOnBinary(const CopyConfig &Config,
- object::ELFObjectFileBase &In, Buffer &Out) {
- ELFReader Reader(&In, Config.ExtractPartition);
+}
+
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::ELFObjectFileBase &In, Buffer &Out) {
+ ELFReader Reader(&In, Config.ExtractPartition);
Expected<std::unique_ptr<Object>> Obj =
Reader.create(!Config.SymbolsToAdd.empty());
if (!Obj)
return Obj.takeError();
- // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
- const ElfType OutputElfType =
- Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue())
- : getOutputElfType(In);
- ArrayRef<uint8_t> BuildIdBytes;
-
- if (!Config.BuildIdLinkDir.empty()) {
- auto BuildIdBytesOrErr = findBuildID(Config, In);
- if (auto E = BuildIdBytesOrErr.takeError())
- return E;
- BuildIdBytes = *BuildIdBytesOrErr;
-
- if (BuildIdBytes.size() < 2)
- return createFileError(
- Config.InputFilename,
- createStringError(object_error::parse_failed,
- "build ID is smaller than two bytes"));
- }
-
- if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput)
- if (Error E =
- linkToBuildIdDir(Config, Config.InputFilename,
- Config.BuildIdLinkInput.getValue(), BuildIdBytes))
- return E;
-
+ // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
+ const ElfType OutputElfType =
+ Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue())
+ : getOutputElfType(In);
+ ArrayRef<uint8_t> BuildIdBytes;
+
+ if (!Config.BuildIdLinkDir.empty()) {
+ auto BuildIdBytesOrErr = findBuildID(Config, In);
+ if (auto E = BuildIdBytesOrErr.takeError())
+ return E;
+ BuildIdBytes = *BuildIdBytesOrErr;
+
+ if (BuildIdBytes.size() < 2)
+ return createFileError(
+ Config.InputFilename,
+ createStringError(object_error::parse_failed,
+ "build ID is smaller than two bytes"));
+ }
+
+ if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput)
+ if (Error E =
+ linkToBuildIdDir(Config, Config.InputFilename,
+ Config.BuildIdLinkInput.getValue(), BuildIdBytes))
+ return E;
+
if (Error E = handleArgs(Config, **Obj, Reader, OutputElfType))
- return createFileError(Config.InputFilename, std::move(E));
-
+ return createFileError(Config.InputFilename, std::move(E));
+
if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))
- return createFileError(Config.InputFilename, std::move(E));
- if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput)
- if (Error E =
- linkToBuildIdDir(Config, Config.OutputFilename,
- Config.BuildIdLinkOutput.getValue(), BuildIdBytes))
- return createFileError(Config.OutputFilename, std::move(E));
-
- return Error::success();
-}
-
-} // end namespace elf
-} // end namespace objcopy
-} // end namespace llvm
+ return createFileError(Config.InputFilename, std::move(E));
+ if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput)
+ if (Error E =
+ linkToBuildIdDir(Config, Config.OutputFilename,
+ Config.BuildIdLinkOutput.getValue(), BuildIdBytes))
+ return createFileError(Config.OutputFilename, std::move(E));
+
+ return Error::success();
+}
+
+} // end namespace elf
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h
index e13e237e29..619a0bd908 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/ELFObjcopy.h
@@ -1,36 +1,36 @@
-//===- ELFObjcopy.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_OBJCOPY_ELFOBJCOPY_H
-#define LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H
-
-namespace llvm {
-class Error;
-class MemoryBuffer;
-
-namespace object {
-class ELFObjectFileBase;
-} // end namespace object
-
-namespace objcopy {
-struct CopyConfig;
-class Buffer;
-
-namespace elf {
-Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
- Buffer &Out);
-Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
- Buffer &Out);
-Error executeObjcopyOnBinary(const CopyConfig &Config,
- object::ELFObjectFileBase &In, Buffer &Out);
-
-} // end namespace elf
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H
+//===- ELFObjcopy.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_OBJCOPY_ELFOBJCOPY_H
+#define LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H
+
+namespace llvm {
+class Error;
+class MemoryBuffer;
+
+namespace object {
+class ELFObjectFileBase;
+} // end namespace object
+
+namespace objcopy {
+struct CopyConfig;
+class Buffer;
+
+namespace elf {
+Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out);
+Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out);
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::ELFObjectFileBase &In, Buffer &Out);
+
+} // end namespace elf
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp
index 0ff82f951b..d3094d351b 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.cpp
@@ -1,551 +1,551 @@
-//===- Object.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 "Object.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/MC/MCTargetOptions.h"
+//===- Object.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 "Object.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/Support/Compression.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/Path.h"
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <iterator>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-namespace llvm {
-namespace objcopy {
-namespace elf {
-
-using namespace object;
-using namespace ELF;
-
-template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) {
- uint8_t *B = Buf.getBufferStart() + Obj.ProgramHdrSegment.Offset +
- Seg.Index * sizeof(Elf_Phdr);
- Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(B);
- Phdr.p_type = Seg.Type;
- Phdr.p_flags = Seg.Flags;
- Phdr.p_offset = Seg.Offset;
- Phdr.p_vaddr = Seg.VAddr;
- Phdr.p_paddr = Seg.PAddr;
- Phdr.p_filesz = Seg.FileSize;
- Phdr.p_memsz = Seg.MemSize;
- Phdr.p_align = Seg.Align;
-}
-
-Error SectionBase::removeSectionReferences(
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+namespace elf {
+
+using namespace object;
+using namespace ELF;
+
+template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) {
+ uint8_t *B = Buf.getBufferStart() + Obj.ProgramHdrSegment.Offset +
+ Seg.Index * sizeof(Elf_Phdr);
+ Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(B);
+ Phdr.p_type = Seg.Type;
+ Phdr.p_flags = Seg.Flags;
+ Phdr.p_offset = Seg.Offset;
+ Phdr.p_vaddr = Seg.VAddr;
+ Phdr.p_paddr = Seg.PAddr;
+ Phdr.p_filesz = Seg.FileSize;
+ Phdr.p_memsz = Seg.MemSize;
+ Phdr.p_align = Seg.Align;
+}
+
+Error SectionBase::removeSectionReferences(
bool, function_ref<bool(const SectionBase *)>) {
- return Error::success();
-}
-
+ return Error::success();
+}
+
Error SectionBase::removeSymbols(function_ref<bool(const Symbol &)>) {
- return Error::success();
-}
-
+ return Error::success();
+}
+
Error SectionBase::initialize(SectionTableRef) { return Error::success(); }
-void SectionBase::finalize() {}
-void SectionBase::markSymbols() {}
-void SectionBase::replaceSectionReferences(
- const DenseMap<SectionBase *, SectionBase *> &) {}
-void SectionBase::onRemove() {}
-
-template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
- uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset;
- Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B);
- Shdr.sh_name = Sec.NameIndex;
- Shdr.sh_type = Sec.Type;
- Shdr.sh_flags = Sec.Flags;
- Shdr.sh_addr = Sec.Addr;
- Shdr.sh_offset = Sec.Offset;
- Shdr.sh_size = Sec.Size;
- Shdr.sh_link = Sec.Link;
- Shdr.sh_info = Sec.Info;
- Shdr.sh_addralign = Sec.Align;
- Shdr.sh_entsize = Sec.EntrySize;
-}
-
+void SectionBase::finalize() {}
+void SectionBase::markSymbols() {}
+void SectionBase::replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &) {}
+void SectionBase::onRemove() {}
+
+template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
+ uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset;
+ Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B);
+ Shdr.sh_name = Sec.NameIndex;
+ Shdr.sh_type = Sec.Type;
+ Shdr.sh_flags = Sec.Flags;
+ Shdr.sh_addr = Sec.Addr;
+ Shdr.sh_offset = Sec.Offset;
+ Shdr.sh_size = Sec.Size;
+ Shdr.sh_link = Sec.Link;
+ Shdr.sh_info = Sec.Info;
+ Shdr.sh_addralign = Sec.Align;
+ Shdr.sh_entsize = Sec.EntrySize;
+}
+
template <class ELFT> Error ELFSectionSizer<ELFT>::visit(Section &) {
return Error::success();
}
-
+
template <class ELFT> Error ELFSectionSizer<ELFT>::visit(OwnedDataSection &) {
return Error::success();
}
-
+
template <class ELFT> Error ELFSectionSizer<ELFT>::visit(StringTableSection &) {
return Error::success();
}
-
-template <class ELFT>
+
+template <class ELFT>
Error ELFSectionSizer<ELFT>::visit(DynamicRelocationSection &) {
return Error::success();
}
-
-template <class ELFT>
+
+template <class ELFT>
Error ELFSectionSizer<ELFT>::visit(SymbolTableSection &Sec) {
- Sec.EntrySize = sizeof(Elf_Sym);
- Sec.Size = Sec.Symbols.size() * Sec.EntrySize;
- // Align to the largest field in Elf_Sym.
- Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
+ Sec.EntrySize = sizeof(Elf_Sym);
+ Sec.Size = Sec.Symbols.size() * Sec.EntrySize;
+ // Align to the largest field in Elf_Sym.
+ Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
return Error::success();
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFSectionSizer<ELFT>::visit(RelocationSection &Sec) {
- Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela);
- Sec.Size = Sec.Relocations.size() * Sec.EntrySize;
- // Align to the largest field in Elf_Rel(a).
- Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
+ Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela);
+ Sec.Size = Sec.Relocations.size() * Sec.EntrySize;
+ // Align to the largest field in Elf_Rel(a).
+ Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
return Error::success();
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFSectionSizer<ELFT>::visit(GnuDebugLinkSection &) {
return Error::success();
}
-
+
template <class ELFT> Error ELFSectionSizer<ELFT>::visit(GroupSection &Sec) {
- Sec.Size = sizeof(Elf_Word) + Sec.GroupMembers.size() * sizeof(Elf_Word);
+ Sec.Size = sizeof(Elf_Word) + Sec.GroupMembers.size() * sizeof(Elf_Word);
return Error::success();
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFSectionSizer<ELFT>::visit(SectionIndexSection &) {
return Error::success();
}
-
+
template <class ELFT> Error ELFSectionSizer<ELFT>::visit(CompressedSection &) {
return Error::success();
}
-
-template <class ELFT>
+
+template <class ELFT>
Error ELFSectionSizer<ELFT>::visit(DecompressedSection &) {
return Error::success();
}
-
+
Error BinarySectionWriter::visit(const SectionIndexSection &Sec) {
return createStringError(errc::operation_not_permitted,
"cannot write symbol section index table '" +
Sec.Name + "' ");
-}
-
+}
+
Error BinarySectionWriter::visit(const SymbolTableSection &Sec) {
return createStringError(errc::operation_not_permitted,
"cannot write symbol table '" + Sec.Name +
"' out to binary");
-}
-
+}
+
Error BinarySectionWriter::visit(const RelocationSection &Sec) {
return createStringError(errc::operation_not_permitted,
"cannot write relocation section '" + Sec.Name +
"' out to binary");
-}
-
+}
+
Error BinarySectionWriter::visit(const GnuDebugLinkSection &Sec) {
return createStringError(errc::operation_not_permitted,
"cannot write '" + Sec.Name + "' out to binary");
-}
-
+}
+
Error BinarySectionWriter::visit(const GroupSection &Sec) {
return createStringError(errc::operation_not_permitted,
"cannot write '" + Sec.Name + "' out to binary");
-}
-
+}
+
Error SectionWriter::visit(const Section &Sec) {
- if (Sec.Type != SHT_NOBITS)
- llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset);
+ if (Sec.Type != SHT_NOBITS)
+ llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset);
return Error::success();
-}
-
-static bool addressOverflows32bit(uint64_t Addr) {
- // Sign extended 32 bit addresses (e.g 0xFFFFFFFF80000000) are ok
- return Addr > UINT32_MAX && Addr + 0x80000000 > UINT32_MAX;
-}
-
-template <class T> static T checkedGetHex(StringRef S) {
- T Value;
- bool Fail = S.getAsInteger(16, Value);
- assert(!Fail);
- (void)Fail;
- return Value;
-}
-
-// Fills exactly Len bytes of buffer with hexadecimal characters
-// representing value 'X'
-template <class T, class Iterator>
-static Iterator utohexstr(T X, Iterator It, size_t Len) {
- // Fill range with '0'
- std::fill(It, It + Len, '0');
-
- for (long I = Len - 1; I >= 0; --I) {
- unsigned char Mod = static_cast<unsigned char>(X) & 15;
- *(It + I) = hexdigit(Mod, false);
- X >>= 4;
- }
- assert(X == 0);
- return It + Len;
-}
-
-uint8_t IHexRecord::getChecksum(StringRef S) {
- assert((S.size() & 1) == 0);
- uint8_t Checksum = 0;
- while (!S.empty()) {
- Checksum += checkedGetHex<uint8_t>(S.take_front(2));
- S = S.drop_front(2);
- }
- return -Checksum;
-}
-
-IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr,
- ArrayRef<uint8_t> Data) {
- IHexLineData Line(getLineLength(Data.size()));
- assert(Line.size());
- auto Iter = Line.begin();
- *Iter++ = ':';
- Iter = utohexstr(Data.size(), Iter, 2);
- Iter = utohexstr(Addr, Iter, 4);
- Iter = utohexstr(Type, Iter, 2);
- for (uint8_t X : Data)
- Iter = utohexstr(X, Iter, 2);
- StringRef S(Line.data() + 1, std::distance(Line.begin() + 1, Iter));
- Iter = utohexstr(getChecksum(S), Iter, 2);
- *Iter++ = '\r';
- *Iter++ = '\n';
- assert(Iter == Line.end());
- return Line;
-}
-
-static Error checkRecord(const IHexRecord &R) {
- switch (R.Type) {
- case IHexRecord::Data:
- if (R.HexData.size() == 0)
- return createStringError(
- errc::invalid_argument,
- "zero data length is not allowed for data records");
- break;
- case IHexRecord::EndOfFile:
- break;
- case IHexRecord::SegmentAddr:
- // 20-bit segment address. Data length must be 2 bytes
- // (4 bytes in hex)
- if (R.HexData.size() != 4)
- return createStringError(
- errc::invalid_argument,
- "segment address data should be 2 bytes in size");
- break;
- case IHexRecord::StartAddr80x86:
- case IHexRecord::StartAddr:
- if (R.HexData.size() != 8)
- return createStringError(errc::invalid_argument,
- "start address data should be 4 bytes in size");
- // According to Intel HEX specification '03' record
- // only specifies the code address within the 20-bit
- // segmented address space of the 8086/80186. This
- // means 12 high order bits should be zeroes.
- if (R.Type == IHexRecord::StartAddr80x86 &&
- R.HexData.take_front(3) != "000")
- return createStringError(errc::invalid_argument,
- "start address exceeds 20 bit for 80x86");
- break;
- case IHexRecord::ExtendedAddr:
- // 16-31 bits of linear base address
- if (R.HexData.size() != 4)
- return createStringError(
- errc::invalid_argument,
- "extended address data should be 2 bytes in size");
- break;
- default:
- // Unknown record type
- return createStringError(errc::invalid_argument, "unknown record type: %u",
- static_cast<unsigned>(R.Type));
- }
- return Error::success();
-}
-
-// Checks that IHEX line contains valid characters.
-// This allows converting hexadecimal data to integers
-// without extra verification.
-static Error checkChars(StringRef Line) {
- assert(!Line.empty());
- if (Line[0] != ':')
- return createStringError(errc::invalid_argument,
- "missing ':' in the beginning of line.");
-
- for (size_t Pos = 1; Pos < Line.size(); ++Pos)
- if (hexDigitValue(Line[Pos]) == -1U)
- return createStringError(errc::invalid_argument,
- "invalid character at position %zu.", Pos + 1);
- return Error::success();
-}
-
-Expected<IHexRecord> IHexRecord::parse(StringRef Line) {
- assert(!Line.empty());
-
- // ':' + Length + Address + Type + Checksum with empty data ':LLAAAATTCC'
- if (Line.size() < 11)
- return createStringError(errc::invalid_argument,
- "line is too short: %zu chars.", Line.size());
-
- if (Error E = checkChars(Line))
- return std::move(E);
-
- IHexRecord Rec;
- size_t DataLen = checkedGetHex<uint8_t>(Line.substr(1, 2));
- if (Line.size() != getLength(DataLen))
- return createStringError(errc::invalid_argument,
- "invalid line length %zu (should be %zu)",
- Line.size(), getLength(DataLen));
-
- Rec.Addr = checkedGetHex<uint16_t>(Line.substr(3, 4));
- Rec.Type = checkedGetHex<uint8_t>(Line.substr(7, 2));
- Rec.HexData = Line.substr(9, DataLen * 2);
-
- if (getChecksum(Line.drop_front(1)) != 0)
- return createStringError(errc::invalid_argument, "incorrect checksum.");
- if (Error E = checkRecord(Rec))
- return std::move(E);
- return Rec;
-}
-
-static uint64_t sectionPhysicalAddr(const SectionBase *Sec) {
- Segment *Seg = Sec->ParentSegment;
- if (Seg && Seg->Type != ELF::PT_LOAD)
- Seg = nullptr;
- return Seg ? Seg->PAddr + Sec->OriginalOffset - Seg->OriginalOffset
- : Sec->Addr;
-}
-
-void IHexSectionWriterBase::writeSection(const SectionBase *Sec,
- ArrayRef<uint8_t> Data) {
- assert(Data.size() == Sec->Size);
- const uint32_t ChunkSize = 16;
- uint32_t Addr = sectionPhysicalAddr(Sec) & 0xFFFFFFFFU;
- while (!Data.empty()) {
- uint64_t DataSize = std::min<uint64_t>(Data.size(), ChunkSize);
- if (Addr > SegmentAddr + BaseAddr + 0xFFFFU) {
- if (Addr > 0xFFFFFU) {
- // Write extended address record, zeroing segment address
- // if needed.
- if (SegmentAddr != 0)
- SegmentAddr = writeSegmentAddr(0U);
- BaseAddr = writeBaseAddr(Addr);
- } else {
- // We can still remain 16-bit
- SegmentAddr = writeSegmentAddr(Addr);
- }
- }
- uint64_t SegOffset = Addr - BaseAddr - SegmentAddr;
- assert(SegOffset <= 0xFFFFU);
- DataSize = std::min(DataSize, 0x10000U - SegOffset);
- writeData(0, SegOffset, Data.take_front(DataSize));
- Addr += DataSize;
- Data = Data.drop_front(DataSize);
- }
-}
-
-uint64_t IHexSectionWriterBase::writeSegmentAddr(uint64_t Addr) {
- assert(Addr <= 0xFFFFFU);
- uint8_t Data[] = {static_cast<uint8_t>((Addr & 0xF0000U) >> 12), 0};
- writeData(2, 0, Data);
- return Addr & 0xF0000U;
-}
-
-uint64_t IHexSectionWriterBase::writeBaseAddr(uint64_t Addr) {
- assert(Addr <= 0xFFFFFFFFU);
- uint64_t Base = Addr & 0xFFFF0000U;
- uint8_t Data[] = {static_cast<uint8_t>(Base >> 24),
- static_cast<uint8_t>((Base >> 16) & 0xFF)};
- writeData(4, 0, Data);
- return Base;
-}
-
+}
+
+static bool addressOverflows32bit(uint64_t Addr) {
+ // Sign extended 32 bit addresses (e.g 0xFFFFFFFF80000000) are ok
+ return Addr > UINT32_MAX && Addr + 0x80000000 > UINT32_MAX;
+}
+
+template <class T> static T checkedGetHex(StringRef S) {
+ T Value;
+ bool Fail = S.getAsInteger(16, Value);
+ assert(!Fail);
+ (void)Fail;
+ return Value;
+}
+
+// Fills exactly Len bytes of buffer with hexadecimal characters
+// representing value 'X'
+template <class T, class Iterator>
+static Iterator utohexstr(T X, Iterator It, size_t Len) {
+ // Fill range with '0'
+ std::fill(It, It + Len, '0');
+
+ for (long I = Len - 1; I >= 0; --I) {
+ unsigned char Mod = static_cast<unsigned char>(X) & 15;
+ *(It + I) = hexdigit(Mod, false);
+ X >>= 4;
+ }
+ assert(X == 0);
+ return It + Len;
+}
+
+uint8_t IHexRecord::getChecksum(StringRef S) {
+ assert((S.size() & 1) == 0);
+ uint8_t Checksum = 0;
+ while (!S.empty()) {
+ Checksum += checkedGetHex<uint8_t>(S.take_front(2));
+ S = S.drop_front(2);
+ }
+ return -Checksum;
+}
+
+IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr,
+ ArrayRef<uint8_t> Data) {
+ IHexLineData Line(getLineLength(Data.size()));
+ assert(Line.size());
+ auto Iter = Line.begin();
+ *Iter++ = ':';
+ Iter = utohexstr(Data.size(), Iter, 2);
+ Iter = utohexstr(Addr, Iter, 4);
+ Iter = utohexstr(Type, Iter, 2);
+ for (uint8_t X : Data)
+ Iter = utohexstr(X, Iter, 2);
+ StringRef S(Line.data() + 1, std::distance(Line.begin() + 1, Iter));
+ Iter = utohexstr(getChecksum(S), Iter, 2);
+ *Iter++ = '\r';
+ *Iter++ = '\n';
+ assert(Iter == Line.end());
+ return Line;
+}
+
+static Error checkRecord(const IHexRecord &R) {
+ switch (R.Type) {
+ case IHexRecord::Data:
+ if (R.HexData.size() == 0)
+ return createStringError(
+ errc::invalid_argument,
+ "zero data length is not allowed for data records");
+ break;
+ case IHexRecord::EndOfFile:
+ break;
+ case IHexRecord::SegmentAddr:
+ // 20-bit segment address. Data length must be 2 bytes
+ // (4 bytes in hex)
+ if (R.HexData.size() != 4)
+ return createStringError(
+ errc::invalid_argument,
+ "segment address data should be 2 bytes in size");
+ break;
+ case IHexRecord::StartAddr80x86:
+ case IHexRecord::StartAddr:
+ if (R.HexData.size() != 8)
+ return createStringError(errc::invalid_argument,
+ "start address data should be 4 bytes in size");
+ // According to Intel HEX specification '03' record
+ // only specifies the code address within the 20-bit
+ // segmented address space of the 8086/80186. This
+ // means 12 high order bits should be zeroes.
+ if (R.Type == IHexRecord::StartAddr80x86 &&
+ R.HexData.take_front(3) != "000")
+ return createStringError(errc::invalid_argument,
+ "start address exceeds 20 bit for 80x86");
+ break;
+ case IHexRecord::ExtendedAddr:
+ // 16-31 bits of linear base address
+ if (R.HexData.size() != 4)
+ return createStringError(
+ errc::invalid_argument,
+ "extended address data should be 2 bytes in size");
+ break;
+ default:
+ // Unknown record type
+ return createStringError(errc::invalid_argument, "unknown record type: %u",
+ static_cast<unsigned>(R.Type));
+ }
+ return Error::success();
+}
+
+// Checks that IHEX line contains valid characters.
+// This allows converting hexadecimal data to integers
+// without extra verification.
+static Error checkChars(StringRef Line) {
+ assert(!Line.empty());
+ if (Line[0] != ':')
+ return createStringError(errc::invalid_argument,
+ "missing ':' in the beginning of line.");
+
+ for (size_t Pos = 1; Pos < Line.size(); ++Pos)
+ if (hexDigitValue(Line[Pos]) == -1U)
+ return createStringError(errc::invalid_argument,
+ "invalid character at position %zu.", Pos + 1);
+ return Error::success();
+}
+
+Expected<IHexRecord> IHexRecord::parse(StringRef Line) {
+ assert(!Line.empty());
+
+ // ':' + Length + Address + Type + Checksum with empty data ':LLAAAATTCC'
+ if (Line.size() < 11)
+ return createStringError(errc::invalid_argument,
+ "line is too short: %zu chars.", Line.size());
+
+ if (Error E = checkChars(Line))
+ return std::move(E);
+
+ IHexRecord Rec;
+ size_t DataLen = checkedGetHex<uint8_t>(Line.substr(1, 2));
+ if (Line.size() != getLength(DataLen))
+ return createStringError(errc::invalid_argument,
+ "invalid line length %zu (should be %zu)",
+ Line.size(), getLength(DataLen));
+
+ Rec.Addr = checkedGetHex<uint16_t>(Line.substr(3, 4));
+ Rec.Type = checkedGetHex<uint8_t>(Line.substr(7, 2));
+ Rec.HexData = Line.substr(9, DataLen * 2);
+
+ if (getChecksum(Line.drop_front(1)) != 0)
+ return createStringError(errc::invalid_argument, "incorrect checksum.");
+ if (Error E = checkRecord(Rec))
+ return std::move(E);
+ return Rec;
+}
+
+static uint64_t sectionPhysicalAddr(const SectionBase *Sec) {
+ Segment *Seg = Sec->ParentSegment;
+ if (Seg && Seg->Type != ELF::PT_LOAD)
+ Seg = nullptr;
+ return Seg ? Seg->PAddr + Sec->OriginalOffset - Seg->OriginalOffset
+ : Sec->Addr;
+}
+
+void IHexSectionWriterBase::writeSection(const SectionBase *Sec,
+ ArrayRef<uint8_t> Data) {
+ assert(Data.size() == Sec->Size);
+ const uint32_t ChunkSize = 16;
+ uint32_t Addr = sectionPhysicalAddr(Sec) & 0xFFFFFFFFU;
+ while (!Data.empty()) {
+ uint64_t DataSize = std::min<uint64_t>(Data.size(), ChunkSize);
+ if (Addr > SegmentAddr + BaseAddr + 0xFFFFU) {
+ if (Addr > 0xFFFFFU) {
+ // Write extended address record, zeroing segment address
+ // if needed.
+ if (SegmentAddr != 0)
+ SegmentAddr = writeSegmentAddr(0U);
+ BaseAddr = writeBaseAddr(Addr);
+ } else {
+ // We can still remain 16-bit
+ SegmentAddr = writeSegmentAddr(Addr);
+ }
+ }
+ uint64_t SegOffset = Addr - BaseAddr - SegmentAddr;
+ assert(SegOffset <= 0xFFFFU);
+ DataSize = std::min(DataSize, 0x10000U - SegOffset);
+ writeData(0, SegOffset, Data.take_front(DataSize));
+ Addr += DataSize;
+ Data = Data.drop_front(DataSize);
+ }
+}
+
+uint64_t IHexSectionWriterBase::writeSegmentAddr(uint64_t Addr) {
+ assert(Addr <= 0xFFFFFU);
+ uint8_t Data[] = {static_cast<uint8_t>((Addr & 0xF0000U) >> 12), 0};
+ writeData(2, 0, Data);
+ return Addr & 0xF0000U;
+}
+
+uint64_t IHexSectionWriterBase::writeBaseAddr(uint64_t Addr) {
+ assert(Addr <= 0xFFFFFFFFU);
+ uint64_t Base = Addr & 0xFFFF0000U;
+ uint8_t Data[] = {static_cast<uint8_t>(Base >> 24),
+ static_cast<uint8_t>((Base >> 16) & 0xFF)};
+ writeData(4, 0, Data);
+ return Base;
+}
+
void IHexSectionWriterBase::writeData(uint8_t, uint16_t,
- ArrayRef<uint8_t> Data) {
- Offset += IHexRecord::getLineLength(Data.size());
-}
-
+ ArrayRef<uint8_t> Data) {
+ Offset += IHexRecord::getLineLength(Data.size());
+}
+
Error IHexSectionWriterBase::visit(const Section &Sec) {
- writeSection(&Sec, Sec.Contents);
+ writeSection(&Sec, Sec.Contents);
return Error::success();
-}
-
+}
+
Error IHexSectionWriterBase::visit(const OwnedDataSection &Sec) {
- writeSection(&Sec, Sec.Data);
+ writeSection(&Sec, Sec.Data);
return Error::success();
-}
-
+}
+
Error IHexSectionWriterBase::visit(const StringTableSection &Sec) {
- // Check that sizer has already done its work
- assert(Sec.Size == Sec.StrTabBuilder.getSize());
- // We are free to pass an invalid pointer to writeSection as long
- // as we don't actually write any data. The real writer class has
- // to override this method .
- writeSection(&Sec, {nullptr, static_cast<size_t>(Sec.Size)});
+ // Check that sizer has already done its work
+ assert(Sec.Size == Sec.StrTabBuilder.getSize());
+ // We are free to pass an invalid pointer to writeSection as long
+ // as we don't actually write any data. The real writer class has
+ // to override this method .
+ writeSection(&Sec, {nullptr, static_cast<size_t>(Sec.Size)});
return Error::success();
-}
-
+}
+
Error IHexSectionWriterBase::visit(const DynamicRelocationSection &Sec) {
- writeSection(&Sec, Sec.Contents);
+ writeSection(&Sec, Sec.Contents);
return Error::success();
-}
-
-void IHexSectionWriter::writeData(uint8_t Type, uint16_t Addr,
- ArrayRef<uint8_t> Data) {
- IHexLineData HexData = IHexRecord::getLine(Type, Addr, Data);
- memcpy(Out.getBufferStart() + Offset, HexData.data(), HexData.size());
- Offset += HexData.size();
-}
-
+}
+
+void IHexSectionWriter::writeData(uint8_t Type, uint16_t Addr,
+ ArrayRef<uint8_t> Data) {
+ IHexLineData HexData = IHexRecord::getLine(Type, Addr, Data);
+ memcpy(Out.getBufferStart() + Offset, HexData.data(), HexData.size());
+ Offset += HexData.size();
+}
+
Error IHexSectionWriter::visit(const StringTableSection &Sec) {
- assert(Sec.Size == Sec.StrTabBuilder.getSize());
- std::vector<uint8_t> Data(Sec.Size);
- Sec.StrTabBuilder.write(Data.data());
- writeSection(&Sec, Data);
+ assert(Sec.Size == Sec.StrTabBuilder.getSize());
+ std::vector<uint8_t> Data(Sec.Size);
+ Sec.StrTabBuilder.write(Data.data());
+ writeSection(&Sec, Data);
return Error::success();
-}
-
+}
+
Error Section::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
}
-
+
Error Section::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
}
-
+
Error SectionWriter::visit(const OwnedDataSection &Sec) {
- llvm::copy(Sec.Data, Out.getBufferStart() + Sec.Offset);
+ llvm::copy(Sec.Data, Out.getBufferStart() + Sec.Offset);
return Error::success();
-}
-
-static constexpr std::array<uint8_t, 4> ZlibGnuMagic = {{'Z', 'L', 'I', 'B'}};
-
-static bool isDataGnuCompressed(ArrayRef<uint8_t> Data) {
- return Data.size() > ZlibGnuMagic.size() &&
- std::equal(ZlibGnuMagic.begin(), ZlibGnuMagic.end(), Data.data());
-}
-
-template <class ELFT>
-static std::tuple<uint64_t, uint64_t>
-getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) {
- const bool IsGnuDebug = isDataGnuCompressed(Data);
- const uint64_t DecompressedSize =
- IsGnuDebug
- ? support::endian::read64be(Data.data() + ZlibGnuMagic.size())
- : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())->ch_size;
- const uint64_t DecompressedAlign =
- IsGnuDebug ? 1
- : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())
- ->ch_addralign;
-
- return std::make_tuple(DecompressedSize, DecompressedAlign);
-}
-
-template <class ELFT>
+}
+
+static constexpr std::array<uint8_t, 4> ZlibGnuMagic = {{'Z', 'L', 'I', 'B'}};
+
+static bool isDataGnuCompressed(ArrayRef<uint8_t> Data) {
+ return Data.size() > ZlibGnuMagic.size() &&
+ std::equal(ZlibGnuMagic.begin(), ZlibGnuMagic.end(), Data.data());
+}
+
+template <class ELFT>
+static std::tuple<uint64_t, uint64_t>
+getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) {
+ const bool IsGnuDebug = isDataGnuCompressed(Data);
+ const uint64_t DecompressedSize =
+ IsGnuDebug
+ ? support::endian::read64be(Data.data() + ZlibGnuMagic.size())
+ : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())->ch_size;
+ const uint64_t DecompressedAlign =
+ IsGnuDebug ? 1
+ : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())
+ ->ch_addralign;
+
+ return std::make_tuple(DecompressedSize, DecompressedAlign);
+}
+
+template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) {
- const size_t DataOffset = isDataGnuCompressed(Sec.OriginalData)
- ? (ZlibGnuMagic.size() + sizeof(Sec.Size))
- : sizeof(Elf_Chdr_Impl<ELFT>);
-
- StringRef CompressedContent(
- reinterpret_cast<const char *>(Sec.OriginalData.data()) + DataOffset,
- Sec.OriginalData.size() - DataOffset);
-
- SmallVector<char, 128> DecompressedContent;
+ const size_t DataOffset = isDataGnuCompressed(Sec.OriginalData)
+ ? (ZlibGnuMagic.size() + sizeof(Sec.Size))
+ : sizeof(Elf_Chdr_Impl<ELFT>);
+
+ StringRef CompressedContent(
+ reinterpret_cast<const char *>(Sec.OriginalData.data()) + DataOffset,
+ Sec.OriginalData.size() - DataOffset);
+
+ SmallVector<char, 128> DecompressedContent;
if (Error Err = zlib::uncompress(CompressedContent, DecompressedContent,
static_cast<size_t>(Sec.Size)))
return createStringError(errc::invalid_argument,
"'" + Sec.Name + "': " + toString(std::move(Err)));
-
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
- std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf);
+
+ uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+ std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf);
return Error::success();
-}
-
+}
+
Error BinarySectionWriter::visit(const DecompressedSection &Sec) {
return createStringError(errc::operation_not_permitted,
"cannot write compressed section '" + Sec.Name +
"' ");
-}
-
+}
+
Error DecompressedSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error DecompressedSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
+}
+
Error OwnedDataSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error OwnedDataSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
-void OwnedDataSection::appendHexData(StringRef HexData) {
- assert((HexData.size() & 1) == 0);
- while (!HexData.empty()) {
- Data.push_back(checkedGetHex<uint8_t>(HexData.take_front(2)));
- HexData = HexData.drop_front(2);
- }
- Size = Data.size();
-}
-
+}
+
+void OwnedDataSection::appendHexData(StringRef HexData) {
+ assert((HexData.size() & 1) == 0);
+ while (!HexData.empty()) {
+ Data.push_back(checkedGetHex<uint8_t>(HexData.take_front(2)));
+ HexData = HexData.drop_front(2);
+ }
+ Size = Data.size();
+}
+
Error BinarySectionWriter::visit(const CompressedSection &Sec) {
return createStringError(errc::operation_not_permitted,
"cannot write compressed section '" + Sec.Name +
"' ");
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const CompressedSection &Sec) {
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
- if (Sec.CompressionType == DebugCompressionType::None) {
- std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
+ uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+ if (Sec.CompressionType == DebugCompressionType::None) {
+ std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
return Error::success();
- }
-
- if (Sec.CompressionType == DebugCompressionType::GNU) {
- const char *Magic = "ZLIB";
- memcpy(Buf, Magic, strlen(Magic));
- Buf += strlen(Magic);
- const uint64_t DecompressedSize =
- support::endian::read64be(&Sec.DecompressedSize);
- memcpy(Buf, &DecompressedSize, sizeof(DecompressedSize));
- Buf += sizeof(DecompressedSize);
- } else {
- Elf_Chdr_Impl<ELFT> Chdr;
- Chdr.ch_type = ELF::ELFCOMPRESS_ZLIB;
- Chdr.ch_size = Sec.DecompressedSize;
- Chdr.ch_addralign = Sec.DecompressedAlign;
- memcpy(Buf, &Chdr, sizeof(Chdr));
- Buf += sizeof(Chdr);
- }
-
- std::copy(Sec.CompressedData.begin(), Sec.CompressedData.end(), Buf);
+ }
+
+ if (Sec.CompressionType == DebugCompressionType::GNU) {
+ const char *Magic = "ZLIB";
+ memcpy(Buf, Magic, strlen(Magic));
+ Buf += strlen(Magic);
+ const uint64_t DecompressedSize =
+ support::endian::read64be(&Sec.DecompressedSize);
+ memcpy(Buf, &DecompressedSize, sizeof(DecompressedSize));
+ Buf += sizeof(DecompressedSize);
+ } else {
+ Elf_Chdr_Impl<ELFT> Chdr;
+ Chdr.ch_type = ELF::ELFCOMPRESS_ZLIB;
+ Chdr.ch_size = Sec.DecompressedSize;
+ Chdr.ch_addralign = Sec.DecompressedAlign;
+ memcpy(Buf, &Chdr, sizeof(Chdr));
+ Buf += sizeof(Chdr);
+ }
+
+ std::copy(Sec.CompressedData.begin(), Sec.CompressedData.end(), Buf);
return Error::success();
-}
-
+}
+
Expected<CompressedSection>
CompressedSection::create(const SectionBase &Sec,
DebugCompressionType CompressionType) {
@@ -564,87 +564,87 @@ CompressedSection::create(ArrayRef<uint8_t> CompressedData,
return CompressedSection(CompressedData, DecompressedSize, DecompressedAlign);
}
-CompressedSection::CompressedSection(const SectionBase &Sec,
+CompressedSection::CompressedSection(const SectionBase &Sec,
DebugCompressionType CompressionType,
Error &OutErr)
- : SectionBase(Sec), CompressionType(CompressionType),
- DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) {
+ : SectionBase(Sec), CompressionType(CompressionType),
+ DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) {
ErrorAsOutParameter EAO(&OutErr);
if (Error Err = zlib::compress(
- StringRef(reinterpret_cast<const char *>(OriginalData.data()),
- OriginalData.size()),
+ StringRef(reinterpret_cast<const char *>(OriginalData.data()),
+ OriginalData.size()),
CompressedData)) {
OutErr = createStringError(llvm::errc::invalid_argument,
"'" + Name + "': " + toString(std::move(Err)));
return;
}
-
- size_t ChdrSize;
- if (CompressionType == DebugCompressionType::GNU) {
- Name = ".z" + Sec.Name.substr(1);
- ChdrSize = sizeof("ZLIB") - 1 + sizeof(uint64_t);
- } else {
- Flags |= ELF::SHF_COMPRESSED;
- ChdrSize =
- std::max(std::max(sizeof(object::Elf_Chdr_Impl<object::ELF64LE>),
- sizeof(object::Elf_Chdr_Impl<object::ELF64BE>)),
- std::max(sizeof(object::Elf_Chdr_Impl<object::ELF32LE>),
- sizeof(object::Elf_Chdr_Impl<object::ELF32BE>)));
- }
- Size = ChdrSize + CompressedData.size();
- Align = 8;
-}
-
-CompressedSection::CompressedSection(ArrayRef<uint8_t> CompressedData,
- uint64_t DecompressedSize,
- uint64_t DecompressedAlign)
- : CompressionType(DebugCompressionType::None),
- DecompressedSize(DecompressedSize), DecompressedAlign(DecompressedAlign) {
- OriginalData = CompressedData;
-}
-
+
+ size_t ChdrSize;
+ if (CompressionType == DebugCompressionType::GNU) {
+ Name = ".z" + Sec.Name.substr(1);
+ ChdrSize = sizeof("ZLIB") - 1 + sizeof(uint64_t);
+ } else {
+ Flags |= ELF::SHF_COMPRESSED;
+ ChdrSize =
+ std::max(std::max(sizeof(object::Elf_Chdr_Impl<object::ELF64LE>),
+ sizeof(object::Elf_Chdr_Impl<object::ELF64BE>)),
+ std::max(sizeof(object::Elf_Chdr_Impl<object::ELF32LE>),
+ sizeof(object::Elf_Chdr_Impl<object::ELF32BE>)));
+ }
+ Size = ChdrSize + CompressedData.size();
+ Align = 8;
+}
+
+CompressedSection::CompressedSection(ArrayRef<uint8_t> CompressedData,
+ uint64_t DecompressedSize,
+ uint64_t DecompressedAlign)
+ : CompressionType(DebugCompressionType::None),
+ DecompressedSize(DecompressedSize), DecompressedAlign(DecompressedAlign) {
+ OriginalData = CompressedData;
+}
+
Error CompressedSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error CompressedSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
-void StringTableSection::addString(StringRef Name) { StrTabBuilder.add(Name); }
-
-uint32_t StringTableSection::findIndex(StringRef Name) const {
- return StrTabBuilder.getOffset(Name);
-}
-
-void StringTableSection::prepareForLayout() {
- StrTabBuilder.finalize();
- Size = StrTabBuilder.getSize();
-}
-
+}
+
+void StringTableSection::addString(StringRef Name) { StrTabBuilder.add(Name); }
+
+uint32_t StringTableSection::findIndex(StringRef Name) const {
+ return StrTabBuilder.getOffset(Name);
+}
+
+void StringTableSection::prepareForLayout() {
+ StrTabBuilder.finalize();
+ Size = StrTabBuilder.getSize();
+}
+
Error SectionWriter::visit(const StringTableSection &Sec) {
- Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset);
+ Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset);
return Error::success();
-}
-
+}
+
Error StringTableSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error StringTableSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const SectionIndexSection &Sec) {
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
- llvm::copy(Sec.Indexes, reinterpret_cast<Elf_Word *>(Buf));
+ uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+ llvm::copy(Sec.Indexes, reinterpret_cast<Elf_Word *>(Buf));
return Error::success();
-}
-
+}
+
Error SectionIndexSection::initialize(SectionTableRef SecTable) {
- Size = 0;
+ Size = 0;
Expected<SymbolTableSection *> Sec =
SecTable.getSectionOfType<SymbolTableSection>(
Link,
@@ -656,145 +656,145 @@ Error SectionIndexSection::initialize(SectionTableRef SecTable) {
return Sec.takeError();
setSymTab(*Sec);
- Symbols->setShndxTable(this);
+ Symbols->setShndxTable(this);
return Error::success();
-}
-
-void SectionIndexSection::finalize() { Link = Symbols->Index; }
-
+}
+
+void SectionIndexSection::finalize() { Link = Symbols->Index; }
+
Error SectionIndexSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error SectionIndexSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
-static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) {
- switch (Index) {
- case SHN_ABS:
- case SHN_COMMON:
- return true;
- }
-
- if (Machine == EM_AMDGPU) {
- return Index == SHN_AMDGPU_LDS;
- }
-
- if (Machine == EM_HEXAGON) {
- switch (Index) {
- case SHN_HEXAGON_SCOMMON:
- case SHN_HEXAGON_SCOMMON_1:
- case SHN_HEXAGON_SCOMMON_2:
- case SHN_HEXAGON_SCOMMON_4:
- case SHN_HEXAGON_SCOMMON_8:
- return true;
- }
- }
- return false;
-}
-
-// Large indexes force us to clarify exactly what this function should do. This
-// function should return the value that will appear in st_shndx when written
-// out.
-uint16_t Symbol::getShndx() const {
- if (DefinedIn != nullptr) {
- if (DefinedIn->Index >= SHN_LORESERVE)
- return SHN_XINDEX;
- return DefinedIn->Index;
- }
-
- if (ShndxType == SYMBOL_SIMPLE_INDEX) {
- // This means that we don't have a defined section but we do need to
- // output a legitimate section index.
- return SHN_UNDEF;
- }
-
- assert(ShndxType == SYMBOL_ABS || ShndxType == SYMBOL_COMMON ||
- (ShndxType >= SYMBOL_LOPROC && ShndxType <= SYMBOL_HIPROC) ||
- (ShndxType >= SYMBOL_LOOS && ShndxType <= SYMBOL_HIOS));
- return static_cast<uint16_t>(ShndxType);
-}
-
-bool Symbol::isCommon() const { return getShndx() == SHN_COMMON; }
-
-void SymbolTableSection::assignIndices() {
- uint32_t Index = 0;
- for (auto &Sym : Symbols)
- Sym->Index = Index++;
-}
-
-void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type,
- SectionBase *DefinedIn, uint64_t Value,
- uint8_t Visibility, uint16_t Shndx,
- uint64_t SymbolSize) {
- Symbol Sym;
- Sym.Name = Name.str();
- Sym.Binding = Bind;
- Sym.Type = Type;
- Sym.DefinedIn = DefinedIn;
- if (DefinedIn != nullptr)
- DefinedIn->HasSymbol = true;
- if (DefinedIn == nullptr) {
- if (Shndx >= SHN_LORESERVE)
- Sym.ShndxType = static_cast<SymbolShndxType>(Shndx);
- else
- Sym.ShndxType = SYMBOL_SIMPLE_INDEX;
- }
- Sym.Value = Value;
- Sym.Visibility = Visibility;
- Sym.Size = SymbolSize;
- Sym.Index = Symbols.size();
- Symbols.emplace_back(std::make_unique<Symbol>(Sym));
- Size += this->EntrySize;
-}
-
-Error SymbolTableSection::removeSectionReferences(
+}
+
+static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) {
+ switch (Index) {
+ case SHN_ABS:
+ case SHN_COMMON:
+ return true;
+ }
+
+ if (Machine == EM_AMDGPU) {
+ return Index == SHN_AMDGPU_LDS;
+ }
+
+ if (Machine == EM_HEXAGON) {
+ switch (Index) {
+ case SHN_HEXAGON_SCOMMON:
+ case SHN_HEXAGON_SCOMMON_1:
+ case SHN_HEXAGON_SCOMMON_2:
+ case SHN_HEXAGON_SCOMMON_4:
+ case SHN_HEXAGON_SCOMMON_8:
+ return true;
+ }
+ }
+ return false;
+}
+
+// Large indexes force us to clarify exactly what this function should do. This
+// function should return the value that will appear in st_shndx when written
+// out.
+uint16_t Symbol::getShndx() const {
+ if (DefinedIn != nullptr) {
+ if (DefinedIn->Index >= SHN_LORESERVE)
+ return SHN_XINDEX;
+ return DefinedIn->Index;
+ }
+
+ if (ShndxType == SYMBOL_SIMPLE_INDEX) {
+ // This means that we don't have a defined section but we do need to
+ // output a legitimate section index.
+ return SHN_UNDEF;
+ }
+
+ assert(ShndxType == SYMBOL_ABS || ShndxType == SYMBOL_COMMON ||
+ (ShndxType >= SYMBOL_LOPROC && ShndxType <= SYMBOL_HIPROC) ||
+ (ShndxType >= SYMBOL_LOOS && ShndxType <= SYMBOL_HIOS));
+ return static_cast<uint16_t>(ShndxType);
+}
+
+bool Symbol::isCommon() const { return getShndx() == SHN_COMMON; }
+
+void SymbolTableSection::assignIndices() {
+ uint32_t Index = 0;
+ for (auto &Sym : Symbols)
+ Sym->Index = Index++;
+}
+
+void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type,
+ SectionBase *DefinedIn, uint64_t Value,
+ uint8_t Visibility, uint16_t Shndx,
+ uint64_t SymbolSize) {
+ Symbol Sym;
+ Sym.Name = Name.str();
+ Sym.Binding = Bind;
+ Sym.Type = Type;
+ Sym.DefinedIn = DefinedIn;
+ if (DefinedIn != nullptr)
+ DefinedIn->HasSymbol = true;
+ if (DefinedIn == nullptr) {
+ if (Shndx >= SHN_LORESERVE)
+ Sym.ShndxType = static_cast<SymbolShndxType>(Shndx);
+ else
+ Sym.ShndxType = SYMBOL_SIMPLE_INDEX;
+ }
+ Sym.Value = Value;
+ Sym.Visibility = Visibility;
+ Sym.Size = SymbolSize;
+ Sym.Index = Symbols.size();
+ Symbols.emplace_back(std::make_unique<Symbol>(Sym));
+ Size += this->EntrySize;
+}
+
+Error SymbolTableSection::removeSectionReferences(
bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
- if (ToRemove(SectionIndexTable))
- SectionIndexTable = nullptr;
- if (ToRemove(SymbolNames)) {
- if (!AllowBrokenLinks)
- return createStringError(
- llvm::errc::invalid_argument,
- "string table '%s' cannot be removed because it is "
- "referenced by the symbol table '%s'",
- SymbolNames->Name.data(), this->Name.data());
- SymbolNames = nullptr;
- }
- return removeSymbols(
- [ToRemove](const Symbol &Sym) { return ToRemove(Sym.DefinedIn); });
-}
-
-void SymbolTableSection::updateSymbols(function_ref<void(Symbol &)> Callable) {
- std::for_each(std::begin(Symbols) + 1, std::end(Symbols),
- [Callable](SymPtr &Sym) { Callable(*Sym); });
- std::stable_partition(
- std::begin(Symbols), std::end(Symbols),
- [](const SymPtr &Sym) { return Sym->Binding == STB_LOCAL; });
- assignIndices();
-}
-
-Error SymbolTableSection::removeSymbols(
- function_ref<bool(const Symbol &)> ToRemove) {
- Symbols.erase(
- std::remove_if(std::begin(Symbols) + 1, std::end(Symbols),
- [ToRemove](const SymPtr &Sym) { return ToRemove(*Sym); }),
- std::end(Symbols));
- Size = Symbols.size() * EntrySize;
- assignIndices();
- return Error::success();
-}
-
-void SymbolTableSection::replaceSectionReferences(
- const DenseMap<SectionBase *, SectionBase *> &FromTo) {
- for (std::unique_ptr<Symbol> &Sym : Symbols)
- if (SectionBase *To = FromTo.lookup(Sym->DefinedIn))
- Sym->DefinedIn = To;
-}
-
+ if (ToRemove(SectionIndexTable))
+ SectionIndexTable = nullptr;
+ if (ToRemove(SymbolNames)) {
+ if (!AllowBrokenLinks)
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "string table '%s' cannot be removed because it is "
+ "referenced by the symbol table '%s'",
+ SymbolNames->Name.data(), this->Name.data());
+ SymbolNames = nullptr;
+ }
+ return removeSymbols(
+ [ToRemove](const Symbol &Sym) { return ToRemove(Sym.DefinedIn); });
+}
+
+void SymbolTableSection::updateSymbols(function_ref<void(Symbol &)> Callable) {
+ std::for_each(std::begin(Symbols) + 1, std::end(Symbols),
+ [Callable](SymPtr &Sym) { Callable(*Sym); });
+ std::stable_partition(
+ std::begin(Symbols), std::end(Symbols),
+ [](const SymPtr &Sym) { return Sym->Binding == STB_LOCAL; });
+ assignIndices();
+}
+
+Error SymbolTableSection::removeSymbols(
+ function_ref<bool(const Symbol &)> ToRemove) {
+ Symbols.erase(
+ std::remove_if(std::begin(Symbols) + 1, std::end(Symbols),
+ [ToRemove](const SymPtr &Sym) { return ToRemove(*Sym); }),
+ std::end(Symbols));
+ Size = Symbols.size() * EntrySize;
+ assignIndices();
+ return Error::success();
+}
+
+void SymbolTableSection::replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) {
+ for (std::unique_ptr<Symbol> &Sym : Symbols)
+ if (SectionBase *To = FromTo.lookup(Sym->DefinedIn))
+ Sym->DefinedIn = To;
+}
+
Error SymbolTableSection::initialize(SectionTableRef SecTable) {
- Size = 0;
+ Size = 0;
Expected<StringTableSection *> Sec =
SecTable.getSectionOfType<StringTableSection>(
Link,
@@ -807,58 +807,58 @@ Error SymbolTableSection::initialize(SectionTableRef SecTable) {
setStrTab(*Sec);
return Error::success();
-}
-
-void SymbolTableSection::finalize() {
- uint32_t MaxLocalIndex = 0;
- for (std::unique_ptr<Symbol> &Sym : Symbols) {
- Sym->NameIndex =
- SymbolNames == nullptr ? 0 : SymbolNames->findIndex(Sym->Name);
- if (Sym->Binding == STB_LOCAL)
- MaxLocalIndex = std::max(MaxLocalIndex, Sym->Index);
- }
- // Now we need to set the Link and Info fields.
- Link = SymbolNames == nullptr ? 0 : SymbolNames->Index;
- Info = MaxLocalIndex + 1;
-}
-
-void SymbolTableSection::prepareForLayout() {
- // Reserve proper amount of space in section index table, so we can
- // layout sections correctly. We will fill the table with correct
- // indexes later in fillShdnxTable.
- if (SectionIndexTable)
- SectionIndexTable->reserve(Symbols.size());
-
- // Add all of our strings to SymbolNames so that SymbolNames has the right
- // size before layout is decided.
- // If the symbol names section has been removed, don't try to add strings to
- // the table.
- if (SymbolNames != nullptr)
- for (std::unique_ptr<Symbol> &Sym : Symbols)
- SymbolNames->addString(Sym->Name);
-}
-
-void SymbolTableSection::fillShndxTable() {
- if (SectionIndexTable == nullptr)
- return;
- // Fill section index table with real section indexes. This function must
- // be called after assignOffsets.
- for (const std::unique_ptr<Symbol> &Sym : Symbols) {
- if (Sym->DefinedIn != nullptr && Sym->DefinedIn->Index >= SHN_LORESERVE)
- SectionIndexTable->addIndex(Sym->DefinedIn->Index);
- else
- SectionIndexTable->addIndex(SHN_UNDEF);
- }
-}
-
+}
+
+void SymbolTableSection::finalize() {
+ uint32_t MaxLocalIndex = 0;
+ for (std::unique_ptr<Symbol> &Sym : Symbols) {
+ Sym->NameIndex =
+ SymbolNames == nullptr ? 0 : SymbolNames->findIndex(Sym->Name);
+ if (Sym->Binding == STB_LOCAL)
+ MaxLocalIndex = std::max(MaxLocalIndex, Sym->Index);
+ }
+ // Now we need to set the Link and Info fields.
+ Link = SymbolNames == nullptr ? 0 : SymbolNames->Index;
+ Info = MaxLocalIndex + 1;
+}
+
+void SymbolTableSection::prepareForLayout() {
+ // Reserve proper amount of space in section index table, so we can
+ // layout sections correctly. We will fill the table with correct
+ // indexes later in fillShdnxTable.
+ if (SectionIndexTable)
+ SectionIndexTable->reserve(Symbols.size());
+
+ // Add all of our strings to SymbolNames so that SymbolNames has the right
+ // size before layout is decided.
+ // If the symbol names section has been removed, don't try to add strings to
+ // the table.
+ if (SymbolNames != nullptr)
+ for (std::unique_ptr<Symbol> &Sym : Symbols)
+ SymbolNames->addString(Sym->Name);
+}
+
+void SymbolTableSection::fillShndxTable() {
+ if (SectionIndexTable == nullptr)
+ return;
+ // Fill section index table with real section indexes. This function must
+ // be called after assignOffsets.
+ for (const std::unique_ptr<Symbol> &Sym : Symbols) {
+ if (Sym->DefinedIn != nullptr && Sym->DefinedIn->Index >= SHN_LORESERVE)
+ SectionIndexTable->addIndex(Sym->DefinedIn->Index);
+ else
+ SectionIndexTable->addIndex(SHN_UNDEF);
+ }
+}
+
Expected<const Symbol *>
SymbolTableSection::getSymbolByIndex(uint32_t Index) const {
- if (Symbols.size() <= Index)
+ if (Symbols.size() <= Index)
return createStringError(errc::invalid_argument,
"invalid symbol index: " + Twine(Index));
- return Symbols[Index].get();
-}
-
+ return Symbols[Index].get();
+}
+
Expected<Symbol *> SymbolTableSection::getSymbolByIndex(uint32_t Index) {
Expected<const Symbol *> Sym =
static_cast<const SymbolTableSection *>(this)->getSymbolByIndex(Index);
@@ -866,73 +866,73 @@ Expected<Symbol *> SymbolTableSection::getSymbolByIndex(uint32_t Index) {
return Sym.takeError();
return const_cast<Symbol *>(*Sym);
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const SymbolTableSection &Sec) {
- Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Out.getBufferStart() + Sec.Offset);
- // Loop though symbols setting each entry of the symbol table.
- for (const std::unique_ptr<Symbol> &Symbol : Sec.Symbols) {
- Sym->st_name = Symbol->NameIndex;
- Sym->st_value = Symbol->Value;
- Sym->st_size = Symbol->Size;
- Sym->st_other = Symbol->Visibility;
- Sym->setBinding(Symbol->Binding);
- Sym->setType(Symbol->Type);
- Sym->st_shndx = Symbol->getShndx();
- ++Sym;
- }
+ Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Out.getBufferStart() + Sec.Offset);
+ // Loop though symbols setting each entry of the symbol table.
+ for (const std::unique_ptr<Symbol> &Symbol : Sec.Symbols) {
+ Sym->st_name = Symbol->NameIndex;
+ Sym->st_value = Symbol->Value;
+ Sym->st_size = Symbol->Size;
+ Sym->st_other = Symbol->Visibility;
+ Sym->setBinding(Symbol->Binding);
+ Sym->setType(Symbol->Type);
+ Sym->st_shndx = Symbol->getShndx();
+ ++Sym;
+ }
return Error::success();
-}
-
+}
+
Error SymbolTableSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error SymbolTableSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
-Error RelocationSection::removeSectionReferences(
+}
+
+Error RelocationSection::removeSectionReferences(
bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
- if (ToRemove(Symbols)) {
- if (!AllowBrokenLinks)
- return createStringError(
- llvm::errc::invalid_argument,
- "symbol table '%s' cannot be removed because it is "
- "referenced by the relocation section '%s'",
- Symbols->Name.data(), this->Name.data());
- Symbols = nullptr;
- }
-
- for (const Relocation &R : Relocations) {
- if (!R.RelocSymbol || !R.RelocSymbol->DefinedIn ||
- !ToRemove(R.RelocSymbol->DefinedIn))
- continue;
- return createStringError(llvm::errc::invalid_argument,
- "section '%s' cannot be removed: (%s+0x%" PRIx64
- ") has relocation against symbol '%s'",
- R.RelocSymbol->DefinedIn->Name.data(),
- SecToApplyRel->Name.data(), R.Offset,
- R.RelocSymbol->Name.c_str());
- }
-
- return Error::success();
-}
-
-template <class SymTabType>
+ if (ToRemove(Symbols)) {
+ if (!AllowBrokenLinks)
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "symbol table '%s' cannot be removed because it is "
+ "referenced by the relocation section '%s'",
+ Symbols->Name.data(), this->Name.data());
+ Symbols = nullptr;
+ }
+
+ for (const Relocation &R : Relocations) {
+ if (!R.RelocSymbol || !R.RelocSymbol->DefinedIn ||
+ !ToRemove(R.RelocSymbol->DefinedIn))
+ continue;
+ return createStringError(llvm::errc::invalid_argument,
+ "section '%s' cannot be removed: (%s+0x%" PRIx64
+ ") has relocation against symbol '%s'",
+ R.RelocSymbol->DefinedIn->Name.data(),
+ SecToApplyRel->Name.data(), R.Offset,
+ R.RelocSymbol->Name.c_str());
+ }
+
+ return Error::success();
+}
+
+template <class SymTabType>
Error RelocSectionWithSymtabBase<SymTabType>::initialize(
- SectionTableRef SecTable) {
+ SectionTableRef SecTable) {
if (Link != SHN_UNDEF) {
Expected<SymTabType *> Sec = SecTable.getSectionOfType<SymTabType>(
- Link,
- "Link field value " + Twine(Link) + " in section " + Name +
- " is invalid",
- "Link field value " + Twine(Link) + " in section " + Name +
+ Link,
+ "Link field value " + Twine(Link) + " in section " + Name +
+ " is invalid",
+ "Link field value " + Twine(Link) + " in section " + Name +
" is not a symbol table");
if (!Sec)
return Sec.takeError();
-
+
setSymTab(*Sec);
}
@@ -945,467 +945,467 @@ Error RelocSectionWithSymtabBase<SymTabType>::initialize(
setSection(*Sec);
} else
- setSection(nullptr);
+ setSection(nullptr);
return Error::success();
-}
-
-template <class SymTabType>
-void RelocSectionWithSymtabBase<SymTabType>::finalize() {
- this->Link = Symbols ? Symbols->Index : 0;
-
- if (SecToApplyRel != nullptr)
- this->Info = SecToApplyRel->Index;
-}
-
-template <class ELFT>
+}
+
+template <class SymTabType>
+void RelocSectionWithSymtabBase<SymTabType>::finalize() {
+ this->Link = Symbols ? Symbols->Index : 0;
+
+ if (SecToApplyRel != nullptr)
+ this->Info = SecToApplyRel->Index;
+}
+
+template <class ELFT>
static void setAddend(Elf_Rel_Impl<ELFT, false> &, uint64_t) {}
-
-template <class ELFT>
-static void setAddend(Elf_Rel_Impl<ELFT, true> &Rela, uint64_t Addend) {
- Rela.r_addend = Addend;
-}
-
-template <class RelRange, class T>
-static void writeRel(const RelRange &Relocations, T *Buf) {
- for (const auto &Reloc : Relocations) {
- Buf->r_offset = Reloc.Offset;
- setAddend(*Buf, Reloc.Addend);
- Buf->setSymbolAndType(Reloc.RelocSymbol ? Reloc.RelocSymbol->Index : 0,
- Reloc.Type, false);
- ++Buf;
- }
-}
-
-template <class ELFT>
+
+template <class ELFT>
+static void setAddend(Elf_Rel_Impl<ELFT, true> &Rela, uint64_t Addend) {
+ Rela.r_addend = Addend;
+}
+
+template <class RelRange, class T>
+static void writeRel(const RelRange &Relocations, T *Buf) {
+ for (const auto &Reloc : Relocations) {
+ Buf->r_offset = Reloc.Offset;
+ setAddend(*Buf, Reloc.Addend);
+ Buf->setSymbolAndType(Reloc.RelocSymbol ? Reloc.RelocSymbol->Index : 0,
+ Reloc.Type, false);
+ ++Buf;
+ }
+}
+
+template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const RelocationSection &Sec) {
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
- if (Sec.Type == SHT_REL)
- writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf));
- else
- writeRel(Sec.Relocations, reinterpret_cast<Elf_Rela *>(Buf));
+ uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+ if (Sec.Type == SHT_REL)
+ writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf));
+ else
+ writeRel(Sec.Relocations, reinterpret_cast<Elf_Rela *>(Buf));
return Error::success();
-}
-
+}
+
Error RelocationSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error RelocationSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
-Error RelocationSection::removeSymbols(
- function_ref<bool(const Symbol &)> ToRemove) {
- for (const Relocation &Reloc : Relocations)
- if (Reloc.RelocSymbol && ToRemove(*Reloc.RelocSymbol))
- return createStringError(
- llvm::errc::invalid_argument,
- "not stripping symbol '%s' because it is named in a relocation",
- Reloc.RelocSymbol->Name.data());
- return Error::success();
-}
-
-void RelocationSection::markSymbols() {
- for (const Relocation &Reloc : Relocations)
- if (Reloc.RelocSymbol)
- Reloc.RelocSymbol->Referenced = true;
-}
-
-void RelocationSection::replaceSectionReferences(
- const DenseMap<SectionBase *, SectionBase *> &FromTo) {
- // Update the target section if it was replaced.
- if (SectionBase *To = FromTo.lookup(SecToApplyRel))
- SecToApplyRel = To;
-}
-
+}
+
+Error RelocationSection::removeSymbols(
+ function_ref<bool(const Symbol &)> ToRemove) {
+ for (const Relocation &Reloc : Relocations)
+ if (Reloc.RelocSymbol && ToRemove(*Reloc.RelocSymbol))
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "not stripping symbol '%s' because it is named in a relocation",
+ Reloc.RelocSymbol->Name.data());
+ return Error::success();
+}
+
+void RelocationSection::markSymbols() {
+ for (const Relocation &Reloc : Relocations)
+ if (Reloc.RelocSymbol)
+ Reloc.RelocSymbol->Referenced = true;
+}
+
+void RelocationSection::replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) {
+ // Update the target section if it was replaced.
+ if (SectionBase *To = FromTo.lookup(SecToApplyRel))
+ SecToApplyRel = To;
+}
+
Error SectionWriter::visit(const DynamicRelocationSection &Sec) {
- llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset);
+ llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset);
return Error::success();
-}
-
+}
+
Error DynamicRelocationSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
-Error DynamicRelocationSection::removeSectionReferences(
- bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
- if (ToRemove(Symbols)) {
- if (!AllowBrokenLinks)
- return createStringError(
- llvm::errc::invalid_argument,
- "symbol table '%s' cannot be removed because it is "
- "referenced by the relocation section '%s'",
- Symbols->Name.data(), this->Name.data());
- Symbols = nullptr;
- }
-
- // SecToApplyRel contains a section referenced by sh_info field. It keeps
- // a section to which the relocation section applies. When we remove any
- // sections we also remove their relocation sections. Since we do that much
- // earlier, this assert should never be triggered.
- assert(!SecToApplyRel || !ToRemove(SecToApplyRel));
- return Error::success();
-}
-
-Error Section::removeSectionReferences(
- bool AllowBrokenDependency,
- function_ref<bool(const SectionBase *)> ToRemove) {
- if (ToRemove(LinkSection)) {
- if (!AllowBrokenDependency)
- return createStringError(llvm::errc::invalid_argument,
- "section '%s' cannot be removed because it is "
- "referenced by the section '%s'",
- LinkSection->Name.data(), this->Name.data());
- LinkSection = nullptr;
- }
- return Error::success();
-}
-
-void GroupSection::finalize() {
- this->Info = Sym ? Sym->Index : 0;
- this->Link = SymTab ? SymTab->Index : 0;
-}
-
-Error GroupSection::removeSectionReferences(
- bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
- if (ToRemove(SymTab)) {
- if (!AllowBrokenLinks)
- return createStringError(
- llvm::errc::invalid_argument,
- "section '.symtab' cannot be removed because it is "
- "referenced by the group section '%s'",
- this->Name.data());
- SymTab = nullptr;
- Sym = nullptr;
- }
- llvm::erase_if(GroupMembers, ToRemove);
- return Error::success();
-}
-
-Error GroupSection::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
- if (ToRemove(*Sym))
- return createStringError(llvm::errc::invalid_argument,
- "symbol '%s' cannot be removed because it is "
- "referenced by the section '%s[%d]'",
- Sym->Name.data(), this->Name.data(), this->Index);
- return Error::success();
-}
-
-void GroupSection::markSymbols() {
- if (Sym)
- Sym->Referenced = true;
-}
-
-void GroupSection::replaceSectionReferences(
- const DenseMap<SectionBase *, SectionBase *> &FromTo) {
- for (SectionBase *&Sec : GroupMembers)
- if (SectionBase *To = FromTo.lookup(Sec))
- Sec = To;
-}
-
-void GroupSection::onRemove() {
- // As the header section of the group is removed, drop the Group flag in its
- // former members.
- for (SectionBase *Sec : GroupMembers)
- Sec->Flags &= ~SHF_GROUP;
-}
-
+}
+
+Error DynamicRelocationSection::removeSectionReferences(
+ bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
+ if (ToRemove(Symbols)) {
+ if (!AllowBrokenLinks)
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "symbol table '%s' cannot be removed because it is "
+ "referenced by the relocation section '%s'",
+ Symbols->Name.data(), this->Name.data());
+ Symbols = nullptr;
+ }
+
+ // SecToApplyRel contains a section referenced by sh_info field. It keeps
+ // a section to which the relocation section applies. When we remove any
+ // sections we also remove their relocation sections. Since we do that much
+ // earlier, this assert should never be triggered.
+ assert(!SecToApplyRel || !ToRemove(SecToApplyRel));
+ return Error::success();
+}
+
+Error Section::removeSectionReferences(
+ bool AllowBrokenDependency,
+ function_ref<bool(const SectionBase *)> ToRemove) {
+ if (ToRemove(LinkSection)) {
+ if (!AllowBrokenDependency)
+ return createStringError(llvm::errc::invalid_argument,
+ "section '%s' cannot be removed because it is "
+ "referenced by the section '%s'",
+ LinkSection->Name.data(), this->Name.data());
+ LinkSection = nullptr;
+ }
+ return Error::success();
+}
+
+void GroupSection::finalize() {
+ this->Info = Sym ? Sym->Index : 0;
+ this->Link = SymTab ? SymTab->Index : 0;
+}
+
+Error GroupSection::removeSectionReferences(
+ bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
+ if (ToRemove(SymTab)) {
+ if (!AllowBrokenLinks)
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "section '.symtab' cannot be removed because it is "
+ "referenced by the group section '%s'",
+ this->Name.data());
+ SymTab = nullptr;
+ Sym = nullptr;
+ }
+ llvm::erase_if(GroupMembers, ToRemove);
+ return Error::success();
+}
+
+Error GroupSection::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
+ if (ToRemove(*Sym))
+ return createStringError(llvm::errc::invalid_argument,
+ "symbol '%s' cannot be removed because it is "
+ "referenced by the section '%s[%d]'",
+ Sym->Name.data(), this->Name.data(), this->Index);
+ return Error::success();
+}
+
+void GroupSection::markSymbols() {
+ if (Sym)
+ Sym->Referenced = true;
+}
+
+void GroupSection::replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) {
+ for (SectionBase *&Sec : GroupMembers)
+ if (SectionBase *To = FromTo.lookup(Sec))
+ Sec = To;
+}
+
+void GroupSection::onRemove() {
+ // As the header section of the group is removed, drop the Group flag in its
+ // former members.
+ for (SectionBase *Sec : GroupMembers)
+ Sec->Flags &= ~SHF_GROUP;
+}
+
Error Section::initialize(SectionTableRef SecTable) {
- if (Link == ELF::SHN_UNDEF)
+ if (Link == ELF::SHN_UNDEF)
return Error::success();
Expected<SectionBase *> Sec =
- SecTable.getSection(Link, "Link field value " + Twine(Link) +
- " in section " + Name + " is invalid");
+ SecTable.getSection(Link, "Link field value " + Twine(Link) +
+ " in section " + Name + " is invalid");
if (!Sec)
return Sec.takeError();
LinkSection = *Sec;
- if (LinkSection->Type == ELF::SHT_SYMTAB)
- LinkSection = nullptr;
+ if (LinkSection->Type == ELF::SHT_SYMTAB)
+ LinkSection = nullptr;
return Error::success();
-}
-
-void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; }
-
-void GnuDebugLinkSection::init(StringRef File) {
- FileName = sys::path::filename(File);
- // The format for the .gnu_debuglink starts with the file name and is
- // followed by a null terminator and then the CRC32 of the file. The CRC32
- // should be 4 byte aligned. So we add the FileName size, a 1 for the null
- // byte, and then finally push the size to alignment and add 4.
- Size = alignTo(FileName.size() + 1, 4) + 4;
- // The CRC32 will only be aligned if we align the whole section.
- Align = 4;
- Type = OriginalType = ELF::SHT_PROGBITS;
- Name = ".gnu_debuglink";
- // For sections not found in segments, OriginalOffset is only used to
- // establish the order that sections should go in. By using the maximum
- // possible offset we cause this section to wind up at the end.
- OriginalOffset = std::numeric_limits<uint64_t>::max();
-}
-
-GnuDebugLinkSection::GnuDebugLinkSection(StringRef File,
- uint32_t PrecomputedCRC)
- : FileName(File), CRC32(PrecomputedCRC) {
- init(File);
-}
-
-template <class ELFT>
+}
+
+void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; }
+
+void GnuDebugLinkSection::init(StringRef File) {
+ FileName = sys::path::filename(File);
+ // The format for the .gnu_debuglink starts with the file name and is
+ // followed by a null terminator and then the CRC32 of the file. The CRC32
+ // should be 4 byte aligned. So we add the FileName size, a 1 for the null
+ // byte, and then finally push the size to alignment and add 4.
+ Size = alignTo(FileName.size() + 1, 4) + 4;
+ // The CRC32 will only be aligned if we align the whole section.
+ Align = 4;
+ Type = OriginalType = ELF::SHT_PROGBITS;
+ Name = ".gnu_debuglink";
+ // For sections not found in segments, OriginalOffset is only used to
+ // establish the order that sections should go in. By using the maximum
+ // possible offset we cause this section to wind up at the end.
+ OriginalOffset = std::numeric_limits<uint64_t>::max();
+}
+
+GnuDebugLinkSection::GnuDebugLinkSection(StringRef File,
+ uint32_t PrecomputedCRC)
+ : FileName(File), CRC32(PrecomputedCRC) {
+ init(File);
+}
+
+template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const GnuDebugLinkSection &Sec) {
- unsigned char *Buf = Out.getBufferStart() + Sec.Offset;
- Elf_Word *CRC =
- reinterpret_cast<Elf_Word *>(Buf + Sec.Size - sizeof(Elf_Word));
- *CRC = Sec.CRC32;
- llvm::copy(Sec.FileName, Buf);
+ unsigned char *Buf = Out.getBufferStart() + Sec.Offset;
+ Elf_Word *CRC =
+ reinterpret_cast<Elf_Word *>(Buf + Sec.Size - sizeof(Elf_Word));
+ *CRC = Sec.CRC32;
+ llvm::copy(Sec.FileName, Buf);
return Error::success();
-}
-
+}
+
Error GnuDebugLinkSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error GnuDebugLinkSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const GroupSection &Sec) {
- ELF::Elf32_Word *Buf =
- reinterpret_cast<ELF::Elf32_Word *>(Out.getBufferStart() + Sec.Offset);
- *Buf++ = Sec.FlagWord;
- for (SectionBase *S : Sec.GroupMembers)
- support::endian::write32<ELFT::TargetEndianness>(Buf++, S->Index);
+ ELF::Elf32_Word *Buf =
+ reinterpret_cast<ELF::Elf32_Word *>(Out.getBufferStart() + Sec.Offset);
+ *Buf++ = Sec.FlagWord;
+ for (SectionBase *S : Sec.GroupMembers)
+ support::endian::write32<ELFT::TargetEndianness>(Buf++, S->Index);
return Error::success();
-}
-
+}
+
Error GroupSection::accept(SectionVisitor &Visitor) const {
return Visitor.visit(*this);
-}
-
+}
+
Error GroupSection::accept(MutableSectionVisitor &Visitor) {
return Visitor.visit(*this);
-}
-
-// Returns true IFF a section is wholly inside the range of a segment
-static bool sectionWithinSegment(const SectionBase &Sec, const Segment &Seg) {
- // If a section is empty it should be treated like it has a size of 1. This is
- // to clarify the case when an empty section lies on a boundary between two
- // segments and ensures that the section "belongs" to the second segment and
- // not the first.
- uint64_t SecSize = Sec.Size ? Sec.Size : 1;
-
- if (Sec.Type == SHT_NOBITS) {
- if (!(Sec.Flags & SHF_ALLOC))
- return false;
-
- bool SectionIsTLS = Sec.Flags & SHF_TLS;
- bool SegmentIsTLS = Seg.Type == PT_TLS;
- if (SectionIsTLS != SegmentIsTLS)
- return false;
-
- return Seg.VAddr <= Sec.Addr &&
- Seg.VAddr + Seg.MemSize >= Sec.Addr + SecSize;
- }
-
- return Seg.Offset <= Sec.OriginalOffset &&
- Seg.Offset + Seg.FileSize >= Sec.OriginalOffset + SecSize;
-}
-
-// Returns true IFF a segment's original offset is inside of another segment's
-// range.
-static bool segmentOverlapsSegment(const Segment &Child,
- const Segment &Parent) {
-
- return Parent.OriginalOffset <= Child.OriginalOffset &&
- Parent.OriginalOffset + Parent.FileSize > Child.OriginalOffset;
-}
-
-static bool compareSegmentsByOffset(const Segment *A, const Segment *B) {
- // Any segment without a parent segment should come before a segment
- // that has a parent segment.
- if (A->OriginalOffset < B->OriginalOffset)
- return true;
- if (A->OriginalOffset > B->OriginalOffset)
- return false;
- return A->Index < B->Index;
-}
-
-void BasicELFBuilder::initFileHeader() {
- Obj->Flags = 0x0;
- Obj->Type = ET_REL;
- Obj->OSABI = ELFOSABI_NONE;
- Obj->ABIVersion = 0;
- Obj->Entry = 0x0;
- Obj->Machine = EM_NONE;
- Obj->Version = 1;
-}
-
-void BasicELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; }
-
-StringTableSection *BasicELFBuilder::addStrTab() {
- auto &StrTab = Obj->addSection<StringTableSection>();
- StrTab.Name = ".strtab";
-
- Obj->SectionNames = &StrTab;
- return &StrTab;
-}
-
-SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) {
- auto &SymTab = Obj->addSection<SymbolTableSection>();
-
- SymTab.Name = ".symtab";
- SymTab.Link = StrTab->Index;
-
- // The symbol table always needs a null symbol
- SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0);
-
- Obj->SymbolTable = &SymTab;
- return &SymTab;
-}
-
+}
+
+// Returns true IFF a section is wholly inside the range of a segment
+static bool sectionWithinSegment(const SectionBase &Sec, const Segment &Seg) {
+ // If a section is empty it should be treated like it has a size of 1. This is
+ // to clarify the case when an empty section lies on a boundary between two
+ // segments and ensures that the section "belongs" to the second segment and
+ // not the first.
+ uint64_t SecSize = Sec.Size ? Sec.Size : 1;
+
+ if (Sec.Type == SHT_NOBITS) {
+ if (!(Sec.Flags & SHF_ALLOC))
+ return false;
+
+ bool SectionIsTLS = Sec.Flags & SHF_TLS;
+ bool SegmentIsTLS = Seg.Type == PT_TLS;
+ if (SectionIsTLS != SegmentIsTLS)
+ return false;
+
+ return Seg.VAddr <= Sec.Addr &&
+ Seg.VAddr + Seg.MemSize >= Sec.Addr + SecSize;
+ }
+
+ return Seg.Offset <= Sec.OriginalOffset &&
+ Seg.Offset + Seg.FileSize >= Sec.OriginalOffset + SecSize;
+}
+
+// Returns true IFF a segment's original offset is inside of another segment's
+// range.
+static bool segmentOverlapsSegment(const Segment &Child,
+ const Segment &Parent) {
+
+ return Parent.OriginalOffset <= Child.OriginalOffset &&
+ Parent.OriginalOffset + Parent.FileSize > Child.OriginalOffset;
+}
+
+static bool compareSegmentsByOffset(const Segment *A, const Segment *B) {
+ // Any segment without a parent segment should come before a segment
+ // that has a parent segment.
+ if (A->OriginalOffset < B->OriginalOffset)
+ return true;
+ if (A->OriginalOffset > B->OriginalOffset)
+ return false;
+ return A->Index < B->Index;
+}
+
+void BasicELFBuilder::initFileHeader() {
+ Obj->Flags = 0x0;
+ Obj->Type = ET_REL;
+ Obj->OSABI = ELFOSABI_NONE;
+ Obj->ABIVersion = 0;
+ Obj->Entry = 0x0;
+ Obj->Machine = EM_NONE;
+ Obj->Version = 1;
+}
+
+void BasicELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; }
+
+StringTableSection *BasicELFBuilder::addStrTab() {
+ auto &StrTab = Obj->addSection<StringTableSection>();
+ StrTab.Name = ".strtab";
+
+ Obj->SectionNames = &StrTab;
+ return &StrTab;
+}
+
+SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) {
+ auto &SymTab = Obj->addSection<SymbolTableSection>();
+
+ SymTab.Name = ".symtab";
+ SymTab.Link = StrTab->Index;
+
+ // The symbol table always needs a null symbol
+ SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0);
+
+ Obj->SymbolTable = &SymTab;
+ return &SymTab;
+}
+
Error BasicELFBuilder::initSections() {
- for (SectionBase &Sec : Obj->sections())
+ for (SectionBase &Sec : Obj->sections())
if (Error Err = Sec.initialize(Obj->sections()))
return Err;
return Error::success();
-}
-
-void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
- auto Data = ArrayRef<uint8_t>(
- reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()),
- MemBuf->getBufferSize());
- auto &DataSection = Obj->addSection<Section>(Data);
- DataSection.Name = ".data";
- DataSection.Type = ELF::SHT_PROGBITS;
- DataSection.Size = Data.size();
- DataSection.Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE;
-
- std::string SanitizedFilename = MemBuf->getBufferIdentifier().str();
- std::replace_if(std::begin(SanitizedFilename), std::end(SanitizedFilename),
- [](char C) { return !isalnum(C); }, '_');
- Twine Prefix = Twine("_binary_") + SanitizedFilename;
-
- SymTab->addSymbol(Prefix + "_start", STB_GLOBAL, STT_NOTYPE, &DataSection,
- /*Value=*/0, NewSymbolVisibility, 0, 0);
- SymTab->addSymbol(Prefix + "_end", STB_GLOBAL, STT_NOTYPE, &DataSection,
- /*Value=*/DataSection.Size, NewSymbolVisibility, 0, 0);
- SymTab->addSymbol(Prefix + "_size", STB_GLOBAL, STT_NOTYPE, nullptr,
- /*Value=*/DataSection.Size, NewSymbolVisibility, SHN_ABS,
- 0);
-}
-
+}
+
+void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
+ auto Data = ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()),
+ MemBuf->getBufferSize());
+ auto &DataSection = Obj->addSection<Section>(Data);
+ DataSection.Name = ".data";
+ DataSection.Type = ELF::SHT_PROGBITS;
+ DataSection.Size = Data.size();
+ DataSection.Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE;
+
+ std::string SanitizedFilename = MemBuf->getBufferIdentifier().str();
+ std::replace_if(std::begin(SanitizedFilename), std::end(SanitizedFilename),
+ [](char C) { return !isalnum(C); }, '_');
+ Twine Prefix = Twine("_binary_") + SanitizedFilename;
+
+ SymTab->addSymbol(Prefix + "_start", STB_GLOBAL, STT_NOTYPE, &DataSection,
+ /*Value=*/0, NewSymbolVisibility, 0, 0);
+ SymTab->addSymbol(Prefix + "_end", STB_GLOBAL, STT_NOTYPE, &DataSection,
+ /*Value=*/DataSection.Size, NewSymbolVisibility, 0, 0);
+ SymTab->addSymbol(Prefix + "_size", STB_GLOBAL, STT_NOTYPE, nullptr,
+ /*Value=*/DataSection.Size, NewSymbolVisibility, SHN_ABS,
+ 0);
+}
+
Expected<std::unique_ptr<Object>> BinaryELFBuilder::build() {
- initFileHeader();
- initHeaderSegment();
-
- SymbolTableSection *SymTab = addSymTab(addStrTab());
+ initFileHeader();
+ initHeaderSegment();
+
+ SymbolTableSection *SymTab = addSymTab(addStrTab());
if (Error Err = initSections())
return std::move(Err);
- addData(SymTab);
-
- return std::move(Obj);
-}
-
-// Adds sections from IHEX data file. Data should have been
-// fully validated by this time.
-void IHexELFBuilder::addDataSections() {
- OwnedDataSection *Section = nullptr;
- uint64_t SegmentAddr = 0, BaseAddr = 0;
- uint32_t SecNo = 1;
-
- for (const IHexRecord &R : Records) {
- uint64_t RecAddr;
- switch (R.Type) {
- case IHexRecord::Data:
- // Ignore empty data records
- if (R.HexData.empty())
- continue;
- RecAddr = R.Addr + SegmentAddr + BaseAddr;
- if (!Section || Section->Addr + Section->Size != RecAddr)
- // OriginalOffset field is only used to sort section properly, so
- // instead of keeping track of real offset in IHEX file, we use
- // section number.
- Section = &Obj->addSection<OwnedDataSection>(
- ".sec" + std::to_string(SecNo++), RecAddr,
- ELF::SHF_ALLOC | ELF::SHF_WRITE, SecNo);
- Section->appendHexData(R.HexData);
- break;
- case IHexRecord::EndOfFile:
- break;
- case IHexRecord::SegmentAddr:
- // 20-bit segment address.
- SegmentAddr = checkedGetHex<uint16_t>(R.HexData) << 4;
- break;
- case IHexRecord::StartAddr80x86:
- case IHexRecord::StartAddr:
- Obj->Entry = checkedGetHex<uint32_t>(R.HexData);
- assert(Obj->Entry <= 0xFFFFFU);
- break;
- case IHexRecord::ExtendedAddr:
- // 16-31 bits of linear base address
- BaseAddr = checkedGetHex<uint16_t>(R.HexData) << 16;
- break;
- default:
- llvm_unreachable("unknown record type");
- }
- }
-}
-
+ addData(SymTab);
+
+ return std::move(Obj);
+}
+
+// Adds sections from IHEX data file. Data should have been
+// fully validated by this time.
+void IHexELFBuilder::addDataSections() {
+ OwnedDataSection *Section = nullptr;
+ uint64_t SegmentAddr = 0, BaseAddr = 0;
+ uint32_t SecNo = 1;
+
+ for (const IHexRecord &R : Records) {
+ uint64_t RecAddr;
+ switch (R.Type) {
+ case IHexRecord::Data:
+ // Ignore empty data records
+ if (R.HexData.empty())
+ continue;
+ RecAddr = R.Addr + SegmentAddr + BaseAddr;
+ if (!Section || Section->Addr + Section->Size != RecAddr)
+ // OriginalOffset field is only used to sort section properly, so
+ // instead of keeping track of real offset in IHEX file, we use
+ // section number.
+ Section = &Obj->addSection<OwnedDataSection>(
+ ".sec" + std::to_string(SecNo++), RecAddr,
+ ELF::SHF_ALLOC | ELF::SHF_WRITE, SecNo);
+ Section->appendHexData(R.HexData);
+ break;
+ case IHexRecord::EndOfFile:
+ break;
+ case IHexRecord::SegmentAddr:
+ // 20-bit segment address.
+ SegmentAddr = checkedGetHex<uint16_t>(R.HexData) << 4;
+ break;
+ case IHexRecord::StartAddr80x86:
+ case IHexRecord::StartAddr:
+ Obj->Entry = checkedGetHex<uint32_t>(R.HexData);
+ assert(Obj->Entry <= 0xFFFFFU);
+ break;
+ case IHexRecord::ExtendedAddr:
+ // 16-31 bits of linear base address
+ BaseAddr = checkedGetHex<uint16_t>(R.HexData) << 16;
+ break;
+ default:
+ llvm_unreachable("unknown record type");
+ }
+ }
+}
+
Expected<std::unique_ptr<Object>> IHexELFBuilder::build() {
- initFileHeader();
- initHeaderSegment();
- StringTableSection *StrTab = addStrTab();
- addSymTab(StrTab);
+ initFileHeader();
+ initHeaderSegment();
+ StringTableSection *StrTab = addStrTab();
+ addSymTab(StrTab);
if (Error Err = initSections())
return std::move(Err);
- addDataSections();
-
- return std::move(Obj);
-}
-
-template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) {
- for (Segment &Parent : Obj.segments()) {
- // Every segment will overlap with itself but we don't want a segment to
- // be its own parent so we avoid that situation.
- if (&Child != &Parent && segmentOverlapsSegment(Child, Parent)) {
- // We want a canonical "most parental" segment but this requires
- // inspecting the ParentSegment.
- if (compareSegmentsByOffset(&Parent, &Child))
- if (Child.ParentSegment == nullptr ||
- compareSegmentsByOffset(&Parent, Child.ParentSegment)) {
- Child.ParentSegment = &Parent;
- }
- }
- }
-}
-
+ addDataSections();
+
+ return std::move(Obj);
+}
+
+template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) {
+ for (Segment &Parent : Obj.segments()) {
+ // Every segment will overlap with itself but we don't want a segment to
+ // be its own parent so we avoid that situation.
+ if (&Child != &Parent && segmentOverlapsSegment(Child, Parent)) {
+ // We want a canonical "most parental" segment but this requires
+ // inspecting the ParentSegment.
+ if (compareSegmentsByOffset(&Parent, &Child))
+ if (Child.ParentSegment == nullptr ||
+ compareSegmentsByOffset(&Parent, Child.ParentSegment)) {
+ Child.ParentSegment = &Parent;
+ }
+ }
+ }
+}
+
template <class ELFT> Error ELFBuilder<ELFT>::findEhdrOffset() {
- if (!ExtractPartition)
+ if (!ExtractPartition)
return Error::success();
-
- for (const SectionBase &Sec : Obj.sections()) {
- if (Sec.Type == SHT_LLVM_PART_EHDR && Sec.Name == *ExtractPartition) {
- EhdrOffset = Sec.Offset;
+
+ for (const SectionBase &Sec : Obj.sections()) {
+ if (Sec.Type == SHT_LLVM_PART_EHDR && Sec.Name == *ExtractPartition) {
+ EhdrOffset = Sec.Offset;
return Error::success();
- }
- }
+ }
+ }
return createStringError(errc::invalid_argument,
"could not find partition named '" +
*ExtractPartition + "'");
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &HeadersFile) {
- uint32_t Index = 0;
+ uint32_t Index = 0;
Expected<typename ELFFile<ELFT>::Elf_Phdr_Range> Headers =
HeadersFile.program_headers();
@@ -1413,114 +1413,114 @@ Error ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &HeadersFile) {
return Headers.takeError();
for (const typename ELFFile<ELFT>::Elf_Phdr &Phdr : *Headers) {
- if (Phdr.p_offset + Phdr.p_filesz > HeadersFile.getBufSize())
+ if (Phdr.p_offset + Phdr.p_filesz > HeadersFile.getBufSize())
return createStringError(
errc::invalid_argument,
"program header with offset 0x" + Twine::utohexstr(Phdr.p_offset) +
" and file size 0x" + Twine::utohexstr(Phdr.p_filesz) +
" goes past the end of the file");
-
- ArrayRef<uint8_t> Data{HeadersFile.base() + Phdr.p_offset,
- (size_t)Phdr.p_filesz};
- Segment &Seg = Obj.addSegment(Data);
- Seg.Type = Phdr.p_type;
- Seg.Flags = Phdr.p_flags;
- Seg.OriginalOffset = Phdr.p_offset + EhdrOffset;
- Seg.Offset = Phdr.p_offset + EhdrOffset;
- Seg.VAddr = Phdr.p_vaddr;
- Seg.PAddr = Phdr.p_paddr;
- Seg.FileSize = Phdr.p_filesz;
- Seg.MemSize = Phdr.p_memsz;
- Seg.Align = Phdr.p_align;
- Seg.Index = Index++;
- for (SectionBase &Sec : Obj.sections())
- if (sectionWithinSegment(Sec, Seg)) {
- Seg.addSection(&Sec);
- if (!Sec.ParentSegment || Sec.ParentSegment->Offset > Seg.Offset)
- Sec.ParentSegment = &Seg;
- }
- }
-
- auto &ElfHdr = Obj.ElfHdrSegment;
- ElfHdr.Index = Index++;
- ElfHdr.OriginalOffset = ElfHdr.Offset = EhdrOffset;
-
+
+ ArrayRef<uint8_t> Data{HeadersFile.base() + Phdr.p_offset,
+ (size_t)Phdr.p_filesz};
+ Segment &Seg = Obj.addSegment(Data);
+ Seg.Type = Phdr.p_type;
+ Seg.Flags = Phdr.p_flags;
+ Seg.OriginalOffset = Phdr.p_offset + EhdrOffset;
+ Seg.Offset = Phdr.p_offset + EhdrOffset;
+ Seg.VAddr = Phdr.p_vaddr;
+ Seg.PAddr = Phdr.p_paddr;
+ Seg.FileSize = Phdr.p_filesz;
+ Seg.MemSize = Phdr.p_memsz;
+ Seg.Align = Phdr.p_align;
+ Seg.Index = Index++;
+ for (SectionBase &Sec : Obj.sections())
+ if (sectionWithinSegment(Sec, Seg)) {
+ Seg.addSection(&Sec);
+ if (!Sec.ParentSegment || Sec.ParentSegment->Offset > Seg.Offset)
+ Sec.ParentSegment = &Seg;
+ }
+ }
+
+ auto &ElfHdr = Obj.ElfHdrSegment;
+ ElfHdr.Index = Index++;
+ ElfHdr.OriginalOffset = ElfHdr.Offset = EhdrOffset;
+
const typename ELFT::Ehdr &Ehdr = HeadersFile.getHeader();
- auto &PrHdr = Obj.ProgramHdrSegment;
- PrHdr.Type = PT_PHDR;
- PrHdr.Flags = 0;
- // The spec requires us to have p_vaddr % p_align == p_offset % p_align.
- // Whereas this works automatically for ElfHdr, here OriginalOffset is
- // always non-zero and to ensure the equation we assign the same value to
- // VAddr as well.
- PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = EhdrOffset + Ehdr.e_phoff;
- PrHdr.PAddr = 0;
- PrHdr.FileSize = PrHdr.MemSize = Ehdr.e_phentsize * Ehdr.e_phnum;
- // The spec requires us to naturally align all the fields.
- PrHdr.Align = sizeof(Elf_Addr);
- PrHdr.Index = Index++;
-
- // Now we do an O(n^2) loop through the segments in order to match up
- // segments.
- for (Segment &Child : Obj.segments())
- setParentSegment(Child);
- setParentSegment(ElfHdr);
- setParentSegment(PrHdr);
+ auto &PrHdr = Obj.ProgramHdrSegment;
+ PrHdr.Type = PT_PHDR;
+ PrHdr.Flags = 0;
+ // The spec requires us to have p_vaddr % p_align == p_offset % p_align.
+ // Whereas this works automatically for ElfHdr, here OriginalOffset is
+ // always non-zero and to ensure the equation we assign the same value to
+ // VAddr as well.
+ PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = EhdrOffset + Ehdr.e_phoff;
+ PrHdr.PAddr = 0;
+ PrHdr.FileSize = PrHdr.MemSize = Ehdr.e_phentsize * Ehdr.e_phnum;
+ // The spec requires us to naturally align all the fields.
+ PrHdr.Align = sizeof(Elf_Addr);
+ PrHdr.Index = Index++;
+
+ // Now we do an O(n^2) loop through the segments in order to match up
+ // segments.
+ for (Segment &Child : Obj.segments())
+ setParentSegment(Child);
+ setParentSegment(ElfHdr);
+ setParentSegment(PrHdr);
return Error::success();
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) {
- if (GroupSec->Align % sizeof(ELF::Elf32_Word) != 0)
+ if (GroupSec->Align % sizeof(ELF::Elf32_Word) != 0)
return createStringError(errc::invalid_argument,
"invalid alignment " + Twine(GroupSec->Align) +
" of group section '" + GroupSec->Name + "'");
- SectionTableRef SecTable = Obj.sections();
- if (GroupSec->Link != SHN_UNDEF) {
- auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>(
- GroupSec->Link,
- "link field value '" + Twine(GroupSec->Link) + "' in section '" +
- GroupSec->Name + "' is invalid",
- "link field value '" + Twine(GroupSec->Link) + "' in section '" +
- GroupSec->Name + "' is not a symbol table");
+ SectionTableRef SecTable = Obj.sections();
+ if (GroupSec->Link != SHN_UNDEF) {
+ auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>(
+ GroupSec->Link,
+ "link field value '" + Twine(GroupSec->Link) + "' in section '" +
+ GroupSec->Name + "' is invalid",
+ "link field value '" + Twine(GroupSec->Link) + "' in section '" +
+ GroupSec->Name + "' is not a symbol table");
if (!SymTab)
return SymTab.takeError();
Expected<Symbol *> Sym = (*SymTab)->getSymbolByIndex(GroupSec->Info);
- if (!Sym)
+ if (!Sym)
return createStringError(errc::invalid_argument,
"info field value '" + Twine(GroupSec->Info) +
"' in section '" + GroupSec->Name +
"' is not a valid symbol index");
GroupSec->setSymTab(*SymTab);
GroupSec->setSymbol(*Sym);
- }
- if (GroupSec->Contents.size() % sizeof(ELF::Elf32_Word) ||
- GroupSec->Contents.empty())
+ }
+ if (GroupSec->Contents.size() % sizeof(ELF::Elf32_Word) ||
+ GroupSec->Contents.empty())
return createStringError(errc::invalid_argument,
"the content of the section " + GroupSec->Name +
" is malformed");
- const ELF::Elf32_Word *Word =
- reinterpret_cast<const ELF::Elf32_Word *>(GroupSec->Contents.data());
- const ELF::Elf32_Word *End =
- Word + GroupSec->Contents.size() / sizeof(ELF::Elf32_Word);
- GroupSec->setFlagWord(*Word++);
- for (; Word != End; ++Word) {
- uint32_t Index = support::endian::read32<ELFT::TargetEndianness>(Word);
+ const ELF::Elf32_Word *Word =
+ reinterpret_cast<const ELF::Elf32_Word *>(GroupSec->Contents.data());
+ const ELF::Elf32_Word *End =
+ Word + GroupSec->Contents.size() / sizeof(ELF::Elf32_Word);
+ GroupSec->setFlagWord(*Word++);
+ for (; Word != End; ++Word) {
+ uint32_t Index = support::endian::read32<ELFT::TargetEndianness>(Word);
Expected<SectionBase *> Sec = SecTable.getSection(
- Index, "group member index " + Twine(Index) + " in section '" +
+ Index, "group member index " + Twine(Index) + " in section '" +
GroupSec->Name + "' is invalid");
if (!Sec)
return Sec.takeError();
GroupSec->addMember(*Sec);
- }
+ }
return Error::success();
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Error ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) {
Expected<const Elf_Shdr *> Shdr = ElfFile.getSection(SymTab->Index);
if (!Shdr)
@@ -1530,27 +1530,27 @@ Error ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) {
if (!StrTabData)
return StrTabData.takeError();
- ArrayRef<Elf_Word> ShndxData;
-
+ ArrayRef<Elf_Word> ShndxData;
+
Expected<typename ELFFile<ELFT>::Elf_Sym_Range> Symbols =
ElfFile.symbols(*Shdr);
if (!Symbols)
return Symbols.takeError();
for (const typename ELFFile<ELFT>::Elf_Sym &Sym : *Symbols) {
- SectionBase *DefSection = nullptr;
-
+ SectionBase *DefSection = nullptr;
+
Expected<StringRef> Name = Sym.getName(*StrTabData);
if (!Name)
return Name.takeError();
- if (Sym.st_shndx == SHN_XINDEX) {
- if (SymTab->getShndxTable() == nullptr)
+ if (Sym.st_shndx == SHN_XINDEX) {
+ if (SymTab->getShndxTable() == nullptr)
return createStringError(errc::invalid_argument,
"symbol '" + *Name +
"' has index SHN_XINDEX but no "
"SHT_SYMTAB_SHNDX section exists");
- if (ShndxData.data() == nullptr) {
+ if (ShndxData.data() == nullptr) {
Expected<const Elf_Shdr *> ShndxSec =
ElfFile.getSection(SymTab->getShndxTable()->Index);
if (!ShndxSec)
@@ -1567,61 +1567,61 @@ Error ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) {
errc::invalid_argument,
"symbol section index table does not have the same number of "
"entries as the symbol table");
- }
+ }
Elf_Word Index = ShndxData[&Sym - Symbols->begin()];
Expected<SectionBase *> Sec = Obj.sections().getSection(
- Index,
+ Index,
"symbol '" + *Name + "' has invalid section index " + Twine(Index));
if (!Sec)
return Sec.takeError();
DefSection = *Sec;
- } else if (Sym.st_shndx >= SHN_LORESERVE) {
- if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) {
+ } else if (Sym.st_shndx >= SHN_LORESERVE) {
+ if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) {
return createStringError(
errc::invalid_argument,
"symbol '" + *Name +
"' has unsupported value greater than or equal "
"to SHN_LORESERVE: " +
Twine(Sym.st_shndx));
- }
- } else if (Sym.st_shndx != SHN_UNDEF) {
+ }
+ } else if (Sym.st_shndx != SHN_UNDEF) {
Expected<SectionBase *> Sec = Obj.sections().getSection(
Sym.st_shndx, "symbol '" + *Name +
- "' is defined has invalid section index " +
- Twine(Sym.st_shndx));
+ "' is defined has invalid section index " +
+ Twine(Sym.st_shndx));
if (!Sec)
return Sec.takeError();
DefSection = *Sec;
- }
-
+ }
+
SymTab->addSymbol(*Name, Sym.getBinding(), Sym.getType(), DefSection,
- Sym.getValue(), Sym.st_other, Sym.st_shndx, Sym.st_size);
- }
+ Sym.getValue(), Sym.st_other, Sym.st_shndx, Sym.st_size);
+ }
return Error::success();
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
static void getAddend(uint64_t &, const Elf_Rel_Impl<ELFT, false> &) {}
-
-template <class ELFT>
-static void getAddend(uint64_t &ToSet, const Elf_Rel_Impl<ELFT, true> &Rela) {
- ToSet = Rela.r_addend;
-}
-
-template <class T>
+
+template <class ELFT>
+static void getAddend(uint64_t &ToSet, const Elf_Rel_Impl<ELFT, true> &Rela) {
+ ToSet = Rela.r_addend;
+}
+
+template <class T>
static Error initRelocations(RelocationSection *Relocs,
SymbolTableSection *SymbolTable, T RelRange) {
- for (const auto &Rel : RelRange) {
- Relocation ToAdd;
- ToAdd.Offset = Rel.r_offset;
- getAddend(ToAdd.Addend, Rel);
- ToAdd.Type = Rel.getType(false);
-
- if (uint32_t Sym = Rel.getSymbol(false)) {
- if (!SymbolTable)
+ for (const auto &Rel : RelRange) {
+ Relocation ToAdd;
+ ToAdd.Offset = Rel.r_offset;
+ getAddend(ToAdd.Addend, Rel);
+ ToAdd.Type = Rel.getType(false);
+
+ if (uint32_t Sym = Rel.getSymbol(false)) {
+ if (!SymbolTable)
return createStringError(
errc::invalid_argument,
"'" + Relocs->Name + "': relocation references symbol with index " +
@@ -1631,22 +1631,22 @@ static Error initRelocations(RelocationSection *Relocs,
return SymByIndex.takeError();
ToAdd.RelocSymbol = *SymByIndex;
- }
-
- Relocs->addRelocation(ToAdd);
- }
+ }
+
+ Relocs->addRelocation(ToAdd);
+ }
return Error::success();
-}
-
+}
+
Expected<SectionBase *> SectionTableRef::getSection(uint32_t Index,
Twine ErrMsg) {
- if (Index == SHN_UNDEF || Index > Sections.size())
+ if (Index == SHN_UNDEF || Index > Sections.size())
return createStringError(errc::invalid_argument, ErrMsg);
- return Sections[Index - 1].get();
-}
-
-template <class T>
+ return Sections[Index - 1].get();
+}
+
+template <class T>
Expected<T *> SectionTableRef::getSectionOfType(uint32_t Index,
Twine IndexErrMsg,
Twine TypeErrMsg) {
@@ -1655,81 +1655,81 @@ Expected<T *> SectionTableRef::getSectionOfType(uint32_t Index,
return BaseSec.takeError();
if (T *Sec = dyn_cast<T>(*BaseSec))
- return Sec;
+ return Sec;
return createStringError(errc::invalid_argument, TypeErrMsg);
-}
-
-template <class ELFT>
+}
+
+template <class ELFT>
Expected<SectionBase &> ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) {
- switch (Shdr.sh_type) {
- case SHT_REL:
- case SHT_RELA:
- if (Shdr.sh_flags & SHF_ALLOC) {
+ switch (Shdr.sh_type) {
+ case SHT_REL:
+ case SHT_RELA:
+ if (Shdr.sh_flags & SHF_ALLOC) {
if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr))
return Obj.addSection<DynamicRelocationSection>(*Data);
else
return Data.takeError();
- }
- return Obj.addSection<RelocationSection>();
- case SHT_STRTAB:
- // If a string table is allocated we don't want to mess with it. That would
- // mean altering the memory image. There are no special link types or
- // anything so we can just use a Section.
- if (Shdr.sh_flags & SHF_ALLOC) {
+ }
+ return Obj.addSection<RelocationSection>();
+ case SHT_STRTAB:
+ // If a string table is allocated we don't want to mess with it. That would
+ // mean altering the memory image. There are no special link types or
+ // anything so we can just use a Section.
+ if (Shdr.sh_flags & SHF_ALLOC) {
if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr))
return Obj.addSection<Section>(*Data);
else
return Data.takeError();
- }
- return Obj.addSection<StringTableSection>();
- case SHT_HASH:
- case SHT_GNU_HASH:
- // Hash tables should refer to SHT_DYNSYM which we're not going to change.
- // Because of this we don't need to mess with the hash tables either.
+ }
+ return Obj.addSection<StringTableSection>();
+ case SHT_HASH:
+ case SHT_GNU_HASH:
+ // Hash tables should refer to SHT_DYNSYM which we're not going to change.
+ // Because of this we don't need to mess with the hash tables either.
if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr))
return Obj.addSection<Section>(*Data);
else
return Data.takeError();
- case SHT_GROUP:
+ case SHT_GROUP:
if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr))
return Obj.addSection<GroupSection>(*Data);
else
return Data.takeError();
- case SHT_DYNSYM:
+ case SHT_DYNSYM:
if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr))
return Obj.addSection<DynamicSymbolTableSection>(*Data);
else
return Data.takeError();
- case SHT_DYNAMIC:
+ case SHT_DYNAMIC:
if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr))
return Obj.addSection<DynamicSection>(*Data);
else
return Data.takeError();
- case SHT_SYMTAB: {
- auto &SymTab = Obj.addSection<SymbolTableSection>();
- Obj.SymbolTable = &SymTab;
- return SymTab;
- }
- case SHT_SYMTAB_SHNDX: {
- auto &ShndxSection = Obj.addSection<SectionIndexSection>();
- Obj.SectionIndexTable = &ShndxSection;
- return ShndxSection;
- }
- case SHT_NOBITS:
+ case SHT_SYMTAB: {
+ auto &SymTab = Obj.addSection<SymbolTableSection>();
+ Obj.SymbolTable = &SymTab;
+ return SymTab;
+ }
+ case SHT_SYMTAB_SHNDX: {
+ auto &ShndxSection = Obj.addSection<SectionIndexSection>();
+ Obj.SectionIndexTable = &ShndxSection;
+ return ShndxSection;
+ }
+ case SHT_NOBITS:
return Obj.addSection<Section>(ArrayRef<uint8_t>());
- default: {
+ default: {
Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr);
if (!Data)
return Data.takeError();
-
+
Expected<StringRef> Name = ElfFile.getSectionName(Shdr);
if (!Name)
return Name.takeError();
if (Name->startswith(".zdebug") || (Shdr.sh_flags & ELF::SHF_COMPRESSED)) {
- uint64_t DecompressedSize, DecompressedAlign;
- std::tie(DecompressedSize, DecompressedAlign) =
+ uint64_t DecompressedSize, DecompressedAlign;
+ std::tie(DecompressedSize, DecompressedAlign) =
getDecompressedSizeAndAlignment<ELFT>(*Data);
Expected<CompressedSection> NewSection =
CompressedSection::create(*Data, DecompressedSize, DecompressedAlign);
@@ -1737,25 +1737,25 @@ Expected<SectionBase &> ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) {
return NewSection.takeError();
return Obj.addSection<CompressedSection>(std::move(*NewSection));
- }
-
+ }
+
return Obj.addSection<Section>(*Data);
- }
- }
-}
-
+ }
+ }
+}
+
template <class ELFT> Error ELFBuilder<ELFT>::readSectionHeaders() {
- uint32_t Index = 0;
+ uint32_t Index = 0;
Expected<typename ELFFile<ELFT>::Elf_Shdr_Range> Sections =
ElfFile.sections();
if (!Sections)
return Sections.takeError();
for (const typename ELFFile<ELFT>::Elf_Shdr &Shdr : *Sections) {
- if (Index == 0) {
- ++Index;
- continue;
- }
+ if (Index == 0) {
+ ++Index;
+ continue;
+ }
Expected<SectionBase &> Sec = makeSection(Shdr);
if (!Sec)
return Sec.takeError();
@@ -1777,68 +1777,68 @@ template <class ELFT> Error ELFBuilder<ELFT>::readSectionHeaders() {
Sec->Index = Index++;
Sec->OriginalIndex = Sec->Index;
Sec->OriginalData =
- ArrayRef<uint8_t>(ElfFile.base() + Shdr.sh_offset,
- (Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size);
- }
+ ArrayRef<uint8_t>(ElfFile.base() + Shdr.sh_offset,
+ (Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size);
+ }
return Error::success();
-}
-
+}
+
template <class ELFT> Error ELFBuilder<ELFT>::readSections(bool EnsureSymtab) {
uint32_t ShstrIndex = ElfFile.getHeader().e_shstrndx;
if (ShstrIndex == SHN_XINDEX) {
Expected<const Elf_Shdr *> Sec = ElfFile.getSection(0);
if (!Sec)
return Sec.takeError();
-
+
ShstrIndex = (*Sec)->sh_link;
}
- if (ShstrIndex == SHN_UNDEF)
- Obj.HadShdrs = false;
+ if (ShstrIndex == SHN_UNDEF)
+ Obj.HadShdrs = false;
else {
Expected<StringTableSection *> Sec =
- Obj.sections().template getSectionOfType<StringTableSection>(
- ShstrIndex,
- "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " +
- " is invalid",
- "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " +
- " does not reference a string table");
+ Obj.sections().template getSectionOfType<StringTableSection>(
+ ShstrIndex,
+ "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " +
+ " is invalid",
+ "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " +
+ " does not reference a string table");
if (!Sec)
return Sec.takeError();
-
+
Obj.SectionNames = *Sec;
}
- // If a section index table exists we'll need to initialize it before we
- // initialize the symbol table because the symbol table might need to
- // reference it.
- if (Obj.SectionIndexTable)
+ // If a section index table exists we'll need to initialize it before we
+ // initialize the symbol table because the symbol table might need to
+ // reference it.
+ if (Obj.SectionIndexTable)
if (Error Err = Obj.SectionIndexTable->initialize(Obj.sections()))
return Err;
-
- // Now that all of the sections have been added we can fill out some extra
- // details about symbol tables. We need the symbol table filled out before
- // any relocations.
- if (Obj.SymbolTable) {
+
+ // Now that all of the sections have been added we can fill out some extra
+ // details about symbol tables. We need the symbol table filled out before
+ // any relocations.
+ if (Obj.SymbolTable) {
if (Error Err = Obj.SymbolTable->initialize(Obj.sections()))
return Err;
if (Error Err = initSymbolTable(Obj.SymbolTable))
return Err;
- } else if (EnsureSymtab) {
+ } else if (EnsureSymtab) {
if (Error Err = Obj.addNewSymbolTable())
return Err;
- }
-
- // Now that all sections and symbols have been added we can add
- // relocations that reference symbols and set the link and info fields for
- // relocation sections.
+ }
+
+ // Now that all sections and symbols have been added we can add
+ // relocations that reference symbols and set the link and info fields for
+ // relocation sections.
for (SectionBase &Sec : Obj.sections()) {
- if (&Sec == Obj.SymbolTable)
- continue;
+ if (&Sec == Obj.SymbolTable)
+ continue;
if (Error Err = Sec.initialize(Obj.sections()))
return Err;
- if (auto RelSec = dyn_cast<RelocationSection>(&Sec)) {
+ if (auto RelSec = dyn_cast<RelocationSection>(&Sec)) {
Expected<typename ELFFile<ELFT>::Elf_Shdr_Range> Sections =
ElfFile.sections();
if (!Sections)
@@ -1863,78 +1863,78 @@ template <class ELFT> Error ELFBuilder<ELFT>::readSections(bool EnsureSymtab) {
if (Error Err = initRelocations(RelSec, Obj.SymbolTable, *Relas))
return Err;
}
- } else if (auto GroupSec = dyn_cast<GroupSection>(&Sec)) {
+ } else if (auto GroupSec = dyn_cast<GroupSection>(&Sec)) {
if (Error Err = initGroupSection(GroupSec))
return Err;
- }
- }
+ }
+ }
return Error::success();
-}
-
+}
+
template <class ELFT> Error ELFBuilder<ELFT>::build(bool EnsureSymtab) {
if (Error E = readSectionHeaders())
return E;
if (Error E = findEhdrOffset())
return E;
-
- // The ELFFile whose ELF headers and program headers are copied into the
- // output file. Normally the same as ElfFile, but if we're extracting a
- // loadable partition it will point to the partition's headers.
+
+ // The ELFFile whose ELF headers and program headers are copied into the
+ // output file. Normally the same as ElfFile, but if we're extracting a
+ // loadable partition it will point to the partition's headers.
Expected<ELFFile<ELFT>> HeadersFile = ELFFile<ELFT>::create(toStringRef(
{ElfFile.base() + EhdrOffset, ElfFile.getBufSize() - EhdrOffset}));
if (!HeadersFile)
return HeadersFile.takeError();
-
+
const typename ELFFile<ELFT>::Elf_Ehdr &Ehdr = HeadersFile->getHeader();
- Obj.OSABI = Ehdr.e_ident[EI_OSABI];
- Obj.ABIVersion = Ehdr.e_ident[EI_ABIVERSION];
- Obj.Type = Ehdr.e_type;
- Obj.Machine = Ehdr.e_machine;
- Obj.Version = Ehdr.e_version;
- Obj.Entry = Ehdr.e_entry;
- Obj.Flags = Ehdr.e_flags;
-
+ Obj.OSABI = Ehdr.e_ident[EI_OSABI];
+ Obj.ABIVersion = Ehdr.e_ident[EI_ABIVERSION];
+ Obj.Type = Ehdr.e_type;
+ Obj.Machine = Ehdr.e_machine;
+ Obj.Version = Ehdr.e_version;
+ Obj.Entry = Ehdr.e_entry;
+ Obj.Flags = Ehdr.e_flags;
+
if (Error E = readSections(EnsureSymtab))
return E;
return readProgramHeaders(*HeadersFile);
-}
-
-Writer::~Writer() {}
-
-Reader::~Reader() {}
-
+}
+
+Writer::~Writer() {}
+
+Reader::~Reader() {}
+
Expected<std::unique_ptr<Object>>
BinaryReader::create(bool /*EnsureSymtab*/) const {
- return BinaryELFBuilder(MemBuf, NewSymbolVisibility).build();
-}
-
-Expected<std::vector<IHexRecord>> IHexReader::parse() const {
- SmallVector<StringRef, 16> Lines;
- std::vector<IHexRecord> Records;
- bool HasSections = false;
-
- MemBuf->getBuffer().split(Lines, '\n');
- Records.reserve(Lines.size());
- for (size_t LineNo = 1; LineNo <= Lines.size(); ++LineNo) {
- StringRef Line = Lines[LineNo - 1].trim();
- if (Line.empty())
- continue;
-
- Expected<IHexRecord> R = IHexRecord::parse(Line);
- if (!R)
- return parseError(LineNo, R.takeError());
- if (R->Type == IHexRecord::EndOfFile)
- break;
- HasSections |= (R->Type == IHexRecord::Data);
- Records.push_back(*R);
- }
- if (!HasSections)
- return parseError(-1U, "no sections");
-
- return std::move(Records);
-}
-
+ return BinaryELFBuilder(MemBuf, NewSymbolVisibility).build();
+}
+
+Expected<std::vector<IHexRecord>> IHexReader::parse() const {
+ SmallVector<StringRef, 16> Lines;
+ std::vector<IHexRecord> Records;
+ bool HasSections = false;
+
+ MemBuf->getBuffer().split(Lines, '\n');
+ Records.reserve(Lines.size());
+ for (size_t LineNo = 1; LineNo <= Lines.size(); ++LineNo) {
+ StringRef Line = Lines[LineNo - 1].trim();
+ if (Line.empty())
+ continue;
+
+ Expected<IHexRecord> R = IHexRecord::parse(Line);
+ if (!R)
+ return parseError(LineNo, R.takeError());
+ if (R->Type == IHexRecord::EndOfFile)
+ break;
+ HasSections |= (R->Type == IHexRecord::Data);
+ Records.push_back(*R);
+ }
+ if (!HasSections)
+ return parseError(-1U, "no sections");
+
+ return std::move(Records);
+}
+
Expected<std::unique_ptr<Object>>
IHexReader::create(bool /*EnsureSymtab*/) const {
Expected<std::vector<IHexRecord>> Records = parse();
@@ -1942,375 +1942,375 @@ IHexReader::create(bool /*EnsureSymtab*/) const {
return Records.takeError();
return IHexELFBuilder(*Records).build();
-}
-
+}
+
Expected<std::unique_ptr<Object>> ELFReader::create(bool EnsureSymtab) const {
- auto Obj = std::make_unique<Object>();
- if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
- ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition);
+ auto Obj = std::make_unique<Object>();
+ if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
+ ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition);
if (Error Err = Builder.build(EnsureSymtab))
return std::move(Err);
return std::move(Obj);
- } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
- ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition);
+ } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
+ ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition);
if (Error Err = Builder.build(EnsureSymtab))
return std::move(Err);
return std::move(Obj);
- } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
- ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition);
+ } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
+ ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition);
if (Error Err = Builder.build(EnsureSymtab))
return std::move(Err);
return std::move(Obj);
- } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
- ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition);
+ } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
+ ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition);
if (Error Err = Builder.build(EnsureSymtab))
return std::move(Err);
return std::move(Obj);
- }
+ }
return createStringError(errc::invalid_argument, "invalid file type");
-}
-
-template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
- Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf.getBufferStart());
- std::fill(Ehdr.e_ident, Ehdr.e_ident + 16, 0);
- Ehdr.e_ident[EI_MAG0] = 0x7f;
- Ehdr.e_ident[EI_MAG1] = 'E';
- Ehdr.e_ident[EI_MAG2] = 'L';
- Ehdr.e_ident[EI_MAG3] = 'F';
- Ehdr.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
- Ehdr.e_ident[EI_DATA] =
- ELFT::TargetEndianness == support::big ? ELFDATA2MSB : ELFDATA2LSB;
- Ehdr.e_ident[EI_VERSION] = EV_CURRENT;
- Ehdr.e_ident[EI_OSABI] = Obj.OSABI;
- Ehdr.e_ident[EI_ABIVERSION] = Obj.ABIVersion;
-
- Ehdr.e_type = Obj.Type;
- Ehdr.e_machine = Obj.Machine;
- Ehdr.e_version = Obj.Version;
- Ehdr.e_entry = Obj.Entry;
- // We have to use the fully-qualified name llvm::size
- // since some compilers complain on ambiguous resolution.
- Ehdr.e_phnum = llvm::size(Obj.segments());
- Ehdr.e_phoff = (Ehdr.e_phnum != 0) ? Obj.ProgramHdrSegment.Offset : 0;
- Ehdr.e_phentsize = (Ehdr.e_phnum != 0) ? sizeof(Elf_Phdr) : 0;
- Ehdr.e_flags = Obj.Flags;
- Ehdr.e_ehsize = sizeof(Elf_Ehdr);
- if (WriteSectionHeaders && Obj.sections().size() != 0) {
- Ehdr.e_shentsize = sizeof(Elf_Shdr);
- Ehdr.e_shoff = Obj.SHOff;
- // """
- // If the number of sections is greater than or equal to
- // SHN_LORESERVE (0xff00), this member has the value zero and the actual
- // number of section header table entries is contained in the sh_size field
- // of the section header at index 0.
- // """
- auto Shnum = Obj.sections().size() + 1;
- if (Shnum >= SHN_LORESERVE)
- Ehdr.e_shnum = 0;
- else
- Ehdr.e_shnum = Shnum;
- // """
- // If the section name string table section index is greater than or equal
- // to SHN_LORESERVE (0xff00), this member has the value SHN_XINDEX (0xffff)
- // and the actual index of the section name string table section is
- // contained in the sh_link field of the section header at index 0.
- // """
- if (Obj.SectionNames->Index >= SHN_LORESERVE)
- Ehdr.e_shstrndx = SHN_XINDEX;
- else
- Ehdr.e_shstrndx = Obj.SectionNames->Index;
- } else {
- Ehdr.e_shentsize = 0;
- Ehdr.e_shoff = 0;
- Ehdr.e_shnum = 0;
- Ehdr.e_shstrndx = 0;
- }
-}
-
-template <class ELFT> void ELFWriter<ELFT>::writePhdrs() {
- for (auto &Seg : Obj.segments())
- writePhdr(Seg);
-}
-
-template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {
- // This reference serves to write the dummy section header at the begining
- // of the file. It is not used for anything else
- Elf_Shdr &Shdr =
- *reinterpret_cast<Elf_Shdr *>(Buf.getBufferStart() + Obj.SHOff);
- Shdr.sh_name = 0;
- Shdr.sh_type = SHT_NULL;
- Shdr.sh_flags = 0;
- Shdr.sh_addr = 0;
- Shdr.sh_offset = 0;
- // See writeEhdr for why we do this.
- uint64_t Shnum = Obj.sections().size() + 1;
- if (Shnum >= SHN_LORESERVE)
- Shdr.sh_size = Shnum;
- else
- Shdr.sh_size = 0;
- // See writeEhdr for why we do this.
- if (Obj.SectionNames != nullptr && Obj.SectionNames->Index >= SHN_LORESERVE)
- Shdr.sh_link = Obj.SectionNames->Index;
- else
- Shdr.sh_link = 0;
- Shdr.sh_info = 0;
- Shdr.sh_addralign = 0;
- Shdr.sh_entsize = 0;
-
- for (SectionBase &Sec : Obj.sections())
- writeShdr(Sec);
-}
-
+}
+
+template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
+ Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf.getBufferStart());
+ std::fill(Ehdr.e_ident, Ehdr.e_ident + 16, 0);
+ Ehdr.e_ident[EI_MAG0] = 0x7f;
+ Ehdr.e_ident[EI_MAG1] = 'E';
+ Ehdr.e_ident[EI_MAG2] = 'L';
+ Ehdr.e_ident[EI_MAG3] = 'F';
+ Ehdr.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
+ Ehdr.e_ident[EI_DATA] =
+ ELFT::TargetEndianness == support::big ? ELFDATA2MSB : ELFDATA2LSB;
+ Ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ Ehdr.e_ident[EI_OSABI] = Obj.OSABI;
+ Ehdr.e_ident[EI_ABIVERSION] = Obj.ABIVersion;
+
+ Ehdr.e_type = Obj.Type;
+ Ehdr.e_machine = Obj.Machine;
+ Ehdr.e_version = Obj.Version;
+ Ehdr.e_entry = Obj.Entry;
+ // We have to use the fully-qualified name llvm::size
+ // since some compilers complain on ambiguous resolution.
+ Ehdr.e_phnum = llvm::size(Obj.segments());
+ Ehdr.e_phoff = (Ehdr.e_phnum != 0) ? Obj.ProgramHdrSegment.Offset : 0;
+ Ehdr.e_phentsize = (Ehdr.e_phnum != 0) ? sizeof(Elf_Phdr) : 0;
+ Ehdr.e_flags = Obj.Flags;
+ Ehdr.e_ehsize = sizeof(Elf_Ehdr);
+ if (WriteSectionHeaders && Obj.sections().size() != 0) {
+ Ehdr.e_shentsize = sizeof(Elf_Shdr);
+ Ehdr.e_shoff = Obj.SHOff;
+ // """
+ // If the number of sections is greater than or equal to
+ // SHN_LORESERVE (0xff00), this member has the value zero and the actual
+ // number of section header table entries is contained in the sh_size field
+ // of the section header at index 0.
+ // """
+ auto Shnum = Obj.sections().size() + 1;
+ if (Shnum >= SHN_LORESERVE)
+ Ehdr.e_shnum = 0;
+ else
+ Ehdr.e_shnum = Shnum;
+ // """
+ // If the section name string table section index is greater than or equal
+ // to SHN_LORESERVE (0xff00), this member has the value SHN_XINDEX (0xffff)
+ // and the actual index of the section name string table section is
+ // contained in the sh_link field of the section header at index 0.
+ // """
+ if (Obj.SectionNames->Index >= SHN_LORESERVE)
+ Ehdr.e_shstrndx = SHN_XINDEX;
+ else
+ Ehdr.e_shstrndx = Obj.SectionNames->Index;
+ } else {
+ Ehdr.e_shentsize = 0;
+ Ehdr.e_shoff = 0;
+ Ehdr.e_shnum = 0;
+ Ehdr.e_shstrndx = 0;
+ }
+}
+
+template <class ELFT> void ELFWriter<ELFT>::writePhdrs() {
+ for (auto &Seg : Obj.segments())
+ writePhdr(Seg);
+}
+
+template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {
+ // This reference serves to write the dummy section header at the begining
+ // of the file. It is not used for anything else
+ Elf_Shdr &Shdr =
+ *reinterpret_cast<Elf_Shdr *>(Buf.getBufferStart() + Obj.SHOff);
+ Shdr.sh_name = 0;
+ Shdr.sh_type = SHT_NULL;
+ Shdr.sh_flags = 0;
+ Shdr.sh_addr = 0;
+ Shdr.sh_offset = 0;
+ // See writeEhdr for why we do this.
+ uint64_t Shnum = Obj.sections().size() + 1;
+ if (Shnum >= SHN_LORESERVE)
+ Shdr.sh_size = Shnum;
+ else
+ Shdr.sh_size = 0;
+ // See writeEhdr for why we do this.
+ if (Obj.SectionNames != nullptr && Obj.SectionNames->Index >= SHN_LORESERVE)
+ Shdr.sh_link = Obj.SectionNames->Index;
+ else
+ Shdr.sh_link = 0;
+ Shdr.sh_info = 0;
+ Shdr.sh_addralign = 0;
+ Shdr.sh_entsize = 0;
+
+ for (SectionBase &Sec : Obj.sections())
+ writeShdr(Sec);
+}
+
template <class ELFT> Error ELFWriter<ELFT>::writeSectionData() {
- for (SectionBase &Sec : Obj.sections())
- // Segments are responsible for writing their contents, so only write the
- // section data if the section is not in a segment. Note that this renders
- // sections in segments effectively immutable.
- if (Sec.ParentSegment == nullptr)
+ for (SectionBase &Sec : Obj.sections())
+ // Segments are responsible for writing their contents, so only write the
+ // section data if the section is not in a segment. Note that this renders
+ // sections in segments effectively immutable.
+ if (Sec.ParentSegment == nullptr)
if (Error Err = Sec.accept(*SecWriter))
return Err;
return Error::success();
-}
-
-template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {
- for (Segment &Seg : Obj.segments()) {
- size_t Size = std::min<size_t>(Seg.FileSize, Seg.getContents().size());
- std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(),
- Size);
- }
-
- // Iterate over removed sections and overwrite their old data with zeroes.
- for (auto &Sec : Obj.removedSections()) {
- Segment *Parent = Sec.ParentSegment;
- if (Parent == nullptr || Sec.Type == SHT_NOBITS || Sec.Size == 0)
- continue;
- uint64_t Offset =
- Sec.OriginalOffset - Parent->OriginalOffset + Parent->Offset;
- std::memset(Buf.getBufferStart() + Offset, 0, Sec.Size);
- }
-}
-
-template <class ELFT>
-ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH,
- bool OnlyKeepDebug)
- : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs),
- OnlyKeepDebug(OnlyKeepDebug) {}
-
+}
+
+template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {
+ for (Segment &Seg : Obj.segments()) {
+ size_t Size = std::min<size_t>(Seg.FileSize, Seg.getContents().size());
+ std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(),
+ Size);
+ }
+
+ // Iterate over removed sections and overwrite their old data with zeroes.
+ for (auto &Sec : Obj.removedSections()) {
+ Segment *Parent = Sec.ParentSegment;
+ if (Parent == nullptr || Sec.Type == SHT_NOBITS || Sec.Size == 0)
+ continue;
+ uint64_t Offset =
+ Sec.OriginalOffset - Parent->OriginalOffset + Parent->Offset;
+ std::memset(Buf.getBufferStart() + Offset, 0, Sec.Size);
+ }
+}
+
+template <class ELFT>
+ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH,
+ bool OnlyKeepDebug)
+ : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs),
+ OnlyKeepDebug(OnlyKeepDebug) {}
+
Error Object::removeSections(
bool AllowBrokenLinks, std::function<bool(const SectionBase &)> ToRemove) {
-
- auto Iter = std::stable_partition(
- std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) {
- if (ToRemove(*Sec))
- return false;
- if (auto RelSec = dyn_cast<RelocationSectionBase>(Sec.get())) {
- if (auto ToRelSec = RelSec->getSection())
- return !ToRemove(*ToRelSec);
- }
- return true;
- });
- if (SymbolTable != nullptr && ToRemove(*SymbolTable))
- SymbolTable = nullptr;
- if (SectionNames != nullptr && ToRemove(*SectionNames))
- SectionNames = nullptr;
- if (SectionIndexTable != nullptr && ToRemove(*SectionIndexTable))
- SectionIndexTable = nullptr;
- // Now make sure there are no remaining references to the sections that will
- // be removed. Sometimes it is impossible to remove a reference so we emit
- // an error here instead.
- std::unordered_set<const SectionBase *> RemoveSections;
- RemoveSections.reserve(std::distance(Iter, std::end(Sections)));
- for (auto &RemoveSec : make_range(Iter, std::end(Sections))) {
- for (auto &Segment : Segments)
- Segment->removeSection(RemoveSec.get());
- RemoveSec->onRemove();
- RemoveSections.insert(RemoveSec.get());
- }
-
- // For each section that remains alive, we want to remove the dead references.
- // This either might update the content of the section (e.g. remove symbols
- // from symbol table that belongs to removed section) or trigger an error if
- // a live section critically depends on a section being removed somehow
- // (e.g. the removed section is referenced by a relocation).
- for (auto &KeepSec : make_range(std::begin(Sections), Iter)) {
+
+ auto Iter = std::stable_partition(
+ std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) {
+ if (ToRemove(*Sec))
+ return false;
+ if (auto RelSec = dyn_cast<RelocationSectionBase>(Sec.get())) {
+ if (auto ToRelSec = RelSec->getSection())
+ return !ToRemove(*ToRelSec);
+ }
+ return true;
+ });
+ if (SymbolTable != nullptr && ToRemove(*SymbolTable))
+ SymbolTable = nullptr;
+ if (SectionNames != nullptr && ToRemove(*SectionNames))
+ SectionNames = nullptr;
+ if (SectionIndexTable != nullptr && ToRemove(*SectionIndexTable))
+ SectionIndexTable = nullptr;
+ // Now make sure there are no remaining references to the sections that will
+ // be removed. Sometimes it is impossible to remove a reference so we emit
+ // an error here instead.
+ std::unordered_set<const SectionBase *> RemoveSections;
+ RemoveSections.reserve(std::distance(Iter, std::end(Sections)));
+ for (auto &RemoveSec : make_range(Iter, std::end(Sections))) {
+ for (auto &Segment : Segments)
+ Segment->removeSection(RemoveSec.get());
+ RemoveSec->onRemove();
+ RemoveSections.insert(RemoveSec.get());
+ }
+
+ // For each section that remains alive, we want to remove the dead references.
+ // This either might update the content of the section (e.g. remove symbols
+ // from symbol table that belongs to removed section) or trigger an error if
+ // a live section critically depends on a section being removed somehow
+ // (e.g. the removed section is referenced by a relocation).
+ for (auto &KeepSec : make_range(std::begin(Sections), Iter)) {
if (Error E = KeepSec->removeSectionReferences(
AllowBrokenLinks, [&RemoveSections](const SectionBase *Sec) {
- return RemoveSections.find(Sec) != RemoveSections.end();
- }))
- return E;
- }
-
- // Transfer removed sections into the Object RemovedSections container for use
- // later.
- std::move(Iter, Sections.end(), std::back_inserter(RemovedSections));
- // Now finally get rid of them all together.
- Sections.erase(Iter, std::end(Sections));
- return Error::success();
-}
-
-Error Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
- if (SymbolTable)
- for (const SecPtr &Sec : Sections)
- if (Error E = Sec->removeSymbols(ToRemove))
- return E;
- return Error::success();
-}
-
+ return RemoveSections.find(Sec) != RemoveSections.end();
+ }))
+ return E;
+ }
+
+ // Transfer removed sections into the Object RemovedSections container for use
+ // later.
+ std::move(Iter, Sections.end(), std::back_inserter(RemovedSections));
+ // Now finally get rid of them all together.
+ Sections.erase(Iter, std::end(Sections));
+ return Error::success();
+}
+
+Error Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
+ if (SymbolTable)
+ for (const SecPtr &Sec : Sections)
+ if (Error E = Sec->removeSymbols(ToRemove))
+ return E;
+ return Error::success();
+}
+
Error Object::addNewSymbolTable() {
- assert(!SymbolTable && "Object must not has a SymbolTable.");
-
- // Reuse an existing SHT_STRTAB section if it exists.
- StringTableSection *StrTab = nullptr;
- for (SectionBase &Sec : sections()) {
- if (Sec.Type == ELF::SHT_STRTAB && !(Sec.Flags & SHF_ALLOC)) {
- StrTab = static_cast<StringTableSection *>(&Sec);
-
- // Prefer a string table that is not the section header string table, if
- // such a table exists.
- if (SectionNames != &Sec)
- break;
- }
- }
- if (!StrTab)
- StrTab = &addSection<StringTableSection>();
-
- SymbolTableSection &SymTab = addSection<SymbolTableSection>();
- SymTab.Name = ".symtab";
- SymTab.Link = StrTab->Index;
+ assert(!SymbolTable && "Object must not has a SymbolTable.");
+
+ // Reuse an existing SHT_STRTAB section if it exists.
+ StringTableSection *StrTab = nullptr;
+ for (SectionBase &Sec : sections()) {
+ if (Sec.Type == ELF::SHT_STRTAB && !(Sec.Flags & SHF_ALLOC)) {
+ StrTab = static_cast<StringTableSection *>(&Sec);
+
+ // Prefer a string table that is not the section header string table, if
+ // such a table exists.
+ if (SectionNames != &Sec)
+ break;
+ }
+ }
+ if (!StrTab)
+ StrTab = &addSection<StringTableSection>();
+
+ SymbolTableSection &SymTab = addSection<SymbolTableSection>();
+ SymTab.Name = ".symtab";
+ SymTab.Link = StrTab->Index;
if (Error Err = SymTab.initialize(sections()))
return Err;
- SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0);
-
- SymbolTable = &SymTab;
+ SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0);
+
+ SymbolTable = &SymTab;
return Error::success();
-}
-
-void Object::sortSections() {
- // Use stable_sort to maintain the original ordering as closely as possible.
- llvm::stable_sort(Sections, [](const SecPtr &A, const SecPtr &B) {
- // Put SHT_GROUP sections first, since group section headers must come
- // before the sections they contain. This also matches what GNU objcopy
- // does.
- if (A->Type != B->Type &&
- (A->Type == ELF::SHT_GROUP || B->Type == ELF::SHT_GROUP))
- return A->Type == ELF::SHT_GROUP;
- // For all other sections, sort by offset order.
- return A->OriginalOffset < B->OriginalOffset;
- });
-}
-
-// Orders segments such that if x = y->ParentSegment then y comes before x.
-static void orderSegments(std::vector<Segment *> &Segments) {
- llvm::stable_sort(Segments, compareSegmentsByOffset);
-}
-
-// This function finds a consistent layout for a list of segments starting from
-// an Offset. It assumes that Segments have been sorted by orderSegments and
-// returns an Offset one past the end of the last segment.
-static uint64_t layoutSegments(std::vector<Segment *> &Segments,
- uint64_t Offset) {
- assert(llvm::is_sorted(Segments, compareSegmentsByOffset));
- // The only way a segment should move is if a section was between two
- // segments and that section was removed. If that section isn't in a segment
- // then it's acceptable, but not ideal, to simply move it to after the
- // segments. So we can simply layout segments one after the other accounting
- // for alignment.
- for (Segment *Seg : Segments) {
- // We assume that segments have been ordered by OriginalOffset and Index
- // such that a parent segment will always come before a child segment in
- // OrderedSegments. This means that the Offset of the ParentSegment should
- // already be set and we can set our offset relative to it.
- if (Seg->ParentSegment != nullptr) {
- Segment *Parent = Seg->ParentSegment;
- Seg->Offset =
- Parent->Offset + Seg->OriginalOffset - Parent->OriginalOffset;
- } else {
- Seg->Offset =
- alignTo(Offset, std::max<uint64_t>(Seg->Align, 1), Seg->VAddr);
- }
- Offset = std::max(Offset, Seg->Offset + Seg->FileSize);
- }
- return Offset;
-}
-
-// This function finds a consistent layout for a list of sections. It assumes
-// that the ->ParentSegment of each section has already been laid out. The
-// supplied starting Offset is used for the starting offset of any section that
-// does not have a ParentSegment. It returns either the offset given if all
-// sections had a ParentSegment or an offset one past the last section if there
-// was a section that didn't have a ParentSegment.
-template <class Range>
-static uint64_t layoutSections(Range Sections, uint64_t Offset) {
- // Now the offset of every segment has been set we can assign the offsets
- // of each section. For sections that are covered by a segment we should use
- // the segment's original offset and the section's original offset to compute
- // the offset from the start of the segment. Using the offset from the start
- // of the segment we can assign a new offset to the section. For sections not
- // covered by segments we can just bump Offset to the next valid location.
- uint32_t Index = 1;
- for (auto &Sec : Sections) {
- Sec.Index = Index++;
- if (Sec.ParentSegment != nullptr) {
- auto Segment = *Sec.ParentSegment;
- Sec.Offset =
- Segment.Offset + (Sec.OriginalOffset - Segment.OriginalOffset);
- } else {
- Offset = alignTo(Offset, Sec.Align == 0 ? 1 : Sec.Align);
- Sec.Offset = Offset;
- if (Sec.Type != SHT_NOBITS)
- Offset += Sec.Size;
- }
- }
- return Offset;
-}
-
-// Rewrite sh_offset after some sections are changed to SHT_NOBITS and thus
-// occupy no space in the file.
-static uint64_t layoutSectionsForOnlyKeepDebug(Object &Obj, uint64_t Off) {
- uint32_t Index = 1;
- for (auto &Sec : Obj.sections()) {
- Sec.Index = Index++;
-
- auto *FirstSec = Sec.ParentSegment && Sec.ParentSegment->Type == PT_LOAD
- ? Sec.ParentSegment->firstSection()
- : nullptr;
-
- // The first section in a PT_LOAD has to have congruent offset and address
- // modulo the alignment, which usually equals the maximum page size.
- if (FirstSec && FirstSec == &Sec)
- Off = alignTo(Off, Sec.ParentSegment->Align, Sec.Addr);
-
- // sh_offset is not significant for SHT_NOBITS sections, but the congruence
- // rule must be followed if it is the first section in a PT_LOAD. Do not
- // advance Off.
- if (Sec.Type == SHT_NOBITS) {
- Sec.Offset = Off;
- continue;
- }
-
- if (!FirstSec) {
- // FirstSec being nullptr generally means that Sec does not have the
- // SHF_ALLOC flag.
- Off = Sec.Align ? alignTo(Off, Sec.Align) : Off;
- } else if (FirstSec != &Sec) {
- // The offset is relative to the first section in the PT_LOAD segment. Use
- // sh_offset for non-SHF_ALLOC sections.
- Off = Sec.OriginalOffset - FirstSec->OriginalOffset + FirstSec->Offset;
- }
- Sec.Offset = Off;
- Off += Sec.Size;
- }
- return Off;
-}
-
+}
+
+void Object::sortSections() {
+ // Use stable_sort to maintain the original ordering as closely as possible.
+ llvm::stable_sort(Sections, [](const SecPtr &A, const SecPtr &B) {
+ // Put SHT_GROUP sections first, since group section headers must come
+ // before the sections they contain. This also matches what GNU objcopy
+ // does.
+ if (A->Type != B->Type &&
+ (A->Type == ELF::SHT_GROUP || B->Type == ELF::SHT_GROUP))
+ return A->Type == ELF::SHT_GROUP;
+ // For all other sections, sort by offset order.
+ return A->OriginalOffset < B->OriginalOffset;
+ });
+}
+
+// Orders segments such that if x = y->ParentSegment then y comes before x.
+static void orderSegments(std::vector<Segment *> &Segments) {
+ llvm::stable_sort(Segments, compareSegmentsByOffset);
+}
+
+// This function finds a consistent layout for a list of segments starting from
+// an Offset. It assumes that Segments have been sorted by orderSegments and
+// returns an Offset one past the end of the last segment.
+static uint64_t layoutSegments(std::vector<Segment *> &Segments,
+ uint64_t Offset) {
+ assert(llvm::is_sorted(Segments, compareSegmentsByOffset));
+ // The only way a segment should move is if a section was between two
+ // segments and that section was removed. If that section isn't in a segment
+ // then it's acceptable, but not ideal, to simply move it to after the
+ // segments. So we can simply layout segments one after the other accounting
+ // for alignment.
+ for (Segment *Seg : Segments) {
+ // We assume that segments have been ordered by OriginalOffset and Index
+ // such that a parent segment will always come before a child segment in
+ // OrderedSegments. This means that the Offset of the ParentSegment should
+ // already be set and we can set our offset relative to it.
+ if (Seg->ParentSegment != nullptr) {
+ Segment *Parent = Seg->ParentSegment;
+ Seg->Offset =
+ Parent->Offset + Seg->OriginalOffset - Parent->OriginalOffset;
+ } else {
+ Seg->Offset =
+ alignTo(Offset, std::max<uint64_t>(Seg->Align, 1), Seg->VAddr);
+ }
+ Offset = std::max(Offset, Seg->Offset + Seg->FileSize);
+ }
+ return Offset;
+}
+
+// This function finds a consistent layout for a list of sections. It assumes
+// that the ->ParentSegment of each section has already been laid out. The
+// supplied starting Offset is used for the starting offset of any section that
+// does not have a ParentSegment. It returns either the offset given if all
+// sections had a ParentSegment or an offset one past the last section if there
+// was a section that didn't have a ParentSegment.
+template <class Range>
+static uint64_t layoutSections(Range Sections, uint64_t Offset) {
+ // Now the offset of every segment has been set we can assign the offsets
+ // of each section. For sections that are covered by a segment we should use
+ // the segment's original offset and the section's original offset to compute
+ // the offset from the start of the segment. Using the offset from the start
+ // of the segment we can assign a new offset to the section. For sections not
+ // covered by segments we can just bump Offset to the next valid location.
+ uint32_t Index = 1;
+ for (auto &Sec : Sections) {
+ Sec.Index = Index++;
+ if (Sec.ParentSegment != nullptr) {
+ auto Segment = *Sec.ParentSegment;
+ Sec.Offset =
+ Segment.Offset + (Sec.OriginalOffset - Segment.OriginalOffset);
+ } else {
+ Offset = alignTo(Offset, Sec.Align == 0 ? 1 : Sec.Align);
+ Sec.Offset = Offset;
+ if (Sec.Type != SHT_NOBITS)
+ Offset += Sec.Size;
+ }
+ }
+ return Offset;
+}
+
+// Rewrite sh_offset after some sections are changed to SHT_NOBITS and thus
+// occupy no space in the file.
+static uint64_t layoutSectionsForOnlyKeepDebug(Object &Obj, uint64_t Off) {
+ uint32_t Index = 1;
+ for (auto &Sec : Obj.sections()) {
+ Sec.Index = Index++;
+
+ auto *FirstSec = Sec.ParentSegment && Sec.ParentSegment->Type == PT_LOAD
+ ? Sec.ParentSegment->firstSection()
+ : nullptr;
+
+ // The first section in a PT_LOAD has to have congruent offset and address
+ // modulo the alignment, which usually equals the maximum page size.
+ if (FirstSec && FirstSec == &Sec)
+ Off = alignTo(Off, Sec.ParentSegment->Align, Sec.Addr);
+
+ // sh_offset is not significant for SHT_NOBITS sections, but the congruence
+ // rule must be followed if it is the first section in a PT_LOAD. Do not
+ // advance Off.
+ if (Sec.Type == SHT_NOBITS) {
+ Sec.Offset = Off;
+ continue;
+ }
+
+ if (!FirstSec) {
+ // FirstSec being nullptr generally means that Sec does not have the
+ // SHF_ALLOC flag.
+ Off = Sec.Align ? alignTo(Off, Sec.Align) : Off;
+ } else if (FirstSec != &Sec) {
+ // The offset is relative to the first section in the PT_LOAD segment. Use
+ // sh_offset for non-SHF_ALLOC sections.
+ Off = Sec.OriginalOffset - FirstSec->OriginalOffset + FirstSec->Offset;
+ }
+ Sec.Offset = Off;
+ Off += Sec.Size;
+ }
+ return Off;
+}
+
// Rewrite p_offset and p_filesz of non-PT_PHDR segments after sh_offset values
// have been updated.
-static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments,
- uint64_t HdrEnd) {
- uint64_t MaxOffset = 0;
- for (Segment *Seg : Segments) {
+static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments,
+ uint64_t HdrEnd) {
+ uint64_t MaxOffset = 0;
+ for (Segment *Seg : Segments) {
// An empty segment contains no section (see sectionWithinSegment). If it
// has a parent segment, copy the parent segment's offset field. This works
// for empty PT_TLS. We don't handle empty segments without a parent for
@@ -2318,377 +2318,377 @@ static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments,
if (Seg->ParentSegment != nullptr && Seg->MemSize == 0)
Seg->Offset = Seg->ParentSegment->Offset;
- const SectionBase *FirstSec = Seg->firstSection();
- if (Seg->Type == PT_PHDR || !FirstSec)
- continue;
-
- uint64_t Offset = FirstSec->Offset;
- uint64_t FileSize = 0;
- for (const SectionBase *Sec : Seg->Sections) {
- uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size;
- if (Sec->Offset + Size > Offset)
- FileSize = std::max(FileSize, Sec->Offset + Size - Offset);
- }
-
- // If the segment includes EHDR and program headers, don't make it smaller
- // than the headers.
- if (Seg->Offset < HdrEnd && HdrEnd <= Seg->Offset + Seg->FileSize) {
- FileSize += Offset - Seg->Offset;
- Offset = Seg->Offset;
- FileSize = std::max(FileSize, HdrEnd - Offset);
- }
-
- Seg->Offset = Offset;
- Seg->FileSize = FileSize;
- MaxOffset = std::max(MaxOffset, Offset + FileSize);
- }
- return MaxOffset;
-}
-
-template <class ELFT> void ELFWriter<ELFT>::initEhdrSegment() {
- Segment &ElfHdr = Obj.ElfHdrSegment;
- ElfHdr.Type = PT_PHDR;
- ElfHdr.Flags = 0;
- ElfHdr.VAddr = 0;
- ElfHdr.PAddr = 0;
- ElfHdr.FileSize = ElfHdr.MemSize = sizeof(Elf_Ehdr);
- ElfHdr.Align = 0;
-}
-
-template <class ELFT> void ELFWriter<ELFT>::assignOffsets() {
- // We need a temporary list of segments that has a special order to it
- // so that we know that anytime ->ParentSegment is set that segment has
- // already had its offset properly set.
- std::vector<Segment *> OrderedSegments;
- for (Segment &Segment : Obj.segments())
- OrderedSegments.push_back(&Segment);
- OrderedSegments.push_back(&Obj.ElfHdrSegment);
- OrderedSegments.push_back(&Obj.ProgramHdrSegment);
- orderSegments(OrderedSegments);
-
- uint64_t Offset;
- if (OnlyKeepDebug) {
- // For --only-keep-debug, the sections that did not preserve contents were
- // changed to SHT_NOBITS. We now rewrite sh_offset fields of sections, and
- // then rewrite p_offset/p_filesz of program headers.
- uint64_t HdrEnd =
- sizeof(Elf_Ehdr) + llvm::size(Obj.segments()) * sizeof(Elf_Phdr);
- Offset = layoutSectionsForOnlyKeepDebug(Obj, HdrEnd);
- Offset = std::max(Offset,
- layoutSegmentsForOnlyKeepDebug(OrderedSegments, HdrEnd));
- } else {
- // Offset is used as the start offset of the first segment to be laid out.
- // Since the ELF Header (ElfHdrSegment) must be at the start of the file,
- // we start at offset 0.
- Offset = layoutSegments(OrderedSegments, 0);
- Offset = layoutSections(Obj.sections(), Offset);
- }
- // If we need to write the section header table out then we need to align the
- // Offset so that SHOffset is valid.
- if (WriteSectionHeaders)
- Offset = alignTo(Offset, sizeof(Elf_Addr));
- Obj.SHOff = Offset;
-}
-
-template <class ELFT> size_t ELFWriter<ELFT>::totalSize() const {
- // We already have the section header offset so we can calculate the total
- // size by just adding up the size of each section header.
- if (!WriteSectionHeaders)
- return Obj.SHOff;
- size_t ShdrCount = Obj.sections().size() + 1; // Includes null shdr.
- return Obj.SHOff + ShdrCount * sizeof(Elf_Shdr);
-}
-
-template <class ELFT> Error ELFWriter<ELFT>::write() {
- // Segment data must be written first, so that the ELF header and program
- // header tables can overwrite it, if covered by a segment.
- writeSegmentData();
- writeEhdr();
- writePhdrs();
+ const SectionBase *FirstSec = Seg->firstSection();
+ if (Seg->Type == PT_PHDR || !FirstSec)
+ continue;
+
+ uint64_t Offset = FirstSec->Offset;
+ uint64_t FileSize = 0;
+ for (const SectionBase *Sec : Seg->Sections) {
+ uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size;
+ if (Sec->Offset + Size > Offset)
+ FileSize = std::max(FileSize, Sec->Offset + Size - Offset);
+ }
+
+ // If the segment includes EHDR and program headers, don't make it smaller
+ // than the headers.
+ if (Seg->Offset < HdrEnd && HdrEnd <= Seg->Offset + Seg->FileSize) {
+ FileSize += Offset - Seg->Offset;
+ Offset = Seg->Offset;
+ FileSize = std::max(FileSize, HdrEnd - Offset);
+ }
+
+ Seg->Offset = Offset;
+ Seg->FileSize = FileSize;
+ MaxOffset = std::max(MaxOffset, Offset + FileSize);
+ }
+ return MaxOffset;
+}
+
+template <class ELFT> void ELFWriter<ELFT>::initEhdrSegment() {
+ Segment &ElfHdr = Obj.ElfHdrSegment;
+ ElfHdr.Type = PT_PHDR;
+ ElfHdr.Flags = 0;
+ ElfHdr.VAddr = 0;
+ ElfHdr.PAddr = 0;
+ ElfHdr.FileSize = ElfHdr.MemSize = sizeof(Elf_Ehdr);
+ ElfHdr.Align = 0;
+}
+
+template <class ELFT> void ELFWriter<ELFT>::assignOffsets() {
+ // We need a temporary list of segments that has a special order to it
+ // so that we know that anytime ->ParentSegment is set that segment has
+ // already had its offset properly set.
+ std::vector<Segment *> OrderedSegments;
+ for (Segment &Segment : Obj.segments())
+ OrderedSegments.push_back(&Segment);
+ OrderedSegments.push_back(&Obj.ElfHdrSegment);
+ OrderedSegments.push_back(&Obj.ProgramHdrSegment);
+ orderSegments(OrderedSegments);
+
+ uint64_t Offset;
+ if (OnlyKeepDebug) {
+ // For --only-keep-debug, the sections that did not preserve contents were
+ // changed to SHT_NOBITS. We now rewrite sh_offset fields of sections, and
+ // then rewrite p_offset/p_filesz of program headers.
+ uint64_t HdrEnd =
+ sizeof(Elf_Ehdr) + llvm::size(Obj.segments()) * sizeof(Elf_Phdr);
+ Offset = layoutSectionsForOnlyKeepDebug(Obj, HdrEnd);
+ Offset = std::max(Offset,
+ layoutSegmentsForOnlyKeepDebug(OrderedSegments, HdrEnd));
+ } else {
+ // Offset is used as the start offset of the first segment to be laid out.
+ // Since the ELF Header (ElfHdrSegment) must be at the start of the file,
+ // we start at offset 0.
+ Offset = layoutSegments(OrderedSegments, 0);
+ Offset = layoutSections(Obj.sections(), Offset);
+ }
+ // If we need to write the section header table out then we need to align the
+ // Offset so that SHOffset is valid.
+ if (WriteSectionHeaders)
+ Offset = alignTo(Offset, sizeof(Elf_Addr));
+ Obj.SHOff = Offset;
+}
+
+template <class ELFT> size_t ELFWriter<ELFT>::totalSize() const {
+ // We already have the section header offset so we can calculate the total
+ // size by just adding up the size of each section header.
+ if (!WriteSectionHeaders)
+ return Obj.SHOff;
+ size_t ShdrCount = Obj.sections().size() + 1; // Includes null shdr.
+ return Obj.SHOff + ShdrCount * sizeof(Elf_Shdr);
+}
+
+template <class ELFT> Error ELFWriter<ELFT>::write() {
+ // Segment data must be written first, so that the ELF header and program
+ // header tables can overwrite it, if covered by a segment.
+ writeSegmentData();
+ writeEhdr();
+ writePhdrs();
if (Error E = writeSectionData())
return E;
- if (WriteSectionHeaders)
- writeShdrs();
- return Buf.commit();
-}
-
-static Error removeUnneededSections(Object &Obj) {
- // We can remove an empty symbol table from non-relocatable objects.
- // Relocatable objects typically have relocation sections whose
- // sh_link field points to .symtab, so we can't remove .symtab
- // even if it is empty.
- if (Obj.isRelocatable() || Obj.SymbolTable == nullptr ||
- !Obj.SymbolTable->empty())
- return Error::success();
-
- // .strtab can be used for section names. In such a case we shouldn't
- // remove it.
- auto *StrTab = Obj.SymbolTable->getStrTab() == Obj.SectionNames
- ? nullptr
- : Obj.SymbolTable->getStrTab();
- return Obj.removeSections(false, [&](const SectionBase &Sec) {
- return &Sec == Obj.SymbolTable || &Sec == StrTab;
- });
-}
-
-template <class ELFT> Error ELFWriter<ELFT>::finalize() {
- // It could happen that SectionNames has been removed and yet the user wants
- // a section header table output. We need to throw an error if a user tries
- // to do that.
- if (Obj.SectionNames == nullptr && WriteSectionHeaders)
- return createStringError(llvm::errc::invalid_argument,
- "cannot write section header table because "
- "section header string table was removed");
-
- if (Error E = removeUnneededSections(Obj))
- return E;
- Obj.sortSections();
-
- // We need to assign indexes before we perform layout because we need to know
- // if we need large indexes or not. We can assign indexes first and check as
- // we go to see if we will actully need large indexes.
- bool NeedsLargeIndexes = false;
- if (Obj.sections().size() >= SHN_LORESERVE) {
- SectionTableRef Sections = Obj.sections();
- NeedsLargeIndexes =
+ if (WriteSectionHeaders)
+ writeShdrs();
+ return Buf.commit();
+}
+
+static Error removeUnneededSections(Object &Obj) {
+ // We can remove an empty symbol table from non-relocatable objects.
+ // Relocatable objects typically have relocation sections whose
+ // sh_link field points to .symtab, so we can't remove .symtab
+ // even if it is empty.
+ if (Obj.isRelocatable() || Obj.SymbolTable == nullptr ||
+ !Obj.SymbolTable->empty())
+ return Error::success();
+
+ // .strtab can be used for section names. In such a case we shouldn't
+ // remove it.
+ auto *StrTab = Obj.SymbolTable->getStrTab() == Obj.SectionNames
+ ? nullptr
+ : Obj.SymbolTable->getStrTab();
+ return Obj.removeSections(false, [&](const SectionBase &Sec) {
+ return &Sec == Obj.SymbolTable || &Sec == StrTab;
+ });
+}
+
+template <class ELFT> Error ELFWriter<ELFT>::finalize() {
+ // It could happen that SectionNames has been removed and yet the user wants
+ // a section header table output. We need to throw an error if a user tries
+ // to do that.
+ if (Obj.SectionNames == nullptr && WriteSectionHeaders)
+ return createStringError(llvm::errc::invalid_argument,
+ "cannot write section header table because "
+ "section header string table was removed");
+
+ if (Error E = removeUnneededSections(Obj))
+ return E;
+ Obj.sortSections();
+
+ // We need to assign indexes before we perform layout because we need to know
+ // if we need large indexes or not. We can assign indexes first and check as
+ // we go to see if we will actully need large indexes.
+ bool NeedsLargeIndexes = false;
+ if (Obj.sections().size() >= SHN_LORESERVE) {
+ SectionTableRef Sections = Obj.sections();
+ NeedsLargeIndexes =
any_of(drop_begin(Sections, SHN_LORESERVE),
[](const SectionBase &Sec) { return Sec.HasSymbol; });
- // TODO: handle case where only one section needs the large index table but
- // only needs it because the large index table hasn't been removed yet.
- }
-
- if (NeedsLargeIndexes) {
- // This means we definitely need to have a section index table but if we
- // already have one then we should use it instead of making a new one.
- if (Obj.SymbolTable != nullptr && Obj.SectionIndexTable == nullptr) {
- // Addition of a section to the end does not invalidate the indexes of
- // other sections and assigns the correct index to the new section.
- auto &Shndx = Obj.addSection<SectionIndexSection>();
- Obj.SymbolTable->setShndxTable(&Shndx);
- Shndx.setSymTab(Obj.SymbolTable);
- }
- } else {
- // Since we don't need SectionIndexTable we should remove it and all
- // references to it.
- if (Obj.SectionIndexTable != nullptr) {
- // We do not support sections referring to the section index table.
- if (Error E = Obj.removeSections(false /*AllowBrokenLinks*/,
- [this](const SectionBase &Sec) {
- return &Sec == Obj.SectionIndexTable;
- }))
- return E;
- }
- }
-
- // Make sure we add the names of all the sections. Importantly this must be
- // done after we decide to add or remove SectionIndexes.
- if (Obj.SectionNames != nullptr)
- for (const SectionBase &Sec : Obj.sections())
- Obj.SectionNames->addString(Sec.Name);
-
- initEhdrSegment();
-
- // Before we can prepare for layout the indexes need to be finalized.
- // Also, the output arch may not be the same as the input arch, so fix up
- // size-related fields before doing layout calculations.
- uint64_t Index = 0;
- auto SecSizer = std::make_unique<ELFSectionSizer<ELFT>>();
- for (SectionBase &Sec : Obj.sections()) {
- Sec.Index = Index++;
+ // TODO: handle case where only one section needs the large index table but
+ // only needs it because the large index table hasn't been removed yet.
+ }
+
+ if (NeedsLargeIndexes) {
+ // This means we definitely need to have a section index table but if we
+ // already have one then we should use it instead of making a new one.
+ if (Obj.SymbolTable != nullptr && Obj.SectionIndexTable == nullptr) {
+ // Addition of a section to the end does not invalidate the indexes of
+ // other sections and assigns the correct index to the new section.
+ auto &Shndx = Obj.addSection<SectionIndexSection>();
+ Obj.SymbolTable->setShndxTable(&Shndx);
+ Shndx.setSymTab(Obj.SymbolTable);
+ }
+ } else {
+ // Since we don't need SectionIndexTable we should remove it and all
+ // references to it.
+ if (Obj.SectionIndexTable != nullptr) {
+ // We do not support sections referring to the section index table.
+ if (Error E = Obj.removeSections(false /*AllowBrokenLinks*/,
+ [this](const SectionBase &Sec) {
+ return &Sec == Obj.SectionIndexTable;
+ }))
+ return E;
+ }
+ }
+
+ // Make sure we add the names of all the sections. Importantly this must be
+ // done after we decide to add or remove SectionIndexes.
+ if (Obj.SectionNames != nullptr)
+ for (const SectionBase &Sec : Obj.sections())
+ Obj.SectionNames->addString(Sec.Name);
+
+ initEhdrSegment();
+
+ // Before we can prepare for layout the indexes need to be finalized.
+ // Also, the output arch may not be the same as the input arch, so fix up
+ // size-related fields before doing layout calculations.
+ uint64_t Index = 0;
+ auto SecSizer = std::make_unique<ELFSectionSizer<ELFT>>();
+ for (SectionBase &Sec : Obj.sections()) {
+ Sec.Index = Index++;
if (Error Err = Sec.accept(*SecSizer))
return Err;
- }
-
- // The symbol table does not update all other sections on update. For
- // instance, symbol names are not added as new symbols are added. This means
- // that some sections, like .strtab, don't yet have their final size.
- if (Obj.SymbolTable != nullptr)
- Obj.SymbolTable->prepareForLayout();
-
- // Now that all strings are added we want to finalize string table builders,
- // because that affects section sizes which in turn affects section offsets.
- for (SectionBase &Sec : Obj.sections())
- if (auto StrTab = dyn_cast<StringTableSection>(&Sec))
- StrTab->prepareForLayout();
-
- assignOffsets();
-
- // layoutSections could have modified section indexes, so we need
- // to fill the index table after assignOffsets.
- if (Obj.SymbolTable != nullptr)
- Obj.SymbolTable->fillShndxTable();
-
- // Finally now that all offsets and indexes have been set we can finalize any
- // remaining issues.
- uint64_t Offset = Obj.SHOff + sizeof(Elf_Shdr);
- for (SectionBase &Sec : Obj.sections()) {
- Sec.HeaderOffset = Offset;
- Offset += sizeof(Elf_Shdr);
- if (WriteSectionHeaders)
- Sec.NameIndex = Obj.SectionNames->findIndex(Sec.Name);
- Sec.finalize();
- }
-
- if (Error E = Buf.allocate(totalSize()))
- return E;
- SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf);
- return Error::success();
-}
-
-Error BinaryWriter::write() {
- for (const SectionBase &Sec : Obj.allocSections())
+ }
+
+ // The symbol table does not update all other sections on update. For
+ // instance, symbol names are not added as new symbols are added. This means
+ // that some sections, like .strtab, don't yet have their final size.
+ if (Obj.SymbolTable != nullptr)
+ Obj.SymbolTable->prepareForLayout();
+
+ // Now that all strings are added we want to finalize string table builders,
+ // because that affects section sizes which in turn affects section offsets.
+ for (SectionBase &Sec : Obj.sections())
+ if (auto StrTab = dyn_cast<StringTableSection>(&Sec))
+ StrTab->prepareForLayout();
+
+ assignOffsets();
+
+ // layoutSections could have modified section indexes, so we need
+ // to fill the index table after assignOffsets.
+ if (Obj.SymbolTable != nullptr)
+ Obj.SymbolTable->fillShndxTable();
+
+ // Finally now that all offsets and indexes have been set we can finalize any
+ // remaining issues.
+ uint64_t Offset = Obj.SHOff + sizeof(Elf_Shdr);
+ for (SectionBase &Sec : Obj.sections()) {
+ Sec.HeaderOffset = Offset;
+ Offset += sizeof(Elf_Shdr);
+ if (WriteSectionHeaders)
+ Sec.NameIndex = Obj.SectionNames->findIndex(Sec.Name);
+ Sec.finalize();
+ }
+
+ if (Error E = Buf.allocate(totalSize()))
+ return E;
+ SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf);
+ return Error::success();
+}
+
+Error BinaryWriter::write() {
+ for (const SectionBase &Sec : Obj.allocSections())
if (Error Err = Sec.accept(*SecWriter))
return Err;
- return Buf.commit();
-}
-
-Error BinaryWriter::finalize() {
- // Compute the section LMA based on its sh_offset and the containing segment's
- // p_offset and p_paddr. Also compute the minimum LMA of all non-empty
- // sections as MinAddr. In the output, the contents between address 0 and
- // MinAddr will be skipped.
- uint64_t MinAddr = UINT64_MAX;
- for (SectionBase &Sec : Obj.allocSections()) {
- if (Sec.ParentSegment != nullptr)
- Sec.Addr =
- Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr;
- if (Sec.Size > 0)
- MinAddr = std::min(MinAddr, Sec.Addr);
- }
-
- // Now that every section has been laid out we just need to compute the total
- // file size. This might not be the same as the offset returned by
- // layoutSections, because we want to truncate the last segment to the end of
- // its last non-empty section, to match GNU objcopy's behaviour.
- TotalSize = 0;
- for (SectionBase &Sec : Obj.allocSections())
- if (Sec.Type != SHT_NOBITS && Sec.Size > 0) {
- Sec.Offset = Sec.Addr - MinAddr;
- TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size);
- }
-
- if (Error E = Buf.allocate(TotalSize))
- return E;
- SecWriter = std::make_unique<BinarySectionWriter>(Buf);
- return Error::success();
-}
-
-bool IHexWriter::SectionCompare::operator()(const SectionBase *Lhs,
- const SectionBase *Rhs) const {
- return (sectionPhysicalAddr(Lhs) & 0xFFFFFFFFU) <
- (sectionPhysicalAddr(Rhs) & 0xFFFFFFFFU);
-}
-
-uint64_t IHexWriter::writeEntryPointRecord(uint8_t *Buf) {
- IHexLineData HexData;
- uint8_t Data[4] = {};
- // We don't write entry point record if entry is zero.
- if (Obj.Entry == 0)
- return 0;
-
- if (Obj.Entry <= 0xFFFFFU) {
- Data[0] = ((Obj.Entry & 0xF0000U) >> 12) & 0xFF;
- support::endian::write(&Data[2], static_cast<uint16_t>(Obj.Entry),
- support::big);
- HexData = IHexRecord::getLine(IHexRecord::StartAddr80x86, 0, Data);
- } else {
- support::endian::write(Data, static_cast<uint32_t>(Obj.Entry),
- support::big);
- HexData = IHexRecord::getLine(IHexRecord::StartAddr, 0, Data);
- }
- memcpy(Buf, HexData.data(), HexData.size());
- return HexData.size();
-}
-
-uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) {
- IHexLineData HexData = IHexRecord::getLine(IHexRecord::EndOfFile, 0, {});
- memcpy(Buf, HexData.data(), HexData.size());
- return HexData.size();
-}
-
-Error IHexWriter::write() {
- IHexSectionWriter Writer(Buf);
- // Write sections.
- for (const SectionBase *Sec : Sections)
+ return Buf.commit();
+}
+
+Error BinaryWriter::finalize() {
+ // Compute the section LMA based on its sh_offset and the containing segment's
+ // p_offset and p_paddr. Also compute the minimum LMA of all non-empty
+ // sections as MinAddr. In the output, the contents between address 0 and
+ // MinAddr will be skipped.
+ uint64_t MinAddr = UINT64_MAX;
+ for (SectionBase &Sec : Obj.allocSections()) {
+ if (Sec.ParentSegment != nullptr)
+ Sec.Addr =
+ Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr;
+ if (Sec.Size > 0)
+ MinAddr = std::min(MinAddr, Sec.Addr);
+ }
+
+ // Now that every section has been laid out we just need to compute the total
+ // file size. This might not be the same as the offset returned by
+ // layoutSections, because we want to truncate the last segment to the end of
+ // its last non-empty section, to match GNU objcopy's behaviour.
+ TotalSize = 0;
+ for (SectionBase &Sec : Obj.allocSections())
+ if (Sec.Type != SHT_NOBITS && Sec.Size > 0) {
+ Sec.Offset = Sec.Addr - MinAddr;
+ TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size);
+ }
+
+ if (Error E = Buf.allocate(TotalSize))
+ return E;
+ SecWriter = std::make_unique<BinarySectionWriter>(Buf);
+ return Error::success();
+}
+
+bool IHexWriter::SectionCompare::operator()(const SectionBase *Lhs,
+ const SectionBase *Rhs) const {
+ return (sectionPhysicalAddr(Lhs) & 0xFFFFFFFFU) <
+ (sectionPhysicalAddr(Rhs) & 0xFFFFFFFFU);
+}
+
+uint64_t IHexWriter::writeEntryPointRecord(uint8_t *Buf) {
+ IHexLineData HexData;
+ uint8_t Data[4] = {};
+ // We don't write entry point record if entry is zero.
+ if (Obj.Entry == 0)
+ return 0;
+
+ if (Obj.Entry <= 0xFFFFFU) {
+ Data[0] = ((Obj.Entry & 0xF0000U) >> 12) & 0xFF;
+ support::endian::write(&Data[2], static_cast<uint16_t>(Obj.Entry),
+ support::big);
+ HexData = IHexRecord::getLine(IHexRecord::StartAddr80x86, 0, Data);
+ } else {
+ support::endian::write(Data, static_cast<uint32_t>(Obj.Entry),
+ support::big);
+ HexData = IHexRecord::getLine(IHexRecord::StartAddr, 0, Data);
+ }
+ memcpy(Buf, HexData.data(), HexData.size());
+ return HexData.size();
+}
+
+uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) {
+ IHexLineData HexData = IHexRecord::getLine(IHexRecord::EndOfFile, 0, {});
+ memcpy(Buf, HexData.data(), HexData.size());
+ return HexData.size();
+}
+
+Error IHexWriter::write() {
+ IHexSectionWriter Writer(Buf);
+ // Write sections.
+ for (const SectionBase *Sec : Sections)
if (Error Err = Sec->accept(Writer))
return Err;
-
- uint64_t Offset = Writer.getBufferOffset();
- // Write entry point address.
- Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset);
- // Write EOF.
- Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset);
- assert(Offset == TotalSize);
- return Buf.commit();
-}
-
-Error IHexWriter::checkSection(const SectionBase &Sec) {
- uint64_t Addr = sectionPhysicalAddr(&Sec);
- if (addressOverflows32bit(Addr) || addressOverflows32bit(Addr + Sec.Size - 1))
- return createStringError(
- errc::invalid_argument,
+
+ uint64_t Offset = Writer.getBufferOffset();
+ // Write entry point address.
+ Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset);
+ // Write EOF.
+ Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset);
+ assert(Offset == TotalSize);
+ return Buf.commit();
+}
+
+Error IHexWriter::checkSection(const SectionBase &Sec) {
+ uint64_t Addr = sectionPhysicalAddr(&Sec);
+ if (addressOverflows32bit(Addr) || addressOverflows32bit(Addr + Sec.Size - 1))
+ return createStringError(
+ errc::invalid_argument,
"Section '%s' address range [0x%llx, 0x%llx] is not 32 bit",
Sec.Name.c_str(), Addr, Addr + Sec.Size - 1);
- return Error::success();
-}
-
-Error IHexWriter::finalize() {
- bool UseSegments = false;
- auto ShouldWrite = [](const SectionBase &Sec) {
- return (Sec.Flags & ELF::SHF_ALLOC) && (Sec.Type != ELF::SHT_NOBITS);
- };
- auto IsInPtLoad = [](const SectionBase &Sec) {
- return Sec.ParentSegment && Sec.ParentSegment->Type == ELF::PT_LOAD;
- };
-
- // We can't write 64-bit addresses.
- if (addressOverflows32bit(Obj.Entry))
- return createStringError(errc::invalid_argument,
- "Entry point address 0x%llx overflows 32 bits.",
- Obj.Entry);
-
- // If any section we're to write has segment then we
- // switch to using physical addresses. Otherwise we
- // use section virtual address.
- for (const SectionBase &Sec : Obj.sections())
- if (ShouldWrite(Sec) && IsInPtLoad(Sec)) {
- UseSegments = true;
- break;
- }
-
- for (const SectionBase &Sec : Obj.sections())
- if (ShouldWrite(Sec) && (!UseSegments || IsInPtLoad(Sec))) {
- if (Error E = checkSection(Sec))
- return E;
- Sections.insert(&Sec);
- }
-
- IHexSectionWriterBase LengthCalc(Buf);
- for (const SectionBase *Sec : Sections)
+ return Error::success();
+}
+
+Error IHexWriter::finalize() {
+ bool UseSegments = false;
+ auto ShouldWrite = [](const SectionBase &Sec) {
+ return (Sec.Flags & ELF::SHF_ALLOC) && (Sec.Type != ELF::SHT_NOBITS);
+ };
+ auto IsInPtLoad = [](const SectionBase &Sec) {
+ return Sec.ParentSegment && Sec.ParentSegment->Type == ELF::PT_LOAD;
+ };
+
+ // We can't write 64-bit addresses.
+ if (addressOverflows32bit(Obj.Entry))
+ return createStringError(errc::invalid_argument,
+ "Entry point address 0x%llx overflows 32 bits.",
+ Obj.Entry);
+
+ // If any section we're to write has segment then we
+ // switch to using physical addresses. Otherwise we
+ // use section virtual address.
+ for (const SectionBase &Sec : Obj.sections())
+ if (ShouldWrite(Sec) && IsInPtLoad(Sec)) {
+ UseSegments = true;
+ break;
+ }
+
+ for (const SectionBase &Sec : Obj.sections())
+ if (ShouldWrite(Sec) && (!UseSegments || IsInPtLoad(Sec))) {
+ if (Error E = checkSection(Sec))
+ return E;
+ Sections.insert(&Sec);
+ }
+
+ IHexSectionWriterBase LengthCalc(Buf);
+ for (const SectionBase *Sec : Sections)
if (Error Err = Sec->accept(LengthCalc))
return Err;
-
- // We need space to write section records + StartAddress record
- // (if start adress is not zero) + EndOfFile record.
- TotalSize = LengthCalc.getBufferOffset() +
- (Obj.Entry ? IHexRecord::getLineLength(4) : 0) +
- IHexRecord::getLineLength(0);
- if (Error E = Buf.allocate(TotalSize))
- return E;
- return Error::success();
-}
-
-template class ELFBuilder<ELF64LE>;
-template class ELFBuilder<ELF64BE>;
-template class ELFBuilder<ELF32LE>;
-template class ELFBuilder<ELF32BE>;
-
-template class ELFWriter<ELF64LE>;
-template class ELFWriter<ELF64BE>;
-template class ELFWriter<ELF32LE>;
-template class ELFWriter<ELF32BE>;
-
-} // end namespace elf
-} // end namespace objcopy
-} // end namespace llvm
+
+ // We need space to write section records + StartAddress record
+ // (if start adress is not zero) + EndOfFile record.
+ TotalSize = LengthCalc.getBufferOffset() +
+ (Obj.Entry ? IHexRecord::getLineLength(4) : 0) +
+ IHexRecord::getLineLength(0);
+ if (Error E = Buf.allocate(TotalSize))
+ return E;
+ return Error::success();
+}
+
+template class ELFBuilder<ELF64LE>;
+template class ELFBuilder<ELF64BE>;
+template class ELFBuilder<ELF32LE>;
+template class ELFBuilder<ELF32BE>;
+
+template class ELFWriter<ELF64LE>;
+template class ELFWriter<ELF64BE>;
+template class ELFWriter<ELF32LE>;
+template class ELFWriter<ELF32BE>;
+
+} // end namespace elf
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h
index 0205c2d4f3..8a0ceb67d7 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/ELF/Object.h
@@ -1,79 +1,79 @@
-//===- Object.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_OBJCOPY_OBJECT_H
-#define LLVM_TOOLS_OBJCOPY_OBJECT_H
-
-#include "Buffer.h"
-#include "CopyConfig.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/MC/StringTableBuilder.h"
-#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include <cstddef>
-#include <cstdint>
-#include <functional>
-#include <memory>
-#include <set>
-#include <vector>
-
-namespace llvm {
-enum class DebugCompressionType;
-namespace objcopy {
-namespace elf {
-
-class SectionBase;
-class Section;
-class OwnedDataSection;
-class StringTableSection;
-class SymbolTableSection;
-class RelocationSection;
-class DynamicRelocationSection;
-class GnuDebugLinkSection;
-class GroupSection;
-class SectionIndexSection;
-class CompressedSection;
-class DecompressedSection;
-class Segment;
-class Object;
-struct Symbol;
-
-class SectionTableRef {
- MutableArrayRef<std::unique_ptr<SectionBase>> Sections;
-
-public:
- using iterator = pointee_iterator<std::unique_ptr<SectionBase> *>;
-
- explicit SectionTableRef(MutableArrayRef<std::unique_ptr<SectionBase>> Secs)
- : Sections(Secs) {}
- SectionTableRef(const SectionTableRef &) = default;
-
- iterator begin() const { return iterator(Sections.data()); }
- iterator end() const { return iterator(Sections.data() + Sections.size()); }
- size_t size() const { return Sections.size(); }
-
+//===- Object.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_OBJCOPY_OBJECT_H
+#define LLVM_TOOLS_OBJCOPY_OBJECT_H
+
+#include "Buffer.h"
+#include "CopyConfig.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <set>
+#include <vector>
+
+namespace llvm {
+enum class DebugCompressionType;
+namespace objcopy {
+namespace elf {
+
+class SectionBase;
+class Section;
+class OwnedDataSection;
+class StringTableSection;
+class SymbolTableSection;
+class RelocationSection;
+class DynamicRelocationSection;
+class GnuDebugLinkSection;
+class GroupSection;
+class SectionIndexSection;
+class CompressedSection;
+class DecompressedSection;
+class Segment;
+class Object;
+struct Symbol;
+
+class SectionTableRef {
+ MutableArrayRef<std::unique_ptr<SectionBase>> Sections;
+
+public:
+ using iterator = pointee_iterator<std::unique_ptr<SectionBase> *>;
+
+ explicit SectionTableRef(MutableArrayRef<std::unique_ptr<SectionBase>> Secs)
+ : Sections(Secs) {}
+ SectionTableRef(const SectionTableRef &) = default;
+
+ iterator begin() const { return iterator(Sections.data()); }
+ iterator end() const { return iterator(Sections.data() + Sections.size()); }
+ size_t size() const { return Sections.size(); }
+
Expected<SectionBase *> getSection(uint32_t Index, Twine ErrMsg);
-
- template <class T>
+
+ template <class T>
Expected<T *> getSectionOfType(uint32_t Index, Twine IndexErrMsg,
Twine TypeErrMsg);
-};
-
-enum ElfType { ELFT_ELF32LE, ELFT_ELF64LE, ELFT_ELF32BE, ELFT_ELF64BE };
-
-class SectionVisitor {
-public:
- virtual ~SectionVisitor() = default;
-
+};
+
+enum ElfType { ELFT_ELF32LE, ELFT_ELF64LE, ELFT_ELF32BE, ELFT_ELF64BE };
+
+class SectionVisitor {
+public:
+ virtual ~SectionVisitor() = default;
+
virtual Error visit(const Section &Sec) = 0;
virtual Error visit(const OwnedDataSection &Sec) = 0;
virtual Error visit(const StringTableSection &Sec) = 0;
@@ -85,12 +85,12 @@ public:
virtual Error visit(const SectionIndexSection &Sec) = 0;
virtual Error visit(const CompressedSection &Sec) = 0;
virtual Error visit(const DecompressedSection &Sec) = 0;
-};
-
-class MutableSectionVisitor {
-public:
- virtual ~MutableSectionVisitor() = default;
-
+};
+
+class MutableSectionVisitor {
+public:
+ virtual ~MutableSectionVisitor() = default;
+
virtual Error visit(Section &Sec) = 0;
virtual Error visit(OwnedDataSection &Sec) = 0;
virtual Error visit(StringTableSection &Sec) = 0;
@@ -102,15 +102,15 @@ public:
virtual Error visit(SectionIndexSection &Sec) = 0;
virtual Error visit(CompressedSection &Sec) = 0;
virtual Error visit(DecompressedSection &Sec) = 0;
-};
-
-class SectionWriter : public SectionVisitor {
-protected:
- Buffer &Out;
-
-public:
- virtual ~SectionWriter() = default;
-
+};
+
+class SectionWriter : public SectionVisitor {
+protected:
+ Buffer &Out;
+
+public:
+ virtual ~SectionWriter() = default;
+
Error visit(const Section &Sec) override;
Error visit(const OwnedDataSection &Sec) override;
Error visit(const StringTableSection &Sec) override;
@@ -122,19 +122,19 @@ public:
virtual Error visit(const SectionIndexSection &Sec) override = 0;
virtual Error visit(const CompressedSection &Sec) override = 0;
virtual Error visit(const DecompressedSection &Sec) override = 0;
-
- explicit SectionWriter(Buffer &Buf) : Out(Buf) {}
-};
-
-template <class ELFT> class ELFSectionWriter : public SectionWriter {
-private:
- using Elf_Word = typename ELFT::Word;
- using Elf_Rel = typename ELFT::Rel;
- using Elf_Rela = typename ELFT::Rela;
- using Elf_Sym = typename ELFT::Sym;
-
-public:
- virtual ~ELFSectionWriter() {}
+
+ explicit SectionWriter(Buffer &Buf) : Out(Buf) {}
+};
+
+template <class ELFT> class ELFSectionWriter : public SectionWriter {
+private:
+ using Elf_Word = typename ELFT::Word;
+ using Elf_Rel = typename ELFT::Rel;
+ using Elf_Rela = typename ELFT::Rela;
+ using Elf_Sym = typename ELFT::Sym;
+
+public:
+ virtual ~ELFSectionWriter() {}
Error visit(const SymbolTableSection &Sec) override;
Error visit(const RelocationSection &Sec) override;
Error visit(const GnuDebugLinkSection &Sec) override;
@@ -142,19 +142,19 @@ public:
Error visit(const SectionIndexSection &Sec) override;
Error visit(const CompressedSection &Sec) override;
Error visit(const DecompressedSection &Sec) override;
-
- explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
-};
-
-template <class ELFT> class ELFSectionSizer : public MutableSectionVisitor {
-private:
- using Elf_Rel = typename ELFT::Rel;
- using Elf_Rela = typename ELFT::Rela;
- using Elf_Sym = typename ELFT::Sym;
- using Elf_Word = typename ELFT::Word;
- using Elf_Xword = typename ELFT::Xword;
-
-public:
+
+ explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
+};
+
+template <class ELFT> class ELFSectionSizer : public MutableSectionVisitor {
+private:
+ using Elf_Rel = typename ELFT::Rel;
+ using Elf_Rela = typename ELFT::Rela;
+ using Elf_Sym = typename ELFT::Sym;
+ using Elf_Word = typename ELFT::Word;
+ using Elf_Xword = typename ELFT::Xword;
+
+public:
Error visit(Section &Sec) override;
Error visit(OwnedDataSection &Sec) override;
Error visit(StringTableSection &Sec) override;
@@ -166,19 +166,19 @@ public:
Error visit(SectionIndexSection &Sec) override;
Error visit(CompressedSection &Sec) override;
Error visit(DecompressedSection &Sec) override;
-};
-
-#define MAKE_SEC_WRITER_FRIEND \
- friend class SectionWriter; \
- friend class IHexSectionWriterBase; \
- friend class IHexSectionWriter; \
- template <class ELFT> friend class ELFSectionWriter; \
- template <class ELFT> friend class ELFSectionSizer;
-
-class BinarySectionWriter : public SectionWriter {
-public:
- virtual ~BinarySectionWriter() {}
-
+};
+
+#define MAKE_SEC_WRITER_FRIEND \
+ friend class SectionWriter; \
+ friend class IHexSectionWriterBase; \
+ friend class IHexSectionWriter; \
+ template <class ELFT> friend class ELFSectionWriter; \
+ template <class ELFT> friend class ELFSectionSizer;
+
+class BinarySectionWriter : public SectionWriter {
+public:
+ virtual ~BinarySectionWriter() {}
+
Error visit(const SymbolTableSection &Sec) override;
Error visit(const RelocationSection &Sec) override;
Error visit(const GnuDebugLinkSection &Sec) override;
@@ -186,766 +186,766 @@ public:
Error visit(const SectionIndexSection &Sec) override;
Error visit(const CompressedSection &Sec) override;
Error visit(const DecompressedSection &Sec) override;
-
- explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
-};
-
-using IHexLineData = SmallVector<char, 64>;
-
-struct IHexRecord {
- // Memory address of the record.
- uint16_t Addr;
- // Record type (see below).
- uint16_t Type;
- // Record data in hexadecimal form.
- StringRef HexData;
-
- // Helper method to get file length of the record
- // including newline character
- static size_t getLength(size_t DataSize) {
- // :LLAAAATT[DD...DD]CC'
- return DataSize * 2 + 11;
- }
-
- // Gets length of line in a file (getLength + CRLF).
- static size_t getLineLength(size_t DataSize) {
- return getLength(DataSize) + 2;
- }
-
- // Given type, address and data returns line which can
- // be written to output file.
- static IHexLineData getLine(uint8_t Type, uint16_t Addr,
- ArrayRef<uint8_t> Data);
-
- // Parses the line and returns record if possible.
- // Line should be trimmed from whitespace characters.
- static Expected<IHexRecord> parse(StringRef Line);
-
- // Calculates checksum of stringified record representation
- // S must NOT contain leading ':' and trailing whitespace
- // characters
- static uint8_t getChecksum(StringRef S);
-
- enum Type {
- // Contains data and a 16-bit starting address for the data.
- // The byte count specifies number of data bytes in the record.
- Data = 0,
- // Must occur exactly once per file in the last line of the file.
- // The data field is empty (thus byte count is 00) and the address
- // field is typically 0000.
- EndOfFile = 1,
- // The data field contains a 16-bit segment base address (thus byte
- // count is always 02) compatible with 80x86 real mode addressing.
- // The address field (typically 0000) is ignored. The segment address
- // from the most recent 02 record is multiplied by 16 and added to each
- // subsequent data record address to form the physical starting address
- // for the data. This allows addressing up to one megabyte of address
- // space.
- SegmentAddr = 2,
- // or 80x86 processors, specifies the initial content of the CS:IP
- // registers. The address field is 0000, the byte count is always 04,
- // the first two data bytes are the CS value, the latter two are the
- // IP value.
- StartAddr80x86 = 3,
- // Allows for 32 bit addressing (up to 4GiB). The record's address field
- // is ignored (typically 0000) and its byte count is always 02. The two
- // data bytes (big endian) specify the upper 16 bits of the 32 bit
- // absolute address for all subsequent type 00 records
- ExtendedAddr = 4,
- // The address field is 0000 (not used) and the byte count is always 04.
- // The four data bytes represent a 32-bit address value. In the case of
- // 80386 and higher CPUs, this address is loaded into the EIP register.
- StartAddr = 5,
- // We have no other valid types
- InvalidType = 6
- };
-};
-
-// Base class for IHexSectionWriter. This class implements writing algorithm,
-// but doesn't actually write records. It is used for output buffer size
-// calculation in IHexWriter::finalize.
-class IHexSectionWriterBase : public BinarySectionWriter {
- // 20-bit segment address
- uint32_t SegmentAddr = 0;
- // Extended linear address
- uint32_t BaseAddr = 0;
-
- // Write segment address corresponding to 'Addr'
- uint64_t writeSegmentAddr(uint64_t Addr);
- // Write extended linear (base) address corresponding to 'Addr'
- uint64_t writeBaseAddr(uint64_t Addr);
-
-protected:
- // Offset in the output buffer
- uint64_t Offset = 0;
-
- void writeSection(const SectionBase *Sec, ArrayRef<uint8_t> Data);
- virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data);
-
-public:
- explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {}
-
- uint64_t getBufferOffset() const { return Offset; }
+
+ explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
+};
+
+using IHexLineData = SmallVector<char, 64>;
+
+struct IHexRecord {
+ // Memory address of the record.
+ uint16_t Addr;
+ // Record type (see below).
+ uint16_t Type;
+ // Record data in hexadecimal form.
+ StringRef HexData;
+
+ // Helper method to get file length of the record
+ // including newline character
+ static size_t getLength(size_t DataSize) {
+ // :LLAAAATT[DD...DD]CC'
+ return DataSize * 2 + 11;
+ }
+
+ // Gets length of line in a file (getLength + CRLF).
+ static size_t getLineLength(size_t DataSize) {
+ return getLength(DataSize) + 2;
+ }
+
+ // Given type, address and data returns line which can
+ // be written to output file.
+ static IHexLineData getLine(uint8_t Type, uint16_t Addr,
+ ArrayRef<uint8_t> Data);
+
+ // Parses the line and returns record if possible.
+ // Line should be trimmed from whitespace characters.
+ static Expected<IHexRecord> parse(StringRef Line);
+
+ // Calculates checksum of stringified record representation
+ // S must NOT contain leading ':' and trailing whitespace
+ // characters
+ static uint8_t getChecksum(StringRef S);
+
+ enum Type {
+ // Contains data and a 16-bit starting address for the data.
+ // The byte count specifies number of data bytes in the record.
+ Data = 0,
+ // Must occur exactly once per file in the last line of the file.
+ // The data field is empty (thus byte count is 00) and the address
+ // field is typically 0000.
+ EndOfFile = 1,
+ // The data field contains a 16-bit segment base address (thus byte
+ // count is always 02) compatible with 80x86 real mode addressing.
+ // The address field (typically 0000) is ignored. The segment address
+ // from the most recent 02 record is multiplied by 16 and added to each
+ // subsequent data record address to form the physical starting address
+ // for the data. This allows addressing up to one megabyte of address
+ // space.
+ SegmentAddr = 2,
+ // or 80x86 processors, specifies the initial content of the CS:IP
+ // registers. The address field is 0000, the byte count is always 04,
+ // the first two data bytes are the CS value, the latter two are the
+ // IP value.
+ StartAddr80x86 = 3,
+ // Allows for 32 bit addressing (up to 4GiB). The record's address field
+ // is ignored (typically 0000) and its byte count is always 02. The two
+ // data bytes (big endian) specify the upper 16 bits of the 32 bit
+ // absolute address for all subsequent type 00 records
+ ExtendedAddr = 4,
+ // The address field is 0000 (not used) and the byte count is always 04.
+ // The four data bytes represent a 32-bit address value. In the case of
+ // 80386 and higher CPUs, this address is loaded into the EIP register.
+ StartAddr = 5,
+ // We have no other valid types
+ InvalidType = 6
+ };
+};
+
+// Base class for IHexSectionWriter. This class implements writing algorithm,
+// but doesn't actually write records. It is used for output buffer size
+// calculation in IHexWriter::finalize.
+class IHexSectionWriterBase : public BinarySectionWriter {
+ // 20-bit segment address
+ uint32_t SegmentAddr = 0;
+ // Extended linear address
+ uint32_t BaseAddr = 0;
+
+ // Write segment address corresponding to 'Addr'
+ uint64_t writeSegmentAddr(uint64_t Addr);
+ // Write extended linear (base) address corresponding to 'Addr'
+ uint64_t writeBaseAddr(uint64_t Addr);
+
+protected:
+ // Offset in the output buffer
+ uint64_t Offset = 0;
+
+ void writeSection(const SectionBase *Sec, ArrayRef<uint8_t> Data);
+ virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data);
+
+public:
+ explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {}
+
+ uint64_t getBufferOffset() const { return Offset; }
Error visit(const Section &Sec) final;
Error visit(const OwnedDataSection &Sec) final;
Error visit(const StringTableSection &Sec) override;
Error visit(const DynamicRelocationSection &Sec) final;
- using BinarySectionWriter::visit;
-};
-
-// Real IHEX section writer
-class IHexSectionWriter : public IHexSectionWriterBase {
-public:
- IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {}
-
- void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override;
+ using BinarySectionWriter::visit;
+};
+
+// Real IHEX section writer
+class IHexSectionWriter : public IHexSectionWriterBase {
+public:
+ IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {}
+
+ void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override;
Error visit(const StringTableSection &Sec) override;
-};
-
-class Writer {
-protected:
- Object &Obj;
- Buffer &Buf;
-
-public:
- virtual ~Writer();
- virtual Error finalize() = 0;
- virtual Error write() = 0;
-
- Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {}
-};
-
-template <class ELFT> class ELFWriter : public Writer {
-private:
- using Elf_Addr = typename ELFT::Addr;
- using Elf_Shdr = typename ELFT::Shdr;
- using Elf_Phdr = typename ELFT::Phdr;
- using Elf_Ehdr = typename ELFT::Ehdr;
-
- void initEhdrSegment();
-
- void writeEhdr();
- void writePhdr(const Segment &Seg);
- void writeShdr(const SectionBase &Sec);
-
- void writePhdrs();
- void writeShdrs();
+};
+
+class Writer {
+protected:
+ Object &Obj;
+ Buffer &Buf;
+
+public:
+ virtual ~Writer();
+ virtual Error finalize() = 0;
+ virtual Error write() = 0;
+
+ Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {}
+};
+
+template <class ELFT> class ELFWriter : public Writer {
+private:
+ using Elf_Addr = typename ELFT::Addr;
+ using Elf_Shdr = typename ELFT::Shdr;
+ using Elf_Phdr = typename ELFT::Phdr;
+ using Elf_Ehdr = typename ELFT::Ehdr;
+
+ void initEhdrSegment();
+
+ void writeEhdr();
+ void writePhdr(const Segment &Seg);
+ void writeShdr(const SectionBase &Sec);
+
+ void writePhdrs();
+ void writeShdrs();
Error writeSectionData();
- void writeSegmentData();
-
- void assignOffsets();
-
- std::unique_ptr<ELFSectionWriter<ELFT>> SecWriter;
-
- size_t totalSize() const;
-
-public:
- virtual ~ELFWriter() {}
- bool WriteSectionHeaders;
-
- // For --only-keep-debug, select an alternative section/segment layout
- // algorithm.
- bool OnlyKeepDebug;
-
- Error finalize() override;
- Error write() override;
- ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool OnlyKeepDebug);
-};
-
-class BinaryWriter : public Writer {
-private:
- std::unique_ptr<BinarySectionWriter> SecWriter;
-
- uint64_t TotalSize = 0;
-
-public:
- ~BinaryWriter() {}
- Error finalize() override;
- Error write() override;
- BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
-};
-
-class IHexWriter : public Writer {
- struct SectionCompare {
- bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const;
- };
-
- std::set<const SectionBase *, SectionCompare> Sections;
- size_t TotalSize = 0;
-
- Error checkSection(const SectionBase &Sec);
- uint64_t writeEntryPointRecord(uint8_t *Buf);
- uint64_t writeEndOfFileRecord(uint8_t *Buf);
-
-public:
- ~IHexWriter() {}
- Error finalize() override;
- Error write() override;
- IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
-};
-
-class SectionBase {
-public:
- std::string Name;
- Segment *ParentSegment = nullptr;
- uint64_t HeaderOffset = 0;
- uint32_t Index = 0;
-
+ void writeSegmentData();
+
+ void assignOffsets();
+
+ std::unique_ptr<ELFSectionWriter<ELFT>> SecWriter;
+
+ size_t totalSize() const;
+
+public:
+ virtual ~ELFWriter() {}
+ bool WriteSectionHeaders;
+
+ // For --only-keep-debug, select an alternative section/segment layout
+ // algorithm.
+ bool OnlyKeepDebug;
+
+ Error finalize() override;
+ Error write() override;
+ ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool OnlyKeepDebug);
+};
+
+class BinaryWriter : public Writer {
+private:
+ std::unique_ptr<BinarySectionWriter> SecWriter;
+
+ uint64_t TotalSize = 0;
+
+public:
+ ~BinaryWriter() {}
+ Error finalize() override;
+ Error write() override;
+ BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
+};
+
+class IHexWriter : public Writer {
+ struct SectionCompare {
+ bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const;
+ };
+
+ std::set<const SectionBase *, SectionCompare> Sections;
+ size_t TotalSize = 0;
+
+ Error checkSection(const SectionBase &Sec);
+ uint64_t writeEntryPointRecord(uint8_t *Buf);
+ uint64_t writeEndOfFileRecord(uint8_t *Buf);
+
+public:
+ ~IHexWriter() {}
+ Error finalize() override;
+ Error write() override;
+ IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
+};
+
+class SectionBase {
+public:
+ std::string Name;
+ Segment *ParentSegment = nullptr;
+ uint64_t HeaderOffset = 0;
+ uint32_t Index = 0;
+
uint32_t OriginalIndex = 0;
- uint64_t OriginalFlags = 0;
- uint64_t OriginalType = ELF::SHT_NULL;
- uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max();
-
- uint64_t Addr = 0;
- uint64_t Align = 1;
- uint32_t EntrySize = 0;
- uint64_t Flags = 0;
- uint64_t Info = 0;
- uint64_t Link = ELF::SHN_UNDEF;
- uint64_t NameIndex = 0;
- uint64_t Offset = 0;
- uint64_t Size = 0;
- uint64_t Type = ELF::SHT_NULL;
- ArrayRef<uint8_t> OriginalData;
+ uint64_t OriginalFlags = 0;
+ uint64_t OriginalType = ELF::SHT_NULL;
+ uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max();
+
+ uint64_t Addr = 0;
+ uint64_t Align = 1;
+ uint32_t EntrySize = 0;
+ uint64_t Flags = 0;
+ uint64_t Info = 0;
+ uint64_t Link = ELF::SHN_UNDEF;
+ uint64_t NameIndex = 0;
+ uint64_t Offset = 0;
+ uint64_t Size = 0;
+ uint64_t Type = ELF::SHT_NULL;
+ ArrayRef<uint8_t> OriginalData;
bool HasSymbol = false;
-
- SectionBase() = default;
- SectionBase(const SectionBase &) = default;
-
- virtual ~SectionBase() = default;
-
+
+ SectionBase() = default;
+ SectionBase(const SectionBase &) = default;
+
+ virtual ~SectionBase() = default;
+
virtual Error initialize(SectionTableRef SecTable);
- virtual void finalize();
- // Remove references to these sections. The list of sections must be sorted.
- virtual Error
- removeSectionReferences(bool AllowBrokenLinks,
- function_ref<bool(const SectionBase *)> ToRemove);
- virtual Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
+ virtual void finalize();
+ // Remove references to these sections. The list of sections must be sorted.
+ virtual Error
+ removeSectionReferences(bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove);
+ virtual Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
virtual Error accept(SectionVisitor &Visitor) const = 0;
virtual Error accept(MutableSectionVisitor &Visitor) = 0;
- virtual void markSymbols();
- virtual void
- replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &);
- // Notify the section that it is subject to removal.
- virtual void onRemove();
-};
-
-class Segment {
-private:
- struct SectionCompare {
- bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const {
- // Some sections might have the same address if one of them is empty. To
- // fix this we can use the lexicographic ordering on ->Addr and the
+ virtual void markSymbols();
+ virtual void
+ replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &);
+ // Notify the section that it is subject to removal.
+ virtual void onRemove();
+};
+
+class Segment {
+private:
+ struct SectionCompare {
+ bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const {
+ // Some sections might have the same address if one of them is empty. To
+ // fix this we can use the lexicographic ordering on ->Addr and the
// original index.
- if (Lhs->OriginalOffset == Rhs->OriginalOffset)
+ if (Lhs->OriginalOffset == Rhs->OriginalOffset)
return Lhs->OriginalIndex < Rhs->OriginalIndex;
- return Lhs->OriginalOffset < Rhs->OriginalOffset;
- }
- };
-
-public:
- uint32_t Type = 0;
- uint32_t Flags = 0;
- uint64_t Offset = 0;
- uint64_t VAddr = 0;
- uint64_t PAddr = 0;
- uint64_t FileSize = 0;
- uint64_t MemSize = 0;
- uint64_t Align = 0;
-
- uint32_t Index = 0;
- uint64_t OriginalOffset = 0;
- Segment *ParentSegment = nullptr;
- ArrayRef<uint8_t> Contents;
- std::set<const SectionBase *, SectionCompare> Sections;
-
- explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {}
- Segment() = default;
-
- const SectionBase *firstSection() const {
- if (!Sections.empty())
- return *Sections.begin();
- return nullptr;
- }
-
- void removeSection(const SectionBase *Sec) { Sections.erase(Sec); }
- void addSection(const SectionBase *Sec) { Sections.insert(Sec); }
-
- ArrayRef<uint8_t> getContents() const { return Contents; }
-};
-
-class Section : public SectionBase {
- MAKE_SEC_WRITER_FRIEND
-
- ArrayRef<uint8_t> Contents;
- SectionBase *LinkSection = nullptr;
-
-public:
- explicit Section(ArrayRef<uint8_t> Data) : Contents(Data) {}
-
+ return Lhs->OriginalOffset < Rhs->OriginalOffset;
+ }
+ };
+
+public:
+ uint32_t Type = 0;
+ uint32_t Flags = 0;
+ uint64_t Offset = 0;
+ uint64_t VAddr = 0;
+ uint64_t PAddr = 0;
+ uint64_t FileSize = 0;
+ uint64_t MemSize = 0;
+ uint64_t Align = 0;
+
+ uint32_t Index = 0;
+ uint64_t OriginalOffset = 0;
+ Segment *ParentSegment = nullptr;
+ ArrayRef<uint8_t> Contents;
+ std::set<const SectionBase *, SectionCompare> Sections;
+
+ explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {}
+ Segment() = default;
+
+ const SectionBase *firstSection() const {
+ if (!Sections.empty())
+ return *Sections.begin();
+ return nullptr;
+ }
+
+ void removeSection(const SectionBase *Sec) { Sections.erase(Sec); }
+ void addSection(const SectionBase *Sec) { Sections.insert(Sec); }
+
+ ArrayRef<uint8_t> getContents() const { return Contents; }
+};
+
+class Section : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+ ArrayRef<uint8_t> Contents;
+ SectionBase *LinkSection = nullptr;
+
+public:
+ explicit Section(ArrayRef<uint8_t> Data) : Contents(Data) {}
+
Error accept(SectionVisitor &Visitor) const override;
Error accept(MutableSectionVisitor &Visitor) override;
Error removeSectionReferences(
bool AllowBrokenLinks,
- function_ref<bool(const SectionBase *)> ToRemove) override;
+ function_ref<bool(const SectionBase *)> ToRemove) override;
Error initialize(SectionTableRef SecTable) override;
- void finalize() override;
-};
-
-class OwnedDataSection : public SectionBase {
- MAKE_SEC_WRITER_FRIEND
-
- std::vector<uint8_t> Data;
-
-public:
- OwnedDataSection(StringRef SecName, ArrayRef<uint8_t> Data)
- : Data(std::begin(Data), std::end(Data)) {
- Name = SecName.str();
- Type = OriginalType = ELF::SHT_PROGBITS;
- Size = Data.size();
- OriginalOffset = std::numeric_limits<uint64_t>::max();
- }
-
- OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags,
- uint64_t SecOff) {
- Name = SecName.str();
- Type = OriginalType = ELF::SHT_PROGBITS;
- Addr = SecAddr;
- Flags = OriginalFlags = SecFlags;
- OriginalOffset = SecOff;
- }
-
- void appendHexData(StringRef HexData);
+ void finalize() override;
+};
+
+class OwnedDataSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+ std::vector<uint8_t> Data;
+
+public:
+ OwnedDataSection(StringRef SecName, ArrayRef<uint8_t> Data)
+ : Data(std::begin(Data), std::end(Data)) {
+ Name = SecName.str();
+ Type = OriginalType = ELF::SHT_PROGBITS;
+ Size = Data.size();
+ OriginalOffset = std::numeric_limits<uint64_t>::max();
+ }
+
+ OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags,
+ uint64_t SecOff) {
+ Name = SecName.str();
+ Type = OriginalType = ELF::SHT_PROGBITS;
+ Addr = SecAddr;
+ Flags = OriginalFlags = SecFlags;
+ OriginalOffset = SecOff;
+ }
+
+ void appendHexData(StringRef HexData);
Error accept(SectionVisitor &Sec) const override;
Error accept(MutableSectionVisitor &Visitor) override;
-};
-
-class CompressedSection : public SectionBase {
- MAKE_SEC_WRITER_FRIEND
-
- DebugCompressionType CompressionType;
- uint64_t DecompressedSize;
- uint64_t DecompressedAlign;
- SmallVector<char, 128> CompressedData;
-
-public:
+};
+
+class CompressedSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+ DebugCompressionType CompressionType;
+ uint64_t DecompressedSize;
+ uint64_t DecompressedAlign;
+ SmallVector<char, 128> CompressedData;
+
+public:
static Expected<CompressedSection>
create(const SectionBase &Sec, DebugCompressionType CompressionType);
static Expected<CompressedSection> create(ArrayRef<uint8_t> CompressedData,
uint64_t DecompressedSize,
uint64_t DecompressedAlign);
-
- uint64_t getDecompressedSize() const { return DecompressedSize; }
- uint64_t getDecompressedAlign() const { return DecompressedAlign; }
-
+
+ uint64_t getDecompressedSize() const { return DecompressedSize; }
+ uint64_t getDecompressedAlign() const { return DecompressedAlign; }
+
Error accept(SectionVisitor &Visitor) const override;
Error accept(MutableSectionVisitor &Visitor) override;
-
- static bool classof(const SectionBase *S) {
- return (S->OriginalFlags & ELF::SHF_COMPRESSED) ||
- (StringRef(S->Name).startswith(".zdebug"));
- }
+
+ static bool classof(const SectionBase *S) {
+ return (S->OriginalFlags & ELF::SHF_COMPRESSED) ||
+ (StringRef(S->Name).startswith(".zdebug"));
+ }
private:
CompressedSection(const SectionBase &Sec,
DebugCompressionType CompressionType, Error &Err);
CompressedSection(ArrayRef<uint8_t> CompressedData, uint64_t DecompressedSize,
uint64_t DecompressedAlign);
-};
-
-class DecompressedSection : public SectionBase {
- MAKE_SEC_WRITER_FRIEND
-
-public:
- explicit DecompressedSection(const CompressedSection &Sec)
- : SectionBase(Sec) {
- Size = Sec.getDecompressedSize();
- Align = Sec.getDecompressedAlign();
- Flags = OriginalFlags = (Flags & ~ELF::SHF_COMPRESSED);
- if (StringRef(Name).startswith(".zdebug"))
- Name = "." + Name.substr(2);
- }
-
+};
+
+class DecompressedSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+public:
+ explicit DecompressedSection(const CompressedSection &Sec)
+ : SectionBase(Sec) {
+ Size = Sec.getDecompressedSize();
+ Align = Sec.getDecompressedAlign();
+ Flags = OriginalFlags = (Flags & ~ELF::SHF_COMPRESSED);
+ if (StringRef(Name).startswith(".zdebug"))
+ Name = "." + Name.substr(2);
+ }
+
Error accept(SectionVisitor &Visitor) const override;
Error accept(MutableSectionVisitor &Visitor) override;
-};
-
-// There are two types of string tables that can exist, dynamic and not dynamic.
-// In the dynamic case the string table is allocated. Changing a dynamic string
-// table would mean altering virtual addresses and thus the memory image. So
-// dynamic string tables should not have an interface to modify them or
-// reconstruct them. This type lets us reconstruct a string table. To avoid
-// this class being used for dynamic string tables (which has happened) the
-// classof method checks that the particular instance is not allocated. This
-// then agrees with the makeSection method used to construct most sections.
-class StringTableSection : public SectionBase {
- MAKE_SEC_WRITER_FRIEND
-
- StringTableBuilder StrTabBuilder;
-
-public:
- StringTableSection() : StrTabBuilder(StringTableBuilder::ELF) {
- Type = OriginalType = ELF::SHT_STRTAB;
- }
-
- void addString(StringRef Name);
- uint32_t findIndex(StringRef Name) const;
- void prepareForLayout();
+};
+
+// There are two types of string tables that can exist, dynamic and not dynamic.
+// In the dynamic case the string table is allocated. Changing a dynamic string
+// table would mean altering virtual addresses and thus the memory image. So
+// dynamic string tables should not have an interface to modify them or
+// reconstruct them. This type lets us reconstruct a string table. To avoid
+// this class being used for dynamic string tables (which has happened) the
+// classof method checks that the particular instance is not allocated. This
+// then agrees with the makeSection method used to construct most sections.
+class StringTableSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+ StringTableBuilder StrTabBuilder;
+
+public:
+ StringTableSection() : StrTabBuilder(StringTableBuilder::ELF) {
+ Type = OriginalType = ELF::SHT_STRTAB;
+ }
+
+ void addString(StringRef Name);
+ uint32_t findIndex(StringRef Name) const;
+ void prepareForLayout();
Error accept(SectionVisitor &Visitor) const override;
Error accept(MutableSectionVisitor &Visitor) override;
-
- static bool classof(const SectionBase *S) {
- if (S->OriginalFlags & ELF::SHF_ALLOC)
- return false;
- return S->OriginalType == ELF::SHT_STRTAB;
- }
-};
-
-// Symbols have a st_shndx field that normally stores an index but occasionally
-// stores a different special value. This enum keeps track of what the st_shndx
-// field means. Most of the values are just copies of the special SHN_* values.
-// SYMBOL_SIMPLE_INDEX means that the st_shndx is just an index of a section.
-enum SymbolShndxType {
- SYMBOL_SIMPLE_INDEX = 0,
- SYMBOL_ABS = ELF::SHN_ABS,
- SYMBOL_COMMON = ELF::SHN_COMMON,
- SYMBOL_LOPROC = ELF::SHN_LOPROC,
- SYMBOL_AMDGPU_LDS = ELF::SHN_AMDGPU_LDS,
- SYMBOL_HEXAGON_SCOMMON = ELF::SHN_HEXAGON_SCOMMON,
- SYMBOL_HEXAGON_SCOMMON_2 = ELF::SHN_HEXAGON_SCOMMON_2,
- SYMBOL_HEXAGON_SCOMMON_4 = ELF::SHN_HEXAGON_SCOMMON_4,
- SYMBOL_HEXAGON_SCOMMON_8 = ELF::SHN_HEXAGON_SCOMMON_8,
- SYMBOL_HIPROC = ELF::SHN_HIPROC,
- SYMBOL_LOOS = ELF::SHN_LOOS,
- SYMBOL_HIOS = ELF::SHN_HIOS,
- SYMBOL_XINDEX = ELF::SHN_XINDEX,
-};
-
-struct Symbol {
- uint8_t Binding;
- SectionBase *DefinedIn = nullptr;
- SymbolShndxType ShndxType;
- uint32_t Index;
- std::string Name;
- uint32_t NameIndex;
- uint64_t Size;
- uint8_t Type;
- uint64_t Value;
- uint8_t Visibility;
- bool Referenced = false;
-
- uint16_t getShndx() const;
- bool isCommon() const;
-};
-
-class SectionIndexSection : public SectionBase {
- MAKE_SEC_WRITER_FRIEND
-
-private:
- std::vector<uint32_t> Indexes;
- SymbolTableSection *Symbols = nullptr;
-
-public:
- virtual ~SectionIndexSection() {}
- void addIndex(uint32_t Index) {
- assert(Size > 0);
+
+ static bool classof(const SectionBase *S) {
+ if (S->OriginalFlags & ELF::SHF_ALLOC)
+ return false;
+ return S->OriginalType == ELF::SHT_STRTAB;
+ }
+};
+
+// Symbols have a st_shndx field that normally stores an index but occasionally
+// stores a different special value. This enum keeps track of what the st_shndx
+// field means. Most of the values are just copies of the special SHN_* values.
+// SYMBOL_SIMPLE_INDEX means that the st_shndx is just an index of a section.
+enum SymbolShndxType {
+ SYMBOL_SIMPLE_INDEX = 0,
+ SYMBOL_ABS = ELF::SHN_ABS,
+ SYMBOL_COMMON = ELF::SHN_COMMON,
+ SYMBOL_LOPROC = ELF::SHN_LOPROC,
+ SYMBOL_AMDGPU_LDS = ELF::SHN_AMDGPU_LDS,
+ SYMBOL_HEXAGON_SCOMMON = ELF::SHN_HEXAGON_SCOMMON,
+ SYMBOL_HEXAGON_SCOMMON_2 = ELF::SHN_HEXAGON_SCOMMON_2,
+ SYMBOL_HEXAGON_SCOMMON_4 = ELF::SHN_HEXAGON_SCOMMON_4,
+ SYMBOL_HEXAGON_SCOMMON_8 = ELF::SHN_HEXAGON_SCOMMON_8,
+ SYMBOL_HIPROC = ELF::SHN_HIPROC,
+ SYMBOL_LOOS = ELF::SHN_LOOS,
+ SYMBOL_HIOS = ELF::SHN_HIOS,
+ SYMBOL_XINDEX = ELF::SHN_XINDEX,
+};
+
+struct Symbol {
+ uint8_t Binding;
+ SectionBase *DefinedIn = nullptr;
+ SymbolShndxType ShndxType;
+ uint32_t Index;
+ std::string Name;
+ uint32_t NameIndex;
+ uint64_t Size;
+ uint8_t Type;
+ uint64_t Value;
+ uint8_t Visibility;
+ bool Referenced = false;
+
+ uint16_t getShndx() const;
+ bool isCommon() const;
+};
+
+class SectionIndexSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+private:
+ std::vector<uint32_t> Indexes;
+ SymbolTableSection *Symbols = nullptr;
+
+public:
+ virtual ~SectionIndexSection() {}
+ void addIndex(uint32_t Index) {
+ assert(Size > 0);
Indexes.push_back(Index);
+ }
+
+ void reserve(size_t NumSymbols) {
+ Indexes.reserve(NumSymbols);
+ Size = NumSymbols * 4;
}
-
- void reserve(size_t NumSymbols) {
- Indexes.reserve(NumSymbols);
- Size = NumSymbols * 4;
- }
- void setSymTab(SymbolTableSection *SymTab) { Symbols = SymTab; }
+ void setSymTab(SymbolTableSection *SymTab) { Symbols = SymTab; }
Error initialize(SectionTableRef SecTable) override;
- void finalize() override;
+ void finalize() override;
Error accept(SectionVisitor &Visitor) const override;
Error accept(MutableSectionVisitor &Visitor) override;
-
- SectionIndexSection() {
- Name = ".symtab_shndx";
- Align = 4;
- EntrySize = 4;
- Type = OriginalType = ELF::SHT_SYMTAB_SHNDX;
- }
-};
-
-class SymbolTableSection : public SectionBase {
- MAKE_SEC_WRITER_FRIEND
-
- void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; }
- void assignIndices();
-
-protected:
- std::vector<std::unique_ptr<Symbol>> Symbols;
- StringTableSection *SymbolNames = nullptr;
- SectionIndexSection *SectionIndexTable = nullptr;
-
- using SymPtr = std::unique_ptr<Symbol>;
-
-public:
- SymbolTableSection() { Type = OriginalType = ELF::SHT_SYMTAB; }
-
- void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn,
- uint64_t Value, uint8_t Visibility, uint16_t Shndx,
- uint64_t SymbolSize);
- void prepareForLayout();
- // An 'empty' symbol table still contains a null symbol.
- bool empty() const { return Symbols.size() == 1; }
- void setShndxTable(SectionIndexSection *ShndxTable) {
- SectionIndexTable = ShndxTable;
- }
- const SectionIndexSection *getShndxTable() const { return SectionIndexTable; }
- void fillShndxTable();
- const SectionBase *getStrTab() const { return SymbolNames; }
+
+ SectionIndexSection() {
+ Name = ".symtab_shndx";
+ Align = 4;
+ EntrySize = 4;
+ Type = OriginalType = ELF::SHT_SYMTAB_SHNDX;
+ }
+};
+
+class SymbolTableSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+ void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; }
+ void assignIndices();
+
+protected:
+ std::vector<std::unique_ptr<Symbol>> Symbols;
+ StringTableSection *SymbolNames = nullptr;
+ SectionIndexSection *SectionIndexTable = nullptr;
+
+ using SymPtr = std::unique_ptr<Symbol>;
+
+public:
+ SymbolTableSection() { Type = OriginalType = ELF::SHT_SYMTAB; }
+
+ void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn,
+ uint64_t Value, uint8_t Visibility, uint16_t Shndx,
+ uint64_t SymbolSize);
+ void prepareForLayout();
+ // An 'empty' symbol table still contains a null symbol.
+ bool empty() const { return Symbols.size() == 1; }
+ void setShndxTable(SectionIndexSection *ShndxTable) {
+ SectionIndexTable = ShndxTable;
+ }
+ const SectionIndexSection *getShndxTable() const { return SectionIndexTable; }
+ void fillShndxTable();
+ const SectionBase *getStrTab() const { return SymbolNames; }
Expected<const Symbol *> getSymbolByIndex(uint32_t Index) const;
Expected<Symbol *> getSymbolByIndex(uint32_t Index);
- void updateSymbols(function_ref<void(Symbol &)> Callable);
-
+ void updateSymbols(function_ref<void(Symbol &)> Callable);
+
Error removeSectionReferences(
bool AllowBrokenLinks,
- function_ref<bool(const SectionBase *)> ToRemove) override;
+ function_ref<bool(const SectionBase *)> ToRemove) override;
Error initialize(SectionTableRef SecTable) override;
- void finalize() override;
+ void finalize() override;
Error accept(SectionVisitor &Visitor) const override;
Error accept(MutableSectionVisitor &Visitor) override;
- Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
- void replaceSectionReferences(
- const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
-
- static bool classof(const SectionBase *S) {
- return S->OriginalType == ELF::SHT_SYMTAB;
- }
-};
-
-struct Relocation {
- Symbol *RelocSymbol = nullptr;
- uint64_t Offset;
- uint64_t Addend;
- uint32_t Type;
-};
-
-// All relocation sections denote relocations to apply to another section.
-// However, some relocation sections use a dynamic symbol table and others use
-// a regular symbol table. Because the types of the two symbol tables differ in
-// our system (because they should behave differently) we can't uniformly
-// represent all relocations with the same base class if we expose an interface
-// that mentions the symbol table type. So we split the two base types into two
-// different classes, one which handles the section the relocation is applied to
-// and another which handles the symbol table type. The symbol table type is
-// taken as a type parameter to the class (see RelocSectionWithSymtabBase).
-class RelocationSectionBase : public SectionBase {
-protected:
- SectionBase *SecToApplyRel = nullptr;
-
-public:
- const SectionBase *getSection() const { return SecToApplyRel; }
- void setSection(SectionBase *Sec) { SecToApplyRel = Sec; }
-
- static bool classof(const SectionBase *S) {
- return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
- }
-};
-
-// Takes the symbol table type to use as a parameter so that we can deduplicate
-// that code between the two symbol table types.
-template <class SymTabType>
-class RelocSectionWithSymtabBase : public RelocationSectionBase {
- void setSymTab(SymTabType *SymTab) { Symbols = SymTab; }
-
-protected:
- RelocSectionWithSymtabBase() = default;
-
- SymTabType *Symbols = nullptr;
-
-public:
+ Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
+ void replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
+
+ static bool classof(const SectionBase *S) {
+ return S->OriginalType == ELF::SHT_SYMTAB;
+ }
+};
+
+struct Relocation {
+ Symbol *RelocSymbol = nullptr;
+ uint64_t Offset;
+ uint64_t Addend;
+ uint32_t Type;
+};
+
+// All relocation sections denote relocations to apply to another section.
+// However, some relocation sections use a dynamic symbol table and others use
+// a regular symbol table. Because the types of the two symbol tables differ in
+// our system (because they should behave differently) we can't uniformly
+// represent all relocations with the same base class if we expose an interface
+// that mentions the symbol table type. So we split the two base types into two
+// different classes, one which handles the section the relocation is applied to
+// and another which handles the symbol table type. The symbol table type is
+// taken as a type parameter to the class (see RelocSectionWithSymtabBase).
+class RelocationSectionBase : public SectionBase {
+protected:
+ SectionBase *SecToApplyRel = nullptr;
+
+public:
+ const SectionBase *getSection() const { return SecToApplyRel; }
+ void setSection(SectionBase *Sec) { SecToApplyRel = Sec; }
+
+ static bool classof(const SectionBase *S) {
+ return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
+ }
+};
+
+// Takes the symbol table type to use as a parameter so that we can deduplicate
+// that code between the two symbol table types.
+template <class SymTabType>
+class RelocSectionWithSymtabBase : public RelocationSectionBase {
+ void setSymTab(SymTabType *SymTab) { Symbols = SymTab; }
+
+protected:
+ RelocSectionWithSymtabBase() = default;
+
+ SymTabType *Symbols = nullptr;
+
+public:
Error initialize(SectionTableRef SecTable) override;
- void finalize() override;
-};
-
-class RelocationSection
- : public RelocSectionWithSymtabBase<SymbolTableSection> {
- MAKE_SEC_WRITER_FRIEND
-
- std::vector<Relocation> Relocations;
-
-public:
- void addRelocation(Relocation Rel) { Relocations.push_back(Rel); }
+ void finalize() override;
+};
+
+class RelocationSection
+ : public RelocSectionWithSymtabBase<SymbolTableSection> {
+ MAKE_SEC_WRITER_FRIEND
+
+ std::vector<Relocation> Relocations;
+
+public:
+ void addRelocation(Relocation Rel) { Relocations.push_back(Rel); }
Error accept(SectionVisitor &Visitor) const override;
Error accept(MutableSectionVisitor &Visitor) override;
Error removeSectionReferences(
bool AllowBrokenLinks,
- function_ref<bool(const SectionBase *)> ToRemove) override;
- Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
- void markSymbols() override;
- void replaceSectionReferences(
- const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
-
- static bool classof(const SectionBase *S) {
- if (S->OriginalFlags & ELF::SHF_ALLOC)
- return false;
- return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
- }
-};
-
-// TODO: The way stripping and groups interact is complicated
-// and still needs to be worked on.
-
-class GroupSection : public SectionBase {
- MAKE_SEC_WRITER_FRIEND
- const SymbolTableSection *SymTab = nullptr;
- Symbol *Sym = nullptr;
- ELF::Elf32_Word FlagWord;
- SmallVector<SectionBase *, 3> GroupMembers;
-
-public:
- // TODO: Contents is present in several classes of the hierarchy.
- // This needs to be refactored to avoid duplication.
- ArrayRef<uint8_t> Contents;
-
- explicit GroupSection(ArrayRef<uint8_t> Data) : Contents(Data) {}
-
- void setSymTab(const SymbolTableSection *SymTabSec) { SymTab = SymTabSec; }
- void setSymbol(Symbol *S) { Sym = S; }
- void setFlagWord(ELF::Elf32_Word W) { FlagWord = W; }
- void addMember(SectionBase *Sec) { GroupMembers.push_back(Sec); }
-
+ function_ref<bool(const SectionBase *)> ToRemove) override;
+ Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
+ void markSymbols() override;
+ void replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
+
+ static bool classof(const SectionBase *S) {
+ if (S->OriginalFlags & ELF::SHF_ALLOC)
+ return false;
+ return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
+ }
+};
+
+// TODO: The way stripping and groups interact is complicated
+// and still needs to be worked on.
+
+class GroupSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+ const SymbolTableSection *SymTab = nullptr;
+ Symbol *Sym = nullptr;
+ ELF::Elf32_Word FlagWord;
+ SmallVector<SectionBase *, 3> GroupMembers;
+
+public:
+ // TODO: Contents is present in several classes of the hierarchy.
+ // This needs to be refactored to avoid duplication.
+ ArrayRef<uint8_t> Contents;
+
+ explicit GroupSection(ArrayRef<uint8_t> Data) : Contents(Data) {}
+
+ void setSymTab(const SymbolTableSection *SymTabSec) { SymTab = SymTabSec; }
+ void setSymbol(Symbol *S) { Sym = S; }
+ void setFlagWord(ELF::Elf32_Word W) { FlagWord = W; }
+ void addMember(SectionBase *Sec) { GroupMembers.push_back(Sec); }
+
Error accept(SectionVisitor &) const override;
Error accept(MutableSectionVisitor &Visitor) override;
- void finalize() override;
- Error removeSectionReferences(
- bool AllowBrokenLinks,
- function_ref<bool(const SectionBase *)> ToRemove) override;
- Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
- void markSymbols() override;
- void replaceSectionReferences(
- const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
- void onRemove() override;
-
- static bool classof(const SectionBase *S) {
- return S->OriginalType == ELF::SHT_GROUP;
- }
-};
-
-class DynamicSymbolTableSection : public Section {
-public:
- explicit DynamicSymbolTableSection(ArrayRef<uint8_t> Data) : Section(Data) {}
-
- static bool classof(const SectionBase *S) {
- return S->OriginalType == ELF::SHT_DYNSYM;
- }
-};
-
-class DynamicSection : public Section {
-public:
- explicit DynamicSection(ArrayRef<uint8_t> Data) : Section(Data) {}
-
- static bool classof(const SectionBase *S) {
- return S->OriginalType == ELF::SHT_DYNAMIC;
- }
-};
-
-class DynamicRelocationSection
- : public RelocSectionWithSymtabBase<DynamicSymbolTableSection> {
- MAKE_SEC_WRITER_FRIEND
-
-private:
- ArrayRef<uint8_t> Contents;
-
-public:
- explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {}
-
+ void finalize() override;
+ Error removeSectionReferences(
+ bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove) override;
+ Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
+ void markSymbols() override;
+ void replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
+ void onRemove() override;
+
+ static bool classof(const SectionBase *S) {
+ return S->OriginalType == ELF::SHT_GROUP;
+ }
+};
+
+class DynamicSymbolTableSection : public Section {
+public:
+ explicit DynamicSymbolTableSection(ArrayRef<uint8_t> Data) : Section(Data) {}
+
+ static bool classof(const SectionBase *S) {
+ return S->OriginalType == ELF::SHT_DYNSYM;
+ }
+};
+
+class DynamicSection : public Section {
+public:
+ explicit DynamicSection(ArrayRef<uint8_t> Data) : Section(Data) {}
+
+ static bool classof(const SectionBase *S) {
+ return S->OriginalType == ELF::SHT_DYNAMIC;
+ }
+};
+
+class DynamicRelocationSection
+ : public RelocSectionWithSymtabBase<DynamicSymbolTableSection> {
+ MAKE_SEC_WRITER_FRIEND
+
+private:
+ ArrayRef<uint8_t> Contents;
+
+public:
+ explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {}
+
Error accept(SectionVisitor &) const override;
Error accept(MutableSectionVisitor &Visitor) override;
- Error removeSectionReferences(
- bool AllowBrokenLinks,
- function_ref<bool(const SectionBase *)> ToRemove) override;
-
- static bool classof(const SectionBase *S) {
- if (!(S->OriginalFlags & ELF::SHF_ALLOC))
- return false;
- return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
- }
-};
-
-class GnuDebugLinkSection : public SectionBase {
- MAKE_SEC_WRITER_FRIEND
-
-private:
- StringRef FileName;
- uint32_t CRC32;
-
- void init(StringRef File);
-
-public:
- // If we add this section from an external source we can use this ctor.
- explicit GnuDebugLinkSection(StringRef File, uint32_t PrecomputedCRC);
+ Error removeSectionReferences(
+ bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove) override;
+
+ static bool classof(const SectionBase *S) {
+ if (!(S->OriginalFlags & ELF::SHF_ALLOC))
+ return false;
+ return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
+ }
+};
+
+class GnuDebugLinkSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+private:
+ StringRef FileName;
+ uint32_t CRC32;
+
+ void init(StringRef File);
+
+public:
+ // If we add this section from an external source we can use this ctor.
+ explicit GnuDebugLinkSection(StringRef File, uint32_t PrecomputedCRC);
Error accept(SectionVisitor &Visitor) const override;
Error accept(MutableSectionVisitor &Visitor) override;
-};
-
-class Reader {
-public:
- virtual ~Reader();
+};
+
+class Reader {
+public:
+ virtual ~Reader();
virtual Expected<std::unique_ptr<Object>> create(bool EnsureSymtab) const = 0;
-};
-
-using object::Binary;
-using object::ELFFile;
-using object::ELFObjectFile;
-using object::OwningBinary;
-
-class BasicELFBuilder {
-protected:
- std::unique_ptr<Object> Obj;
-
- void initFileHeader();
- void initHeaderSegment();
- StringTableSection *addStrTab();
- SymbolTableSection *addSymTab(StringTableSection *StrTab);
+};
+
+using object::Binary;
+using object::ELFFile;
+using object::ELFObjectFile;
+using object::OwningBinary;
+
+class BasicELFBuilder {
+protected:
+ std::unique_ptr<Object> Obj;
+
+ void initFileHeader();
+ void initHeaderSegment();
+ StringTableSection *addStrTab();
+ SymbolTableSection *addSymTab(StringTableSection *StrTab);
Error initSections();
-
-public:
- BasicELFBuilder() : Obj(std::make_unique<Object>()) {}
-};
-
-class BinaryELFBuilder : public BasicELFBuilder {
- MemoryBuffer *MemBuf;
- uint8_t NewSymbolVisibility;
- void addData(SymbolTableSection *SymTab);
-
-public:
- BinaryELFBuilder(MemoryBuffer *MB, uint8_t NewSymbolVisibility)
- : BasicELFBuilder(), MemBuf(MB),
- NewSymbolVisibility(NewSymbolVisibility) {}
-
+
+public:
+ BasicELFBuilder() : Obj(std::make_unique<Object>()) {}
+};
+
+class BinaryELFBuilder : public BasicELFBuilder {
+ MemoryBuffer *MemBuf;
+ uint8_t NewSymbolVisibility;
+ void addData(SymbolTableSection *SymTab);
+
+public:
+ BinaryELFBuilder(MemoryBuffer *MB, uint8_t NewSymbolVisibility)
+ : BasicELFBuilder(), MemBuf(MB),
+ NewSymbolVisibility(NewSymbolVisibility) {}
+
Expected<std::unique_ptr<Object>> build();
-};
-
-class IHexELFBuilder : public BasicELFBuilder {
- const std::vector<IHexRecord> &Records;
-
- void addDataSections();
-
-public:
- IHexELFBuilder(const std::vector<IHexRecord> &Records)
- : BasicELFBuilder(), Records(Records) {}
-
+};
+
+class IHexELFBuilder : public BasicELFBuilder {
+ const std::vector<IHexRecord> &Records;
+
+ void addDataSections();
+
+public:
+ IHexELFBuilder(const std::vector<IHexRecord> &Records)
+ : BasicELFBuilder(), Records(Records) {}
+
Expected<std::unique_ptr<Object>> build();
-};
-
-template <class ELFT> class ELFBuilder {
-private:
- using Elf_Addr = typename ELFT::Addr;
- using Elf_Shdr = typename ELFT::Shdr;
- using Elf_Word = typename ELFT::Word;
-
- const ELFFile<ELFT> &ElfFile;
- Object &Obj;
- size_t EhdrOffset = 0;
- Optional<StringRef> ExtractPartition;
-
- void setParentSegment(Segment &Child);
+};
+
+template <class ELFT> class ELFBuilder {
+private:
+ using Elf_Addr = typename ELFT::Addr;
+ using Elf_Shdr = typename ELFT::Shdr;
+ using Elf_Word = typename ELFT::Word;
+
+ const ELFFile<ELFT> &ElfFile;
+ Object &Obj;
+ size_t EhdrOffset = 0;
+ Optional<StringRef> ExtractPartition;
+
+ void setParentSegment(Segment &Child);
Error readProgramHeaders(const ELFFile<ELFT> &HeadersFile);
Error initGroupSection(GroupSection *GroupSec);
Error initSymbolTable(SymbolTableSection *SymTab);
@@ -953,149 +953,149 @@ private:
Error readSections(bool EnsureSymtab);
Error findEhdrOffset();
Expected<SectionBase &> makeSection(const Elf_Shdr &Shdr);
-
-public:
- ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj,
- Optional<StringRef> ExtractPartition)
+
+public:
+ ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj,
+ Optional<StringRef> ExtractPartition)
: ElfFile(ElfObj.getELFFile()), Obj(Obj),
- ExtractPartition(ExtractPartition) {}
-
+ ExtractPartition(ExtractPartition) {}
+
Error build(bool EnsureSymtab);
-};
-
-class BinaryReader : public Reader {
- MemoryBuffer *MemBuf;
- uint8_t NewSymbolVisibility;
-
-public:
- BinaryReader(MemoryBuffer *MB, const uint8_t NewSymbolVisibility)
- : MemBuf(MB), NewSymbolVisibility(NewSymbolVisibility) {}
+};
+
+class BinaryReader : public Reader {
+ MemoryBuffer *MemBuf;
+ uint8_t NewSymbolVisibility;
+
+public:
+ BinaryReader(MemoryBuffer *MB, const uint8_t NewSymbolVisibility)
+ : MemBuf(MB), NewSymbolVisibility(NewSymbolVisibility) {}
Expected<std::unique_ptr<Object>> create(bool EnsureSymtab) const override;
-};
-
-class IHexReader : public Reader {
- MemoryBuffer *MemBuf;
-
- Expected<std::vector<IHexRecord>> parse() const;
- Error parseError(size_t LineNo, Error E) const {
- return LineNo == -1U
- ? createFileError(MemBuf->getBufferIdentifier(), std::move(E))
- : createFileError(MemBuf->getBufferIdentifier(), LineNo,
- std::move(E));
- }
- template <typename... Ts>
- Error parseError(size_t LineNo, char const *Fmt, const Ts &... Vals) const {
- Error E = createStringError(errc::invalid_argument, Fmt, Vals...);
- return parseError(LineNo, std::move(E));
- }
-
-public:
- IHexReader(MemoryBuffer *MB) : MemBuf(MB) {}
-
+};
+
+class IHexReader : public Reader {
+ MemoryBuffer *MemBuf;
+
+ Expected<std::vector<IHexRecord>> parse() const;
+ Error parseError(size_t LineNo, Error E) const {
+ return LineNo == -1U
+ ? createFileError(MemBuf->getBufferIdentifier(), std::move(E))
+ : createFileError(MemBuf->getBufferIdentifier(), LineNo,
+ std::move(E));
+ }
+ template <typename... Ts>
+ Error parseError(size_t LineNo, char const *Fmt, const Ts &... Vals) const {
+ Error E = createStringError(errc::invalid_argument, Fmt, Vals...);
+ return parseError(LineNo, std::move(E));
+ }
+
+public:
+ IHexReader(MemoryBuffer *MB) : MemBuf(MB) {}
+
Expected<std::unique_ptr<Object>> create(bool EnsureSymtab) const override;
-};
-
-class ELFReader : public Reader {
- Binary *Bin;
- Optional<StringRef> ExtractPartition;
-
-public:
+};
+
+class ELFReader : public Reader {
+ Binary *Bin;
+ Optional<StringRef> ExtractPartition;
+
+public:
Expected<std::unique_ptr<Object>> create(bool EnsureSymtab) const override;
- explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition)
- : Bin(B), ExtractPartition(ExtractPartition) {}
-};
-
-class Object {
-private:
- using SecPtr = std::unique_ptr<SectionBase>;
- using SegPtr = std::unique_ptr<Segment>;
-
- std::vector<SecPtr> Sections;
- std::vector<SegPtr> Segments;
- std::vector<SecPtr> RemovedSections;
-
- static bool sectionIsAlloc(const SectionBase &Sec) {
- return Sec.Flags & ELF::SHF_ALLOC;
- };
-
-public:
- template <class T>
- using Range = iterator_range<
- pointee_iterator<typename std::vector<std::unique_ptr<T>>::iterator>>;
-
- template <class T>
- using ConstRange = iterator_range<pointee_iterator<
- typename std::vector<std::unique_ptr<T>>::const_iterator>>;
-
- // It is often the case that the ELF header and the program header table are
- // not present in any segment. This could be a problem during file layout,
- // because other segments may get assigned an offset where either of the
- // two should reside, which will effectively corrupt the resulting binary.
- // Other than that we use these segments to track program header offsets
- // when they may not follow the ELF header.
- Segment ElfHdrSegment;
- Segment ProgramHdrSegment;
-
- uint8_t OSABI;
- uint8_t ABIVersion;
- uint64_t Entry;
- uint64_t SHOff;
- uint32_t Type;
- uint32_t Machine;
- uint32_t Version;
- uint32_t Flags;
-
- bool HadShdrs = true;
- bool MustBeRelocatable = false;
- StringTableSection *SectionNames = nullptr;
- SymbolTableSection *SymbolTable = nullptr;
- SectionIndexSection *SectionIndexTable = nullptr;
-
- void sortSections();
- SectionTableRef sections() { return SectionTableRef(Sections); }
- ConstRange<SectionBase> sections() const {
- return make_pointee_range(Sections);
- }
- iterator_range<
- filter_iterator<pointee_iterator<std::vector<SecPtr>::const_iterator>,
- decltype(&sectionIsAlloc)>>
- allocSections() const {
- return make_filter_range(make_pointee_range(Sections), sectionIsAlloc);
- }
-
- SectionBase *findSection(StringRef Name) {
- auto SecIt =
- find_if(Sections, [&](const SecPtr &Sec) { return Sec->Name == Name; });
- return SecIt == Sections.end() ? nullptr : SecIt->get();
- }
- SectionTableRef removedSections() { return SectionTableRef(RemovedSections); }
-
- Range<Segment> segments() { return make_pointee_range(Segments); }
- ConstRange<Segment> segments() const { return make_pointee_range(Segments); }
-
- Error removeSections(bool AllowBrokenLinks,
- std::function<bool(const SectionBase &)> ToRemove);
- Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
- template <class T, class... Ts> T &addSection(Ts &&... Args) {
- auto Sec = std::make_unique<T>(std::forward<Ts>(Args)...);
- auto Ptr = Sec.get();
- MustBeRelocatable |= isa<RelocationSection>(*Ptr);
- Sections.emplace_back(std::move(Sec));
- Ptr->Index = Sections.size();
- return *Ptr;
- }
+ explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition)
+ : Bin(B), ExtractPartition(ExtractPartition) {}
+};
+
+class Object {
+private:
+ using SecPtr = std::unique_ptr<SectionBase>;
+ using SegPtr = std::unique_ptr<Segment>;
+
+ std::vector<SecPtr> Sections;
+ std::vector<SegPtr> Segments;
+ std::vector<SecPtr> RemovedSections;
+
+ static bool sectionIsAlloc(const SectionBase &Sec) {
+ return Sec.Flags & ELF::SHF_ALLOC;
+ };
+
+public:
+ template <class T>
+ using Range = iterator_range<
+ pointee_iterator<typename std::vector<std::unique_ptr<T>>::iterator>>;
+
+ template <class T>
+ using ConstRange = iterator_range<pointee_iterator<
+ typename std::vector<std::unique_ptr<T>>::const_iterator>>;
+
+ // It is often the case that the ELF header and the program header table are
+ // not present in any segment. This could be a problem during file layout,
+ // because other segments may get assigned an offset where either of the
+ // two should reside, which will effectively corrupt the resulting binary.
+ // Other than that we use these segments to track program header offsets
+ // when they may not follow the ELF header.
+ Segment ElfHdrSegment;
+ Segment ProgramHdrSegment;
+
+ uint8_t OSABI;
+ uint8_t ABIVersion;
+ uint64_t Entry;
+ uint64_t SHOff;
+ uint32_t Type;
+ uint32_t Machine;
+ uint32_t Version;
+ uint32_t Flags;
+
+ bool HadShdrs = true;
+ bool MustBeRelocatable = false;
+ StringTableSection *SectionNames = nullptr;
+ SymbolTableSection *SymbolTable = nullptr;
+ SectionIndexSection *SectionIndexTable = nullptr;
+
+ void sortSections();
+ SectionTableRef sections() { return SectionTableRef(Sections); }
+ ConstRange<SectionBase> sections() const {
+ return make_pointee_range(Sections);
+ }
+ iterator_range<
+ filter_iterator<pointee_iterator<std::vector<SecPtr>::const_iterator>,
+ decltype(&sectionIsAlloc)>>
+ allocSections() const {
+ return make_filter_range(make_pointee_range(Sections), sectionIsAlloc);
+ }
+
+ SectionBase *findSection(StringRef Name) {
+ auto SecIt =
+ find_if(Sections, [&](const SecPtr &Sec) { return Sec->Name == Name; });
+ return SecIt == Sections.end() ? nullptr : SecIt->get();
+ }
+ SectionTableRef removedSections() { return SectionTableRef(RemovedSections); }
+
+ Range<Segment> segments() { return make_pointee_range(Segments); }
+ ConstRange<Segment> segments() const { return make_pointee_range(Segments); }
+
+ Error removeSections(bool AllowBrokenLinks,
+ std::function<bool(const SectionBase &)> ToRemove);
+ Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
+ template <class T, class... Ts> T &addSection(Ts &&... Args) {
+ auto Sec = std::make_unique<T>(std::forward<Ts>(Args)...);
+ auto Ptr = Sec.get();
+ MustBeRelocatable |= isa<RelocationSection>(*Ptr);
+ Sections.emplace_back(std::move(Sec));
+ Ptr->Index = Sections.size();
+ return *Ptr;
+ }
Error addNewSymbolTable();
- Segment &addSegment(ArrayRef<uint8_t> Data) {
- Segments.emplace_back(std::make_unique<Segment>(Data));
- return *Segments.back();
- }
- bool isRelocatable() const {
- return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable;
- }
-};
-
-} // end namespace elf
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_OBJCOPY_OBJECT_H
+ Segment &addSegment(ArrayRef<uint8_t> Data) {
+ Segments.emplace_back(std::make_unique<Segment>(Data));
+ return *Segments.back();
+ }
+ bool isRelocatable() const {
+ return (Type != ELF::ET_DYN && Type != ELF::ET_EXEC) || MustBeRelocatable;
+ }
+};
+
+} // end namespace elf
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_OBJECT_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/InstallNameToolOpts.td b/contrib/libs/llvm12/tools/llvm-objcopy/InstallNameToolOpts.td
index 88dea84400..bada17fdb2 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/InstallNameToolOpts.td
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/InstallNameToolOpts.td
@@ -1,43 +1,43 @@
-//===-- InstallNameToolOpts.td - llvm-install-name-tool options --------*-===//
-//
-// 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 file describes the command line options of llvm-install-name.
-//
-//===----------------------------------------------------------------------===//
-
-include "llvm/Option/OptParser.td"
-
-def help : Flag<["--"], "help">;
-def h : Flag<["-"], "h">, Alias<help>;
-
-def add_rpath : Option<["-", "--"], "add_rpath", KIND_SEPARATE>,
- HelpText<"Add new rpath">;
-
+//===-- InstallNameToolOpts.td - llvm-install-name-tool options --------*-===//
+//
+// 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 file describes the command line options of llvm-install-name.
+//
+//===----------------------------------------------------------------------===//
+
+include "llvm/Option/OptParser.td"
+
+def help : Flag<["--"], "help">;
+def h : Flag<["-"], "h">, Alias<help>;
+
+def add_rpath : Option<["-", "--"], "add_rpath", KIND_SEPARATE>,
+ HelpText<"Add new rpath">;
+
def prepend_rpath : Option<["-", "--"], "prepend_rpath", KIND_SEPARATE>,
HelpText<"Add new rpath before other rpaths">;
-def delete_rpath: Option<["-", "--"], "delete_rpath", KIND_SEPARATE>,
- HelpText<"Delete specified rpath">;
-
+def delete_rpath: Option<["-", "--"], "delete_rpath", KIND_SEPARATE>,
+ HelpText<"Delete specified rpath">;
+
def delete_all_rpaths: Flag<["-", "--"], "delete_all_rpaths">,
HelpText<"Delete all rpath directives">;
-def rpath: MultiArg<["-", "--"], "rpath", 2>,
- HelpText<"Change rpath path name">;
-
-def id : Option<["-","--"], "id", KIND_SEPARATE>,
- HelpText<"Change dynamic shared library id">;
-
-def change: MultiArg<["-", "--"], "change", 2>,
- HelpText<"Change dependent shared library install name">;
-
-def version : Flag<["--"], "version">,
- HelpText<"Print the version and exit.">;
+def rpath: MultiArg<["-", "--"], "rpath", 2>,
+ HelpText<"Change rpath path name">;
+
+def id : Option<["-","--"], "id", KIND_SEPARATE>,
+ HelpText<"Change dynamic shared library id">;
+
+def change: MultiArg<["-", "--"], "change", 2>,
+ HelpText<"Change dependent shared library install name">;
+
+def version : Flag<["--"], "version">,
+ HelpText<"Print the version and exit.">;
def V : Flag<["-"], "V">,
Alias<version>,
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp
index 8e2bf36238..0688e79297 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp
@@ -1,20 +1,20 @@
-//===- MachOLayoutBuilder.cpp -----------------------------------*- 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 "MachOLayoutBuilder.h"
-#include "llvm/Support/Alignment.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/ErrorHandling.h"
-
-namespace llvm {
-namespace objcopy {
-namespace macho {
-
+//===- MachOLayoutBuilder.cpp -----------------------------------*- 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 "MachOLayoutBuilder.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
StringTableBuilder::Kind
MachOLayoutBuilder::getStringTableBuilderKind(const Object &O, bool Is64Bit) {
if (O.Header.FileType == MachO::HeaderFileType::MH_OBJECT)
@@ -23,376 +23,376 @@ MachOLayoutBuilder::getStringTableBuilderKind(const Object &O, bool Is64Bit) {
: StringTableBuilder::MachOLinked;
}
-uint32_t MachOLayoutBuilder::computeSizeOfCmds() const {
- uint32_t Size = 0;
- for (const LoadCommand &LC : O.LoadCommands) {
- const MachO::macho_load_command &MLC = LC.MachOLoadCommand;
- auto cmd = MLC.load_command_data.cmd;
- switch (cmd) {
- case MachO::LC_SEGMENT:
- Size += sizeof(MachO::segment_command) +
- sizeof(MachO::section) * LC.Sections.size();
- continue;
- case MachO::LC_SEGMENT_64:
- Size += sizeof(MachO::segment_command_64) +
- sizeof(MachO::section_64) * LC.Sections.size();
- continue;
- }
-
- switch (cmd) {
-#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
- case MachO::LCName: \
- Size += sizeof(MachO::LCStruct) + LC.Payload.size(); \
- break;
-#include "llvm/BinaryFormat/MachO.def"
-#undef HANDLE_LOAD_COMMAND
- }
- }
-
- return Size;
-}
-
-void MachOLayoutBuilder::constructStringTable() {
- for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols)
- StrTableBuilder.add(Sym->Name);
- StrTableBuilder.finalize();
-}
-
-void MachOLayoutBuilder::updateSymbolIndexes() {
- uint32_t Index = 0;
- for (auto &Symbol : O.SymTable.Symbols)
- Symbol->Index = Index++;
-}
-
-// Updates the index and the number of local/external/undefined symbols.
-void MachOLayoutBuilder::updateDySymTab(MachO::macho_load_command &MLC) {
- assert(MLC.load_command_data.cmd == MachO::LC_DYSYMTAB);
- // Make sure that nlist entries in the symbol table are sorted by the those
- // types. The order is: local < defined external < undefined external.
- assert(llvm::is_sorted(O.SymTable.Symbols,
- [](const std::unique_ptr<SymbolEntry> &A,
- const std::unique_ptr<SymbolEntry> &B) {
- bool AL = A->isLocalSymbol(),
- BL = B->isLocalSymbol();
- if (AL != BL)
- return AL;
- return !AL && !A->isUndefinedSymbol() &&
- B->isUndefinedSymbol();
- }) &&
- "Symbols are not sorted by their types.");
-
- uint32_t NumLocalSymbols = 0;
- auto Iter = O.SymTable.Symbols.begin();
- auto End = O.SymTable.Symbols.end();
- for (; Iter != End; ++Iter) {
- if ((*Iter)->isExternalSymbol())
- break;
-
- ++NumLocalSymbols;
- }
-
- uint32_t NumExtDefSymbols = 0;
- for (; Iter != End; ++Iter) {
- if ((*Iter)->isUndefinedSymbol())
- break;
-
- ++NumExtDefSymbols;
- }
-
- MLC.dysymtab_command_data.ilocalsym = 0;
- MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols;
- MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols;
- MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols;
- MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols;
- MLC.dysymtab_command_data.nundefsym =
- O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols);
-}
-
-// Recomputes and updates offset and size fields in load commands and sections
-// since they could be modified.
-uint64_t MachOLayoutBuilder::layoutSegments() {
- auto HeaderSize =
- Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
- const bool IsObjectFile =
- O.Header.FileType == MachO::HeaderFileType::MH_OBJECT;
- uint64_t Offset = IsObjectFile ? (HeaderSize + O.Header.SizeOfCmds) : 0;
- for (LoadCommand &LC : O.LoadCommands) {
- auto &MLC = LC.MachOLoadCommand;
- StringRef Segname;
- uint64_t SegmentVmAddr;
- uint64_t SegmentVmSize;
- switch (MLC.load_command_data.cmd) {
- case MachO::LC_SEGMENT:
- SegmentVmAddr = MLC.segment_command_data.vmaddr;
- SegmentVmSize = MLC.segment_command_data.vmsize;
- Segname = StringRef(MLC.segment_command_data.segname,
- strnlen(MLC.segment_command_data.segname,
- sizeof(MLC.segment_command_data.segname)));
- break;
- case MachO::LC_SEGMENT_64:
- SegmentVmAddr = MLC.segment_command_64_data.vmaddr;
- SegmentVmSize = MLC.segment_command_64_data.vmsize;
- Segname = StringRef(MLC.segment_command_64_data.segname,
- strnlen(MLC.segment_command_64_data.segname,
- sizeof(MLC.segment_command_64_data.segname)));
- break;
- default:
- continue;
- }
-
- if (Segname == "__LINKEDIT") {
- // We update the __LINKEDIT segment later (in layoutTail).
- assert(LC.Sections.empty() && "__LINKEDIT segment has sections");
- LinkEditLoadCommand = &MLC;
- continue;
- }
-
- // Update file offsets and sizes of sections.
- uint64_t SegOffset = Offset;
- uint64_t SegFileSize = 0;
- uint64_t VMSize = 0;
- for (std::unique_ptr<Section> &Sec : LC.Sections) {
- assert(SegmentVmAddr <= Sec->Addr &&
- "Section's address cannot be smaller than Segment's one");
- uint32_t SectOffset = Sec->Addr - SegmentVmAddr;
- if (IsObjectFile) {
+uint32_t MachOLayoutBuilder::computeSizeOfCmds() const {
+ uint32_t Size = 0;
+ for (const LoadCommand &LC : O.LoadCommands) {
+ const MachO::macho_load_command &MLC = LC.MachOLoadCommand;
+ auto cmd = MLC.load_command_data.cmd;
+ switch (cmd) {
+ case MachO::LC_SEGMENT:
+ Size += sizeof(MachO::segment_command) +
+ sizeof(MachO::section) * LC.Sections.size();
+ continue;
+ case MachO::LC_SEGMENT_64:
+ Size += sizeof(MachO::segment_command_64) +
+ sizeof(MachO::section_64) * LC.Sections.size();
+ continue;
+ }
+
+ switch (cmd) {
+#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
+ case MachO::LCName: \
+ Size += sizeof(MachO::LCStruct) + LC.Payload.size(); \
+ break;
+#include "llvm/BinaryFormat/MachO.def"
+#undef HANDLE_LOAD_COMMAND
+ }
+ }
+
+ return Size;
+}
+
+void MachOLayoutBuilder::constructStringTable() {
+ for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols)
+ StrTableBuilder.add(Sym->Name);
+ StrTableBuilder.finalize();
+}
+
+void MachOLayoutBuilder::updateSymbolIndexes() {
+ uint32_t Index = 0;
+ for (auto &Symbol : O.SymTable.Symbols)
+ Symbol->Index = Index++;
+}
+
+// Updates the index and the number of local/external/undefined symbols.
+void MachOLayoutBuilder::updateDySymTab(MachO::macho_load_command &MLC) {
+ assert(MLC.load_command_data.cmd == MachO::LC_DYSYMTAB);
+ // Make sure that nlist entries in the symbol table are sorted by the those
+ // types. The order is: local < defined external < undefined external.
+ assert(llvm::is_sorted(O.SymTable.Symbols,
+ [](const std::unique_ptr<SymbolEntry> &A,
+ const std::unique_ptr<SymbolEntry> &B) {
+ bool AL = A->isLocalSymbol(),
+ BL = B->isLocalSymbol();
+ if (AL != BL)
+ return AL;
+ return !AL && !A->isUndefinedSymbol() &&
+ B->isUndefinedSymbol();
+ }) &&
+ "Symbols are not sorted by their types.");
+
+ uint32_t NumLocalSymbols = 0;
+ auto Iter = O.SymTable.Symbols.begin();
+ auto End = O.SymTable.Symbols.end();
+ for (; Iter != End; ++Iter) {
+ if ((*Iter)->isExternalSymbol())
+ break;
+
+ ++NumLocalSymbols;
+ }
+
+ uint32_t NumExtDefSymbols = 0;
+ for (; Iter != End; ++Iter) {
+ if ((*Iter)->isUndefinedSymbol())
+ break;
+
+ ++NumExtDefSymbols;
+ }
+
+ MLC.dysymtab_command_data.ilocalsym = 0;
+ MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols;
+ MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols;
+ MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols;
+ MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols;
+ MLC.dysymtab_command_data.nundefsym =
+ O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols);
+}
+
+// Recomputes and updates offset and size fields in load commands and sections
+// since they could be modified.
+uint64_t MachOLayoutBuilder::layoutSegments() {
+ auto HeaderSize =
+ Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
+ const bool IsObjectFile =
+ O.Header.FileType == MachO::HeaderFileType::MH_OBJECT;
+ uint64_t Offset = IsObjectFile ? (HeaderSize + O.Header.SizeOfCmds) : 0;
+ for (LoadCommand &LC : O.LoadCommands) {
+ auto &MLC = LC.MachOLoadCommand;
+ StringRef Segname;
+ uint64_t SegmentVmAddr;
+ uint64_t SegmentVmSize;
+ switch (MLC.load_command_data.cmd) {
+ case MachO::LC_SEGMENT:
+ SegmentVmAddr = MLC.segment_command_data.vmaddr;
+ SegmentVmSize = MLC.segment_command_data.vmsize;
+ Segname = StringRef(MLC.segment_command_data.segname,
+ strnlen(MLC.segment_command_data.segname,
+ sizeof(MLC.segment_command_data.segname)));
+ break;
+ case MachO::LC_SEGMENT_64:
+ SegmentVmAddr = MLC.segment_command_64_data.vmaddr;
+ SegmentVmSize = MLC.segment_command_64_data.vmsize;
+ Segname = StringRef(MLC.segment_command_64_data.segname,
+ strnlen(MLC.segment_command_64_data.segname,
+ sizeof(MLC.segment_command_64_data.segname)));
+ break;
+ default:
+ continue;
+ }
+
+ if (Segname == "__LINKEDIT") {
+ // We update the __LINKEDIT segment later (in layoutTail).
+ assert(LC.Sections.empty() && "__LINKEDIT segment has sections");
+ LinkEditLoadCommand = &MLC;
+ continue;
+ }
+
+ // Update file offsets and sizes of sections.
+ uint64_t SegOffset = Offset;
+ uint64_t SegFileSize = 0;
+ uint64_t VMSize = 0;
+ for (std::unique_ptr<Section> &Sec : LC.Sections) {
+ assert(SegmentVmAddr <= Sec->Addr &&
+ "Section's address cannot be smaller than Segment's one");
+ uint32_t SectOffset = Sec->Addr - SegmentVmAddr;
+ if (IsObjectFile) {
if (!Sec->hasValidOffset()) {
- Sec->Offset = 0;
- } else {
- uint64_t PaddingSize =
- offsetToAlignment(SegFileSize, Align(1ull << Sec->Align));
- Sec->Offset = SegOffset + SegFileSize + PaddingSize;
- Sec->Size = Sec->Content.size();
- SegFileSize += PaddingSize + Sec->Size;
- }
- } else {
+ Sec->Offset = 0;
+ } else {
+ uint64_t PaddingSize =
+ offsetToAlignment(SegFileSize, Align(1ull << Sec->Align));
+ Sec->Offset = SegOffset + SegFileSize + PaddingSize;
+ Sec->Size = Sec->Content.size();
+ SegFileSize += PaddingSize + Sec->Size;
+ }
+ } else {
if (!Sec->hasValidOffset()) {
- Sec->Offset = 0;
- } else {
- Sec->Offset = SegOffset + SectOffset;
- Sec->Size = Sec->Content.size();
- SegFileSize = std::max(SegFileSize, SectOffset + Sec->Size);
- }
- }
- VMSize = std::max(VMSize, SectOffset + Sec->Size);
- }
-
- if (IsObjectFile) {
- Offset += SegFileSize;
- } else {
- Offset = alignTo(Offset + SegFileSize, PageSize);
- SegFileSize = alignTo(SegFileSize, PageSize);
- // Use the original vmsize if the segment is __PAGEZERO.
- VMSize =
- Segname == "__PAGEZERO" ? SegmentVmSize : alignTo(VMSize, PageSize);
- }
-
- switch (MLC.load_command_data.cmd) {
- case MachO::LC_SEGMENT:
- MLC.segment_command_data.cmdsize =
- sizeof(MachO::segment_command) +
- sizeof(MachO::section) * LC.Sections.size();
- MLC.segment_command_data.nsects = LC.Sections.size();
- MLC.segment_command_data.fileoff = SegOffset;
- MLC.segment_command_data.vmsize = VMSize;
- MLC.segment_command_data.filesize = SegFileSize;
- break;
- case MachO::LC_SEGMENT_64:
- MLC.segment_command_64_data.cmdsize =
- sizeof(MachO::segment_command_64) +
- sizeof(MachO::section_64) * LC.Sections.size();
- MLC.segment_command_64_data.nsects = LC.Sections.size();
- MLC.segment_command_64_data.fileoff = SegOffset;
- MLC.segment_command_64_data.vmsize = VMSize;
- MLC.segment_command_64_data.filesize = SegFileSize;
- break;
- }
- }
-
- return Offset;
-}
-
-uint64_t MachOLayoutBuilder::layoutRelocations(uint64_t Offset) {
- for (LoadCommand &LC : O.LoadCommands)
- for (std::unique_ptr<Section> &Sec : LC.Sections) {
- Sec->RelOff = Sec->Relocations.empty() ? 0 : Offset;
- Sec->NReloc = Sec->Relocations.size();
- Offset += sizeof(MachO::any_relocation_info) * Sec->NReloc;
- }
-
- return Offset;
-}
-
-Error MachOLayoutBuilder::layoutTail(uint64_t Offset) {
- // If we are building the layout of an executable or dynamic library
- // which does not have any segments other than __LINKEDIT,
- // the Offset can be equal to zero by this time. It happens because of the
- // convention that in such cases the file offsets specified by LC_SEGMENT
- // start with zero (unlike the case of a relocatable object file).
- const uint64_t HeaderSize =
- Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
- assert((!(O.Header.FileType == MachO::HeaderFileType::MH_OBJECT) ||
- Offset >= HeaderSize + O.Header.SizeOfCmds) &&
- "Incorrect tail offset");
- Offset = std::max(Offset, HeaderSize + O.Header.SizeOfCmds);
-
- // The order of LINKEDIT elements is as follows:
- // rebase info, binding info, weak binding info, lazy binding info, export
- // trie, data-in-code, symbol table, indirect symbol table, symbol table
- // strings, code signature.
- uint64_t NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
- uint64_t StartOfLinkEdit = Offset;
- uint64_t StartOfRebaseInfo = StartOfLinkEdit;
- uint64_t StartOfBindingInfo = StartOfRebaseInfo + O.Rebases.Opcodes.size();
- uint64_t StartOfWeakBindingInfo = StartOfBindingInfo + O.Binds.Opcodes.size();
- uint64_t StartOfLazyBindingInfo =
- StartOfWeakBindingInfo + O.WeakBinds.Opcodes.size();
- uint64_t StartOfExportTrie =
- StartOfLazyBindingInfo + O.LazyBinds.Opcodes.size();
- uint64_t StartOfFunctionStarts = StartOfExportTrie + O.Exports.Trie.size();
- uint64_t StartOfDataInCode =
- StartOfFunctionStarts + O.FunctionStarts.Data.size();
- uint64_t StartOfSymbols = StartOfDataInCode + O.DataInCode.Data.size();
- uint64_t StartOfIndirectSymbols =
- StartOfSymbols + NListSize * O.SymTable.Symbols.size();
- uint64_t StartOfSymbolStrings =
- StartOfIndirectSymbols +
- sizeof(uint32_t) * O.IndirectSymTable.Symbols.size();
- uint64_t StartOfCodeSignature =
- StartOfSymbolStrings + StrTableBuilder.getSize();
+ Sec->Offset = 0;
+ } else {
+ Sec->Offset = SegOffset + SectOffset;
+ Sec->Size = Sec->Content.size();
+ SegFileSize = std::max(SegFileSize, SectOffset + Sec->Size);
+ }
+ }
+ VMSize = std::max(VMSize, SectOffset + Sec->Size);
+ }
+
+ if (IsObjectFile) {
+ Offset += SegFileSize;
+ } else {
+ Offset = alignTo(Offset + SegFileSize, PageSize);
+ SegFileSize = alignTo(SegFileSize, PageSize);
+ // Use the original vmsize if the segment is __PAGEZERO.
+ VMSize =
+ Segname == "__PAGEZERO" ? SegmentVmSize : alignTo(VMSize, PageSize);
+ }
+
+ switch (MLC.load_command_data.cmd) {
+ case MachO::LC_SEGMENT:
+ MLC.segment_command_data.cmdsize =
+ sizeof(MachO::segment_command) +
+ sizeof(MachO::section) * LC.Sections.size();
+ MLC.segment_command_data.nsects = LC.Sections.size();
+ MLC.segment_command_data.fileoff = SegOffset;
+ MLC.segment_command_data.vmsize = VMSize;
+ MLC.segment_command_data.filesize = SegFileSize;
+ break;
+ case MachO::LC_SEGMENT_64:
+ MLC.segment_command_64_data.cmdsize =
+ sizeof(MachO::segment_command_64) +
+ sizeof(MachO::section_64) * LC.Sections.size();
+ MLC.segment_command_64_data.nsects = LC.Sections.size();
+ MLC.segment_command_64_data.fileoff = SegOffset;
+ MLC.segment_command_64_data.vmsize = VMSize;
+ MLC.segment_command_64_data.filesize = SegFileSize;
+ break;
+ }
+ }
+
+ return Offset;
+}
+
+uint64_t MachOLayoutBuilder::layoutRelocations(uint64_t Offset) {
+ for (LoadCommand &LC : O.LoadCommands)
+ for (std::unique_ptr<Section> &Sec : LC.Sections) {
+ Sec->RelOff = Sec->Relocations.empty() ? 0 : Offset;
+ Sec->NReloc = Sec->Relocations.size();
+ Offset += sizeof(MachO::any_relocation_info) * Sec->NReloc;
+ }
+
+ return Offset;
+}
+
+Error MachOLayoutBuilder::layoutTail(uint64_t Offset) {
+ // If we are building the layout of an executable or dynamic library
+ // which does not have any segments other than __LINKEDIT,
+ // the Offset can be equal to zero by this time. It happens because of the
+ // convention that in such cases the file offsets specified by LC_SEGMENT
+ // start with zero (unlike the case of a relocatable object file).
+ const uint64_t HeaderSize =
+ Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
+ assert((!(O.Header.FileType == MachO::HeaderFileType::MH_OBJECT) ||
+ Offset >= HeaderSize + O.Header.SizeOfCmds) &&
+ "Incorrect tail offset");
+ Offset = std::max(Offset, HeaderSize + O.Header.SizeOfCmds);
+
+ // The order of LINKEDIT elements is as follows:
+ // rebase info, binding info, weak binding info, lazy binding info, export
+ // trie, data-in-code, symbol table, indirect symbol table, symbol table
+ // strings, code signature.
+ uint64_t NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
+ uint64_t StartOfLinkEdit = Offset;
+ uint64_t StartOfRebaseInfo = StartOfLinkEdit;
+ uint64_t StartOfBindingInfo = StartOfRebaseInfo + O.Rebases.Opcodes.size();
+ uint64_t StartOfWeakBindingInfo = StartOfBindingInfo + O.Binds.Opcodes.size();
+ uint64_t StartOfLazyBindingInfo =
+ StartOfWeakBindingInfo + O.WeakBinds.Opcodes.size();
+ uint64_t StartOfExportTrie =
+ StartOfLazyBindingInfo + O.LazyBinds.Opcodes.size();
+ uint64_t StartOfFunctionStarts = StartOfExportTrie + O.Exports.Trie.size();
+ uint64_t StartOfDataInCode =
+ StartOfFunctionStarts + O.FunctionStarts.Data.size();
+ uint64_t StartOfSymbols = StartOfDataInCode + O.DataInCode.Data.size();
+ uint64_t StartOfIndirectSymbols =
+ StartOfSymbols + NListSize * O.SymTable.Symbols.size();
+ uint64_t StartOfSymbolStrings =
+ StartOfIndirectSymbols +
+ sizeof(uint32_t) * O.IndirectSymTable.Symbols.size();
+ uint64_t StartOfCodeSignature =
+ StartOfSymbolStrings + StrTableBuilder.getSize();
if (O.CodeSignatureCommandIndex)
StartOfCodeSignature = alignTo(StartOfCodeSignature, 16);
- uint64_t LinkEditSize =
- (StartOfCodeSignature + O.CodeSignature.Data.size()) - StartOfLinkEdit;
-
- // Now we have determined the layout of the contents of the __LINKEDIT
- // segment. Update its load command.
- if (LinkEditLoadCommand) {
- MachO::macho_load_command *MLC = LinkEditLoadCommand;
- switch (LinkEditLoadCommand->load_command_data.cmd) {
- case MachO::LC_SEGMENT:
- MLC->segment_command_data.cmdsize = sizeof(MachO::segment_command);
- MLC->segment_command_data.fileoff = StartOfLinkEdit;
- MLC->segment_command_data.vmsize = alignTo(LinkEditSize, PageSize);
- MLC->segment_command_data.filesize = LinkEditSize;
- break;
- case MachO::LC_SEGMENT_64:
- MLC->segment_command_64_data.cmdsize = sizeof(MachO::segment_command_64);
- MLC->segment_command_64_data.fileoff = StartOfLinkEdit;
- MLC->segment_command_64_data.vmsize = alignTo(LinkEditSize, PageSize);
- MLC->segment_command_64_data.filesize = LinkEditSize;
- break;
- }
- }
-
- for (LoadCommand &LC : O.LoadCommands) {
- auto &MLC = LC.MachOLoadCommand;
- auto cmd = MLC.load_command_data.cmd;
- switch (cmd) {
- case MachO::LC_CODE_SIGNATURE:
- MLC.linkedit_data_command_data.dataoff = StartOfCodeSignature;
- MLC.linkedit_data_command_data.datasize = O.CodeSignature.Data.size();
- break;
- case MachO::LC_SYMTAB:
- MLC.symtab_command_data.symoff = StartOfSymbols;
- MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size();
- MLC.symtab_command_data.stroff = StartOfSymbolStrings;
- MLC.symtab_command_data.strsize = StrTableBuilder.getSize();
- break;
- case MachO::LC_DYSYMTAB: {
- if (MLC.dysymtab_command_data.ntoc != 0 ||
- MLC.dysymtab_command_data.nmodtab != 0 ||
- MLC.dysymtab_command_data.nextrefsyms != 0 ||
- MLC.dysymtab_command_data.nlocrel != 0 ||
- MLC.dysymtab_command_data.nextrel != 0)
- return createStringError(llvm::errc::not_supported,
- "shared library is not yet supported");
-
- if (!O.IndirectSymTable.Symbols.empty()) {
- MLC.dysymtab_command_data.indirectsymoff = StartOfIndirectSymbols;
- MLC.dysymtab_command_data.nindirectsyms =
- O.IndirectSymTable.Symbols.size();
- }
-
- updateDySymTab(MLC);
- break;
- }
- case MachO::LC_DATA_IN_CODE:
- MLC.linkedit_data_command_data.dataoff = StartOfDataInCode;
- MLC.linkedit_data_command_data.datasize = O.DataInCode.Data.size();
- break;
- case MachO::LC_FUNCTION_STARTS:
- MLC.linkedit_data_command_data.dataoff = StartOfFunctionStarts;
- MLC.linkedit_data_command_data.datasize = O.FunctionStarts.Data.size();
- break;
- case MachO::LC_DYLD_INFO:
- case MachO::LC_DYLD_INFO_ONLY:
- MLC.dyld_info_command_data.rebase_off =
- O.Rebases.Opcodes.empty() ? 0 : StartOfRebaseInfo;
- MLC.dyld_info_command_data.rebase_size = O.Rebases.Opcodes.size();
- MLC.dyld_info_command_data.bind_off =
- O.Binds.Opcodes.empty() ? 0 : StartOfBindingInfo;
- MLC.dyld_info_command_data.bind_size = O.Binds.Opcodes.size();
- MLC.dyld_info_command_data.weak_bind_off =
- O.WeakBinds.Opcodes.empty() ? 0 : StartOfWeakBindingInfo;
- MLC.dyld_info_command_data.weak_bind_size = O.WeakBinds.Opcodes.size();
- MLC.dyld_info_command_data.lazy_bind_off =
- O.LazyBinds.Opcodes.empty() ? 0 : StartOfLazyBindingInfo;
- MLC.dyld_info_command_data.lazy_bind_size = O.LazyBinds.Opcodes.size();
- MLC.dyld_info_command_data.export_off =
- O.Exports.Trie.empty() ? 0 : StartOfExportTrie;
- MLC.dyld_info_command_data.export_size = O.Exports.Trie.size();
- break;
- // Note that LC_ENCRYPTION_INFO.cryptoff despite its name and the comment in
- // <mach-o/loader.h> is not an offset in the binary file, instead, it is a
- // relative virtual address. At the moment modification of the __TEXT
- // segment of executables isn't supported anyway (e.g. data in code entries
- // are not recalculated). Moreover, in general
- // LC_ENCRYPT_INFO/LC_ENCRYPTION_INFO_64 are nontrivial to update because
- // without making additional assumptions (e.g. that the entire __TEXT
- // segment should be encrypted) we do not know how to recalculate the
- // boundaries of the encrypted part. For now just copy over these load
- // commands until we encounter a real world usecase where
- // LC_ENCRYPT_INFO/LC_ENCRYPTION_INFO_64 need to be adjusted.
- case MachO::LC_ENCRYPTION_INFO:
- case MachO::LC_ENCRYPTION_INFO_64:
- case MachO::LC_LOAD_DYLINKER:
- case MachO::LC_MAIN:
- case MachO::LC_RPATH:
- case MachO::LC_SEGMENT:
- case MachO::LC_SEGMENT_64:
- case MachO::LC_VERSION_MIN_MACOSX:
- case MachO::LC_VERSION_MIN_IPHONEOS:
- case MachO::LC_VERSION_MIN_TVOS:
- case MachO::LC_VERSION_MIN_WATCHOS:
- case MachO::LC_BUILD_VERSION:
- case MachO::LC_ID_DYLIB:
- case MachO::LC_LOAD_DYLIB:
- case MachO::LC_LOAD_WEAK_DYLIB:
- case MachO::LC_UUID:
- case MachO::LC_SOURCE_VERSION:
- // Nothing to update.
- break;
- default:
- // Abort if it's unsupported in order to prevent corrupting the object.
- return createStringError(llvm::errc::not_supported,
- "unsupported load command (cmd=0x%x)", cmd);
- }
- }
-
- return Error::success();
-}
-
-Error MachOLayoutBuilder::layout() {
- O.Header.NCmds = O.LoadCommands.size();
- O.Header.SizeOfCmds = computeSizeOfCmds();
- constructStringTable();
- updateSymbolIndexes();
- uint64_t Offset = layoutSegments();
- Offset = layoutRelocations(Offset);
- return layoutTail(Offset);
-}
-
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
+ uint64_t LinkEditSize =
+ (StartOfCodeSignature + O.CodeSignature.Data.size()) - StartOfLinkEdit;
+
+ // Now we have determined the layout of the contents of the __LINKEDIT
+ // segment. Update its load command.
+ if (LinkEditLoadCommand) {
+ MachO::macho_load_command *MLC = LinkEditLoadCommand;
+ switch (LinkEditLoadCommand->load_command_data.cmd) {
+ case MachO::LC_SEGMENT:
+ MLC->segment_command_data.cmdsize = sizeof(MachO::segment_command);
+ MLC->segment_command_data.fileoff = StartOfLinkEdit;
+ MLC->segment_command_data.vmsize = alignTo(LinkEditSize, PageSize);
+ MLC->segment_command_data.filesize = LinkEditSize;
+ break;
+ case MachO::LC_SEGMENT_64:
+ MLC->segment_command_64_data.cmdsize = sizeof(MachO::segment_command_64);
+ MLC->segment_command_64_data.fileoff = StartOfLinkEdit;
+ MLC->segment_command_64_data.vmsize = alignTo(LinkEditSize, PageSize);
+ MLC->segment_command_64_data.filesize = LinkEditSize;
+ break;
+ }
+ }
+
+ for (LoadCommand &LC : O.LoadCommands) {
+ auto &MLC = LC.MachOLoadCommand;
+ auto cmd = MLC.load_command_data.cmd;
+ switch (cmd) {
+ case MachO::LC_CODE_SIGNATURE:
+ MLC.linkedit_data_command_data.dataoff = StartOfCodeSignature;
+ MLC.linkedit_data_command_data.datasize = O.CodeSignature.Data.size();
+ break;
+ case MachO::LC_SYMTAB:
+ MLC.symtab_command_data.symoff = StartOfSymbols;
+ MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size();
+ MLC.symtab_command_data.stroff = StartOfSymbolStrings;
+ MLC.symtab_command_data.strsize = StrTableBuilder.getSize();
+ break;
+ case MachO::LC_DYSYMTAB: {
+ if (MLC.dysymtab_command_data.ntoc != 0 ||
+ MLC.dysymtab_command_data.nmodtab != 0 ||
+ MLC.dysymtab_command_data.nextrefsyms != 0 ||
+ MLC.dysymtab_command_data.nlocrel != 0 ||
+ MLC.dysymtab_command_data.nextrel != 0)
+ return createStringError(llvm::errc::not_supported,
+ "shared library is not yet supported");
+
+ if (!O.IndirectSymTable.Symbols.empty()) {
+ MLC.dysymtab_command_data.indirectsymoff = StartOfIndirectSymbols;
+ MLC.dysymtab_command_data.nindirectsyms =
+ O.IndirectSymTable.Symbols.size();
+ }
+
+ updateDySymTab(MLC);
+ break;
+ }
+ case MachO::LC_DATA_IN_CODE:
+ MLC.linkedit_data_command_data.dataoff = StartOfDataInCode;
+ MLC.linkedit_data_command_data.datasize = O.DataInCode.Data.size();
+ break;
+ case MachO::LC_FUNCTION_STARTS:
+ MLC.linkedit_data_command_data.dataoff = StartOfFunctionStarts;
+ MLC.linkedit_data_command_data.datasize = O.FunctionStarts.Data.size();
+ break;
+ case MachO::LC_DYLD_INFO:
+ case MachO::LC_DYLD_INFO_ONLY:
+ MLC.dyld_info_command_data.rebase_off =
+ O.Rebases.Opcodes.empty() ? 0 : StartOfRebaseInfo;
+ MLC.dyld_info_command_data.rebase_size = O.Rebases.Opcodes.size();
+ MLC.dyld_info_command_data.bind_off =
+ O.Binds.Opcodes.empty() ? 0 : StartOfBindingInfo;
+ MLC.dyld_info_command_data.bind_size = O.Binds.Opcodes.size();
+ MLC.dyld_info_command_data.weak_bind_off =
+ O.WeakBinds.Opcodes.empty() ? 0 : StartOfWeakBindingInfo;
+ MLC.dyld_info_command_data.weak_bind_size = O.WeakBinds.Opcodes.size();
+ MLC.dyld_info_command_data.lazy_bind_off =
+ O.LazyBinds.Opcodes.empty() ? 0 : StartOfLazyBindingInfo;
+ MLC.dyld_info_command_data.lazy_bind_size = O.LazyBinds.Opcodes.size();
+ MLC.dyld_info_command_data.export_off =
+ O.Exports.Trie.empty() ? 0 : StartOfExportTrie;
+ MLC.dyld_info_command_data.export_size = O.Exports.Trie.size();
+ break;
+ // Note that LC_ENCRYPTION_INFO.cryptoff despite its name and the comment in
+ // <mach-o/loader.h> is not an offset in the binary file, instead, it is a
+ // relative virtual address. At the moment modification of the __TEXT
+ // segment of executables isn't supported anyway (e.g. data in code entries
+ // are not recalculated). Moreover, in general
+ // LC_ENCRYPT_INFO/LC_ENCRYPTION_INFO_64 are nontrivial to update because
+ // without making additional assumptions (e.g. that the entire __TEXT
+ // segment should be encrypted) we do not know how to recalculate the
+ // boundaries of the encrypted part. For now just copy over these load
+ // commands until we encounter a real world usecase where
+ // LC_ENCRYPT_INFO/LC_ENCRYPTION_INFO_64 need to be adjusted.
+ case MachO::LC_ENCRYPTION_INFO:
+ case MachO::LC_ENCRYPTION_INFO_64:
+ case MachO::LC_LOAD_DYLINKER:
+ case MachO::LC_MAIN:
+ case MachO::LC_RPATH:
+ case MachO::LC_SEGMENT:
+ case MachO::LC_SEGMENT_64:
+ case MachO::LC_VERSION_MIN_MACOSX:
+ case MachO::LC_VERSION_MIN_IPHONEOS:
+ case MachO::LC_VERSION_MIN_TVOS:
+ case MachO::LC_VERSION_MIN_WATCHOS:
+ case MachO::LC_BUILD_VERSION:
+ case MachO::LC_ID_DYLIB:
+ case MachO::LC_LOAD_DYLIB:
+ case MachO::LC_LOAD_WEAK_DYLIB:
+ case MachO::LC_UUID:
+ case MachO::LC_SOURCE_VERSION:
+ // Nothing to update.
+ break;
+ default:
+ // Abort if it's unsupported in order to prevent corrupting the object.
+ return createStringError(llvm::errc::not_supported,
+ "unsupported load command (cmd=0x%x)", cmd);
+ }
+ }
+
+ return Error::success();
+}
+
+Error MachOLayoutBuilder::layout() {
+ O.Header.NCmds = O.LoadCommands.size();
+ O.Header.SizeOfCmds = computeSizeOfCmds();
+ constructStringTable();
+ updateSymbolIndexes();
+ uint64_t Offset = layoutSegments();
+ Offset = layoutRelocations(Offset);
+ return layoutTail(Offset);
+}
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.h b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.h
index 5fe6683e27..960b1af432 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOLayoutBuilder.h
@@ -1,54 +1,54 @@
-//===- MachOLayoutBuilder.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_OBJCOPY_MACHO_MACHOLAYOUTBUILDER_H
-#define LLVM_OBJCOPY_MACHO_MACHOLAYOUTBUILDER_H
-
-#include "MachOObjcopy.h"
-#include "Object.h"
-
-namespace llvm {
-namespace objcopy {
-namespace macho {
-
-class MachOLayoutBuilder {
- Object &O;
- bool Is64Bit;
- uint64_t PageSize;
-
- // Points to the __LINKEDIT segment if it exists.
- MachO::macho_load_command *LinkEditLoadCommand = nullptr;
+//===- MachOLayoutBuilder.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_OBJCOPY_MACHO_MACHOLAYOUTBUILDER_H
+#define LLVM_OBJCOPY_MACHO_MACHOLAYOUTBUILDER_H
+
+#include "MachOObjcopy.h"
+#include "Object.h"
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+class MachOLayoutBuilder {
+ Object &O;
+ bool Is64Bit;
+ uint64_t PageSize;
+
+ // Points to the __LINKEDIT segment if it exists.
+ MachO::macho_load_command *LinkEditLoadCommand = nullptr;
StringTableBuilder StrTableBuilder;
-
- uint32_t computeSizeOfCmds() const;
- void constructStringTable();
- void updateSymbolIndexes();
- void updateDySymTab(MachO::macho_load_command &MLC);
- uint64_t layoutSegments();
- uint64_t layoutRelocations(uint64_t Offset);
- Error layoutTail(uint64_t Offset);
-
+
+ uint32_t computeSizeOfCmds() const;
+ void constructStringTable();
+ void updateSymbolIndexes();
+ void updateDySymTab(MachO::macho_load_command &MLC);
+ uint64_t layoutSegments();
+ uint64_t layoutRelocations(uint64_t Offset);
+ Error layoutTail(uint64_t Offset);
+
static StringTableBuilder::Kind getStringTableBuilderKind(const Object &O,
bool Is64Bit);
-public:
- MachOLayoutBuilder(Object &O, bool Is64Bit, uint64_t PageSize)
+public:
+ MachOLayoutBuilder(Object &O, bool Is64Bit, uint64_t PageSize)
: O(O), Is64Bit(Is64Bit), PageSize(PageSize),
StrTableBuilder(getStringTableBuilderKind(O, Is64Bit)) {}
-
- // Recomputes and updates fields in the given object such as file offsets.
- Error layout();
-
- StringTableBuilder &getStringTableBuilder() { return StrTableBuilder; }
-};
-
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_OBJCOPY_MACHO_MACHOLAYOUTBUILDER_H
+
+ // Recomputes and updates fields in the given object such as file offsets.
+ Error layout();
+
+ StringTableBuilder &getStringTableBuilder() { return StrTableBuilder; }
+};
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_OBJCOPY_MACHO_MACHOLAYOUTBUILDER_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
index fef4a0ae55..42f223b600 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
@@ -1,233 +1,233 @@
-//===- MachOObjcopy.cpp -----------------------------------------*- 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 "MachOObjcopy.h"
-#include "../CopyConfig.h"
+//===- MachOObjcopy.cpp -----------------------------------------*- 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 "MachOObjcopy.h"
+#include "../CopyConfig.h"
#include "../llvm-objcopy.h"
-#include "MachOReader.h"
-#include "MachOWriter.h"
-#include "llvm/ADT/DenseSet.h"
+#include "MachOReader.h"
+#include "MachOWriter.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/MachOUniversalWriter.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-namespace objcopy {
-namespace macho {
-
-using namespace object;
-using SectionPred = std::function<bool(const std::unique_ptr<Section> &Sec)>;
-using LoadCommandPred = std::function<bool(const LoadCommand &LC)>;
-
-#ifndef NDEBUG
-static bool isLoadCommandWithPayloadString(const LoadCommand &LC) {
- // TODO: Add support for LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB and
- // LC_LAZY_LOAD_DYLIB
- return LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH ||
- LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_ID_DYLIB ||
- LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_DYLIB ||
- LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_WEAK_DYLIB;
-}
-#endif
-
-static StringRef getPayloadString(const LoadCommand &LC) {
- assert(isLoadCommandWithPayloadString(LC) &&
- "unsupported load command encountered");
-
- return StringRef(reinterpret_cast<const char *>(LC.Payload.data()),
- LC.Payload.size())
- .rtrim('\0');
-}
-
-static Error removeSections(const CopyConfig &Config, Object &Obj) {
- SectionPred RemovePred = [](const std::unique_ptr<Section> &) {
- return false;
- };
-
- if (!Config.ToRemove.empty()) {
- RemovePred = [&Config, RemovePred](const std::unique_ptr<Section> &Sec) {
- return Config.ToRemove.matches(Sec->CanonicalName);
- };
- }
-
- if (Config.StripAll || Config.StripDebug) {
- // Remove all debug sections.
- RemovePred = [RemovePred](const std::unique_ptr<Section> &Sec) {
- if (Sec->Segname == "__DWARF")
- return true;
-
- return RemovePred(Sec);
- };
- }
-
- if (!Config.OnlySection.empty()) {
- // Overwrite RemovePred because --only-section takes priority.
- RemovePred = [&Config](const std::unique_ptr<Section> &Sec) {
- return !Config.OnlySection.matches(Sec->CanonicalName);
- };
- }
-
- return Obj.removeSections(RemovePred);
-}
-
-static void markSymbols(const CopyConfig &Config, Object &Obj) {
- // Symbols referenced from the indirect symbol table must not be removed.
- for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols)
- if (ISE.Symbol)
- (*ISE.Symbol)->Referenced = true;
-}
-
-static void updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
- for (SymbolEntry &Sym : Obj.SymTable) {
- auto I = Config.SymbolsToRename.find(Sym.Name);
- if (I != Config.SymbolsToRename.end())
- Sym.Name = std::string(I->getValue());
- }
-
- auto RemovePred = [Config, &Obj](const std::unique_ptr<SymbolEntry> &N) {
- if (N->Referenced)
- return false;
- if (Config.StripAll)
- return true;
- if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT))
- return true;
- // This behavior is consistent with cctools' strip.
- if (Config.StripSwiftSymbols && (Obj.Header.Flags & MachO::MH_DYLDLINK) &&
- Obj.SwiftVersion && *Obj.SwiftVersion && N->isSwiftSymbol())
- return true;
- return false;
- };
-
- Obj.SymTable.removeSymbols(RemovePred);
-}
-
-template <typename LCType>
-static void updateLoadCommandPayloadString(LoadCommand &LC, StringRef S) {
- assert(isLoadCommandWithPayloadString(LC) &&
- "unsupported load command encountered");
-
- uint32_t NewCmdsize = alignTo(sizeof(LCType) + S.size() + 1, 8);
-
- LC.MachOLoadCommand.load_command_data.cmdsize = NewCmdsize;
- LC.Payload.assign(NewCmdsize - sizeof(LCType), 0);
- std::copy(S.begin(), S.end(), LC.Payload.begin());
-}
-
-static LoadCommand buildRPathLoadCommand(StringRef Path) {
- LoadCommand LC;
- MachO::rpath_command RPathLC;
- RPathLC.cmd = MachO::LC_RPATH;
- RPathLC.path = sizeof(MachO::rpath_command);
- RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size() + 1, 8);
- LC.MachOLoadCommand.rpath_command_data = RPathLC;
- LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0);
- std::copy(Path.begin(), Path.end(), LC.Payload.begin());
- return LC;
-}
-
-static Error processLoadCommands(const CopyConfig &Config, Object &Obj) {
- // Remove RPaths.
- DenseSet<StringRef> RPathsToRemove(Config.RPathsToRemove.begin(),
- Config.RPathsToRemove.end());
-
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+using namespace object;
+using SectionPred = std::function<bool(const std::unique_ptr<Section> &Sec)>;
+using LoadCommandPred = std::function<bool(const LoadCommand &LC)>;
+
+#ifndef NDEBUG
+static bool isLoadCommandWithPayloadString(const LoadCommand &LC) {
+ // TODO: Add support for LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB and
+ // LC_LAZY_LOAD_DYLIB
+ return LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH ||
+ LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_ID_DYLIB ||
+ LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_DYLIB ||
+ LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_LOAD_WEAK_DYLIB;
+}
+#endif
+
+static StringRef getPayloadString(const LoadCommand &LC) {
+ assert(isLoadCommandWithPayloadString(LC) &&
+ "unsupported load command encountered");
+
+ return StringRef(reinterpret_cast<const char *>(LC.Payload.data()),
+ LC.Payload.size())
+ .rtrim('\0');
+}
+
+static Error removeSections(const CopyConfig &Config, Object &Obj) {
+ SectionPred RemovePred = [](const std::unique_ptr<Section> &) {
+ return false;
+ };
+
+ if (!Config.ToRemove.empty()) {
+ RemovePred = [&Config, RemovePred](const std::unique_ptr<Section> &Sec) {
+ return Config.ToRemove.matches(Sec->CanonicalName);
+ };
+ }
+
+ if (Config.StripAll || Config.StripDebug) {
+ // Remove all debug sections.
+ RemovePred = [RemovePred](const std::unique_ptr<Section> &Sec) {
+ if (Sec->Segname == "__DWARF")
+ return true;
+
+ return RemovePred(Sec);
+ };
+ }
+
+ if (!Config.OnlySection.empty()) {
+ // Overwrite RemovePred because --only-section takes priority.
+ RemovePred = [&Config](const std::unique_ptr<Section> &Sec) {
+ return !Config.OnlySection.matches(Sec->CanonicalName);
+ };
+ }
+
+ return Obj.removeSections(RemovePred);
+}
+
+static void markSymbols(const CopyConfig &Config, Object &Obj) {
+ // Symbols referenced from the indirect symbol table must not be removed.
+ for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols)
+ if (ISE.Symbol)
+ (*ISE.Symbol)->Referenced = true;
+}
+
+static void updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
+ for (SymbolEntry &Sym : Obj.SymTable) {
+ auto I = Config.SymbolsToRename.find(Sym.Name);
+ if (I != Config.SymbolsToRename.end())
+ Sym.Name = std::string(I->getValue());
+ }
+
+ auto RemovePred = [Config, &Obj](const std::unique_ptr<SymbolEntry> &N) {
+ if (N->Referenced)
+ return false;
+ if (Config.StripAll)
+ return true;
+ if (Config.DiscardMode == DiscardType::All && !(N->n_type & MachO::N_EXT))
+ return true;
+ // This behavior is consistent with cctools' strip.
+ if (Config.StripSwiftSymbols && (Obj.Header.Flags & MachO::MH_DYLDLINK) &&
+ Obj.SwiftVersion && *Obj.SwiftVersion && N->isSwiftSymbol())
+ return true;
+ return false;
+ };
+
+ Obj.SymTable.removeSymbols(RemovePred);
+}
+
+template <typename LCType>
+static void updateLoadCommandPayloadString(LoadCommand &LC, StringRef S) {
+ assert(isLoadCommandWithPayloadString(LC) &&
+ "unsupported load command encountered");
+
+ uint32_t NewCmdsize = alignTo(sizeof(LCType) + S.size() + 1, 8);
+
+ LC.MachOLoadCommand.load_command_data.cmdsize = NewCmdsize;
+ LC.Payload.assign(NewCmdsize - sizeof(LCType), 0);
+ std::copy(S.begin(), S.end(), LC.Payload.begin());
+}
+
+static LoadCommand buildRPathLoadCommand(StringRef Path) {
+ LoadCommand LC;
+ MachO::rpath_command RPathLC;
+ RPathLC.cmd = MachO::LC_RPATH;
+ RPathLC.path = sizeof(MachO::rpath_command);
+ RPathLC.cmdsize = alignTo(sizeof(MachO::rpath_command) + Path.size() + 1, 8);
+ LC.MachOLoadCommand.rpath_command_data = RPathLC;
+ LC.Payload.assign(RPathLC.cmdsize - sizeof(MachO::rpath_command), 0);
+ std::copy(Path.begin(), Path.end(), LC.Payload.begin());
+ return LC;
+}
+
+static Error processLoadCommands(const CopyConfig &Config, Object &Obj) {
+ // Remove RPaths.
+ DenseSet<StringRef> RPathsToRemove(Config.RPathsToRemove.begin(),
+ Config.RPathsToRemove.end());
+
LoadCommandPred RemovePred = [&RPathsToRemove,
&Config](const LoadCommand &LC) {
- if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) {
+ if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH) {
// When removing all RPaths we don't need to care
// about what it contains
if (Config.RemoveAllRpaths)
return true;
- StringRef RPath = getPayloadString(LC);
- if (RPathsToRemove.count(RPath)) {
- RPathsToRemove.erase(RPath);
- return true;
- }
- }
- return false;
- };
-
- if (Error E = Obj.removeLoadCommands(RemovePred))
- return E;
-
- // Emit an error if the Mach-O binary does not contain an rpath path name
- // specified in -delete_rpath.
- for (StringRef RPath : Config.RPathsToRemove) {
- if (RPathsToRemove.count(RPath))
- return createStringError(errc::invalid_argument,
- "no LC_RPATH load command with path: %s",
- RPath.str().c_str());
- }
-
- DenseSet<StringRef> RPaths;
-
- // Get all existing RPaths.
- for (LoadCommand &LC : Obj.LoadCommands) {
- if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH)
- RPaths.insert(getPayloadString(LC));
- }
-
- // Throw errors for invalid RPaths.
- for (const auto &OldNew : Config.RPathsToUpdate) {
- StringRef Old = OldNew.getFirst();
- StringRef New = OldNew.getSecond();
+ StringRef RPath = getPayloadString(LC);
+ if (RPathsToRemove.count(RPath)) {
+ RPathsToRemove.erase(RPath);
+ return true;
+ }
+ }
+ return false;
+ };
+
+ if (Error E = Obj.removeLoadCommands(RemovePred))
+ return E;
+
+ // Emit an error if the Mach-O binary does not contain an rpath path name
+ // specified in -delete_rpath.
+ for (StringRef RPath : Config.RPathsToRemove) {
+ if (RPathsToRemove.count(RPath))
+ return createStringError(errc::invalid_argument,
+ "no LC_RPATH load command with path: %s",
+ RPath.str().c_str());
+ }
+
+ DenseSet<StringRef> RPaths;
+
+ // Get all existing RPaths.
+ for (LoadCommand &LC : Obj.LoadCommands) {
+ if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH)
+ RPaths.insert(getPayloadString(LC));
+ }
+
+ // Throw errors for invalid RPaths.
+ for (const auto &OldNew : Config.RPathsToUpdate) {
+ StringRef Old = OldNew.getFirst();
+ StringRef New = OldNew.getSecond();
if (!RPaths.contains(Old))
- return createStringError(errc::invalid_argument,
- "no LC_RPATH load command with path: " + Old);
+ return createStringError(errc::invalid_argument,
+ "no LC_RPATH load command with path: " + Old);
if (RPaths.contains(New))
- return createStringError(errc::invalid_argument,
+ return createStringError(errc::invalid_argument,
"rpath '" + New +
"' would create a duplicate load command");
- }
-
- // Update load commands.
- for (LoadCommand &LC : Obj.LoadCommands) {
- switch (LC.MachOLoadCommand.load_command_data.cmd) {
- case MachO::LC_ID_DYLIB:
+ }
+
+ // Update load commands.
+ for (LoadCommand &LC : Obj.LoadCommands) {
+ switch (LC.MachOLoadCommand.load_command_data.cmd) {
+ case MachO::LC_ID_DYLIB:
if (Config.SharedLibId)
updateLoadCommandPayloadString<MachO::dylib_command>(
LC, *Config.SharedLibId);
- break;
-
- case MachO::LC_RPATH: {
- StringRef RPath = getPayloadString(LC);
- StringRef NewRPath = Config.RPathsToUpdate.lookup(RPath);
- if (!NewRPath.empty())
- updateLoadCommandPayloadString<MachO::rpath_command>(LC, NewRPath);
- break;
- }
-
- // TODO: Add LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB, and LC_LOAD_UPWARD_DYLIB
- // here once llvm-objcopy supports them.
- case MachO::LC_LOAD_DYLIB:
- case MachO::LC_LOAD_WEAK_DYLIB:
- StringRef InstallName = getPayloadString(LC);
- StringRef NewInstallName =
- Config.InstallNamesToUpdate.lookup(InstallName);
- if (!NewInstallName.empty())
- updateLoadCommandPayloadString<MachO::dylib_command>(LC,
- NewInstallName);
- break;
- }
- }
-
- // Add new RPaths.
- for (StringRef RPath : Config.RPathToAdd) {
+ break;
+
+ case MachO::LC_RPATH: {
+ StringRef RPath = getPayloadString(LC);
+ StringRef NewRPath = Config.RPathsToUpdate.lookup(RPath);
+ if (!NewRPath.empty())
+ updateLoadCommandPayloadString<MachO::rpath_command>(LC, NewRPath);
+ break;
+ }
+
+ // TODO: Add LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB, and LC_LOAD_UPWARD_DYLIB
+ // here once llvm-objcopy supports them.
+ case MachO::LC_LOAD_DYLIB:
+ case MachO::LC_LOAD_WEAK_DYLIB:
+ StringRef InstallName = getPayloadString(LC);
+ StringRef NewInstallName =
+ Config.InstallNamesToUpdate.lookup(InstallName);
+ if (!NewInstallName.empty())
+ updateLoadCommandPayloadString<MachO::dylib_command>(LC,
+ NewInstallName);
+ break;
+ }
+ }
+
+ // Add new RPaths.
+ for (StringRef RPath : Config.RPathToAdd) {
if (RPaths.contains(RPath))
- return createStringError(errc::invalid_argument,
+ return createStringError(errc::invalid_argument,
"rpath '" + RPath +
"' would create a duplicate load command");
- RPaths.insert(RPath);
+ RPaths.insert(RPath);
Obj.LoadCommands.push_back(buildRPathLoadCommand(RPath));
- }
-
+ }
+
for (StringRef RPath : Config.RPathToPrepend) {
if (RPaths.contains(RPath))
return createStringError(errc::invalid_argument,
@@ -244,176 +244,176 @@ static Error processLoadCommands(const CopyConfig &Config, Object &Obj) {
if (!Config.RPathToPrepend.empty())
Obj.updateLoadCommandIndexes();
- return Error::success();
-}
-
-static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
- Object &Obj) {
- for (LoadCommand &LC : Obj.LoadCommands)
- for (const std::unique_ptr<Section> &Sec : LC.Sections) {
- if (Sec->CanonicalName == SecName) {
- Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
- FileOutputBuffer::create(Filename, Sec->Content.size());
- if (!BufferOrErr)
- return BufferOrErr.takeError();
- std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
- llvm::copy(Sec->Content, Buf->getBufferStart());
-
- if (Error E = Buf->commit())
- return E;
- return Error::success();
- }
- }
-
- return createStringError(object_error::parse_failed, "section '%s' not found",
- SecName.str().c_str());
-}
-
-static Error addSection(StringRef SecName, StringRef Filename, Object &Obj) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFile(Filename);
- if (!BufOrErr)
- return createFileError(Filename, errorCodeToError(BufOrErr.getError()));
- std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
-
- std::pair<StringRef, StringRef> Pair = SecName.split(',');
- StringRef TargetSegName = Pair.first;
- Section Sec(TargetSegName, Pair.second);
- Sec.Content = Obj.NewSectionsContents.save(Buf->getBuffer());
+ return Error::success();
+}
+
+static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
+ Object &Obj) {
+ for (LoadCommand &LC : Obj.LoadCommands)
+ for (const std::unique_ptr<Section> &Sec : LC.Sections) {
+ if (Sec->CanonicalName == SecName) {
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(Filename, Sec->Content.size());
+ if (!BufferOrErr)
+ return BufferOrErr.takeError();
+ std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
+ llvm::copy(Sec->Content, Buf->getBufferStart());
+
+ if (Error E = Buf->commit())
+ return E;
+ return Error::success();
+ }
+ }
+
+ return createStringError(object_error::parse_failed, "section '%s' not found",
+ SecName.str().c_str());
+}
+
+static Error addSection(StringRef SecName, StringRef Filename, Object &Obj) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFile(Filename);
+ if (!BufOrErr)
+ return createFileError(Filename, errorCodeToError(BufOrErr.getError()));
+ std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
+
+ std::pair<StringRef, StringRef> Pair = SecName.split(',');
+ StringRef TargetSegName = Pair.first;
+ Section Sec(TargetSegName, Pair.second);
+ Sec.Content = Obj.NewSectionsContents.save(Buf->getBuffer());
Sec.Size = Sec.Content.size();
-
- // Add the a section into an existing segment.
- for (LoadCommand &LC : Obj.LoadCommands) {
- Optional<StringRef> SegName = LC.getSegmentName();
- if (SegName && SegName == TargetSegName) {
+
+ // Add the a section into an existing segment.
+ for (LoadCommand &LC : Obj.LoadCommands) {
+ Optional<StringRef> SegName = LC.getSegmentName();
+ if (SegName && SegName == TargetSegName) {
uint64_t Addr = *LC.getSegmentVMAddr();
for (const std::unique_ptr<Section> &S : LC.Sections)
Addr = std::max(Addr, S->Addr + S->Size);
- LC.Sections.push_back(std::make_unique<Section>(Sec));
+ LC.Sections.push_back(std::make_unique<Section>(Sec));
LC.Sections.back()->Addr = Addr;
- return Error::success();
- }
- }
-
- // There's no segment named TargetSegName. Create a new load command and
- // Insert a new section into it.
+ return Error::success();
+ }
+ }
+
+ // There's no segment named TargetSegName. Create a new load command and
+ // Insert a new section into it.
LoadCommand &NewSegment =
Obj.addSegment(TargetSegName, alignTo(Sec.Size, 16384));
- NewSegment.Sections.push_back(std::make_unique<Section>(Sec));
+ NewSegment.Sections.push_back(std::make_unique<Section>(Sec));
NewSegment.Sections.back()->Addr = *NewSegment.getSegmentVMAddr();
- return Error::success();
-}
-
-// isValidMachOCannonicalName returns success if Name is a MachO cannonical name
-// ("<segment>,<section>") and lengths of both segment and section names are
-// valid.
+ return Error::success();
+}
+
+// isValidMachOCannonicalName returns success if Name is a MachO cannonical name
+// ("<segment>,<section>") and lengths of both segment and section names are
+// valid.
static Error isValidMachOCannonicalName(StringRef Name) {
- if (Name.count(',') != 1)
- return createStringError(errc::invalid_argument,
- "invalid section name '%s' (should be formatted "
- "as '<segment name>,<section name>')",
- Name.str().c_str());
-
- std::pair<StringRef, StringRef> Pair = Name.split(',');
- if (Pair.first.size() > 16)
- return createStringError(errc::invalid_argument,
- "too long segment name: '%s'",
- Pair.first.str().c_str());
- if (Pair.second.size() > 16)
- return createStringError(errc::invalid_argument,
- "too long section name: '%s'",
- Pair.second.str().c_str());
- return Error::success();
-}
-
-static Error handleArgs(const CopyConfig &Config, Object &Obj) {
- if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
- Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
- !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
- !Config.AllocSectionsPrefix.empty() || !Config.KeepSection.empty() ||
- Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() ||
- !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
- !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
- !Config.SectionsToRename.empty() ||
- !Config.UnneededSymbolsToRemove.empty() ||
- !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() ||
- Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates ||
- Config.StripAllGNU || Config.StripDWO || Config.StripNonAlloc ||
- Config.StripSections || Config.Weaken || Config.DecompressDebugSections ||
+ if (Name.count(',') != 1)
+ return createStringError(errc::invalid_argument,
+ "invalid section name '%s' (should be formatted "
+ "as '<segment name>,<section name>')",
+ Name.str().c_str());
+
+ std::pair<StringRef, StringRef> Pair = Name.split(',');
+ if (Pair.first.size() > 16)
+ return createStringError(errc::invalid_argument,
+ "too long segment name: '%s'",
+ Pair.first.str().c_str());
+ if (Pair.second.size() > 16)
+ return createStringError(errc::invalid_argument,
+ "too long section name: '%s'",
+ Pair.second.str().c_str());
+ return Error::success();
+}
+
+static Error handleArgs(const CopyConfig &Config, Object &Obj) {
+ if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
+ Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
+ !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
+ !Config.AllocSectionsPrefix.empty() || !Config.KeepSection.empty() ||
+ Config.NewSymbolVisibility || !Config.SymbolsToGlobalize.empty() ||
+ !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
+ !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
+ !Config.SectionsToRename.empty() ||
+ !Config.UnneededSymbolsToRemove.empty() ||
+ !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() ||
+ Config.ExtractDWO || Config.LocalizeHidden || Config.PreserveDates ||
+ Config.StripAllGNU || Config.StripDWO || Config.StripNonAlloc ||
+ Config.StripSections || Config.Weaken || Config.DecompressDebugSections ||
Config.StripUnneeded || Config.DiscardMode == DiscardType::Locals ||
- !Config.SymbolsToAdd.empty() || Config.EntryExpr) {
- return createStringError(llvm::errc::invalid_argument,
- "option not supported by llvm-objcopy for MachO");
- }
-
- // Dump sections before add/remove for compatibility with GNU objcopy.
- for (StringRef Flag : Config.DumpSection) {
- StringRef SectionName;
- StringRef FileName;
- std::tie(SectionName, FileName) = Flag.split('=');
- if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
- return E;
- }
-
- if (Error E = removeSections(Config, Obj))
- return E;
-
- // Mark symbols to determine which symbols are still needed.
- if (Config.StripAll)
- markSymbols(Config, Obj);
-
- updateAndRemoveSymbols(Config, Obj);
-
- if (Config.StripAll)
- for (LoadCommand &LC : Obj.LoadCommands)
- for (std::unique_ptr<Section> &Sec : LC.Sections)
- Sec->Relocations.clear();
-
- for (const auto &Flag : Config.AddSection) {
- std::pair<StringRef, StringRef> SecPair = Flag.split("=");
- StringRef SecName = SecPair.first;
- StringRef File = SecPair.second;
- if (Error E = isValidMachOCannonicalName(SecName))
- return E;
- if (Error E = addSection(SecName, File, Obj))
- return E;
- }
-
- if (Error E = processLoadCommands(Config, Obj))
- return E;
-
- return Error::success();
-}
-
-Error executeObjcopyOnBinary(const CopyConfig &Config,
- object::MachOObjectFile &In, Buffer &Out) {
- MachOReader Reader(In);
+ !Config.SymbolsToAdd.empty() || Config.EntryExpr) {
+ return createStringError(llvm::errc::invalid_argument,
+ "option not supported by llvm-objcopy for MachO");
+ }
+
+ // Dump sections before add/remove for compatibility with GNU objcopy.
+ for (StringRef Flag : Config.DumpSection) {
+ StringRef SectionName;
+ StringRef FileName;
+ std::tie(SectionName, FileName) = Flag.split('=');
+ if (Error E = dumpSectionToFile(SectionName, FileName, Obj))
+ return E;
+ }
+
+ if (Error E = removeSections(Config, Obj))
+ return E;
+
+ // Mark symbols to determine which symbols are still needed.
+ if (Config.StripAll)
+ markSymbols(Config, Obj);
+
+ updateAndRemoveSymbols(Config, Obj);
+
+ if (Config.StripAll)
+ for (LoadCommand &LC : Obj.LoadCommands)
+ for (std::unique_ptr<Section> &Sec : LC.Sections)
+ Sec->Relocations.clear();
+
+ for (const auto &Flag : Config.AddSection) {
+ std::pair<StringRef, StringRef> SecPair = Flag.split("=");
+ StringRef SecName = SecPair.first;
+ StringRef File = SecPair.second;
+ if (Error E = isValidMachOCannonicalName(SecName))
+ return E;
+ if (Error E = addSection(SecName, File, Obj))
+ return E;
+ }
+
+ if (Error E = processLoadCommands(Config, Obj))
+ return E;
+
+ return Error::success();
+}
+
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::MachOObjectFile &In, Buffer &Out) {
+ MachOReader Reader(In);
Expected<std::unique_ptr<Object>> O = Reader.create();
- if (!O)
+ if (!O)
return createFileError(Config.InputFilename, O.takeError());
-
+
if (Error E = handleArgs(Config, **O))
- return createFileError(Config.InputFilename, std::move(E));
-
- // Page size used for alignment of segment sizes in Mach-O executables and
- // dynamic libraries.
- uint64_t PageSize;
- switch (In.getArch()) {
- case Triple::ArchType::arm:
- case Triple::ArchType::aarch64:
- case Triple::ArchType::aarch64_32:
- PageSize = 16384;
- break;
- default:
- PageSize = 4096;
- }
-
+ return createFileError(Config.InputFilename, std::move(E));
+
+ // Page size used for alignment of segment sizes in Mach-O executables and
+ // dynamic libraries.
+ uint64_t PageSize;
+ switch (In.getArch()) {
+ case Triple::ArchType::arm:
+ case Triple::ArchType::aarch64:
+ case Triple::ArchType::aarch64_32:
+ PageSize = 16384;
+ break;
+ default:
+ PageSize = 4096;
+ }
+
MachOWriter Writer(**O, In.is64Bit(), In.isLittleEndian(), PageSize, Out);
- if (auto E = Writer.finalize())
- return E;
- return Writer.write();
-}
-
+ if (auto E = Writer.finalize())
+ return E;
+ return Writer.write();
+}
+
Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config,
const MachOUniversalBinary &In,
Buffer &Out) {
@@ -483,6 +483,6 @@ Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config,
return Out.commit();
}
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.h b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.h
index c3f5391f79..ae96b8329d 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOObjcopy.h
@@ -1,35 +1,35 @@
-//===- MachOObjcopy.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_OBJCOPY_MACHOOBJCOPY_H
-#define LLVM_TOOLS_OBJCOPY_MACHOOBJCOPY_H
-
-namespace llvm {
-class Error;
-
-namespace object {
-class MachOObjectFile;
-class MachOUniversalBinary;
-} // end namespace object
-
-namespace objcopy {
-struct CopyConfig;
-class Buffer;
-
-namespace macho {
-Error executeObjcopyOnBinary(const CopyConfig &Config,
- object::MachOObjectFile &In, Buffer &Out);
+//===- MachOObjcopy.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_OBJCOPY_MACHOOBJCOPY_H
+#define LLVM_TOOLS_OBJCOPY_MACHOOBJCOPY_H
+
+namespace llvm {
+class Error;
+
+namespace object {
+class MachOObjectFile;
+class MachOUniversalBinary;
+} // end namespace object
+
+namespace objcopy {
+struct CopyConfig;
+class Buffer;
+
+namespace macho {
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::MachOObjectFile &In, Buffer &Out);
Error executeObjcopyOnMachOUniversalBinary(
CopyConfig &Config, const object::MachOUniversalBinary &In, Buffer &Out);
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_OBJCOPY_MACHOOBJCOPY_H
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_MACHOOBJCOPY_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.cpp
index 548a85bd49..85e738667c 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.cpp
@@ -1,341 +1,341 @@
-//===- MachOReader.cpp ------------------------------------------*- 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 "MachOReader.h"
-#include "Object.h"
-#include "llvm/BinaryFormat/MachO.h"
-#include "llvm/Object/MachO.h"
+//===- MachOReader.cpp ------------------------------------------*- 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 "MachOReader.h"
+#include "Object.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/MachO.h"
#include "llvm/Support/Errc.h"
-#include <memory>
-
-namespace llvm {
-namespace objcopy {
-namespace macho {
-
-void MachOReader::readHeader(Object &O) const {
- O.Header.Magic = MachOObj.getHeader().magic;
- O.Header.CPUType = MachOObj.getHeader().cputype;
- O.Header.CPUSubType = MachOObj.getHeader().cpusubtype;
- O.Header.FileType = MachOObj.getHeader().filetype;
- O.Header.NCmds = MachOObj.getHeader().ncmds;
- O.Header.SizeOfCmds = MachOObj.getHeader().sizeofcmds;
- O.Header.Flags = MachOObj.getHeader().flags;
-}
-
-template <typename SectionType>
-Section constructSectionCommon(SectionType Sec, uint32_t Index) {
- StringRef SegName(Sec.segname, strnlen(Sec.segname, sizeof(Sec.segname)));
- StringRef SectName(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname)));
- Section S(SegName, SectName);
- S.Index = Index;
- S.Addr = Sec.addr;
- S.Size = Sec.size;
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+void MachOReader::readHeader(Object &O) const {
+ O.Header.Magic = MachOObj.getHeader().magic;
+ O.Header.CPUType = MachOObj.getHeader().cputype;
+ O.Header.CPUSubType = MachOObj.getHeader().cpusubtype;
+ O.Header.FileType = MachOObj.getHeader().filetype;
+ O.Header.NCmds = MachOObj.getHeader().ncmds;
+ O.Header.SizeOfCmds = MachOObj.getHeader().sizeofcmds;
+ O.Header.Flags = MachOObj.getHeader().flags;
+}
+
+template <typename SectionType>
+Section constructSectionCommon(SectionType Sec, uint32_t Index) {
+ StringRef SegName(Sec.segname, strnlen(Sec.segname, sizeof(Sec.segname)));
+ StringRef SectName(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname)));
+ Section S(SegName, SectName);
+ S.Index = Index;
+ S.Addr = Sec.addr;
+ S.Size = Sec.size;
S.OriginalOffset = Sec.offset;
- S.Align = Sec.align;
- S.RelOff = Sec.reloff;
- S.NReloc = Sec.nreloc;
- S.Flags = Sec.flags;
- S.Reserved1 = Sec.reserved1;
- S.Reserved2 = Sec.reserved2;
- S.Reserved3 = 0;
- return S;
-}
-
-template <typename SectionType>
-Section constructSection(SectionType Sec, uint32_t Index);
-
-template <> Section constructSection(MachO::section Sec, uint32_t Index) {
- return constructSectionCommon(Sec, Index);
-}
-
-template <> Section constructSection(MachO::section_64 Sec, uint32_t Index) {
- Section S = constructSectionCommon(Sec, Index);
- S.Reserved3 = Sec.reserved3;
- return S;
-}
-
-template <typename SectionType, typename SegmentType>
+ S.Align = Sec.align;
+ S.RelOff = Sec.reloff;
+ S.NReloc = Sec.nreloc;
+ S.Flags = Sec.flags;
+ S.Reserved1 = Sec.reserved1;
+ S.Reserved2 = Sec.reserved2;
+ S.Reserved3 = 0;
+ return S;
+}
+
+template <typename SectionType>
+Section constructSection(SectionType Sec, uint32_t Index);
+
+template <> Section constructSection(MachO::section Sec, uint32_t Index) {
+ return constructSectionCommon(Sec, Index);
+}
+
+template <> Section constructSection(MachO::section_64 Sec, uint32_t Index) {
+ Section S = constructSectionCommon(Sec, Index);
+ S.Reserved3 = Sec.reserved3;
+ return S;
+}
+
+template <typename SectionType, typename SegmentType>
Expected<std::vector<std::unique_ptr<Section>>>
-extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd,
- const object::MachOObjectFile &MachOObj,
- uint32_t &NextSectionIndex) {
- auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
- const SectionType *Curr =
- reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType));
- std::vector<std::unique_ptr<Section>> Sections;
- for (; reinterpret_cast<const void *>(Curr) < End; Curr++) {
- if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
- SectionType Sec;
- memcpy((void *)&Sec, Curr, sizeof(SectionType));
- MachO::swapStruct(Sec);
- Sections.push_back(
- std::make_unique<Section>(constructSection(Sec, NextSectionIndex)));
- } else {
- Sections.push_back(
- std::make_unique<Section>(constructSection(*Curr, NextSectionIndex)));
- }
-
- Section &S = *Sections.back();
-
- Expected<object::SectionRef> SecRef =
- MachOObj.getSection(NextSectionIndex++);
- if (!SecRef)
+extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ const object::MachOObjectFile &MachOObj,
+ uint32_t &NextSectionIndex) {
+ auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
+ const SectionType *Curr =
+ reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType));
+ std::vector<std::unique_ptr<Section>> Sections;
+ for (; reinterpret_cast<const void *>(Curr) < End; Curr++) {
+ if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
+ SectionType Sec;
+ memcpy((void *)&Sec, Curr, sizeof(SectionType));
+ MachO::swapStruct(Sec);
+ Sections.push_back(
+ std::make_unique<Section>(constructSection(Sec, NextSectionIndex)));
+ } else {
+ Sections.push_back(
+ std::make_unique<Section>(constructSection(*Curr, NextSectionIndex)));
+ }
+
+ Section &S = *Sections.back();
+
+ Expected<object::SectionRef> SecRef =
+ MachOObj.getSection(NextSectionIndex++);
+ if (!SecRef)
return SecRef.takeError();
-
+
Expected<ArrayRef<uint8_t>> Data =
MachOObj.getSectionContents(SecRef->getRawDataRefImpl());
if (!Data)
return Data.takeError();
-
+
S.Content =
StringRef(reinterpret_cast<const char *>(Data->data()), Data->size());
- S.Relocations.reserve(S.NReloc);
- for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()),
- RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl());
- RI != RE; ++RI) {
- RelocationInfo R;
- R.Symbol = nullptr; // We'll fill this field later.
- R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl());
- R.Scattered = MachOObj.isRelocationScattered(R.Info);
- R.Extern = !R.Scattered && MachOObj.getPlainRelocationExternal(R.Info);
- S.Relocations.push_back(R);
- }
-
- assert(S.NReloc == S.Relocations.size() &&
- "Incorrect number of relocations");
- }
+ S.Relocations.reserve(S.NReloc);
+ for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()),
+ RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl());
+ RI != RE; ++RI) {
+ RelocationInfo R;
+ R.Symbol = nullptr; // We'll fill this field later.
+ R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl());
+ R.Scattered = MachOObj.isRelocationScattered(R.Info);
+ R.Extern = !R.Scattered && MachOObj.getPlainRelocationExternal(R.Info);
+ S.Relocations.push_back(R);
+ }
+
+ assert(S.NReloc == S.Relocations.size() &&
+ "Incorrect number of relocations");
+ }
return std::move(Sections);
-}
-
+}
+
Error MachOReader::readLoadCommands(Object &O) const {
- // For MachO sections indices start from 1.
- uint32_t NextSectionIndex = 1;
- for (auto LoadCmd : MachOObj.load_commands()) {
- LoadCommand LC;
- switch (LoadCmd.C.cmd) {
- case MachO::LC_CODE_SIGNATURE:
- O.CodeSignatureCommandIndex = O.LoadCommands.size();
- break;
- case MachO::LC_SEGMENT:
+ // For MachO sections indices start from 1.
+ uint32_t NextSectionIndex = 1;
+ for (auto LoadCmd : MachOObj.load_commands()) {
+ LoadCommand LC;
+ switch (LoadCmd.C.cmd) {
+ case MachO::LC_CODE_SIGNATURE:
+ O.CodeSignatureCommandIndex = O.LoadCommands.size();
+ break;
+ case MachO::LC_SEGMENT:
if (Expected<std::vector<std::unique_ptr<Section>>> Sections =
extractSections<MachO::section, MachO::segment_command>(
LoadCmd, MachOObj, NextSectionIndex))
LC.Sections = std::move(*Sections);
else
return Sections.takeError();
- break;
- case MachO::LC_SEGMENT_64:
+ break;
+ case MachO::LC_SEGMENT_64:
if (Expected<std::vector<std::unique_ptr<Section>>> Sections =
extractSections<MachO::section_64, MachO::segment_command_64>(
LoadCmd, MachOObj, NextSectionIndex))
LC.Sections = std::move(*Sections);
else
return Sections.takeError();
- break;
- case MachO::LC_SYMTAB:
- O.SymTabCommandIndex = O.LoadCommands.size();
- break;
- case MachO::LC_DYSYMTAB:
- O.DySymTabCommandIndex = O.LoadCommands.size();
- break;
- case MachO::LC_DYLD_INFO:
- case MachO::LC_DYLD_INFO_ONLY:
- O.DyLdInfoCommandIndex = O.LoadCommands.size();
- break;
- case MachO::LC_DATA_IN_CODE:
- O.DataInCodeCommandIndex = O.LoadCommands.size();
- break;
- case MachO::LC_FUNCTION_STARTS:
- O.FunctionStartsCommandIndex = O.LoadCommands.size();
- break;
- }
-#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
- case MachO::LCName: \
- memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
- sizeof(MachO::LCStruct)); \
- if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
- MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
- if (LoadCmd.C.cmdsize > sizeof(MachO::LCStruct)) \
- LC.Payload = ArrayRef<uint8_t>( \
- reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
- sizeof(MachO::LCStruct), \
- LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
- break;
-
- switch (LoadCmd.C.cmd) {
- default:
- memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr,
- sizeof(MachO::load_command));
- if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)
- MachO::swapStruct(LC.MachOLoadCommand.load_command_data);
- if (LoadCmd.C.cmdsize > sizeof(MachO::load_command))
- LC.Payload = ArrayRef<uint8_t>(
- reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +
- sizeof(MachO::load_command),
- LoadCmd.C.cmdsize - sizeof(MachO::load_command));
- break;
-#include "llvm/BinaryFormat/MachO.def"
- }
- O.LoadCommands.push_back(std::move(LC));
- }
+ break;
+ case MachO::LC_SYMTAB:
+ O.SymTabCommandIndex = O.LoadCommands.size();
+ break;
+ case MachO::LC_DYSYMTAB:
+ O.DySymTabCommandIndex = O.LoadCommands.size();
+ break;
+ case MachO::LC_DYLD_INFO:
+ case MachO::LC_DYLD_INFO_ONLY:
+ O.DyLdInfoCommandIndex = O.LoadCommands.size();
+ break;
+ case MachO::LC_DATA_IN_CODE:
+ O.DataInCodeCommandIndex = O.LoadCommands.size();
+ break;
+ case MachO::LC_FUNCTION_STARTS:
+ O.FunctionStartsCommandIndex = O.LoadCommands.size();
+ break;
+ }
+#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
+ case MachO::LCName: \
+ memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
+ sizeof(MachO::LCStruct)); \
+ if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
+ MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
+ if (LoadCmd.C.cmdsize > sizeof(MachO::LCStruct)) \
+ LC.Payload = ArrayRef<uint8_t>( \
+ reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
+ sizeof(MachO::LCStruct), \
+ LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
+ break;
+
+ switch (LoadCmd.C.cmd) {
+ default:
+ memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr,
+ sizeof(MachO::load_command));
+ if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(LC.MachOLoadCommand.load_command_data);
+ if (LoadCmd.C.cmdsize > sizeof(MachO::load_command))
+ LC.Payload = ArrayRef<uint8_t>(
+ reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +
+ sizeof(MachO::load_command),
+ LoadCmd.C.cmdsize - sizeof(MachO::load_command));
+ break;
+#include "llvm/BinaryFormat/MachO.def"
+ }
+ O.LoadCommands.push_back(std::move(LC));
+ }
return Error::success();
-}
-
-template <typename nlist_t>
-SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) {
- assert(nlist.n_strx < StrTable.size() &&
- "n_strx exceeds the size of the string table");
- SymbolEntry SE;
- SE.Name = StringRef(StrTable.data() + nlist.n_strx).str();
- SE.n_type = nlist.n_type;
- SE.n_sect = nlist.n_sect;
- SE.n_desc = nlist.n_desc;
- SE.n_value = nlist.n_value;
- return SE;
-}
-
-void MachOReader::readSymbolTable(Object &O) const {
- StringRef StrTable = MachOObj.getStringTableData();
- for (auto Symbol : MachOObj.symbols()) {
- SymbolEntry SE =
- (MachOObj.is64Bit()
- ? constructSymbolEntry(StrTable, MachOObj.getSymbol64TableEntry(
- Symbol.getRawDataRefImpl()))
- : constructSymbolEntry(StrTable, MachOObj.getSymbolTableEntry(
- Symbol.getRawDataRefImpl())));
-
- O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE));
- }
-}
-
-void MachOReader::setSymbolInRelocationInfo(Object &O) const {
- std::vector<const Section *> Sections;
- for (auto &LC : O.LoadCommands)
- for (std::unique_ptr<Section> &Sec : LC.Sections)
- Sections.push_back(Sec.get());
-
- for (LoadCommand &LC : O.LoadCommands)
- for (std::unique_ptr<Section> &Sec : LC.Sections)
- for (auto &Reloc : Sec->Relocations)
- if (!Reloc.Scattered) {
- const uint32_t SymbolNum =
- Reloc.getPlainRelocationSymbolNum(MachOObj.isLittleEndian());
- if (Reloc.Extern) {
- Reloc.Symbol = O.SymTable.getSymbolByIndex(SymbolNum);
- } else {
- // FIXME: Refactor error handling in MachOReader and report an error
- // if we encounter an invalid relocation.
- assert(SymbolNum >= 1 && SymbolNum <= Sections.size() &&
- "Invalid section index.");
- Reloc.Sec = Sections[SymbolNum - 1];
- }
- }
-}
-
-void MachOReader::readRebaseInfo(Object &O) const {
- O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes();
-}
-
-void MachOReader::readBindInfo(Object &O) const {
- O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes();
-}
-
-void MachOReader::readWeakBindInfo(Object &O) const {
- O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes();
-}
-
-void MachOReader::readLazyBindInfo(Object &O) const {
- O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes();
-}
-
-void MachOReader::readExportInfo(Object &O) const {
- O.Exports.Trie = MachOObj.getDyldInfoExportsTrie();
-}
-
-void MachOReader::readLinkData(Object &O, Optional<size_t> LCIndex,
- LinkData &LD) const {
- if (!LCIndex)
- return;
- const MachO::linkedit_data_command &LC =
- O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data;
- LD.Data =
- arrayRefFromStringRef(MachOObj.getData().substr(LC.dataoff, LC.datasize));
-}
-
-void MachOReader::readCodeSignature(Object &O) const {
- return readLinkData(O, O.CodeSignatureCommandIndex, O.CodeSignature);
-}
-
-void MachOReader::readDataInCodeData(Object &O) const {
- return readLinkData(O, O.DataInCodeCommandIndex, O.DataInCode);
-}
-
-void MachOReader::readFunctionStartsData(Object &O) const {
- return readLinkData(O, O.FunctionStartsCommandIndex, O.FunctionStarts);
-}
-
-void MachOReader::readIndirectSymbolTable(Object &O) const {
- MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand();
- constexpr uint32_t AbsOrLocalMask =
- MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS;
- for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) {
- uint32_t Index = MachOObj.getIndirectSymbolTableEntry(DySymTab, i);
- if ((Index & AbsOrLocalMask) != 0)
- O.IndirectSymTable.Symbols.emplace_back(Index, None);
- else
- O.IndirectSymTable.Symbols.emplace_back(
- Index, O.SymTable.getSymbolByIndex(Index));
- }
-}
-
-void MachOReader::readSwiftVersion(Object &O) const {
- struct ObjCImageInfo {
- uint32_t Version;
- uint32_t Flags;
- } ImageInfo;
-
- for (const LoadCommand &LC : O.LoadCommands)
- for (const std::unique_ptr<Section> &Sec : LC.Sections)
- if (Sec->Sectname == "__objc_imageinfo" &&
- (Sec->Segname == "__DATA" || Sec->Segname == "__DATA_CONST" ||
- Sec->Segname == "__DATA_DIRTY") &&
- Sec->Content.size() >= sizeof(ObjCImageInfo)) {
- memcpy(&ImageInfo, Sec->Content.data(), sizeof(ObjCImageInfo));
- if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
- sys::swapByteOrder(ImageInfo.Version);
- sys::swapByteOrder(ImageInfo.Flags);
- }
- O.SwiftVersion = (ImageInfo.Flags >> 8) & 0xff;
- return;
- }
-}
-
+}
+
+template <typename nlist_t>
+SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) {
+ assert(nlist.n_strx < StrTable.size() &&
+ "n_strx exceeds the size of the string table");
+ SymbolEntry SE;
+ SE.Name = StringRef(StrTable.data() + nlist.n_strx).str();
+ SE.n_type = nlist.n_type;
+ SE.n_sect = nlist.n_sect;
+ SE.n_desc = nlist.n_desc;
+ SE.n_value = nlist.n_value;
+ return SE;
+}
+
+void MachOReader::readSymbolTable(Object &O) const {
+ StringRef StrTable = MachOObj.getStringTableData();
+ for (auto Symbol : MachOObj.symbols()) {
+ SymbolEntry SE =
+ (MachOObj.is64Bit()
+ ? constructSymbolEntry(StrTable, MachOObj.getSymbol64TableEntry(
+ Symbol.getRawDataRefImpl()))
+ : constructSymbolEntry(StrTable, MachOObj.getSymbolTableEntry(
+ Symbol.getRawDataRefImpl())));
+
+ O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE));
+ }
+}
+
+void MachOReader::setSymbolInRelocationInfo(Object &O) const {
+ std::vector<const Section *> Sections;
+ for (auto &LC : O.LoadCommands)
+ for (std::unique_ptr<Section> &Sec : LC.Sections)
+ Sections.push_back(Sec.get());
+
+ for (LoadCommand &LC : O.LoadCommands)
+ for (std::unique_ptr<Section> &Sec : LC.Sections)
+ for (auto &Reloc : Sec->Relocations)
+ if (!Reloc.Scattered) {
+ const uint32_t SymbolNum =
+ Reloc.getPlainRelocationSymbolNum(MachOObj.isLittleEndian());
+ if (Reloc.Extern) {
+ Reloc.Symbol = O.SymTable.getSymbolByIndex(SymbolNum);
+ } else {
+ // FIXME: Refactor error handling in MachOReader and report an error
+ // if we encounter an invalid relocation.
+ assert(SymbolNum >= 1 && SymbolNum <= Sections.size() &&
+ "Invalid section index.");
+ Reloc.Sec = Sections[SymbolNum - 1];
+ }
+ }
+}
+
+void MachOReader::readRebaseInfo(Object &O) const {
+ O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes();
+}
+
+void MachOReader::readBindInfo(Object &O) const {
+ O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes();
+}
+
+void MachOReader::readWeakBindInfo(Object &O) const {
+ O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes();
+}
+
+void MachOReader::readLazyBindInfo(Object &O) const {
+ O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes();
+}
+
+void MachOReader::readExportInfo(Object &O) const {
+ O.Exports.Trie = MachOObj.getDyldInfoExportsTrie();
+}
+
+void MachOReader::readLinkData(Object &O, Optional<size_t> LCIndex,
+ LinkData &LD) const {
+ if (!LCIndex)
+ return;
+ const MachO::linkedit_data_command &LC =
+ O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data;
+ LD.Data =
+ arrayRefFromStringRef(MachOObj.getData().substr(LC.dataoff, LC.datasize));
+}
+
+void MachOReader::readCodeSignature(Object &O) const {
+ return readLinkData(O, O.CodeSignatureCommandIndex, O.CodeSignature);
+}
+
+void MachOReader::readDataInCodeData(Object &O) const {
+ return readLinkData(O, O.DataInCodeCommandIndex, O.DataInCode);
+}
+
+void MachOReader::readFunctionStartsData(Object &O) const {
+ return readLinkData(O, O.FunctionStartsCommandIndex, O.FunctionStarts);
+}
+
+void MachOReader::readIndirectSymbolTable(Object &O) const {
+ MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand();
+ constexpr uint32_t AbsOrLocalMask =
+ MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS;
+ for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) {
+ uint32_t Index = MachOObj.getIndirectSymbolTableEntry(DySymTab, i);
+ if ((Index & AbsOrLocalMask) != 0)
+ O.IndirectSymTable.Symbols.emplace_back(Index, None);
+ else
+ O.IndirectSymTable.Symbols.emplace_back(
+ Index, O.SymTable.getSymbolByIndex(Index));
+ }
+}
+
+void MachOReader::readSwiftVersion(Object &O) const {
+ struct ObjCImageInfo {
+ uint32_t Version;
+ uint32_t Flags;
+ } ImageInfo;
+
+ for (const LoadCommand &LC : O.LoadCommands)
+ for (const std::unique_ptr<Section> &Sec : LC.Sections)
+ if (Sec->Sectname == "__objc_imageinfo" &&
+ (Sec->Segname == "__DATA" || Sec->Segname == "__DATA_CONST" ||
+ Sec->Segname == "__DATA_DIRTY") &&
+ Sec->Content.size() >= sizeof(ObjCImageInfo)) {
+ memcpy(&ImageInfo, Sec->Content.data(), sizeof(ObjCImageInfo));
+ if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(ImageInfo.Version);
+ sys::swapByteOrder(ImageInfo.Flags);
+ }
+ O.SwiftVersion = (ImageInfo.Flags >> 8) & 0xff;
+ return;
+ }
+}
+
Expected<std::unique_ptr<Object>> MachOReader::create() const {
- auto Obj = std::make_unique<Object>();
- readHeader(*Obj);
+ auto Obj = std::make_unique<Object>();
+ readHeader(*Obj);
if (Error E = readLoadCommands(*Obj))
return std::move(E);
- readSymbolTable(*Obj);
- setSymbolInRelocationInfo(*Obj);
- readRebaseInfo(*Obj);
- readBindInfo(*Obj);
- readWeakBindInfo(*Obj);
- readLazyBindInfo(*Obj);
- readExportInfo(*Obj);
- readCodeSignature(*Obj);
- readDataInCodeData(*Obj);
- readFunctionStartsData(*Obj);
- readIndirectSymbolTable(*Obj);
- readSwiftVersion(*Obj);
+ readSymbolTable(*Obj);
+ setSymbolInRelocationInfo(*Obj);
+ readRebaseInfo(*Obj);
+ readBindInfo(*Obj);
+ readWeakBindInfo(*Obj);
+ readLazyBindInfo(*Obj);
+ readExportInfo(*Obj);
+ readCodeSignature(*Obj);
+ readDataInCodeData(*Obj);
+ readFunctionStartsData(*Obj);
+ readIndirectSymbolTable(*Obj);
+ readSwiftVersion(*Obj);
return std::move(Obj);
-}
-
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
+}
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.h b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.h
index b446e02865..77bad3889d 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOReader.h
@@ -1,54 +1,54 @@
-//===- MachOReader.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
-//
-//===----------------------------------------------------------------------===//
-
-#include "MachOObjcopy.h"
-#include "Object.h"
-#include "llvm/BinaryFormat/MachO.h"
-#include "llvm/Object/MachO.h"
-#include <memory>
-
-namespace llvm {
-namespace objcopy {
-namespace macho {
-
-// The hierarchy of readers is responsible for parsing different inputs:
-// raw binaries and regular MachO object files.
-class Reader {
-public:
- virtual ~Reader(){};
+//===- MachOReader.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachOObjcopy.h"
+#include "Object.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/MachO.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+// The hierarchy of readers is responsible for parsing different inputs:
+// raw binaries and regular MachO object files.
+class Reader {
+public:
+ virtual ~Reader(){};
virtual Expected<std::unique_ptr<Object>> create() const = 0;
-};
-
-class MachOReader : public Reader {
- const object::MachOObjectFile &MachOObj;
-
- void readHeader(Object &O) const;
+};
+
+class MachOReader : public Reader {
+ const object::MachOObjectFile &MachOObj;
+
+ void readHeader(Object &O) const;
Error readLoadCommands(Object &O) const;
- void readSymbolTable(Object &O) const;
- void setSymbolInRelocationInfo(Object &O) const;
- void readRebaseInfo(Object &O) const;
- void readBindInfo(Object &O) const;
- void readWeakBindInfo(Object &O) const;
- void readLazyBindInfo(Object &O) const;
- void readExportInfo(Object &O) const;
- void readLinkData(Object &O, Optional<size_t> LCIndex, LinkData &LD) const;
- void readCodeSignature(Object &O) const;
- void readDataInCodeData(Object &O) const;
- void readFunctionStartsData(Object &O) const;
- void readIndirectSymbolTable(Object &O) const;
- void readSwiftVersion(Object &O) const;
-
-public:
- explicit MachOReader(const object::MachOObjectFile &Obj) : MachOObj(Obj) {}
-
+ void readSymbolTable(Object &O) const;
+ void setSymbolInRelocationInfo(Object &O) const;
+ void readRebaseInfo(Object &O) const;
+ void readBindInfo(Object &O) const;
+ void readWeakBindInfo(Object &O) const;
+ void readLazyBindInfo(Object &O) const;
+ void readExportInfo(Object &O) const;
+ void readLinkData(Object &O, Optional<size_t> LCIndex, LinkData &LD) const;
+ void readCodeSignature(Object &O) const;
+ void readDataInCodeData(Object &O) const;
+ void readFunctionStartsData(Object &O) const;
+ void readIndirectSymbolTable(Object &O) const;
+ void readSwiftVersion(Object &O) const;
+
+public:
+ explicit MachOReader(const object::MachOObjectFile &Obj) : MachOObj(Obj) {}
+
Expected<std::unique_ptr<Object>> create() const override;
-};
-
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
+};
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.cpp
index 56dd08df3b..166c62437d 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.cpp
@@ -1,126 +1,126 @@
-//===- MachOWriter.cpp ------------------------------------------*- 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 "MachOWriter.h"
-#include "MachOLayoutBuilder.h"
-#include "Object.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/BinaryFormat/MachO.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/ErrorHandling.h"
-#include <memory>
-
-namespace llvm {
-namespace objcopy {
-namespace macho {
-
-size_t MachOWriter::headerSize() const {
- return Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
-}
-
-size_t MachOWriter::loadCommandsSize() const { return O.Header.SizeOfCmds; }
-
-size_t MachOWriter::symTableSize() const {
- return O.SymTable.Symbols.size() *
- (Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist));
-}
-
-size_t MachOWriter::totalSize() const {
- // Going from tail to head and looking for an appropriate "anchor" to
- // calculate the total size assuming that all the offsets are either valid
- // ("true") or 0 (0 indicates that the corresponding part is missing).
-
- SmallVector<size_t, 7> Ends;
- if (O.SymTabCommandIndex) {
- const MachO::symtab_command &SymTabCommand =
- O.LoadCommands[*O.SymTabCommandIndex]
- .MachOLoadCommand.symtab_command_data;
- if (SymTabCommand.symoff)
- Ends.push_back(SymTabCommand.symoff + symTableSize());
- if (SymTabCommand.stroff)
- Ends.push_back(SymTabCommand.stroff + SymTabCommand.strsize);
- }
- if (O.DyLdInfoCommandIndex) {
- const MachO::dyld_info_command &DyLdInfoCommand =
- O.LoadCommands[*O.DyLdInfoCommandIndex]
- .MachOLoadCommand.dyld_info_command_data;
- if (DyLdInfoCommand.rebase_off) {
- assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
- "Incorrect rebase opcodes size");
- Ends.push_back(DyLdInfoCommand.rebase_off + DyLdInfoCommand.rebase_size);
- }
- if (DyLdInfoCommand.bind_off) {
- assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
- "Incorrect bind opcodes size");
- Ends.push_back(DyLdInfoCommand.bind_off + DyLdInfoCommand.bind_size);
- }
- if (DyLdInfoCommand.weak_bind_off) {
- assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
- "Incorrect weak bind opcodes size");
- Ends.push_back(DyLdInfoCommand.weak_bind_off +
- DyLdInfoCommand.weak_bind_size);
- }
- if (DyLdInfoCommand.lazy_bind_off) {
- assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
- "Incorrect lazy bind opcodes size");
- Ends.push_back(DyLdInfoCommand.lazy_bind_off +
- DyLdInfoCommand.lazy_bind_size);
- }
- if (DyLdInfoCommand.export_off) {
- assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
- "Incorrect trie size");
- Ends.push_back(DyLdInfoCommand.export_off + DyLdInfoCommand.export_size);
- }
- }
-
- if (O.DySymTabCommandIndex) {
- const MachO::dysymtab_command &DySymTabCommand =
- O.LoadCommands[*O.DySymTabCommandIndex]
- .MachOLoadCommand.dysymtab_command_data;
-
- if (DySymTabCommand.indirectsymoff)
- Ends.push_back(DySymTabCommand.indirectsymoff +
- sizeof(uint32_t) * O.IndirectSymTable.Symbols.size());
- }
-
- if (O.CodeSignatureCommandIndex) {
- const MachO::linkedit_data_command &LinkEditDataCommand =
- O.LoadCommands[*O.CodeSignatureCommandIndex]
- .MachOLoadCommand.linkedit_data_command_data;
- if (LinkEditDataCommand.dataoff)
- Ends.push_back(LinkEditDataCommand.dataoff +
- LinkEditDataCommand.datasize);
- }
-
- if (O.DataInCodeCommandIndex) {
- const MachO::linkedit_data_command &LinkEditDataCommand =
- O.LoadCommands[*O.DataInCodeCommandIndex]
- .MachOLoadCommand.linkedit_data_command_data;
-
- if (LinkEditDataCommand.dataoff)
- Ends.push_back(LinkEditDataCommand.dataoff +
- LinkEditDataCommand.datasize);
- }
-
- if (O.FunctionStartsCommandIndex) {
- const MachO::linkedit_data_command &LinkEditDataCommand =
- O.LoadCommands[*O.FunctionStartsCommandIndex]
- .MachOLoadCommand.linkedit_data_command_data;
-
- if (LinkEditDataCommand.dataoff)
- Ends.push_back(LinkEditDataCommand.dataoff +
- LinkEditDataCommand.datasize);
- }
-
- // Otherwise, use the last section / reloction.
- for (const LoadCommand &LC : O.LoadCommands)
- for (const std::unique_ptr<Section> &S : LC.Sections) {
+//===- MachOWriter.cpp ------------------------------------------*- 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 "MachOWriter.h"
+#include "MachOLayoutBuilder.h"
+#include "Object.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+size_t MachOWriter::headerSize() const {
+ return Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
+}
+
+size_t MachOWriter::loadCommandsSize() const { return O.Header.SizeOfCmds; }
+
+size_t MachOWriter::symTableSize() const {
+ return O.SymTable.Symbols.size() *
+ (Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist));
+}
+
+size_t MachOWriter::totalSize() const {
+ // Going from tail to head and looking for an appropriate "anchor" to
+ // calculate the total size assuming that all the offsets are either valid
+ // ("true") or 0 (0 indicates that the corresponding part is missing).
+
+ SmallVector<size_t, 7> Ends;
+ if (O.SymTabCommandIndex) {
+ const MachO::symtab_command &SymTabCommand =
+ O.LoadCommands[*O.SymTabCommandIndex]
+ .MachOLoadCommand.symtab_command_data;
+ if (SymTabCommand.symoff)
+ Ends.push_back(SymTabCommand.symoff + symTableSize());
+ if (SymTabCommand.stroff)
+ Ends.push_back(SymTabCommand.stroff + SymTabCommand.strsize);
+ }
+ if (O.DyLdInfoCommandIndex) {
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ if (DyLdInfoCommand.rebase_off) {
+ assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
+ "Incorrect rebase opcodes size");
+ Ends.push_back(DyLdInfoCommand.rebase_off + DyLdInfoCommand.rebase_size);
+ }
+ if (DyLdInfoCommand.bind_off) {
+ assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
+ "Incorrect bind opcodes size");
+ Ends.push_back(DyLdInfoCommand.bind_off + DyLdInfoCommand.bind_size);
+ }
+ if (DyLdInfoCommand.weak_bind_off) {
+ assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
+ "Incorrect weak bind opcodes size");
+ Ends.push_back(DyLdInfoCommand.weak_bind_off +
+ DyLdInfoCommand.weak_bind_size);
+ }
+ if (DyLdInfoCommand.lazy_bind_off) {
+ assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
+ "Incorrect lazy bind opcodes size");
+ Ends.push_back(DyLdInfoCommand.lazy_bind_off +
+ DyLdInfoCommand.lazy_bind_size);
+ }
+ if (DyLdInfoCommand.export_off) {
+ assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
+ "Incorrect trie size");
+ Ends.push_back(DyLdInfoCommand.export_off + DyLdInfoCommand.export_size);
+ }
+ }
+
+ if (O.DySymTabCommandIndex) {
+ const MachO::dysymtab_command &DySymTabCommand =
+ O.LoadCommands[*O.DySymTabCommandIndex]
+ .MachOLoadCommand.dysymtab_command_data;
+
+ if (DySymTabCommand.indirectsymoff)
+ Ends.push_back(DySymTabCommand.indirectsymoff +
+ sizeof(uint32_t) * O.IndirectSymTable.Symbols.size());
+ }
+
+ if (O.CodeSignatureCommandIndex) {
+ const MachO::linkedit_data_command &LinkEditDataCommand =
+ O.LoadCommands[*O.CodeSignatureCommandIndex]
+ .MachOLoadCommand.linkedit_data_command_data;
+ if (LinkEditDataCommand.dataoff)
+ Ends.push_back(LinkEditDataCommand.dataoff +
+ LinkEditDataCommand.datasize);
+ }
+
+ if (O.DataInCodeCommandIndex) {
+ const MachO::linkedit_data_command &LinkEditDataCommand =
+ O.LoadCommands[*O.DataInCodeCommandIndex]
+ .MachOLoadCommand.linkedit_data_command_data;
+
+ if (LinkEditDataCommand.dataoff)
+ Ends.push_back(LinkEditDataCommand.dataoff +
+ LinkEditDataCommand.datasize);
+ }
+
+ if (O.FunctionStartsCommandIndex) {
+ const MachO::linkedit_data_command &LinkEditDataCommand =
+ O.LoadCommands[*O.FunctionStartsCommandIndex]
+ .MachOLoadCommand.linkedit_data_command_data;
+
+ if (LinkEditDataCommand.dataoff)
+ Ends.push_back(LinkEditDataCommand.dataoff +
+ LinkEditDataCommand.datasize);
+ }
+
+ // Otherwise, use the last section / reloction.
+ for (const LoadCommand &LC : O.LoadCommands)
+ for (const std::unique_ptr<Section> &S : LC.Sections) {
if (!S->hasValidOffset()) {
assert((S->Offset == 0) && "Skipped section's offset must be zero");
assert((S->isVirtualSection() || S->Size == 0) &&
@@ -129,398 +129,398 @@ size_t MachOWriter::totalSize() const {
}
assert((S->Offset != 0) &&
"Non-zero-fill section's offset cannot be zero");
- Ends.push_back(S->Offset + S->Size);
- if (S->RelOff)
- Ends.push_back(S->RelOff +
- S->NReloc * sizeof(MachO::any_relocation_info));
- }
-
- if (!Ends.empty())
- return *std::max_element(Ends.begin(), Ends.end());
-
- // Otherwise, we have only Mach header and load commands.
- return headerSize() + loadCommandsSize();
-}
-
-void MachOWriter::writeHeader() {
- MachO::mach_header_64 Header;
-
- Header.magic = O.Header.Magic;
- Header.cputype = O.Header.CPUType;
- Header.cpusubtype = O.Header.CPUSubType;
- Header.filetype = O.Header.FileType;
- Header.ncmds = O.Header.NCmds;
- Header.sizeofcmds = O.Header.SizeOfCmds;
- Header.flags = O.Header.Flags;
- Header.reserved = O.Header.Reserved;
-
- if (IsLittleEndian != sys::IsLittleEndianHost)
- MachO::swapStruct(Header);
-
- auto HeaderSize =
- Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
- memcpy(B.getBufferStart(), &Header, HeaderSize);
-}
-
-void MachOWriter::writeLoadCommands() {
- uint8_t *Begin = B.getBufferStart() + headerSize();
- for (const LoadCommand &LC : O.LoadCommands) {
- // Construct a load command.
- MachO::macho_load_command MLC = LC.MachOLoadCommand;
- switch (MLC.load_command_data.cmd) {
- case MachO::LC_SEGMENT:
- if (IsLittleEndian != sys::IsLittleEndianHost)
- MachO::swapStruct(MLC.segment_command_data);
- memcpy(Begin, &MLC.segment_command_data, sizeof(MachO::segment_command));
- Begin += sizeof(MachO::segment_command);
-
- for (const std::unique_ptr<Section> &Sec : LC.Sections)
- writeSectionInLoadCommand<MachO::section>(*Sec, Begin);
- continue;
- case MachO::LC_SEGMENT_64:
- if (IsLittleEndian != sys::IsLittleEndianHost)
- MachO::swapStruct(MLC.segment_command_64_data);
- memcpy(Begin, &MLC.segment_command_64_data,
- sizeof(MachO::segment_command_64));
- Begin += sizeof(MachO::segment_command_64);
-
- for (const std::unique_ptr<Section> &Sec : LC.Sections)
- writeSectionInLoadCommand<MachO::section_64>(*Sec, Begin);
- continue;
- }
-
-#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
- case MachO::LCName: \
- assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \
- MLC.load_command_data.cmdsize); \
- if (IsLittleEndian != sys::IsLittleEndianHost) \
- MachO::swapStruct(MLC.LCStruct##_data); \
- memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \
- Begin += sizeof(MachO::LCStruct); \
- if (!LC.Payload.empty()) \
- memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \
- Begin += LC.Payload.size(); \
- break;
-
- // Copy the load command as it is.
- switch (MLC.load_command_data.cmd) {
- default:
- assert(sizeof(MachO::load_command) + LC.Payload.size() ==
- MLC.load_command_data.cmdsize);
- if (IsLittleEndian != sys::IsLittleEndianHost)
- MachO::swapStruct(MLC.load_command_data);
- memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command));
- Begin += sizeof(MachO::load_command);
- if (!LC.Payload.empty())
- memcpy(Begin, LC.Payload.data(), LC.Payload.size());
- Begin += LC.Payload.size();
- break;
-#include "llvm/BinaryFormat/MachO.def"
- }
- }
-}
-
-template <typename StructType>
-void MachOWriter::writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out) {
- StructType Temp;
- assert(Sec.Segname.size() <= sizeof(Temp.segname) && "too long segment name");
- assert(Sec.Sectname.size() <= sizeof(Temp.sectname) &&
- "too long section name");
- memset(&Temp, 0, sizeof(StructType));
- memcpy(Temp.segname, Sec.Segname.data(), Sec.Segname.size());
- memcpy(Temp.sectname, Sec.Sectname.data(), Sec.Sectname.size());
- Temp.addr = Sec.Addr;
- Temp.size = Sec.Size;
- Temp.offset = Sec.Offset;
- Temp.align = Sec.Align;
- Temp.reloff = Sec.RelOff;
- Temp.nreloc = Sec.NReloc;
- Temp.flags = Sec.Flags;
- Temp.reserved1 = Sec.Reserved1;
- Temp.reserved2 = Sec.Reserved2;
-
- if (IsLittleEndian != sys::IsLittleEndianHost)
- MachO::swapStruct(Temp);
- memcpy(Out, &Temp, sizeof(StructType));
- Out += sizeof(StructType);
-}
-
-void MachOWriter::writeSections() {
- for (const LoadCommand &LC : O.LoadCommands)
- for (const std::unique_ptr<Section> &Sec : LC.Sections) {
+ Ends.push_back(S->Offset + S->Size);
+ if (S->RelOff)
+ Ends.push_back(S->RelOff +
+ S->NReloc * sizeof(MachO::any_relocation_info));
+ }
+
+ if (!Ends.empty())
+ return *std::max_element(Ends.begin(), Ends.end());
+
+ // Otherwise, we have only Mach header and load commands.
+ return headerSize() + loadCommandsSize();
+}
+
+void MachOWriter::writeHeader() {
+ MachO::mach_header_64 Header;
+
+ Header.magic = O.Header.Magic;
+ Header.cputype = O.Header.CPUType;
+ Header.cpusubtype = O.Header.CPUSubType;
+ Header.filetype = O.Header.FileType;
+ Header.ncmds = O.Header.NCmds;
+ Header.sizeofcmds = O.Header.SizeOfCmds;
+ Header.flags = O.Header.Flags;
+ Header.reserved = O.Header.Reserved;
+
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(Header);
+
+ auto HeaderSize =
+ Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
+ memcpy(B.getBufferStart(), &Header, HeaderSize);
+}
+
+void MachOWriter::writeLoadCommands() {
+ uint8_t *Begin = B.getBufferStart() + headerSize();
+ for (const LoadCommand &LC : O.LoadCommands) {
+ // Construct a load command.
+ MachO::macho_load_command MLC = LC.MachOLoadCommand;
+ switch (MLC.load_command_data.cmd) {
+ case MachO::LC_SEGMENT:
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(MLC.segment_command_data);
+ memcpy(Begin, &MLC.segment_command_data, sizeof(MachO::segment_command));
+ Begin += sizeof(MachO::segment_command);
+
+ for (const std::unique_ptr<Section> &Sec : LC.Sections)
+ writeSectionInLoadCommand<MachO::section>(*Sec, Begin);
+ continue;
+ case MachO::LC_SEGMENT_64:
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(MLC.segment_command_64_data);
+ memcpy(Begin, &MLC.segment_command_64_data,
+ sizeof(MachO::segment_command_64));
+ Begin += sizeof(MachO::segment_command_64);
+
+ for (const std::unique_ptr<Section> &Sec : LC.Sections)
+ writeSectionInLoadCommand<MachO::section_64>(*Sec, Begin);
+ continue;
+ }
+
+#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
+ case MachO::LCName: \
+ assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \
+ MLC.load_command_data.cmdsize); \
+ if (IsLittleEndian != sys::IsLittleEndianHost) \
+ MachO::swapStruct(MLC.LCStruct##_data); \
+ memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \
+ Begin += sizeof(MachO::LCStruct); \
+ if (!LC.Payload.empty()) \
+ memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \
+ Begin += LC.Payload.size(); \
+ break;
+
+ // Copy the load command as it is.
+ switch (MLC.load_command_data.cmd) {
+ default:
+ assert(sizeof(MachO::load_command) + LC.Payload.size() ==
+ MLC.load_command_data.cmdsize);
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(MLC.load_command_data);
+ memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command));
+ Begin += sizeof(MachO::load_command);
+ if (!LC.Payload.empty())
+ memcpy(Begin, LC.Payload.data(), LC.Payload.size());
+ Begin += LC.Payload.size();
+ break;
+#include "llvm/BinaryFormat/MachO.def"
+ }
+ }
+}
+
+template <typename StructType>
+void MachOWriter::writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out) {
+ StructType Temp;
+ assert(Sec.Segname.size() <= sizeof(Temp.segname) && "too long segment name");
+ assert(Sec.Sectname.size() <= sizeof(Temp.sectname) &&
+ "too long section name");
+ memset(&Temp, 0, sizeof(StructType));
+ memcpy(Temp.segname, Sec.Segname.data(), Sec.Segname.size());
+ memcpy(Temp.sectname, Sec.Sectname.data(), Sec.Sectname.size());
+ Temp.addr = Sec.Addr;
+ Temp.size = Sec.Size;
+ Temp.offset = Sec.Offset;
+ Temp.align = Sec.Align;
+ Temp.reloff = Sec.RelOff;
+ Temp.nreloc = Sec.NReloc;
+ Temp.flags = Sec.Flags;
+ Temp.reserved1 = Sec.Reserved1;
+ Temp.reserved2 = Sec.Reserved2;
+
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(Temp);
+ memcpy(Out, &Temp, sizeof(StructType));
+ Out += sizeof(StructType);
+}
+
+void MachOWriter::writeSections() {
+ for (const LoadCommand &LC : O.LoadCommands)
+ for (const std::unique_ptr<Section> &Sec : LC.Sections) {
if (!Sec->hasValidOffset()) {
assert((Sec->Offset == 0) && "Skipped section's offset must be zero");
assert((Sec->isVirtualSection() || Sec->Size == 0) &&
"Non-zero-fill sections with zero offset must have zero size");
- continue;
- }
-
- assert(Sec->Offset && "Section offset can not be zero");
- assert((Sec->Size == Sec->Content.size()) && "Incorrect section size");
- memcpy(B.getBufferStart() + Sec->Offset, Sec->Content.data(),
- Sec->Content.size());
- for (size_t Index = 0; Index < Sec->Relocations.size(); ++Index) {
- RelocationInfo RelocInfo = Sec->Relocations[Index];
- if (!RelocInfo.Scattered) {
- const uint32_t SymbolNum = RelocInfo.Extern
- ? (*RelocInfo.Symbol)->Index
- : (*RelocInfo.Sec)->Index;
- RelocInfo.setPlainRelocationSymbolNum(SymbolNum, IsLittleEndian);
- }
- if (IsLittleEndian != sys::IsLittleEndianHost)
- MachO::swapStruct(
- reinterpret_cast<MachO::any_relocation_info &>(RelocInfo.Info));
- memcpy(B.getBufferStart() + Sec->RelOff +
- Index * sizeof(MachO::any_relocation_info),
- &RelocInfo.Info, sizeof(RelocInfo.Info));
+ continue;
}
- }
-}
-
-template <typename NListType>
-void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out,
- uint32_t Nstrx) {
- NListType ListEntry;
- ListEntry.n_strx = Nstrx;
- ListEntry.n_type = SE.n_type;
- ListEntry.n_sect = SE.n_sect;
- ListEntry.n_desc = SE.n_desc;
- ListEntry.n_value = SE.n_value;
-
- if (IsLittleEndian != sys::IsLittleEndianHost)
- MachO::swapStruct(ListEntry);
- memcpy(Out, reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
- Out += sizeof(NListType);
-}
-
-void MachOWriter::writeStringTable() {
- if (!O.SymTabCommandIndex)
- return;
- const MachO::symtab_command &SymTabCommand =
- O.LoadCommands[*O.SymTabCommandIndex]
- .MachOLoadCommand.symtab_command_data;
-
- uint8_t *StrTable = (uint8_t *)B.getBufferStart() + SymTabCommand.stroff;
- LayoutBuilder.getStringTableBuilder().write(StrTable);
-}
-
-void MachOWriter::writeSymbolTable() {
- if (!O.SymTabCommandIndex)
- return;
- const MachO::symtab_command &SymTabCommand =
- O.LoadCommands[*O.SymTabCommandIndex]
- .MachOLoadCommand.symtab_command_data;
-
- char *SymTable = (char *)B.getBufferStart() + SymTabCommand.symoff;
- for (auto Iter = O.SymTable.Symbols.begin(), End = O.SymTable.Symbols.end();
- Iter != End; Iter++) {
- SymbolEntry *Sym = Iter->get();
- uint32_t Nstrx = LayoutBuilder.getStringTableBuilder().getOffset(Sym->Name);
-
- if (Is64Bit)
- writeNListEntry<MachO::nlist_64>(*Sym, IsLittleEndian, SymTable, Nstrx);
- else
- writeNListEntry<MachO::nlist>(*Sym, IsLittleEndian, SymTable, Nstrx);
- }
-}
-
-void MachOWriter::writeRebaseInfo() {
- if (!O.DyLdInfoCommandIndex)
- return;
- const MachO::dyld_info_command &DyLdInfoCommand =
- O.LoadCommands[*O.DyLdInfoCommandIndex]
- .MachOLoadCommand.dyld_info_command_data;
- char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.rebase_off;
- assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
- "Incorrect rebase opcodes size");
- memcpy(Out, O.Rebases.Opcodes.data(), O.Rebases.Opcodes.size());
-}
-
-void MachOWriter::writeBindInfo() {
- if (!O.DyLdInfoCommandIndex)
- return;
- const MachO::dyld_info_command &DyLdInfoCommand =
- O.LoadCommands[*O.DyLdInfoCommandIndex]
- .MachOLoadCommand.dyld_info_command_data;
- char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.bind_off;
- assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
- "Incorrect bind opcodes size");
- memcpy(Out, O.Binds.Opcodes.data(), O.Binds.Opcodes.size());
-}
-
-void MachOWriter::writeWeakBindInfo() {
- if (!O.DyLdInfoCommandIndex)
- return;
- const MachO::dyld_info_command &DyLdInfoCommand =
- O.LoadCommands[*O.DyLdInfoCommandIndex]
- .MachOLoadCommand.dyld_info_command_data;
- char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.weak_bind_off;
- assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
- "Incorrect weak bind opcodes size");
- memcpy(Out, O.WeakBinds.Opcodes.data(), O.WeakBinds.Opcodes.size());
-}
-
-void MachOWriter::writeLazyBindInfo() {
- if (!O.DyLdInfoCommandIndex)
- return;
- const MachO::dyld_info_command &DyLdInfoCommand =
- O.LoadCommands[*O.DyLdInfoCommandIndex]
- .MachOLoadCommand.dyld_info_command_data;
- char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.lazy_bind_off;
- assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
- "Incorrect lazy bind opcodes size");
- memcpy(Out, O.LazyBinds.Opcodes.data(), O.LazyBinds.Opcodes.size());
-}
-
-void MachOWriter::writeExportInfo() {
- if (!O.DyLdInfoCommandIndex)
- return;
- const MachO::dyld_info_command &DyLdInfoCommand =
- O.LoadCommands[*O.DyLdInfoCommandIndex]
- .MachOLoadCommand.dyld_info_command_data;
- char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.export_off;
- assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
- "Incorrect export trie size");
- memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size());
-}
-
-void MachOWriter::writeIndirectSymbolTable() {
- if (!O.DySymTabCommandIndex)
- return;
-
- const MachO::dysymtab_command &DySymTabCommand =
- O.LoadCommands[*O.DySymTabCommandIndex]
- .MachOLoadCommand.dysymtab_command_data;
-
- uint32_t *Out =
- (uint32_t *)(B.getBufferStart() + DySymTabCommand.indirectsymoff);
- for (const IndirectSymbolEntry &Sym : O.IndirectSymTable.Symbols) {
- uint32_t Entry = (Sym.Symbol) ? (*Sym.Symbol)->Index : Sym.OriginalIndex;
- if (IsLittleEndian != sys::IsLittleEndianHost)
- sys::swapByteOrder(Entry);
- *Out++ = Entry;
- }
-}
-
-void MachOWriter::writeLinkData(Optional<size_t> LCIndex, const LinkData &LD) {
- if (!LCIndex)
- return;
- const MachO::linkedit_data_command &LinkEditDataCommand =
- O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data;
- char *Out = (char *)B.getBufferStart() + LinkEditDataCommand.dataoff;
- assert((LinkEditDataCommand.datasize == LD.Data.size()) &&
- "Incorrect data size");
- memcpy(Out, LD.Data.data(), LD.Data.size());
-}
-
-void MachOWriter::writeCodeSignatureData() {
- return writeLinkData(O.CodeSignatureCommandIndex, O.CodeSignature);
-}
-
-void MachOWriter::writeDataInCodeData() {
- return writeLinkData(O.DataInCodeCommandIndex, O.DataInCode);
-}
-
-void MachOWriter::writeFunctionStartsData() {
- return writeLinkData(O.FunctionStartsCommandIndex, O.FunctionStarts);
-}
-
-void MachOWriter::writeTail() {
- typedef void (MachOWriter::*WriteHandlerType)(void);
- typedef std::pair<uint64_t, WriteHandlerType> WriteOperation;
- SmallVector<WriteOperation, 7> Queue;
-
- if (O.SymTabCommandIndex) {
- const MachO::symtab_command &SymTabCommand =
- O.LoadCommands[*O.SymTabCommandIndex]
- .MachOLoadCommand.symtab_command_data;
- if (SymTabCommand.symoff)
- Queue.push_back({SymTabCommand.symoff, &MachOWriter::writeSymbolTable});
- if (SymTabCommand.stroff)
- Queue.push_back({SymTabCommand.stroff, &MachOWriter::writeStringTable});
- }
-
- if (O.DyLdInfoCommandIndex) {
- const MachO::dyld_info_command &DyLdInfoCommand =
- O.LoadCommands[*O.DyLdInfoCommandIndex]
- .MachOLoadCommand.dyld_info_command_data;
- if (DyLdInfoCommand.rebase_off)
- Queue.push_back(
- {DyLdInfoCommand.rebase_off, &MachOWriter::writeRebaseInfo});
- if (DyLdInfoCommand.bind_off)
- Queue.push_back({DyLdInfoCommand.bind_off, &MachOWriter::writeBindInfo});
- if (DyLdInfoCommand.weak_bind_off)
- Queue.push_back(
- {DyLdInfoCommand.weak_bind_off, &MachOWriter::writeWeakBindInfo});
- if (DyLdInfoCommand.lazy_bind_off)
- Queue.push_back(
- {DyLdInfoCommand.lazy_bind_off, &MachOWriter::writeLazyBindInfo});
- if (DyLdInfoCommand.export_off)
- Queue.push_back(
- {DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo});
- }
-
- if (O.DySymTabCommandIndex) {
- const MachO::dysymtab_command &DySymTabCommand =
- O.LoadCommands[*O.DySymTabCommandIndex]
- .MachOLoadCommand.dysymtab_command_data;
-
- if (DySymTabCommand.indirectsymoff)
- Queue.emplace_back(DySymTabCommand.indirectsymoff,
- &MachOWriter::writeIndirectSymbolTable);
- }
-
- if (O.CodeSignatureCommandIndex) {
- const MachO::linkedit_data_command &LinkEditDataCommand =
- O.LoadCommands[*O.CodeSignatureCommandIndex]
- .MachOLoadCommand.linkedit_data_command_data;
-
- if (LinkEditDataCommand.dataoff)
- Queue.emplace_back(LinkEditDataCommand.dataoff,
- &MachOWriter::writeCodeSignatureData);
- }
-
- if (O.DataInCodeCommandIndex) {
- const MachO::linkedit_data_command &LinkEditDataCommand =
- O.LoadCommands[*O.DataInCodeCommandIndex]
- .MachOLoadCommand.linkedit_data_command_data;
-
- if (LinkEditDataCommand.dataoff)
- Queue.emplace_back(LinkEditDataCommand.dataoff,
- &MachOWriter::writeDataInCodeData);
- }
-
- if (O.FunctionStartsCommandIndex) {
- const MachO::linkedit_data_command &LinkEditDataCommand =
- O.LoadCommands[*O.FunctionStartsCommandIndex]
- .MachOLoadCommand.linkedit_data_command_data;
-
- if (LinkEditDataCommand.dataoff)
- Queue.emplace_back(LinkEditDataCommand.dataoff,
- &MachOWriter::writeFunctionStartsData);
- }
-
- llvm::sort(Queue, [](const WriteOperation &LHS, const WriteOperation &RHS) {
- return LHS.first < RHS.first;
- });
-
- for (auto WriteOp : Queue)
- (this->*WriteOp.second)();
-}
-
-Error MachOWriter::finalize() { return LayoutBuilder.layout(); }
-
-Error MachOWriter::write() {
- if (Error E = B.allocate(totalSize()))
- return E;
- memset(B.getBufferStart(), 0, totalSize());
- writeHeader();
- writeLoadCommands();
- writeSections();
- writeTail();
- return B.commit();
-}
-
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
+
+ assert(Sec->Offset && "Section offset can not be zero");
+ assert((Sec->Size == Sec->Content.size()) && "Incorrect section size");
+ memcpy(B.getBufferStart() + Sec->Offset, Sec->Content.data(),
+ Sec->Content.size());
+ for (size_t Index = 0; Index < Sec->Relocations.size(); ++Index) {
+ RelocationInfo RelocInfo = Sec->Relocations[Index];
+ if (!RelocInfo.Scattered) {
+ const uint32_t SymbolNum = RelocInfo.Extern
+ ? (*RelocInfo.Symbol)->Index
+ : (*RelocInfo.Sec)->Index;
+ RelocInfo.setPlainRelocationSymbolNum(SymbolNum, IsLittleEndian);
+ }
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(
+ reinterpret_cast<MachO::any_relocation_info &>(RelocInfo.Info));
+ memcpy(B.getBufferStart() + Sec->RelOff +
+ Index * sizeof(MachO::any_relocation_info),
+ &RelocInfo.Info, sizeof(RelocInfo.Info));
+ }
+ }
+}
+
+template <typename NListType>
+void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out,
+ uint32_t Nstrx) {
+ NListType ListEntry;
+ ListEntry.n_strx = Nstrx;
+ ListEntry.n_type = SE.n_type;
+ ListEntry.n_sect = SE.n_sect;
+ ListEntry.n_desc = SE.n_desc;
+ ListEntry.n_value = SE.n_value;
+
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(ListEntry);
+ memcpy(Out, reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
+ Out += sizeof(NListType);
+}
+
+void MachOWriter::writeStringTable() {
+ if (!O.SymTabCommandIndex)
+ return;
+ const MachO::symtab_command &SymTabCommand =
+ O.LoadCommands[*O.SymTabCommandIndex]
+ .MachOLoadCommand.symtab_command_data;
+
+ uint8_t *StrTable = (uint8_t *)B.getBufferStart() + SymTabCommand.stroff;
+ LayoutBuilder.getStringTableBuilder().write(StrTable);
+}
+
+void MachOWriter::writeSymbolTable() {
+ if (!O.SymTabCommandIndex)
+ return;
+ const MachO::symtab_command &SymTabCommand =
+ O.LoadCommands[*O.SymTabCommandIndex]
+ .MachOLoadCommand.symtab_command_data;
+
+ char *SymTable = (char *)B.getBufferStart() + SymTabCommand.symoff;
+ for (auto Iter = O.SymTable.Symbols.begin(), End = O.SymTable.Symbols.end();
+ Iter != End; Iter++) {
+ SymbolEntry *Sym = Iter->get();
+ uint32_t Nstrx = LayoutBuilder.getStringTableBuilder().getOffset(Sym->Name);
+
+ if (Is64Bit)
+ writeNListEntry<MachO::nlist_64>(*Sym, IsLittleEndian, SymTable, Nstrx);
+ else
+ writeNListEntry<MachO::nlist>(*Sym, IsLittleEndian, SymTable, Nstrx);
+ }
+}
+
+void MachOWriter::writeRebaseInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.rebase_off;
+ assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
+ "Incorrect rebase opcodes size");
+ memcpy(Out, O.Rebases.Opcodes.data(), O.Rebases.Opcodes.size());
+}
+
+void MachOWriter::writeBindInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.bind_off;
+ assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
+ "Incorrect bind opcodes size");
+ memcpy(Out, O.Binds.Opcodes.data(), O.Binds.Opcodes.size());
+}
+
+void MachOWriter::writeWeakBindInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.weak_bind_off;
+ assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
+ "Incorrect weak bind opcodes size");
+ memcpy(Out, O.WeakBinds.Opcodes.data(), O.WeakBinds.Opcodes.size());
+}
+
+void MachOWriter::writeLazyBindInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.lazy_bind_off;
+ assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
+ "Incorrect lazy bind opcodes size");
+ memcpy(Out, O.LazyBinds.Opcodes.data(), O.LazyBinds.Opcodes.size());
+}
+
+void MachOWriter::writeExportInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.export_off;
+ assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
+ "Incorrect export trie size");
+ memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size());
+}
+
+void MachOWriter::writeIndirectSymbolTable() {
+ if (!O.DySymTabCommandIndex)
+ return;
+
+ const MachO::dysymtab_command &DySymTabCommand =
+ O.LoadCommands[*O.DySymTabCommandIndex]
+ .MachOLoadCommand.dysymtab_command_data;
+
+ uint32_t *Out =
+ (uint32_t *)(B.getBufferStart() + DySymTabCommand.indirectsymoff);
+ for (const IndirectSymbolEntry &Sym : O.IndirectSymTable.Symbols) {
+ uint32_t Entry = (Sym.Symbol) ? (*Sym.Symbol)->Index : Sym.OriginalIndex;
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ sys::swapByteOrder(Entry);
+ *Out++ = Entry;
+ }
+}
+
+void MachOWriter::writeLinkData(Optional<size_t> LCIndex, const LinkData &LD) {
+ if (!LCIndex)
+ return;
+ const MachO::linkedit_data_command &LinkEditDataCommand =
+ O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data;
+ char *Out = (char *)B.getBufferStart() + LinkEditDataCommand.dataoff;
+ assert((LinkEditDataCommand.datasize == LD.Data.size()) &&
+ "Incorrect data size");
+ memcpy(Out, LD.Data.data(), LD.Data.size());
+}
+
+void MachOWriter::writeCodeSignatureData() {
+ return writeLinkData(O.CodeSignatureCommandIndex, O.CodeSignature);
+}
+
+void MachOWriter::writeDataInCodeData() {
+ return writeLinkData(O.DataInCodeCommandIndex, O.DataInCode);
+}
+
+void MachOWriter::writeFunctionStartsData() {
+ return writeLinkData(O.FunctionStartsCommandIndex, O.FunctionStarts);
+}
+
+void MachOWriter::writeTail() {
+ typedef void (MachOWriter::*WriteHandlerType)(void);
+ typedef std::pair<uint64_t, WriteHandlerType> WriteOperation;
+ SmallVector<WriteOperation, 7> Queue;
+
+ if (O.SymTabCommandIndex) {
+ const MachO::symtab_command &SymTabCommand =
+ O.LoadCommands[*O.SymTabCommandIndex]
+ .MachOLoadCommand.symtab_command_data;
+ if (SymTabCommand.symoff)
+ Queue.push_back({SymTabCommand.symoff, &MachOWriter::writeSymbolTable});
+ if (SymTabCommand.stroff)
+ Queue.push_back({SymTabCommand.stroff, &MachOWriter::writeStringTable});
+ }
+
+ if (O.DyLdInfoCommandIndex) {
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ if (DyLdInfoCommand.rebase_off)
+ Queue.push_back(
+ {DyLdInfoCommand.rebase_off, &MachOWriter::writeRebaseInfo});
+ if (DyLdInfoCommand.bind_off)
+ Queue.push_back({DyLdInfoCommand.bind_off, &MachOWriter::writeBindInfo});
+ if (DyLdInfoCommand.weak_bind_off)
+ Queue.push_back(
+ {DyLdInfoCommand.weak_bind_off, &MachOWriter::writeWeakBindInfo});
+ if (DyLdInfoCommand.lazy_bind_off)
+ Queue.push_back(
+ {DyLdInfoCommand.lazy_bind_off, &MachOWriter::writeLazyBindInfo});
+ if (DyLdInfoCommand.export_off)
+ Queue.push_back(
+ {DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo});
+ }
+
+ if (O.DySymTabCommandIndex) {
+ const MachO::dysymtab_command &DySymTabCommand =
+ O.LoadCommands[*O.DySymTabCommandIndex]
+ .MachOLoadCommand.dysymtab_command_data;
+
+ if (DySymTabCommand.indirectsymoff)
+ Queue.emplace_back(DySymTabCommand.indirectsymoff,
+ &MachOWriter::writeIndirectSymbolTable);
+ }
+
+ if (O.CodeSignatureCommandIndex) {
+ const MachO::linkedit_data_command &LinkEditDataCommand =
+ O.LoadCommands[*O.CodeSignatureCommandIndex]
+ .MachOLoadCommand.linkedit_data_command_data;
+
+ if (LinkEditDataCommand.dataoff)
+ Queue.emplace_back(LinkEditDataCommand.dataoff,
+ &MachOWriter::writeCodeSignatureData);
+ }
+
+ if (O.DataInCodeCommandIndex) {
+ const MachO::linkedit_data_command &LinkEditDataCommand =
+ O.LoadCommands[*O.DataInCodeCommandIndex]
+ .MachOLoadCommand.linkedit_data_command_data;
+
+ if (LinkEditDataCommand.dataoff)
+ Queue.emplace_back(LinkEditDataCommand.dataoff,
+ &MachOWriter::writeDataInCodeData);
+ }
+
+ if (O.FunctionStartsCommandIndex) {
+ const MachO::linkedit_data_command &LinkEditDataCommand =
+ O.LoadCommands[*O.FunctionStartsCommandIndex]
+ .MachOLoadCommand.linkedit_data_command_data;
+
+ if (LinkEditDataCommand.dataoff)
+ Queue.emplace_back(LinkEditDataCommand.dataoff,
+ &MachOWriter::writeFunctionStartsData);
+ }
+
+ llvm::sort(Queue, [](const WriteOperation &LHS, const WriteOperation &RHS) {
+ return LHS.first < RHS.first;
+ });
+
+ for (auto WriteOp : Queue)
+ (this->*WriteOp.second)();
+}
+
+Error MachOWriter::finalize() { return LayoutBuilder.layout(); }
+
+Error MachOWriter::write() {
+ if (Error E = B.allocate(totalSize()))
+ return E;
+ memset(B.getBufferStart(), 0, totalSize());
+ writeHeader();
+ writeLoadCommands();
+ writeSections();
+ writeTail();
+ return B.commit();
+}
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.h b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.h
index c2c6f5a55e..a6681b8a4c 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/MachOWriter.h
@@ -1,67 +1,67 @@
-//===- MachOWriter.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
-//
-//===----------------------------------------------------------------------===//
-
-#include "../Buffer.h"
-#include "MachOLayoutBuilder.h"
-#include "MachOObjcopy.h"
-#include "Object.h"
-#include "llvm/BinaryFormat/MachO.h"
-#include "llvm/Object/MachO.h"
-
-namespace llvm {
-class Error;
-
-namespace objcopy {
-namespace macho {
-
-class MachOWriter {
- Object &O;
- bool Is64Bit;
- bool IsLittleEndian;
- uint64_t PageSize;
- Buffer &B;
- MachOLayoutBuilder LayoutBuilder;
-
- size_t headerSize() const;
- size_t loadCommandsSize() const;
- size_t symTableSize() const;
- size_t strTableSize() const;
-
- void writeHeader();
- void writeLoadCommands();
- template <typename StructType>
- void writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out);
- void writeSections();
- void writeSymbolTable();
- void writeStringTable();
- void writeRebaseInfo();
- void writeBindInfo();
- void writeWeakBindInfo();
- void writeLazyBindInfo();
- void writeExportInfo();
- void writeIndirectSymbolTable();
- void writeLinkData(Optional<size_t> LCIndex, const LinkData &LD);
- void writeCodeSignatureData();
- void writeDataInCodeData();
- void writeFunctionStartsData();
- void writeTail();
-
-public:
- MachOWriter(Object &O, bool Is64Bit, bool IsLittleEndian, uint64_t PageSize,
- Buffer &B)
- : O(O), Is64Bit(Is64Bit), IsLittleEndian(IsLittleEndian),
- PageSize(PageSize), B(B), LayoutBuilder(O, Is64Bit, PageSize) {}
-
- size_t totalSize() const;
- Error finalize();
- Error write();
-};
-
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
+//===- MachOWriter.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "../Buffer.h"
+#include "MachOLayoutBuilder.h"
+#include "MachOObjcopy.h"
+#include "Object.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/MachO.h"
+
+namespace llvm {
+class Error;
+
+namespace objcopy {
+namespace macho {
+
+class MachOWriter {
+ Object &O;
+ bool Is64Bit;
+ bool IsLittleEndian;
+ uint64_t PageSize;
+ Buffer &B;
+ MachOLayoutBuilder LayoutBuilder;
+
+ size_t headerSize() const;
+ size_t loadCommandsSize() const;
+ size_t symTableSize() const;
+ size_t strTableSize() const;
+
+ void writeHeader();
+ void writeLoadCommands();
+ template <typename StructType>
+ void writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out);
+ void writeSections();
+ void writeSymbolTable();
+ void writeStringTable();
+ void writeRebaseInfo();
+ void writeBindInfo();
+ void writeWeakBindInfo();
+ void writeLazyBindInfo();
+ void writeExportInfo();
+ void writeIndirectSymbolTable();
+ void writeLinkData(Optional<size_t> LCIndex, const LinkData &LD);
+ void writeCodeSignatureData();
+ void writeDataInCodeData();
+ void writeFunctionStartsData();
+ void writeTail();
+
+public:
+ MachOWriter(Object &O, bool Is64Bit, bool IsLittleEndian, uint64_t PageSize,
+ Buffer &B)
+ : O(O), Is64Bit(Is64Bit), IsLittleEndian(IsLittleEndian),
+ PageSize(PageSize), B(B), LayoutBuilder(O, Is64Bit, PageSize) {}
+
+ size_t totalSize() const;
+ Error finalize();
+ Error write();
+};
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.cpp
index cdb97531fb..184c58ad05 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.cpp
@@ -1,113 +1,113 @@
-//===- Object.cpp - Mach-O object file model --------------------*- 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 "Object.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include <unordered_set>
-
-namespace llvm {
-namespace objcopy {
-namespace macho {
-
-const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const {
- assert(Index < Symbols.size() && "invalid symbol index");
- return Symbols[Index].get();
-}
-
-SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) {
- return const_cast<SymbolEntry *>(
- static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index));
-}
-
-void SymbolTable::removeSymbols(
- function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) {
+//===- Object.cpp - Mach-O object file model --------------------*- 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 "Object.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include <unordered_set>
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const {
+ assert(Index < Symbols.size() && "invalid symbol index");
+ return Symbols[Index].get();
+}
+
+SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) {
+ return const_cast<SymbolEntry *>(
+ static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index));
+}
+
+void SymbolTable::removeSymbols(
+ function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) {
llvm::erase_if(Symbols, ToRemove);
-}
-
-void Object::updateLoadCommandIndexes() {
- // Update indices of special load commands
- for (size_t Index = 0, Size = LoadCommands.size(); Index < Size; ++Index) {
- LoadCommand &LC = LoadCommands[Index];
- switch (LC.MachOLoadCommand.load_command_data.cmd) {
- case MachO::LC_SYMTAB:
- SymTabCommandIndex = Index;
- break;
- case MachO::LC_DYSYMTAB:
- DySymTabCommandIndex = Index;
- break;
- case MachO::LC_DYLD_INFO:
- case MachO::LC_DYLD_INFO_ONLY:
- DyLdInfoCommandIndex = Index;
- break;
- case MachO::LC_DATA_IN_CODE:
- DataInCodeCommandIndex = Index;
- break;
- case MachO::LC_FUNCTION_STARTS:
- FunctionStartsCommandIndex = Index;
- break;
- }
- }
-}
-
-Error Object::removeLoadCommands(
- function_ref<bool(const LoadCommand &)> ToRemove) {
- auto It = std::stable_partition(
- LoadCommands.begin(), LoadCommands.end(),
- [&](const LoadCommand &LC) { return !ToRemove(LC); });
- LoadCommands.erase(It, LoadCommands.end());
-
- updateLoadCommandIndexes();
- return Error::success();
-}
-
-Error Object::removeSections(
- function_ref<bool(const std::unique_ptr<Section> &)> ToRemove) {
- DenseMap<uint32_t, const Section *> OldIndexToSection;
- uint32_t NextSectionIndex = 1;
- for (LoadCommand &LC : LoadCommands) {
- auto It = std::stable_partition(
- std::begin(LC.Sections), std::end(LC.Sections),
- [&](const std::unique_ptr<Section> &Sec) { return !ToRemove(Sec); });
- for (auto I = LC.Sections.begin(), End = It; I != End; ++I) {
- OldIndexToSection[(*I)->Index] = I->get();
- (*I)->Index = NextSectionIndex++;
- }
- LC.Sections.erase(It, LC.Sections.end());
- }
-
- auto IsDead = [&](const std::unique_ptr<SymbolEntry> &S) -> bool {
- Optional<uint32_t> Section = S->section();
- return (Section && !OldIndexToSection.count(*Section));
- };
-
- SmallPtrSet<const SymbolEntry *, 2> DeadSymbols;
- for (const std::unique_ptr<SymbolEntry> &Sym : SymTable.Symbols)
- if (IsDead(Sym))
- DeadSymbols.insert(Sym.get());
-
- for (const LoadCommand &LC : LoadCommands)
- for (const std::unique_ptr<Section> &Sec : LC.Sections)
- for (const RelocationInfo &R : Sec->Relocations)
- if (R.Symbol && *R.Symbol && DeadSymbols.count(*R.Symbol))
- return createStringError(std::errc::invalid_argument,
- "symbol '%s' defined in section with index "
- "'%u' cannot be removed because it is "
- "referenced by a relocation in section '%s'",
- (*R.Symbol)->Name.c_str(),
- *((*R.Symbol)->section()),
- Sec->CanonicalName.c_str());
- SymTable.removeSymbols(IsDead);
- for (std::unique_ptr<SymbolEntry> &S : SymTable.Symbols)
- if (S->section())
- S->n_sect = OldIndexToSection[S->n_sect]->Index;
- return Error::success();
-}
-
+}
+
+void Object::updateLoadCommandIndexes() {
+ // Update indices of special load commands
+ for (size_t Index = 0, Size = LoadCommands.size(); Index < Size; ++Index) {
+ LoadCommand &LC = LoadCommands[Index];
+ switch (LC.MachOLoadCommand.load_command_data.cmd) {
+ case MachO::LC_SYMTAB:
+ SymTabCommandIndex = Index;
+ break;
+ case MachO::LC_DYSYMTAB:
+ DySymTabCommandIndex = Index;
+ break;
+ case MachO::LC_DYLD_INFO:
+ case MachO::LC_DYLD_INFO_ONLY:
+ DyLdInfoCommandIndex = Index;
+ break;
+ case MachO::LC_DATA_IN_CODE:
+ DataInCodeCommandIndex = Index;
+ break;
+ case MachO::LC_FUNCTION_STARTS:
+ FunctionStartsCommandIndex = Index;
+ break;
+ }
+ }
+}
+
+Error Object::removeLoadCommands(
+ function_ref<bool(const LoadCommand &)> ToRemove) {
+ auto It = std::stable_partition(
+ LoadCommands.begin(), LoadCommands.end(),
+ [&](const LoadCommand &LC) { return !ToRemove(LC); });
+ LoadCommands.erase(It, LoadCommands.end());
+
+ updateLoadCommandIndexes();
+ return Error::success();
+}
+
+Error Object::removeSections(
+ function_ref<bool(const std::unique_ptr<Section> &)> ToRemove) {
+ DenseMap<uint32_t, const Section *> OldIndexToSection;
+ uint32_t NextSectionIndex = 1;
+ for (LoadCommand &LC : LoadCommands) {
+ auto It = std::stable_partition(
+ std::begin(LC.Sections), std::end(LC.Sections),
+ [&](const std::unique_ptr<Section> &Sec) { return !ToRemove(Sec); });
+ for (auto I = LC.Sections.begin(), End = It; I != End; ++I) {
+ OldIndexToSection[(*I)->Index] = I->get();
+ (*I)->Index = NextSectionIndex++;
+ }
+ LC.Sections.erase(It, LC.Sections.end());
+ }
+
+ auto IsDead = [&](const std::unique_ptr<SymbolEntry> &S) -> bool {
+ Optional<uint32_t> Section = S->section();
+ return (Section && !OldIndexToSection.count(*Section));
+ };
+
+ SmallPtrSet<const SymbolEntry *, 2> DeadSymbols;
+ for (const std::unique_ptr<SymbolEntry> &Sym : SymTable.Symbols)
+ if (IsDead(Sym))
+ DeadSymbols.insert(Sym.get());
+
+ for (const LoadCommand &LC : LoadCommands)
+ for (const std::unique_ptr<Section> &Sec : LC.Sections)
+ for (const RelocationInfo &R : Sec->Relocations)
+ if (R.Symbol && *R.Symbol && DeadSymbols.count(*R.Symbol))
+ return createStringError(std::errc::invalid_argument,
+ "symbol '%s' defined in section with index "
+ "'%u' cannot be removed because it is "
+ "referenced by a relocation in section '%s'",
+ (*R.Symbol)->Name.c_str(),
+ *((*R.Symbol)->section()),
+ Sec->CanonicalName.c_str());
+ SymTable.removeSymbols(IsDead);
+ for (std::unique_ptr<SymbolEntry> &S : SymTable.Symbols)
+ if (S->section())
+ S->n_sect = OldIndexToSection[S->n_sect]->Index;
+ return Error::success();
+}
+
uint64_t Object::nextAvailableSegmentAddress() const {
uint64_t HeaderSize =
is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
@@ -129,56 +129,56 @@ uint64_t Object::nextAvailableSegmentAddress() const {
}
}
return Addr;
-}
-
-template <typename SegmentType>
+}
+
+template <typename SegmentType>
static void
constructSegment(SegmentType &Seg, llvm::MachO::LoadCommandType CmdType,
StringRef SegName, uint64_t SegVMAddr, uint64_t SegVMSize) {
- assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name");
- memset(&Seg, 0, sizeof(SegmentType));
- Seg.cmd = CmdType;
- strncpy(Seg.segname, SegName.data(), SegName.size());
+ assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name");
+ memset(&Seg, 0, sizeof(SegmentType));
+ Seg.cmd = CmdType;
+ strncpy(Seg.segname, SegName.data(), SegName.size());
Seg.maxprot |=
(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
Seg.initprot |=
(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
Seg.vmaddr = SegVMAddr;
Seg.vmsize = SegVMSize;
-}
-
+}
+
LoadCommand &Object::addSegment(StringRef SegName, uint64_t SegVMSize) {
- LoadCommand LC;
+ LoadCommand LC;
const uint64_t SegVMAddr = nextAvailableSegmentAddress();
- if (is64Bit())
- constructSegment(LC.MachOLoadCommand.segment_command_64_data,
+ if (is64Bit())
+ constructSegment(LC.MachOLoadCommand.segment_command_64_data,
MachO::LC_SEGMENT_64, SegName, SegVMAddr, SegVMSize);
- else
- constructSegment(LC.MachOLoadCommand.segment_command_data,
+ else
+ constructSegment(LC.MachOLoadCommand.segment_command_data,
MachO::LC_SEGMENT, SegName, SegVMAddr, SegVMSize);
-
- LoadCommands.push_back(std::move(LC));
- return LoadCommands.back();
-}
-
-/// Extracts a segment name from a string which is possibly non-null-terminated.
-static StringRef extractSegmentName(const char *SegName) {
- return StringRef(SegName,
- strnlen(SegName, sizeof(MachO::segment_command::segname)));
-}
-
-Optional<StringRef> LoadCommand::getSegmentName() const {
- const MachO::macho_load_command &MLC = MachOLoadCommand;
- switch (MLC.load_command_data.cmd) {
- case MachO::LC_SEGMENT:
- return extractSegmentName(MLC.segment_command_data.segname);
- case MachO::LC_SEGMENT_64:
- return extractSegmentName(MLC.segment_command_64_data.segname);
- default:
- return None;
- }
-}
-
+
+ LoadCommands.push_back(std::move(LC));
+ return LoadCommands.back();
+}
+
+/// Extracts a segment name from a string which is possibly non-null-terminated.
+static StringRef extractSegmentName(const char *SegName) {
+ return StringRef(SegName,
+ strnlen(SegName, sizeof(MachO::segment_command::segname)));
+}
+
+Optional<StringRef> LoadCommand::getSegmentName() const {
+ const MachO::macho_load_command &MLC = MachOLoadCommand;
+ switch (MLC.load_command_data.cmd) {
+ case MachO::LC_SEGMENT:
+ return extractSegmentName(MLC.segment_command_data.segname);
+ case MachO::LC_SEGMENT_64:
+ return extractSegmentName(MLC.segment_command_64_data.segname);
+ default:
+ return None;
+ }
+}
+
Optional<uint64_t> LoadCommand::getSegmentVMAddr() const {
const MachO::macho_load_command &MLC = MachOLoadCommand;
switch (MLC.load_command_data.cmd) {
@@ -191,6 +191,6 @@ Optional<uint64_t> LoadCommand::getSegmentVMAddr() const {
}
}
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.h b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.h
index 0bb4b344b2..095da8c534 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/MachO/Object.h
@@ -1,360 +1,360 @@
-//===- Object.h - Mach-O object file model ----------------------*- 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_OBJCOPY_MACHO_OBJECT_H
-#define LLVM_OBJCOPY_MACHO_OBJECT_H
-
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/BinaryFormat/MachO.h"
-#include "llvm/MC/StringTableBuilder.h"
-#include "llvm/ObjectYAML/DWARFYAML.h"
-#include "llvm/Support/StringSaver.h"
-#include "llvm/Support/YAMLTraits.h"
-#include <cstdint>
-#include <string>
-#include <vector>
-
-namespace llvm {
-namespace objcopy {
-namespace macho {
-
-struct MachHeader {
- uint32_t Magic;
- uint32_t CPUType;
- uint32_t CPUSubType;
- uint32_t FileType;
- uint32_t NCmds;
- uint32_t SizeOfCmds;
- uint32_t Flags;
- uint32_t Reserved = 0;
-};
-
-struct RelocationInfo;
-struct Section {
- uint32_t Index;
- std::string Segname;
- std::string Sectname;
- // CanonicalName is a string formatted as “<Segname>,<Sectname>".
- std::string CanonicalName;
- uint64_t Addr = 0;
- uint64_t Size = 0;
+//===- Object.h - Mach-O object file model ----------------------*- 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_OBJCOPY_MACHO_OBJECT_H
+#define LLVM_OBJCOPY_MACHO_OBJECT_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+struct MachHeader {
+ uint32_t Magic;
+ uint32_t CPUType;
+ uint32_t CPUSubType;
+ uint32_t FileType;
+ uint32_t NCmds;
+ uint32_t SizeOfCmds;
+ uint32_t Flags;
+ uint32_t Reserved = 0;
+};
+
+struct RelocationInfo;
+struct Section {
+ uint32_t Index;
+ std::string Segname;
+ std::string Sectname;
+ // CanonicalName is a string formatted as “<Segname>,<Sectname>".
+ std::string CanonicalName;
+ uint64_t Addr = 0;
+ uint64_t Size = 0;
// Offset in the input file.
Optional<uint32_t> OriginalOffset;
- uint32_t Offset = 0;
- uint32_t Align = 0;
- uint32_t RelOff = 0;
- uint32_t NReloc = 0;
- uint32_t Flags = 0;
- uint32_t Reserved1 = 0;
- uint32_t Reserved2 = 0;
- uint32_t Reserved3 = 0;
- StringRef Content;
- std::vector<RelocationInfo> Relocations;
-
- Section(StringRef SegName, StringRef SectName)
- : Segname(std::string(SegName)), Sectname(std::string(SectName)),
- CanonicalName((Twine(SegName) + Twine(',') + SectName).str()) {}
-
- Section(StringRef SegName, StringRef SectName, StringRef Content)
- : Segname(std::string(SegName)), Sectname(std::string(SectName)),
- CanonicalName((Twine(SegName) + Twine(',') + SectName).str()),
- Content(Content) {}
-
- MachO::SectionType getType() const {
- return static_cast<MachO::SectionType>(Flags & MachO::SECTION_TYPE);
- }
-
- bool isVirtualSection() const {
- return (getType() == MachO::S_ZEROFILL ||
- getType() == MachO::S_GB_ZEROFILL ||
- getType() == MachO::S_THREAD_LOCAL_ZEROFILL);
- }
+ uint32_t Offset = 0;
+ uint32_t Align = 0;
+ uint32_t RelOff = 0;
+ uint32_t NReloc = 0;
+ uint32_t Flags = 0;
+ uint32_t Reserved1 = 0;
+ uint32_t Reserved2 = 0;
+ uint32_t Reserved3 = 0;
+ StringRef Content;
+ std::vector<RelocationInfo> Relocations;
+
+ Section(StringRef SegName, StringRef SectName)
+ : Segname(std::string(SegName)), Sectname(std::string(SectName)),
+ CanonicalName((Twine(SegName) + Twine(',') + SectName).str()) {}
+
+ Section(StringRef SegName, StringRef SectName, StringRef Content)
+ : Segname(std::string(SegName)), Sectname(std::string(SectName)),
+ CanonicalName((Twine(SegName) + Twine(',') + SectName).str()),
+ Content(Content) {}
+
+ MachO::SectionType getType() const {
+ return static_cast<MachO::SectionType>(Flags & MachO::SECTION_TYPE);
+ }
+
+ bool isVirtualSection() const {
+ return (getType() == MachO::S_ZEROFILL ||
+ getType() == MachO::S_GB_ZEROFILL ||
+ getType() == MachO::S_THREAD_LOCAL_ZEROFILL);
+ }
bool hasValidOffset() const {
return !(isVirtualSection() || (OriginalOffset && *OriginalOffset == 0));
}
-};
-
-struct LoadCommand {
- // The type MachO::macho_load_command is defined in llvm/BinaryFormat/MachO.h
- // and it is a union of all the structs corresponding to various load
- // commands.
- MachO::macho_load_command MachOLoadCommand;
-
- // The raw content of the payload of the load command (located right after the
- // corresponding struct). In some cases it is either empty or can be
- // copied-over without digging into its structure.
- std::vector<uint8_t> Payload;
-
- // Some load commands can contain (inside the payload) an array of sections,
- // though the contents of the sections are stored separately. The struct
- // Section describes only sections' metadata and where to find the
- // corresponding content inside the binary.
- std::vector<std::unique_ptr<Section>> Sections;
-
- // Returns the segment name if the load command is a segment command.
- Optional<StringRef> getSegmentName() const;
+};
+
+struct LoadCommand {
+ // The type MachO::macho_load_command is defined in llvm/BinaryFormat/MachO.h
+ // and it is a union of all the structs corresponding to various load
+ // commands.
+ MachO::macho_load_command MachOLoadCommand;
+
+ // The raw content of the payload of the load command (located right after the
+ // corresponding struct). In some cases it is either empty or can be
+ // copied-over without digging into its structure.
+ std::vector<uint8_t> Payload;
+
+ // Some load commands can contain (inside the payload) an array of sections,
+ // though the contents of the sections are stored separately. The struct
+ // Section describes only sections' metadata and where to find the
+ // corresponding content inside the binary.
+ std::vector<std::unique_ptr<Section>> Sections;
+
+ // Returns the segment name if the load command is a segment command.
+ Optional<StringRef> getSegmentName() const;
// Returns the segment vm address if the load command is a segment command.
Optional<uint64_t> getSegmentVMAddr() const;
-};
-
-// A symbol information. Fields which starts with "n_" are same as them in the
-// nlist.
-struct SymbolEntry {
- std::string Name;
- bool Referenced = false;
- uint32_t Index;
- uint8_t n_type;
- uint8_t n_sect;
- uint16_t n_desc;
- uint64_t n_value;
-
- bool isExternalSymbol() const { return n_type & MachO::N_EXT; }
-
- bool isLocalSymbol() const { return !isExternalSymbol(); }
-
- bool isUndefinedSymbol() const {
- return (n_type & MachO::N_TYPE) == MachO::N_UNDF;
- }
-
- bool isSwiftSymbol() const {
- return StringRef(Name).startswith("_$s") ||
- StringRef(Name).startswith("_$S");
- }
-
- Optional<uint32_t> section() const {
- return n_sect == MachO::NO_SECT ? None : Optional<uint32_t>(n_sect);
- }
-};
-
-/// The location of the symbol table inside the binary is described by LC_SYMTAB
-/// load command.
-struct SymbolTable {
- std::vector<std::unique_ptr<SymbolEntry>> Symbols;
-
- using iterator = pointee_iterator<
- std::vector<std::unique_ptr<SymbolEntry>>::const_iterator>;
-
- iterator begin() const { return iterator(Symbols.begin()); }
- iterator end() const { return iterator(Symbols.end()); }
-
- const SymbolEntry *getSymbolByIndex(uint32_t Index) const;
- SymbolEntry *getSymbolByIndex(uint32_t Index);
- void removeSymbols(
- function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove);
-};
-
-struct IndirectSymbolEntry {
- // The original value in an indirect symbol table. Higher bits encode extra
- // information (INDIRECT_SYMBOL_LOCAL and INDIRECT_SYMBOL_ABS).
- uint32_t OriginalIndex;
- /// The Symbol referenced by this entry. It's None if the index is
- /// INDIRECT_SYMBOL_LOCAL or INDIRECT_SYMBOL_ABS.
- Optional<SymbolEntry *> Symbol;
-
- IndirectSymbolEntry(uint32_t OriginalIndex, Optional<SymbolEntry *> Symbol)
- : OriginalIndex(OriginalIndex), Symbol(Symbol) {}
-};
-
-struct IndirectSymbolTable {
- std::vector<IndirectSymbolEntry> Symbols;
-};
-
-/// The location of the string table inside the binary is described by LC_SYMTAB
-/// load command.
-struct StringTable {
- std::vector<std::string> Strings;
-};
-
-struct RelocationInfo {
- // The referenced symbol entry. Set if !Scattered && Extern.
- Optional<const SymbolEntry *> Symbol;
- // The referenced section. Set if !Scattered && !Extern.
- Optional<const Section *> Sec;
- // True if Info is a scattered_relocation_info.
- bool Scattered;
- // True if the r_symbolnum points to a section number (i.e. r_extern=0).
- bool Extern;
- MachO::any_relocation_info Info;
-
- unsigned getPlainRelocationSymbolNum(bool IsLittleEndian) {
- if (IsLittleEndian)
- return Info.r_word1 & 0xffffff;
- return Info.r_word1 >> 8;
- }
-
- void setPlainRelocationSymbolNum(unsigned SymbolNum, bool IsLittleEndian) {
- assert(SymbolNum < (1 << 24) && "SymbolNum out of range");
- if (IsLittleEndian)
- Info.r_word1 = (Info.r_word1 & ~0x00ffffff) | SymbolNum;
- else
- Info.r_word1 = (Info.r_word1 & ~0xffffff00) | (SymbolNum << 8);
- }
-};
-
-/// The location of the rebase info inside the binary is described by
-/// LC_DYLD_INFO load command. Dyld rebases an image whenever dyld loads it at
-/// an address different from its preferred address. The rebase information is
-/// a stream of byte sized opcodes whose symbolic names start with
-/// REBASE_OPCODE_. Conceptually the rebase information is a table of tuples:
-/// <seg-index, seg-offset, type>
-/// The opcodes are a compressed way to encode the table by only
-/// encoding when a column changes. In addition simple patterns
-/// like "every n'th offset for m times" can be encoded in a few
-/// bytes.
-struct RebaseInfo {
- // At the moment we do not parse this info (and it is simply copied over),
- // but the proper support will be added later.
- ArrayRef<uint8_t> Opcodes;
-};
-
-/// The location of the bind info inside the binary is described by
-/// LC_DYLD_INFO load command. Dyld binds an image during the loading process,
-/// if the image requires any pointers to be initialized to symbols in other
-/// images. The bind information is a stream of byte sized opcodes whose
-/// symbolic names start with BIND_OPCODE_. Conceptually the bind information is
-/// a table of tuples: <seg-index, seg-offset, type, symbol-library-ordinal,
-/// symbol-name, addend> The opcodes are a compressed way to encode the table by
-/// only encoding when a column changes. In addition simple patterns like for
-/// runs of pointers initialized to the same value can be encoded in a few
-/// bytes.
-struct BindInfo {
- // At the moment we do not parse this info (and it is simply copied over),
- // but the proper support will be added later.
- ArrayRef<uint8_t> Opcodes;
-};
-
-/// The location of the weak bind info inside the binary is described by
-/// LC_DYLD_INFO load command. Some C++ programs require dyld to unique symbols
-/// so that all images in the process use the same copy of some code/data. This
-/// step is done after binding. The content of the weak_bind info is an opcode
-/// stream like the bind_info. But it is sorted alphabetically by symbol name.
-/// This enable dyld to walk all images with weak binding information in order
-/// and look for collisions. If there are no collisions, dyld does no updating.
-/// That means that some fixups are also encoded in the bind_info. For
-/// instance, all calls to "operator new" are first bound to libstdc++.dylib
-/// using the information in bind_info. Then if some image overrides operator
-/// new that is detected when the weak_bind information is processed and the
-/// call to operator new is then rebound.
-struct WeakBindInfo {
- // At the moment we do not parse this info (and it is simply copied over),
- // but the proper support will be added later.
- ArrayRef<uint8_t> Opcodes;
-};
-
-/// The location of the lazy bind info inside the binary is described by
-/// LC_DYLD_INFO load command. Some uses of external symbols do not need to be
-/// bound immediately. Instead they can be lazily bound on first use. The
-/// lazy_bind contains a stream of BIND opcodes to bind all lazy symbols. Normal
-/// use is that dyld ignores the lazy_bind section when loading an image.
-/// Instead the static linker arranged for the lazy pointer to initially point
-/// to a helper function which pushes the offset into the lazy_bind area for the
-/// symbol needing to be bound, then jumps to dyld which simply adds the offset
-/// to lazy_bind_off to get the information on what to bind.
-struct LazyBindInfo {
- ArrayRef<uint8_t> Opcodes;
-};
-
-/// The location of the export info inside the binary is described by
-/// LC_DYLD_INFO load command. The symbols exported by a dylib are encoded in a
-/// trie. This is a compact representation that factors out common prefixes. It
-/// also reduces LINKEDIT pages in RAM because it encodes all information (name,
-/// address, flags) in one small, contiguous range. The export area is a stream
-/// of nodes. The first node sequentially is the start node for the trie. Nodes
-/// for a symbol start with a uleb128 that is the length of the exported symbol
-/// information for the string so far. If there is no exported symbol, the node
-/// starts with a zero byte. If there is exported info, it follows the length.
-/// First is a uleb128 containing flags. Normally, it is followed by
-/// a uleb128 encoded offset which is location of the content named
-/// by the symbol from the mach_header for the image. If the flags
-/// is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is
-/// a uleb128 encoded library ordinal, then a zero terminated
-/// UTF8 string. If the string is zero length, then the symbol
-/// is re-export from the specified dylib with the same name.
-/// If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following
-/// the flags is two uleb128s: the stub offset and the resolver offset.
-/// The stub is used by non-lazy pointers. The resolver is used
-/// by lazy pointers and must be called to get the actual address to use.
-/// After the optional exported symbol information is a byte of
-/// how many edges (0-255) that this node has leaving it,
-/// followed by each edge.
-/// Each edge is a zero terminated UTF8 of the addition chars
-/// in the symbol, followed by a uleb128 offset for the node that
-/// edge points to.
-struct ExportInfo {
- ArrayRef<uint8_t> Trie;
-};
-
-struct LinkData {
- ArrayRef<uint8_t> Data;
-};
-
-struct Object {
- MachHeader Header;
- std::vector<LoadCommand> LoadCommands;
-
- SymbolTable SymTable;
- StringTable StrTable;
-
- RebaseInfo Rebases;
- BindInfo Binds;
- WeakBindInfo WeakBinds;
- LazyBindInfo LazyBinds;
- ExportInfo Exports;
- IndirectSymbolTable IndirectSymTable;
- LinkData DataInCode;
- LinkData FunctionStarts;
- LinkData CodeSignature;
-
- Optional<uint32_t> SwiftVersion;
-
- /// The index of LC_CODE_SIGNATURE load command if present.
- Optional<size_t> CodeSignatureCommandIndex;
- /// The index of LC_SYMTAB load command if present.
- Optional<size_t> SymTabCommandIndex;
- /// The index of LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command if present.
- Optional<size_t> DyLdInfoCommandIndex;
- /// The index LC_DYSYMTAB load comamnd if present.
- Optional<size_t> DySymTabCommandIndex;
- /// The index LC_DATA_IN_CODE load comamnd if present.
- Optional<size_t> DataInCodeCommandIndex;
- /// The index LC_FUNCTION_STARTS load comamnd if present.
- Optional<size_t> FunctionStartsCommandIndex;
-
- BumpPtrAllocator Alloc;
- StringSaver NewSectionsContents;
-
- Object() : NewSectionsContents(Alloc) {}
-
- Error
- removeSections(function_ref<bool(const std::unique_ptr<Section> &)> ToRemove);
-
- Error removeLoadCommands(function_ref<bool(const LoadCommand &)> ToRemove);
-
- void updateLoadCommandIndexes();
-
- /// Creates a new segment load command in the object and returns a reference
- /// to the newly created load command. The caller should verify that SegName
- /// is not too long (SegName.size() should be less than or equal to 16).
+};
+
+// A symbol information. Fields which starts with "n_" are same as them in the
+// nlist.
+struct SymbolEntry {
+ std::string Name;
+ bool Referenced = false;
+ uint32_t Index;
+ uint8_t n_type;
+ uint8_t n_sect;
+ uint16_t n_desc;
+ uint64_t n_value;
+
+ bool isExternalSymbol() const { return n_type & MachO::N_EXT; }
+
+ bool isLocalSymbol() const { return !isExternalSymbol(); }
+
+ bool isUndefinedSymbol() const {
+ return (n_type & MachO::N_TYPE) == MachO::N_UNDF;
+ }
+
+ bool isSwiftSymbol() const {
+ return StringRef(Name).startswith("_$s") ||
+ StringRef(Name).startswith("_$S");
+ }
+
+ Optional<uint32_t> section() const {
+ return n_sect == MachO::NO_SECT ? None : Optional<uint32_t>(n_sect);
+ }
+};
+
+/// The location of the symbol table inside the binary is described by LC_SYMTAB
+/// load command.
+struct SymbolTable {
+ std::vector<std::unique_ptr<SymbolEntry>> Symbols;
+
+ using iterator = pointee_iterator<
+ std::vector<std::unique_ptr<SymbolEntry>>::const_iterator>;
+
+ iterator begin() const { return iterator(Symbols.begin()); }
+ iterator end() const { return iterator(Symbols.end()); }
+
+ const SymbolEntry *getSymbolByIndex(uint32_t Index) const;
+ SymbolEntry *getSymbolByIndex(uint32_t Index);
+ void removeSymbols(
+ function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove);
+};
+
+struct IndirectSymbolEntry {
+ // The original value in an indirect symbol table. Higher bits encode extra
+ // information (INDIRECT_SYMBOL_LOCAL and INDIRECT_SYMBOL_ABS).
+ uint32_t OriginalIndex;
+ /// The Symbol referenced by this entry. It's None if the index is
+ /// INDIRECT_SYMBOL_LOCAL or INDIRECT_SYMBOL_ABS.
+ Optional<SymbolEntry *> Symbol;
+
+ IndirectSymbolEntry(uint32_t OriginalIndex, Optional<SymbolEntry *> Symbol)
+ : OriginalIndex(OriginalIndex), Symbol(Symbol) {}
+};
+
+struct IndirectSymbolTable {
+ std::vector<IndirectSymbolEntry> Symbols;
+};
+
+/// The location of the string table inside the binary is described by LC_SYMTAB
+/// load command.
+struct StringTable {
+ std::vector<std::string> Strings;
+};
+
+struct RelocationInfo {
+ // The referenced symbol entry. Set if !Scattered && Extern.
+ Optional<const SymbolEntry *> Symbol;
+ // The referenced section. Set if !Scattered && !Extern.
+ Optional<const Section *> Sec;
+ // True if Info is a scattered_relocation_info.
+ bool Scattered;
+ // True if the r_symbolnum points to a section number (i.e. r_extern=0).
+ bool Extern;
+ MachO::any_relocation_info Info;
+
+ unsigned getPlainRelocationSymbolNum(bool IsLittleEndian) {
+ if (IsLittleEndian)
+ return Info.r_word1 & 0xffffff;
+ return Info.r_word1 >> 8;
+ }
+
+ void setPlainRelocationSymbolNum(unsigned SymbolNum, bool IsLittleEndian) {
+ assert(SymbolNum < (1 << 24) && "SymbolNum out of range");
+ if (IsLittleEndian)
+ Info.r_word1 = (Info.r_word1 & ~0x00ffffff) | SymbolNum;
+ else
+ Info.r_word1 = (Info.r_word1 & ~0xffffff00) | (SymbolNum << 8);
+ }
+};
+
+/// The location of the rebase info inside the binary is described by
+/// LC_DYLD_INFO load command. Dyld rebases an image whenever dyld loads it at
+/// an address different from its preferred address. The rebase information is
+/// a stream of byte sized opcodes whose symbolic names start with
+/// REBASE_OPCODE_. Conceptually the rebase information is a table of tuples:
+/// <seg-index, seg-offset, type>
+/// The opcodes are a compressed way to encode the table by only
+/// encoding when a column changes. In addition simple patterns
+/// like "every n'th offset for m times" can be encoded in a few
+/// bytes.
+struct RebaseInfo {
+ // At the moment we do not parse this info (and it is simply copied over),
+ // but the proper support will be added later.
+ ArrayRef<uint8_t> Opcodes;
+};
+
+/// The location of the bind info inside the binary is described by
+/// LC_DYLD_INFO load command. Dyld binds an image during the loading process,
+/// if the image requires any pointers to be initialized to symbols in other
+/// images. The bind information is a stream of byte sized opcodes whose
+/// symbolic names start with BIND_OPCODE_. Conceptually the bind information is
+/// a table of tuples: <seg-index, seg-offset, type, symbol-library-ordinal,
+/// symbol-name, addend> The opcodes are a compressed way to encode the table by
+/// only encoding when a column changes. In addition simple patterns like for
+/// runs of pointers initialized to the same value can be encoded in a few
+/// bytes.
+struct BindInfo {
+ // At the moment we do not parse this info (and it is simply copied over),
+ // but the proper support will be added later.
+ ArrayRef<uint8_t> Opcodes;
+};
+
+/// The location of the weak bind info inside the binary is described by
+/// LC_DYLD_INFO load command. Some C++ programs require dyld to unique symbols
+/// so that all images in the process use the same copy of some code/data. This
+/// step is done after binding. The content of the weak_bind info is an opcode
+/// stream like the bind_info. But it is sorted alphabetically by symbol name.
+/// This enable dyld to walk all images with weak binding information in order
+/// and look for collisions. If there are no collisions, dyld does no updating.
+/// That means that some fixups are also encoded in the bind_info. For
+/// instance, all calls to "operator new" are first bound to libstdc++.dylib
+/// using the information in bind_info. Then if some image overrides operator
+/// new that is detected when the weak_bind information is processed and the
+/// call to operator new is then rebound.
+struct WeakBindInfo {
+ // At the moment we do not parse this info (and it is simply copied over),
+ // but the proper support will be added later.
+ ArrayRef<uint8_t> Opcodes;
+};
+
+/// The location of the lazy bind info inside the binary is described by
+/// LC_DYLD_INFO load command. Some uses of external symbols do not need to be
+/// bound immediately. Instead they can be lazily bound on first use. The
+/// lazy_bind contains a stream of BIND opcodes to bind all lazy symbols. Normal
+/// use is that dyld ignores the lazy_bind section when loading an image.
+/// Instead the static linker arranged for the lazy pointer to initially point
+/// to a helper function which pushes the offset into the lazy_bind area for the
+/// symbol needing to be bound, then jumps to dyld which simply adds the offset
+/// to lazy_bind_off to get the information on what to bind.
+struct LazyBindInfo {
+ ArrayRef<uint8_t> Opcodes;
+};
+
+/// The location of the export info inside the binary is described by
+/// LC_DYLD_INFO load command. The symbols exported by a dylib are encoded in a
+/// trie. This is a compact representation that factors out common prefixes. It
+/// also reduces LINKEDIT pages in RAM because it encodes all information (name,
+/// address, flags) in one small, contiguous range. The export area is a stream
+/// of nodes. The first node sequentially is the start node for the trie. Nodes
+/// for a symbol start with a uleb128 that is the length of the exported symbol
+/// information for the string so far. If there is no exported symbol, the node
+/// starts with a zero byte. If there is exported info, it follows the length.
+/// First is a uleb128 containing flags. Normally, it is followed by
+/// a uleb128 encoded offset which is location of the content named
+/// by the symbol from the mach_header for the image. If the flags
+/// is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is
+/// a uleb128 encoded library ordinal, then a zero terminated
+/// UTF8 string. If the string is zero length, then the symbol
+/// is re-export from the specified dylib with the same name.
+/// If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following
+/// the flags is two uleb128s: the stub offset and the resolver offset.
+/// The stub is used by non-lazy pointers. The resolver is used
+/// by lazy pointers and must be called to get the actual address to use.
+/// After the optional exported symbol information is a byte of
+/// how many edges (0-255) that this node has leaving it,
+/// followed by each edge.
+/// Each edge is a zero terminated UTF8 of the addition chars
+/// in the symbol, followed by a uleb128 offset for the node that
+/// edge points to.
+struct ExportInfo {
+ ArrayRef<uint8_t> Trie;
+};
+
+struct LinkData {
+ ArrayRef<uint8_t> Data;
+};
+
+struct Object {
+ MachHeader Header;
+ std::vector<LoadCommand> LoadCommands;
+
+ SymbolTable SymTable;
+ StringTable StrTable;
+
+ RebaseInfo Rebases;
+ BindInfo Binds;
+ WeakBindInfo WeakBinds;
+ LazyBindInfo LazyBinds;
+ ExportInfo Exports;
+ IndirectSymbolTable IndirectSymTable;
+ LinkData DataInCode;
+ LinkData FunctionStarts;
+ LinkData CodeSignature;
+
+ Optional<uint32_t> SwiftVersion;
+
+ /// The index of LC_CODE_SIGNATURE load command if present.
+ Optional<size_t> CodeSignatureCommandIndex;
+ /// The index of LC_SYMTAB load command if present.
+ Optional<size_t> SymTabCommandIndex;
+ /// The index of LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command if present.
+ Optional<size_t> DyLdInfoCommandIndex;
+ /// The index LC_DYSYMTAB load comamnd if present.
+ Optional<size_t> DySymTabCommandIndex;
+ /// The index LC_DATA_IN_CODE load comamnd if present.
+ Optional<size_t> DataInCodeCommandIndex;
+ /// The index LC_FUNCTION_STARTS load comamnd if present.
+ Optional<size_t> FunctionStartsCommandIndex;
+
+ BumpPtrAllocator Alloc;
+ StringSaver NewSectionsContents;
+
+ Object() : NewSectionsContents(Alloc) {}
+
+ Error
+ removeSections(function_ref<bool(const std::unique_ptr<Section> &)> ToRemove);
+
+ Error removeLoadCommands(function_ref<bool(const LoadCommand &)> ToRemove);
+
+ void updateLoadCommandIndexes();
+
+ /// Creates a new segment load command in the object and returns a reference
+ /// to the newly created load command. The caller should verify that SegName
+ /// is not too long (SegName.size() should be less than or equal to 16).
LoadCommand &addSegment(StringRef SegName, uint64_t SegVMSize);
-
- bool is64Bit() const {
- return Header.Magic == MachO::MH_MAGIC_64 ||
- Header.Magic == MachO::MH_CIGAM_64;
- }
+
+ bool is64Bit() const {
+ return Header.Magic == MachO::MH_MAGIC_64 ||
+ Header.Magic == MachO::MH_CIGAM_64;
+ }
uint64_t nextAvailableSegmentAddress() const;
-};
-
-} // end namespace macho
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_OBJCOPY_MACHO_OBJECT_H
+};
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_OBJCOPY_MACHO_OBJECT_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ObjcopyOpts.td b/contrib/libs/llvm12/tools/llvm-objcopy/ObjcopyOpts.td
index 9e6b6f0005..9cd69596b3 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/ObjcopyOpts.td
@@ -1,229 +1,229 @@
-include "CommonOpts.td"
-
-defm binary_architecture
- : Eq<"binary-architecture", "Ignored for compatibility">;
-def B : JoinedOrSeparate<["-"], "B">,
- Alias<binary_architecture>,
- HelpText<"Alias for --binary-architecture">;
-
-defm target : Eq<"target", "Format of the input and output file">,
- Values<"binary">;
-def F : JoinedOrSeparate<["-"], "F">,
- Alias<target>,
- HelpText<"Alias for --target">;
-
-defm input_target : Eq<"input-target", "Format of the input file">,
- Values<"binary">;
-def I : JoinedOrSeparate<["-"], "I">,
- Alias<input_target>,
- HelpText<"Alias for --input-target">;
-
-defm output_target : Eq<"output-target", "Format of the output file">,
- Values<"binary">;
-def O : JoinedOrSeparate<["-"], "O">,
- Alias<output_target>,
- HelpText<"Alias for --output-target">;
-
-defm new_symbol_visibility : Eq<"new-symbol-visibility", "Visibility of "
- "symbols generated for binary input or added"
- " with --add-symbol unless otherwise"
- " specified. The default value is 'default'.">;
-
-def compress_debug_sections : Flag<["--"], "compress-debug-sections">;
-def compress_debug_sections_eq
- : Joined<["--"], "compress-debug-sections=">,
- MetaVarName<"[ zlib | zlib-gnu ]">,
- HelpText<"Compress DWARF debug sections using specified style. Supported "
- "styles: 'zlib-gnu' and 'zlib'">;
-def decompress_debug_sections : Flag<["--"], "decompress-debug-sections">,
- HelpText<"Decompress DWARF debug sections.">;
-defm split_dwo
- : Eq<"split-dwo", "Equivalent to extract-dwo on the input file to "
- "<dwo-file>, then strip-dwo on the input file">,
- MetaVarName<"dwo-file">;
-
-defm add_gnu_debuglink
- : Eq<"add-gnu-debuglink", "Add a .gnu_debuglink for <debug-file>">,
- MetaVarName<"debug-file">;
-
-defm rename_section
- : Eq<"rename-section",
- "Renames a section from old to new, optionally with specified flags. "
- "Flags supported for GNU compatibility: alloc, load, noload, "
- "readonly, debug, code, data, rom, share, contents, merge, strings.">,
- MetaVarName<"old=new[,flag1,...]">;
-defm redefine_symbol
- : Eq<"redefine-sym", "Change the name of a symbol old to new">,
- MetaVarName<"old=new">;
-defm redefine_symbols
- : Eq<"redefine-syms",
- "Reads a list of symbol pairs from <filename> and runs as if "
- "--redefine-sym=<old>=<new> is set for each one. <filename> "
- "contains two symbols per line separated with whitespace and may "
- "contain comments beginning with '#'. Leading and trailing "
- "whitespace is stripped from each line. May be repeated to read "
- "symbols from many files.">,
- MetaVarName<"filename">;
-
-defm only_section : Eq<"only-section", "Remove all but <section>">,
- MetaVarName<"section">;
-def j : JoinedOrSeparate<["-"], "j">,
- Alias<only_section>,
- HelpText<"Alias for --only-section">;
-defm add_section
- : Eq<"add-section",
- "Make a section named <section> with the contents of <file>.">,
- MetaVarName<"section=file">;
-
-defm set_section_alignment
- : Eq<"set-section-alignment", "Set alignment for a given section.">,
- MetaVarName<"section=align">;
-
-defm set_section_flags
- : Eq<"set-section-flags",
- "Set section flags for a given section. Flags supported for GNU "
- "compatibility: alloc, load, noload, readonly, debug, code, data, "
- "rom, share, contents, merge, strings.">,
- MetaVarName<"section=flag1[,flag2,...]">;
-
-def S : Flag<["-"], "S">,
- Alias<strip_all>,
- HelpText<"Alias for --strip-all">;
-def strip_dwo : Flag<["--"], "strip-dwo">,
- HelpText<"Remove all DWARF .dwo sections from file">;
-def strip_non_alloc
- : Flag<["--"], "strip-non-alloc">,
- HelpText<"Remove all non-allocated sections outside segments">;
-defm strip_unneeded_symbol
- : Eq<"strip-unneeded-symbol",
- "Remove symbol <symbol> if it is not needed by relocations">,
- MetaVarName<"symbol">;
-defm strip_unneeded_symbols
- : Eq<"strip-unneeded-symbols",
- "Reads a list of symbols from <filename> and removes them "
- "if they are not needed by relocations">,
- MetaVarName<"filename">;
-
-def extract_dwo
- : Flag<["--"], "extract-dwo">,
- HelpText<
- "Remove all sections that are not DWARF .dwo sections from file">;
-
-defm extract_partition
- : Eq<"extract-partition", "Extract named partition from input file">,
- MetaVarName<"name">;
-def extract_main_partition
- : Flag<["--"], "extract-main-partition">,
- HelpText<"Extract main partition from the input file">;
-
-def localize_hidden
- : Flag<["--"], "localize-hidden">,
- HelpText<
- "Mark all symbols that have hidden or internal visibility as local">;
-defm localize_symbol : Eq<"localize-symbol", "Mark <symbol> as local">,
- MetaVarName<"symbol">;
-defm localize_symbols
- : Eq<"localize-symbols",
- "Reads a list of symbols from <filename> and marks them local.">,
- MetaVarName<"filename">;
-
-def L : JoinedOrSeparate<["-"], "L">,
- Alias<localize_symbol>,
- HelpText<"Alias for --localize-symbol">;
-
-defm globalize_symbol : Eq<"globalize-symbol", "Mark <symbol> as global">,
- MetaVarName<"symbol">;
-
-defm globalize_symbols
- : Eq<"globalize-symbols",
- "Reads a list of symbols from <filename> and marks them global.">,
- MetaVarName<"filename">;
-
-defm keep_global_symbol
- : Eq<"keep-global-symbol",
- "Convert all symbols except <symbol> to local. May be repeated to "
- "convert all except a set of symbols to local.">,
- MetaVarName<"symbol">;
-def G : JoinedOrSeparate<["-"], "G">,
- Alias<keep_global_symbol>,
- HelpText<"Alias for --keep-global-symbol">;
-
-defm keep_global_symbols
- : Eq<"keep-global-symbols",
- "Reads a list of symbols from <filename> and runs as if "
- "--keep-global-symbol=<symbol> is set for each one. <filename> "
- "contains one symbol per line and may contain comments beginning with "
- "'#'. Leading and trailing whitespace is stripped from each line. May "
- "be repeated to read symbols from many files.">,
- MetaVarName<"filename">;
-
-defm weaken_symbol : Eq<"weaken-symbol", "Mark <symbol> as weak">,
- MetaVarName<"symbol">;
-defm weaken_symbols
- : Eq<"weaken-symbols",
- "Reads a list of symbols from <filename> and marks them weak.">,
- MetaVarName<"filename">;
-
-def W : JoinedOrSeparate<["-"], "W">,
- Alias<weaken_symbol>,
- HelpText<"Alias for --weaken-symbol">;
-def weaken : Flag<["--"], "weaken">,
- HelpText<"Mark all global symbols as weak">;
-
-defm strip_symbols
- : Eq<"strip-symbols",
- "Reads a list of symbols from <filename> and removes them.">,
- MetaVarName<"filename">;
-
-defm keep_symbols
- : Eq<"keep-symbols",
- "Reads a list of symbols from <filename> and runs as if "
- "--keep-symbol=<symbol> is set for each one. <filename> "
- "contains one symbol per line and may contain comments beginning with "
- "'#'. Leading and trailing whitespace is stripped from each line. May "
- "be repeated to read symbols from many files.">,
- MetaVarName<"filename">;
-
-defm dump_section
- : Eq<"dump-section",
- "Dump contents of section named <section> into file <file>">,
- MetaVarName<"section=file">;
-defm prefix_symbols
- : Eq<"prefix-symbols", "Add <prefix> to the start of every symbol name">,
- MetaVarName<"prefix">;
-
-defm prefix_alloc_sections
- : Eq<"prefix-alloc-sections", "Add <prefix> to the start of every allocated section name">,
- MetaVarName<"prefix">;
-
-defm build_id_link_dir
- : Eq<"build-id-link-dir", "Set directory for --build-id-link-input and "
- "--build-id-link-output to <dir>">,
- MetaVarName<"dir">;
-defm build_id_link_input
- : Eq<"build-id-link-input", "Hard-link the input to <dir>/xx/xxx<suffix> "
- "name derived from hex build ID">,
- MetaVarName<"suffix">;
-defm build_id_link_output
- : Eq<"build-id-link-output", "Hard-link the output to <dir>/xx/xxx<suffix> "
- "name derived from hex build ID">,
- MetaVarName<"suffix">;
-
-defm set_start : Eq<"set-start", "Set the start address to <addr>. Overrides "
- "any previous --change-start or --adjust-start values.">,
- MetaVarName<"addr">;
-defm change_start : Eq<"change-start", "Add <incr> to the start address. Can be "
- "specified multiple times, all values will be applied "
- "cumulatively.">,
- MetaVarName<"incr">;
-def adjust_start : JoinedOrSeparate<["--"], "adjust-start">,
- Alias<change_start>,
- HelpText<"Alias for --change-start">;
-
-defm add_symbol
- : Eq<"add-symbol", "Add new symbol <name> to .symtab. Accepted flags: "
- "global, local, weak, default, hidden, protected, file, section, object, "
- "function, indirect-function. Accepted but ignored for "
- "compatibility: debug, constructor, warning, indirect, synthetic, "
- "unique-object, before.">,
- MetaVarName<"name=[section:]value[,flags]">;
+include "CommonOpts.td"
+
+defm binary_architecture
+ : Eq<"binary-architecture", "Ignored for compatibility">;
+def B : JoinedOrSeparate<["-"], "B">,
+ Alias<binary_architecture>,
+ HelpText<"Alias for --binary-architecture">;
+
+defm target : Eq<"target", "Format of the input and output file">,
+ Values<"binary">;
+def F : JoinedOrSeparate<["-"], "F">,
+ Alias<target>,
+ HelpText<"Alias for --target">;
+
+defm input_target : Eq<"input-target", "Format of the input file">,
+ Values<"binary">;
+def I : JoinedOrSeparate<["-"], "I">,
+ Alias<input_target>,
+ HelpText<"Alias for --input-target">;
+
+defm output_target : Eq<"output-target", "Format of the output file">,
+ Values<"binary">;
+def O : JoinedOrSeparate<["-"], "O">,
+ Alias<output_target>,
+ HelpText<"Alias for --output-target">;
+
+defm new_symbol_visibility : Eq<"new-symbol-visibility", "Visibility of "
+ "symbols generated for binary input or added"
+ " with --add-symbol unless otherwise"
+ " specified. The default value is 'default'.">;
+
+def compress_debug_sections : Flag<["--"], "compress-debug-sections">;
+def compress_debug_sections_eq
+ : Joined<["--"], "compress-debug-sections=">,
+ MetaVarName<"[ zlib | zlib-gnu ]">,
+ HelpText<"Compress DWARF debug sections using specified style. Supported "
+ "styles: 'zlib-gnu' and 'zlib'">;
+def decompress_debug_sections : Flag<["--"], "decompress-debug-sections">,
+ HelpText<"Decompress DWARF debug sections.">;
+defm split_dwo
+ : Eq<"split-dwo", "Equivalent to extract-dwo on the input file to "
+ "<dwo-file>, then strip-dwo on the input file">,
+ MetaVarName<"dwo-file">;
+
+defm add_gnu_debuglink
+ : Eq<"add-gnu-debuglink", "Add a .gnu_debuglink for <debug-file>">,
+ MetaVarName<"debug-file">;
+
+defm rename_section
+ : Eq<"rename-section",
+ "Renames a section from old to new, optionally with specified flags. "
+ "Flags supported for GNU compatibility: alloc, load, noload, "
+ "readonly, debug, code, data, rom, share, contents, merge, strings.">,
+ MetaVarName<"old=new[,flag1,...]">;
+defm redefine_symbol
+ : Eq<"redefine-sym", "Change the name of a symbol old to new">,
+ MetaVarName<"old=new">;
+defm redefine_symbols
+ : Eq<"redefine-syms",
+ "Reads a list of symbol pairs from <filename> and runs as if "
+ "--redefine-sym=<old>=<new> is set for each one. <filename> "
+ "contains two symbols per line separated with whitespace and may "
+ "contain comments beginning with '#'. Leading and trailing "
+ "whitespace is stripped from each line. May be repeated to read "
+ "symbols from many files.">,
+ MetaVarName<"filename">;
+
+defm only_section : Eq<"only-section", "Remove all but <section>">,
+ MetaVarName<"section">;
+def j : JoinedOrSeparate<["-"], "j">,
+ Alias<only_section>,
+ HelpText<"Alias for --only-section">;
+defm add_section
+ : Eq<"add-section",
+ "Make a section named <section> with the contents of <file>.">,
+ MetaVarName<"section=file">;
+
+defm set_section_alignment
+ : Eq<"set-section-alignment", "Set alignment for a given section.">,
+ MetaVarName<"section=align">;
+
+defm set_section_flags
+ : Eq<"set-section-flags",
+ "Set section flags for a given section. Flags supported for GNU "
+ "compatibility: alloc, load, noload, readonly, debug, code, data, "
+ "rom, share, contents, merge, strings.">,
+ MetaVarName<"section=flag1[,flag2,...]">;
+
+def S : Flag<["-"], "S">,
+ Alias<strip_all>,
+ HelpText<"Alias for --strip-all">;
+def strip_dwo : Flag<["--"], "strip-dwo">,
+ HelpText<"Remove all DWARF .dwo sections from file">;
+def strip_non_alloc
+ : Flag<["--"], "strip-non-alloc">,
+ HelpText<"Remove all non-allocated sections outside segments">;
+defm strip_unneeded_symbol
+ : Eq<"strip-unneeded-symbol",
+ "Remove symbol <symbol> if it is not needed by relocations">,
+ MetaVarName<"symbol">;
+defm strip_unneeded_symbols
+ : Eq<"strip-unneeded-symbols",
+ "Reads a list of symbols from <filename> and removes them "
+ "if they are not needed by relocations">,
+ MetaVarName<"filename">;
+
+def extract_dwo
+ : Flag<["--"], "extract-dwo">,
+ HelpText<
+ "Remove all sections that are not DWARF .dwo sections from file">;
+
+defm extract_partition
+ : Eq<"extract-partition", "Extract named partition from input file">,
+ MetaVarName<"name">;
+def extract_main_partition
+ : Flag<["--"], "extract-main-partition">,
+ HelpText<"Extract main partition from the input file">;
+
+def localize_hidden
+ : Flag<["--"], "localize-hidden">,
+ HelpText<
+ "Mark all symbols that have hidden or internal visibility as local">;
+defm localize_symbol : Eq<"localize-symbol", "Mark <symbol> as local">,
+ MetaVarName<"symbol">;
+defm localize_symbols
+ : Eq<"localize-symbols",
+ "Reads a list of symbols from <filename> and marks them local.">,
+ MetaVarName<"filename">;
+
+def L : JoinedOrSeparate<["-"], "L">,
+ Alias<localize_symbol>,
+ HelpText<"Alias for --localize-symbol">;
+
+defm globalize_symbol : Eq<"globalize-symbol", "Mark <symbol> as global">,
+ MetaVarName<"symbol">;
+
+defm globalize_symbols
+ : Eq<"globalize-symbols",
+ "Reads a list of symbols from <filename> and marks them global.">,
+ MetaVarName<"filename">;
+
+defm keep_global_symbol
+ : Eq<"keep-global-symbol",
+ "Convert all symbols except <symbol> to local. May be repeated to "
+ "convert all except a set of symbols to local.">,
+ MetaVarName<"symbol">;
+def G : JoinedOrSeparate<["-"], "G">,
+ Alias<keep_global_symbol>,
+ HelpText<"Alias for --keep-global-symbol">;
+
+defm keep_global_symbols
+ : Eq<"keep-global-symbols",
+ "Reads a list of symbols from <filename> and runs as if "
+ "--keep-global-symbol=<symbol> is set for each one. <filename> "
+ "contains one symbol per line and may contain comments beginning with "
+ "'#'. Leading and trailing whitespace is stripped from each line. May "
+ "be repeated to read symbols from many files.">,
+ MetaVarName<"filename">;
+
+defm weaken_symbol : Eq<"weaken-symbol", "Mark <symbol> as weak">,
+ MetaVarName<"symbol">;
+defm weaken_symbols
+ : Eq<"weaken-symbols",
+ "Reads a list of symbols from <filename> and marks them weak.">,
+ MetaVarName<"filename">;
+
+def W : JoinedOrSeparate<["-"], "W">,
+ Alias<weaken_symbol>,
+ HelpText<"Alias for --weaken-symbol">;
+def weaken : Flag<["--"], "weaken">,
+ HelpText<"Mark all global symbols as weak">;
+
+defm strip_symbols
+ : Eq<"strip-symbols",
+ "Reads a list of symbols from <filename> and removes them.">,
+ MetaVarName<"filename">;
+
+defm keep_symbols
+ : Eq<"keep-symbols",
+ "Reads a list of symbols from <filename> and runs as if "
+ "--keep-symbol=<symbol> is set for each one. <filename> "
+ "contains one symbol per line and may contain comments beginning with "
+ "'#'. Leading and trailing whitespace is stripped from each line. May "
+ "be repeated to read symbols from many files.">,
+ MetaVarName<"filename">;
+
+defm dump_section
+ : Eq<"dump-section",
+ "Dump contents of section named <section> into file <file>">,
+ MetaVarName<"section=file">;
+defm prefix_symbols
+ : Eq<"prefix-symbols", "Add <prefix> to the start of every symbol name">,
+ MetaVarName<"prefix">;
+
+defm prefix_alloc_sections
+ : Eq<"prefix-alloc-sections", "Add <prefix> to the start of every allocated section name">,
+ MetaVarName<"prefix">;
+
+defm build_id_link_dir
+ : Eq<"build-id-link-dir", "Set directory for --build-id-link-input and "
+ "--build-id-link-output to <dir>">,
+ MetaVarName<"dir">;
+defm build_id_link_input
+ : Eq<"build-id-link-input", "Hard-link the input to <dir>/xx/xxx<suffix> "
+ "name derived from hex build ID">,
+ MetaVarName<"suffix">;
+defm build_id_link_output
+ : Eq<"build-id-link-output", "Hard-link the output to <dir>/xx/xxx<suffix> "
+ "name derived from hex build ID">,
+ MetaVarName<"suffix">;
+
+defm set_start : Eq<"set-start", "Set the start address to <addr>. Overrides "
+ "any previous --change-start or --adjust-start values.">,
+ MetaVarName<"addr">;
+defm change_start : Eq<"change-start", "Add <incr> to the start address. Can be "
+ "specified multiple times, all values will be applied "
+ "cumulatively.">,
+ MetaVarName<"incr">;
+def adjust_start : JoinedOrSeparate<["--"], "adjust-start">,
+ Alias<change_start>,
+ HelpText<"Alias for --change-start">;
+
+defm add_symbol
+ : Eq<"add-symbol", "Add new symbol <name> to .symtab. Accepted flags: "
+ "global, local, weak, default, hidden, protected, file, section, object, "
+ "function, indirect-function. Accepted but ignored for "
+ "compatibility: debug, constructor, warning, indirect, synthetic, "
+ "unique-object, before.">,
+ MetaVarName<"name=[section:]value[,flags]">;
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/StripOpts.td b/contrib/libs/llvm12/tools/llvm-objcopy/StripOpts.td
index 001da23528..b644d07d18 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/StripOpts.td
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/StripOpts.td
@@ -1,20 +1,20 @@
-include "CommonOpts.td"
-
-def output : JoinedOrSeparate<["-"], "o">, HelpText<"Write output to <file>">,
- MetaVarName<"<file>">;
-
-def s : Flag<["-"], "s">,
- Alias<strip_all>,
- HelpText<"Alias for --strip-all">;
-def no_strip_all : Flag<["--"], "no-strip-all">,
- HelpText<"Disable --strip-all">;
-
-def d : Flag<["-"], "d">,
- Alias<strip_debug>,
- HelpText<"Alias for --strip-debug">;
-def S : Flag<["-"], "S">,
- Alias<strip_debug>,
- HelpText<"Alias for --strip-debug">;
-
-def strip_swift_symbols : Flag<["-"], "T">,
- HelpText<"Remove Swift symbols">;
+include "CommonOpts.td"
+
+def output : JoinedOrSeparate<["-"], "o">, HelpText<"Write output to <file>">,
+ MetaVarName<"<file>">;
+
+def s : Flag<["-"], "s">,
+ Alias<strip_all>,
+ HelpText<"Alias for --strip-all">;
+def no_strip_all : Flag<["--"], "no-strip-all">,
+ HelpText<"Disable --strip-all">;
+
+def d : Flag<["-"], "d">,
+ Alias<strip_debug>,
+ HelpText<"Alias for --strip-debug">;
+def S : Flag<["-"], "S">,
+ Alias<strip_debug>,
+ HelpText<"Alias for --strip-debug">;
+
+def strip_swift_symbols : Flag<["-"], "T">,
+ HelpText<"Remove Swift symbols">;
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.cpp
index 7fd2acd11e..3a872ae1a3 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -1,68 +1,68 @@
-//===- llvm-objcopy.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 "Buffer.h"
-#include "COFF/COFFObjcopy.h"
-#include "CopyConfig.h"
-#include "ELF/ELFObjcopy.h"
-#include "MachO/MachOObjcopy.h"
-#include "wasm/WasmObjcopy.h"
-
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/ArchiveWriter.h"
-#include "llvm/Object/Binary.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/Object/ELFTypes.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Object/MachO.h"
+//===- llvm-objcopy.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 "Buffer.h"
+#include "COFF/COFFObjcopy.h"
+#include "CopyConfig.h"
+#include "ELF/ELFObjcopy.h"
+#include "MachO/MachOObjcopy.h"
+#include "wasm/WasmObjcopy.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
-#include "llvm/Object/Wasm.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/Memory.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/StringSaver.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cassert>
-#include <cstdlib>
-#include <memory>
-#include <string>
-#include <system_error>
-#include <utility>
-
-namespace llvm {
-namespace objcopy {
-
-// The name this program was invoked as.
-StringRef ToolName;
-
+#include "llvm/Object/Wasm.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
+namespace llvm {
+namespace objcopy {
+
+// The name this program was invoked as.
+StringRef ToolName;
+
ErrorSuccess reportWarning(Error E) {
- assert(E);
+ assert(E);
WithColor::warning(errs(), ToolName) << toString(std::move(E)) << '\n';
return Error::success();
-}
-
+}
+
static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) {
StringRef Stem = sys::path::stem(ToolName);
auto Is = [=](StringRef Tool) {
@@ -76,7 +76,7 @@ static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) {
return I != StringRef::npos &&
(I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()]));
};
-
+
if (Is("bitcode-strip") || Is("bitcode_strip"))
return parseBitcodeStripOptions(Args);
else if (Is("strip"))
@@ -85,135 +85,135 @@ static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) {
return parseInstallNameToolOptions(Args);
else
return parseObjcopyOptions(Args, reportWarning);
-}
-
-} // end namespace objcopy
-} // end namespace llvm
-
-using namespace llvm;
-using namespace llvm::object;
-using namespace llvm::objcopy;
-
-// For regular archives this function simply calls llvm::writeArchive,
-// For thin archives it writes the archive file itself as well as its members.
-static Error deepWriteArchive(StringRef ArcName,
- ArrayRef<NewArchiveMember> NewMembers,
- bool WriteSymtab, object::Archive::Kind Kind,
- bool Deterministic, bool Thin) {
- if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind,
- Deterministic, Thin))
- return createFileError(ArcName, std::move(E));
-
- if (!Thin)
- return Error::success();
-
- for (const NewArchiveMember &Member : NewMembers) {
- // Internally, FileBuffer will use the buffer created by
- // FileOutputBuffer::create, for regular files (that is the case for
- // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
- // OnDiskBuffer uses a temporary file and then renames it. So in reality
- // there is no inefficiency / duplicated in-memory buffers in this case. For
- // now in-memory buffers can not be completely avoided since
- // NewArchiveMember still requires them even though writeArchive does not
- // write them on disk.
- FileBuffer FB(Member.MemberName);
- if (Error E = FB.allocate(Member.Buf->getBufferSize()))
- return E;
- std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
- FB.getBufferStart());
- if (Error E = FB.commit())
- return E;
- }
- return Error::success();
-}
-
-/// The function executeObjcopyOnIHex does the dispatch based on the format
-/// of the output specified by the command line options.
-static Error executeObjcopyOnIHex(CopyConfig &Config, MemoryBuffer &In,
- Buffer &Out) {
- // TODO: support output formats other than ELF.
- if (Error E = Config.parseELFConfig())
- return E;
- return elf::executeObjcopyOnIHex(Config, In, Out);
-}
-
-/// The function executeObjcopyOnRawBinary does the dispatch based on the format
-/// of the output specified by the command line options.
-static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In,
- Buffer &Out) {
- switch (Config.OutputFormat) {
- case FileFormat::ELF:
- // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the
- // output format is binary/ihex or it's not given. This behavior differs from
- // GNU objcopy. See https://bugs.llvm.org/show_bug.cgi?id=42171 for details.
- case FileFormat::Binary:
- case FileFormat::IHex:
- case FileFormat::Unspecified:
- if (Error E = Config.parseELFConfig())
- return E;
- return elf::executeObjcopyOnRawBinary(Config, In, Out);
- }
-
- llvm_unreachable("unsupported output format");
-}
-
-/// The function executeObjcopyOnBinary does the dispatch based on the format
-/// of the input binary (ELF, MachO or COFF).
-static Error executeObjcopyOnBinary(CopyConfig &Config, object::Binary &In,
- Buffer &Out) {
- if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) {
- if (Error E = Config.parseELFConfig())
- return E;
- return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out);
- } else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In))
- return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out);
- else if (auto *MachOBinary = dyn_cast<object::MachOObjectFile>(&In))
- return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out);
+}
+
+} // end namespace objcopy
+} // end namespace llvm
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::objcopy;
+
+// For regular archives this function simply calls llvm::writeArchive,
+// For thin archives it writes the archive file itself as well as its members.
+static Error deepWriteArchive(StringRef ArcName,
+ ArrayRef<NewArchiveMember> NewMembers,
+ bool WriteSymtab, object::Archive::Kind Kind,
+ bool Deterministic, bool Thin) {
+ if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind,
+ Deterministic, Thin))
+ return createFileError(ArcName, std::move(E));
+
+ if (!Thin)
+ return Error::success();
+
+ for (const NewArchiveMember &Member : NewMembers) {
+ // Internally, FileBuffer will use the buffer created by
+ // FileOutputBuffer::create, for regular files (that is the case for
+ // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
+ // OnDiskBuffer uses a temporary file and then renames it. So in reality
+ // there is no inefficiency / duplicated in-memory buffers in this case. For
+ // now in-memory buffers can not be completely avoided since
+ // NewArchiveMember still requires them even though writeArchive does not
+ // write them on disk.
+ FileBuffer FB(Member.MemberName);
+ if (Error E = FB.allocate(Member.Buf->getBufferSize()))
+ return E;
+ std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
+ FB.getBufferStart());
+ if (Error E = FB.commit())
+ return E;
+ }
+ return Error::success();
+}
+
+/// The function executeObjcopyOnIHex does the dispatch based on the format
+/// of the output specified by the command line options.
+static Error executeObjcopyOnIHex(CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out) {
+ // TODO: support output formats other than ELF.
+ if (Error E = Config.parseELFConfig())
+ return E;
+ return elf::executeObjcopyOnIHex(Config, In, Out);
+}
+
+/// The function executeObjcopyOnRawBinary does the dispatch based on the format
+/// of the output specified by the command line options.
+static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out) {
+ switch (Config.OutputFormat) {
+ case FileFormat::ELF:
+ // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the
+ // output format is binary/ihex or it's not given. This behavior differs from
+ // GNU objcopy. See https://bugs.llvm.org/show_bug.cgi?id=42171 for details.
+ case FileFormat::Binary:
+ case FileFormat::IHex:
+ case FileFormat::Unspecified:
+ if (Error E = Config.parseELFConfig())
+ return E;
+ return elf::executeObjcopyOnRawBinary(Config, In, Out);
+ }
+
+ llvm_unreachable("unsupported output format");
+}
+
+/// The function executeObjcopyOnBinary does the dispatch based on the format
+/// of the input binary (ELF, MachO or COFF).
+static Error executeObjcopyOnBinary(CopyConfig &Config, object::Binary &In,
+ Buffer &Out) {
+ if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) {
+ if (Error E = Config.parseELFConfig())
+ return E;
+ return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out);
+ } else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In))
+ return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out);
+ else if (auto *MachOBinary = dyn_cast<object::MachOObjectFile>(&In))
+ return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out);
else if (auto *MachOUniversalBinary =
dyn_cast<object::MachOUniversalBinary>(&In))
return macho::executeObjcopyOnMachOUniversalBinary(
Config, *MachOUniversalBinary, Out);
- else if (auto *WasmBinary = dyn_cast<object::WasmObjectFile>(&In))
- return objcopy::wasm::executeObjcopyOnBinary(Config, *WasmBinary, Out);
- else
- return createStringError(object_error::invalid_file_type,
- "unsupported object file format");
-}
-
+ else if (auto *WasmBinary = dyn_cast<object::WasmObjectFile>(&In))
+ return objcopy::wasm::executeObjcopyOnBinary(Config, *WasmBinary, Out);
+ else
+ return createStringError(object_error::invalid_file_type,
+ "unsupported object file format");
+}
+
namespace llvm {
namespace objcopy {
Expected<std::vector<NewArchiveMember>>
createNewArchiveMembers(CopyConfig &Config, const Archive &Ar) {
- std::vector<NewArchiveMember> NewArchiveMembers;
- Error Err = Error::success();
- for (const Archive::Child &Child : Ar.children(Err)) {
- Expected<StringRef> ChildNameOrErr = Child.getName();
- if (!ChildNameOrErr)
- return createFileError(Ar.getFileName(), ChildNameOrErr.takeError());
-
- Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
- if (!ChildOrErr)
- return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")",
- ChildOrErr.takeError());
-
- MemBuffer MB(ChildNameOrErr.get());
- if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MB))
+ std::vector<NewArchiveMember> NewArchiveMembers;
+ Error Err = Error::success();
+ for (const Archive::Child &Child : Ar.children(Err)) {
+ Expected<StringRef> ChildNameOrErr = Child.getName();
+ if (!ChildNameOrErr)
+ return createFileError(Ar.getFileName(), ChildNameOrErr.takeError());
+
+ Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
+ if (!ChildOrErr)
+ return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")",
+ ChildOrErr.takeError());
+
+ MemBuffer MB(ChildNameOrErr.get());
+ if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MB))
return std::move(E);
-
- Expected<NewArchiveMember> Member =
- NewArchiveMember::getOldMember(Child, Config.DeterministicArchives);
- if (!Member)
- return createFileError(Ar.getFileName(), Member.takeError());
- Member->Buf = MB.releaseMemoryBuffer();
- Member->MemberName = Member->Buf->getBufferIdentifier();
- NewArchiveMembers.push_back(std::move(*Member));
- }
- if (Err)
- return createFileError(Config.InputFilename, std::move(Err));
+
+ Expected<NewArchiveMember> Member =
+ NewArchiveMember::getOldMember(Child, Config.DeterministicArchives);
+ if (!Member)
+ return createFileError(Ar.getFileName(), Member.takeError());
+ Member->Buf = MB.releaseMemoryBuffer();
+ Member->MemberName = Member->Buf->getBufferIdentifier();
+ NewArchiveMembers.push_back(std::move(*Member));
+ }
+ if (Err)
+ return createFileError(Config.InputFilename, std::move(Err));
return std::move(NewArchiveMembers);
}
-
+
} // end namespace objcopy
} // end namespace llvm
@@ -224,148 +224,148 @@ static Error executeObjcopyOnArchive(CopyConfig &Config,
if (!NewArchiveMembersOrErr)
return NewArchiveMembersOrErr.takeError();
return deepWriteArchive(Config.OutputFilename, *NewArchiveMembersOrErr,
- Ar.hasSymbolTable(), Ar.kind(),
- Config.DeterministicArchives, Ar.isThin());
-}
-
-static Error restoreStatOnFile(StringRef Filename,
- const sys::fs::file_status &Stat,
- bool PreserveDates) {
- int FD;
-
- // Writing to stdout should not be treated as an error here, just
- // do not set access/modification times or permissions.
- if (Filename == "-")
- return Error::success();
-
- if (auto EC =
- sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
- return createFileError(Filename, EC);
-
- if (PreserveDates)
- if (auto EC = sys::fs::setLastAccessAndModificationTime(
- FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
- return createFileError(Filename, EC);
-
- sys::fs::file_status OStat;
- if (std::error_code EC = sys::fs::status(FD, OStat))
- return createFileError(Filename, EC);
- if (OStat.type() == sys::fs::file_type::regular_file)
-#ifdef _WIN32
- if (auto EC = sys::fs::setPermissions(
- Filename, static_cast<sys::fs::perms>(Stat.permissions() &
- ~sys::fs::getUmask())))
-#else
- if (auto EC = sys::fs::setPermissions(
- FD, static_cast<sys::fs::perms>(Stat.permissions() &
- ~sys::fs::getUmask())))
-#endif
- return createFileError(Filename, EC);
-
- if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
- return createFileError(Filename, EC);
-
- return Error::success();
-}
-
-/// The function executeObjcopy does the higher level dispatch based on the type
-/// of input (raw binary, archive or single object file) and takes care of the
-/// format-agnostic modifications, i.e. preserving dates.
-static Error executeObjcopy(CopyConfig &Config) {
- sys::fs::file_status Stat;
- if (Config.InputFilename != "-") {
- if (auto EC = sys::fs::status(Config.InputFilename, Stat))
- return createFileError(Config.InputFilename, EC);
- } else {
- Stat.permissions(static_cast<sys::fs::perms>(0777));
- }
-
- using ProcessRawFn = Error (*)(CopyConfig &, MemoryBuffer &, Buffer &);
- ProcessRawFn ProcessRaw;
- switch (Config.InputFormat) {
- case FileFormat::Binary:
- ProcessRaw = executeObjcopyOnRawBinary;
- break;
- case FileFormat::IHex:
- ProcessRaw = executeObjcopyOnIHex;
- break;
- default:
- ProcessRaw = nullptr;
- }
-
- if (ProcessRaw) {
- auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
- if (!BufOrErr)
- return createFileError(Config.InputFilename, BufOrErr.getError());
- FileBuffer FB(Config.OutputFilename);
- if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB))
- return E;
- } else {
- Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
- createBinary(Config.InputFilename);
- if (!BinaryOrErr)
- return createFileError(Config.InputFilename, BinaryOrErr.takeError());
-
- if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
- if (Error E = executeObjcopyOnArchive(Config, *Ar))
- return E;
- } else {
- FileBuffer FB(Config.OutputFilename);
- if (Error E = executeObjcopyOnBinary(Config,
- *BinaryOrErr.get().getBinary(), FB))
- return E;
- }
- }
-
- if (Error E =
- restoreStatOnFile(Config.OutputFilename, Stat, Config.PreserveDates))
- return E;
-
- if (!Config.SplitDWO.empty()) {
- Stat.permissions(static_cast<sys::fs::perms>(0666));
- if (Error E =
- restoreStatOnFile(Config.SplitDWO, Stat, Config.PreserveDates))
- return E;
- }
-
- return Error::success();
-}
-
-namespace {
-
-} // anonymous namespace
-
-int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
- ToolName = argv[0];
-
- // Expand response files.
- // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp,
- // into a separate function in the CommandLine library and call that function
- // here. This is duplicated code.
- SmallVector<const char *, 20> NewArgv(argv, argv + argc);
- BumpPtrAllocator A;
- StringSaver Saver(A);
- cl::ExpandResponseFiles(Saver,
- Triple(sys::getProcessTriple()).isOSWindows()
- ? cl::TokenizeWindowsCommandLine
- : cl::TokenizeGNUCommandLine,
- NewArgv);
-
- auto Args = makeArrayRef(NewArgv).drop_front();
+ Ar.hasSymbolTable(), Ar.kind(),
+ Config.DeterministicArchives, Ar.isThin());
+}
+
+static Error restoreStatOnFile(StringRef Filename,
+ const sys::fs::file_status &Stat,
+ bool PreserveDates) {
+ int FD;
+
+ // Writing to stdout should not be treated as an error here, just
+ // do not set access/modification times or permissions.
+ if (Filename == "-")
+ return Error::success();
+
+ if (auto EC =
+ sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
+ return createFileError(Filename, EC);
+
+ if (PreserveDates)
+ if (auto EC = sys::fs::setLastAccessAndModificationTime(
+ FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
+ return createFileError(Filename, EC);
+
+ sys::fs::file_status OStat;
+ if (std::error_code EC = sys::fs::status(FD, OStat))
+ return createFileError(Filename, EC);
+ if (OStat.type() == sys::fs::file_type::regular_file)
+#ifdef _WIN32
+ if (auto EC = sys::fs::setPermissions(
+ Filename, static_cast<sys::fs::perms>(Stat.permissions() &
+ ~sys::fs::getUmask())))
+#else
+ if (auto EC = sys::fs::setPermissions(
+ FD, static_cast<sys::fs::perms>(Stat.permissions() &
+ ~sys::fs::getUmask())))
+#endif
+ return createFileError(Filename, EC);
+
+ if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
+ return createFileError(Filename, EC);
+
+ return Error::success();
+}
+
+/// The function executeObjcopy does the higher level dispatch based on the type
+/// of input (raw binary, archive or single object file) and takes care of the
+/// format-agnostic modifications, i.e. preserving dates.
+static Error executeObjcopy(CopyConfig &Config) {
+ sys::fs::file_status Stat;
+ if (Config.InputFilename != "-") {
+ if (auto EC = sys::fs::status(Config.InputFilename, Stat))
+ return createFileError(Config.InputFilename, EC);
+ } else {
+ Stat.permissions(static_cast<sys::fs::perms>(0777));
+ }
+
+ using ProcessRawFn = Error (*)(CopyConfig &, MemoryBuffer &, Buffer &);
+ ProcessRawFn ProcessRaw;
+ switch (Config.InputFormat) {
+ case FileFormat::Binary:
+ ProcessRaw = executeObjcopyOnRawBinary;
+ break;
+ case FileFormat::IHex:
+ ProcessRaw = executeObjcopyOnIHex;
+ break;
+ default:
+ ProcessRaw = nullptr;
+ }
+
+ if (ProcessRaw) {
+ auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
+ if (!BufOrErr)
+ return createFileError(Config.InputFilename, BufOrErr.getError());
+ FileBuffer FB(Config.OutputFilename);
+ if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB))
+ return E;
+ } else {
+ Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
+ createBinary(Config.InputFilename);
+ if (!BinaryOrErr)
+ return createFileError(Config.InputFilename, BinaryOrErr.takeError());
+
+ if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
+ if (Error E = executeObjcopyOnArchive(Config, *Ar))
+ return E;
+ } else {
+ FileBuffer FB(Config.OutputFilename);
+ if (Error E = executeObjcopyOnBinary(Config,
+ *BinaryOrErr.get().getBinary(), FB))
+ return E;
+ }
+ }
+
+ if (Error E =
+ restoreStatOnFile(Config.OutputFilename, Stat, Config.PreserveDates))
+ return E;
+
+ if (!Config.SplitDWO.empty()) {
+ Stat.permissions(static_cast<sys::fs::perms>(0666));
+ if (Error E =
+ restoreStatOnFile(Config.SplitDWO, Stat, Config.PreserveDates))
+ return E;
+ }
+
+ return Error::success();
+}
+
+namespace {
+
+} // anonymous namespace
+
+int main(int argc, char **argv) {
+ InitLLVM X(argc, argv);
+ ToolName = argv[0];
+
+ // Expand response files.
+ // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp,
+ // into a separate function in the CommandLine library and call that function
+ // here. This is duplicated code.
+ SmallVector<const char *, 20> NewArgv(argv, argv + argc);
+ BumpPtrAllocator A;
+ StringSaver Saver(A);
+ cl::ExpandResponseFiles(Saver,
+ Triple(sys::getProcessTriple()).isOSWindows()
+ ? cl::TokenizeWindowsCommandLine
+ : cl::TokenizeGNUCommandLine,
+ NewArgv);
+
+ auto Args = makeArrayRef(NewArgv).drop_front();
Expected<DriverConfig> DriverConfig = getDriverConfig(Args);
- if (!DriverConfig) {
- logAllUnhandledErrors(DriverConfig.takeError(),
- WithColor::error(errs(), ToolName));
- return 1;
- }
- for (CopyConfig &CopyConfig : DriverConfig->CopyConfigs) {
- if (Error E = executeObjcopy(CopyConfig)) {
- logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName));
- return 1;
- }
- }
-
- return 0;
-}
+ if (!DriverConfig) {
+ logAllUnhandledErrors(DriverConfig.takeError(),
+ WithColor::error(errs(), ToolName));
+ return 1;
+ }
+ for (CopyConfig &CopyConfig : DriverConfig->CopyConfigs) {
+ if (Error E = executeObjcopy(CopyConfig)) {
+ logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName));
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.h b/contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.h
index 97a166769f..9086bcff2e 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/llvm-objcopy.h
@@ -1,22 +1,22 @@
-//===- llvm-objcopy.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_OBJCOPY_OBJCOPY_H
-#define LLVM_TOOLS_OBJCOPY_OBJCOPY_H
-
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-
+//===- llvm-objcopy.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_OBJCOPY_OBJCOPY_H
+#define LLVM_TOOLS_OBJCOPY_OBJCOPY_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
struct NewArchiveMember;
-
+
namespace object {
-
+
class Archive;
} // end namespace object
@@ -26,7 +26,7 @@ struct CopyConfig;
Expected<std::vector<NewArchiveMember>>
createNewArchiveMembers(CopyConfig &Config, const object::Archive &Ar);
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_OBJCOPY_OBJCOPY_H
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_OBJCOPY_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.cpp
index e7a2956fed..4fa82a8c36 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.cpp
@@ -1,34 +1,34 @@
-//===- Object.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 "Object.h"
-
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace llvm {
-namespace objcopy {
-namespace wasm {
-
-using namespace object;
-using namespace llvm::wasm;
-
-void Object::addSectionWithOwnedContents(
- Section NewSection, std::unique_ptr<MemoryBuffer> &&Content) {
- Sections.push_back(NewSection);
- OwnedContents.emplace_back(std::move(Content));
-}
-
-void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
- // TODO: remove reloc sections for the removed section, handle symbols, etc.
+//===- Object.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 "Object.h"
+
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace objcopy {
+namespace wasm {
+
+using namespace object;
+using namespace llvm::wasm;
+
+void Object::addSectionWithOwnedContents(
+ Section NewSection, std::unique_ptr<MemoryBuffer> &&Content) {
+ Sections.push_back(NewSection);
+ OwnedContents.emplace_back(std::move(Content));
+}
+
+void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
+ // TODO: remove reloc sections for the removed section, handle symbols, etc.
llvm::erase_if(Sections, ToRemove);
-}
-
-} // end namespace wasm
-} // end namespace objcopy
-} // end namespace llvm
+}
+
+} // end namespace wasm
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.h b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.h
index 9db91c41e2..da664edd1b 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Object.h
@@ -1,47 +1,47 @@
-//===- Object.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_LLVM_OBJCOPY_WASM_OBJECT_H
-#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_OBJECT_H
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Object/Wasm.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include <vector>
-
-namespace llvm {
-namespace objcopy {
-namespace wasm {
-
-struct Section {
- // For now, each section is only an opaque binary blob with no distinction
- // between custom and known sections.
- uint8_t SectionType;
- StringRef Name;
- ArrayRef<uint8_t> Contents;
-};
-
-struct Object {
- llvm::wasm::WasmObjectHeader Header;
- // For now don't discriminate between kinds of sections.
- std::vector<Section> Sections;
-
- void addSectionWithOwnedContents(Section NewSection,
- std::unique_ptr<MemoryBuffer> &&Content);
- void removeSections(function_ref<bool(const Section &)> ToRemove);
-
-private:
- std::vector<std::unique_ptr<MemoryBuffer>> OwnedContents;
-};
-
-} // end namespace wasm
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_OBJECT_H
+//===- Object.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_LLVM_OBJCOPY_WASM_OBJECT_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_OBJECT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+namespace wasm {
+
+struct Section {
+ // For now, each section is only an opaque binary blob with no distinction
+ // between custom and known sections.
+ uint8_t SectionType;
+ StringRef Name;
+ ArrayRef<uint8_t> Contents;
+};
+
+struct Object {
+ llvm::wasm::WasmObjectHeader Header;
+ // For now don't discriminate between kinds of sections.
+ std::vector<Section> Sections;
+
+ void addSectionWithOwnedContents(Section NewSection,
+ std::unique_ptr<MemoryBuffer> &&Content);
+ void removeSections(function_ref<bool(const Section &)> ToRemove);
+
+private:
+ std::vector<std::unique_ptr<MemoryBuffer>> OwnedContents;
+};
+
+} // end namespace wasm
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_OBJECT_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.cpp
index 13fa84ad80..d4dcc3c682 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.cpp
@@ -1,33 +1,33 @@
-//===- Reader.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 "Reader.h"
-
-namespace llvm {
-namespace objcopy {
-namespace wasm {
-
-using namespace object;
-using namespace llvm::wasm;
-
-Expected<std::unique_ptr<Object>> Reader::create() const {
- auto Obj = std::make_unique<Object>();
- Obj->Header = WasmObj.getHeader();
- std::vector<Section> Sections;
- Obj->Sections.reserve(WasmObj.getNumSections());
- for (const SectionRef &Sec : WasmObj.sections()) {
- const WasmSection &WS = WasmObj.getWasmSection(Sec);
- Obj->Sections.push_back(
- {static_cast<uint8_t>(WS.Type), WS.Name, WS.Content});
- }
- return std::move(Obj);
-}
-
-} // end namespace wasm
-} // end namespace objcopy
-} // end namespace llvm
+//===- Reader.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 "Reader.h"
+
+namespace llvm {
+namespace objcopy {
+namespace wasm {
+
+using namespace object;
+using namespace llvm::wasm;
+
+Expected<std::unique_ptr<Object>> Reader::create() const {
+ auto Obj = std::make_unique<Object>();
+ Obj->Header = WasmObj.getHeader();
+ std::vector<Section> Sections;
+ Obj->Sections.reserve(WasmObj.getNumSections());
+ for (const SectionRef &Sec : WasmObj.sections()) {
+ const WasmSection &WS = WasmObj.getWasmSection(Sec);
+ Obj->Sections.push_back(
+ {static_cast<uint8_t>(WS.Type), WS.Name, WS.Content});
+ }
+ return std::move(Obj);
+}
+
+} // end namespace wasm
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.h b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.h
index 2dcf7dde02..494dd5e563 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Reader.h
@@ -1,31 +1,31 @@
-//===- Reader.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_LLVM_OBJCOPY_WASM_READER_H
-#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_READER_H
-
-#include "Object.h"
-
-namespace llvm {
-namespace objcopy {
-namespace wasm {
-
-class Reader {
-public:
- explicit Reader(const object::WasmObjectFile &O) : WasmObj(O) {}
- Expected<std::unique_ptr<Object>> create() const;
-
-private:
- const object::WasmObjectFile &WasmObj;
-};
-
-} // end namespace wasm
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_READER_H
+//===- Reader.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_LLVM_OBJCOPY_WASM_READER_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_READER_H
+
+#include "Object.h"
+
+namespace llvm {
+namespace objcopy {
+namespace wasm {
+
+class Reader {
+public:
+ explicit Reader(const object::WasmObjectFile &O) : WasmObj(O) {}
+ Expected<std::unique_ptr<Object>> create() const;
+
+private:
+ const object::WasmObjectFile &WasmObj;
+};
+
+} // end namespace wasm
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_READER_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.cpp
index eb0e5635ce..fd83334ed9 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.cpp
@@ -1,113 +1,113 @@
-//===- WasmObjcopy.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 "WasmObjcopy.h"
-#include "Buffer.h"
-#include "CopyConfig.h"
-#include "Object.h"
-#include "Reader.h"
-#include "Writer.h"
-#include "llvm/Support/Errc.h"
-
-namespace llvm {
-namespace objcopy {
-namespace wasm {
-
-using namespace object;
-
-static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
- Object &Obj) {
- for (const Section &Sec : Obj.Sections) {
- if (Sec.Name == SecName) {
- ArrayRef<uint8_t> Contents = Sec.Contents;
- Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
- FileOutputBuffer::create(Filename, Contents.size());
- if (!BufferOrErr)
- return BufferOrErr.takeError();
- std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
- std::copy(Contents.begin(), Contents.end(), Buf->getBufferStart());
- if (Error E = Buf->commit())
- return E;
- return Error::success();
- }
- }
- return createStringError(errc::invalid_argument, "section '%s' not found",
- SecName.str().c_str());
-}
-static Error handleArgs(const CopyConfig &Config, Object &Obj) {
- // Only support AddSection, DumpSection, RemoveSection for now.
- for (StringRef Flag : Config.DumpSection) {
- StringRef SecName;
- StringRef FileName;
- std::tie(SecName, FileName) = Flag.split("=");
- if (Error E = dumpSectionToFile(SecName, FileName, Obj))
- return createFileError(FileName, std::move(E));
- }
-
- Obj.removeSections([&Config](const Section &Sec) {
- if (Config.ToRemove.matches(Sec.Name))
- return true;
- return false;
- });
-
- for (StringRef Flag : Config.AddSection) {
- StringRef SecName, FileName;
- std::tie(SecName, FileName) = Flag.split("=");
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFile(FileName);
- if (!BufOrErr)
- return createFileError(FileName, errorCodeToError(BufOrErr.getError()));
- Section Sec;
- Sec.SectionType = llvm::wasm::WASM_SEC_CUSTOM;
- Sec.Name = SecName;
- std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
- Sec.Contents = makeArrayRef<uint8_t>(
- reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
- Buf->getBufferSize());
- Obj.addSectionWithOwnedContents(Sec, std::move(Buf));
- }
-
- if (!Config.AddGnuDebugLink.empty() || !Config.BuildIdLinkDir.empty() ||
- Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
- Config.ExtractPartition || !Config.SplitDWO.empty() ||
- !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() ||
- Config.DiscardMode != DiscardType::None || Config.NewSymbolVisibility ||
- !Config.SymbolsToAdd.empty() || !Config.RPathToAdd.empty() ||
- !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() ||
- !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
- !Config.SymbolsToRemove.empty() ||
- !Config.UnneededSymbolsToRemove.empty() ||
- !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
- !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() ||
- !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty()) {
- return createStringError(
- llvm::errc::invalid_argument,
- "only add-section, dump-section, and remove-section are supported");
- }
- return Error::success();
-}
-
-Error executeObjcopyOnBinary(const CopyConfig &Config,
- object::WasmObjectFile &In, Buffer &Out) {
- Reader TheReader(In);
- Expected<std::unique_ptr<Object>> ObjOrErr = TheReader.create();
- if (!ObjOrErr)
- return createFileError(Config.InputFilename, ObjOrErr.takeError());
- Object *Obj = ObjOrErr->get();
- assert(Obj && "Unable to deserialize Wasm object");
- if (Error E = handleArgs(Config, *Obj))
- return E;
- Writer TheWriter(*Obj, Out);
- if (Error E = TheWriter.write())
- return createFileError(Config.OutputFilename, std::move(E));
- return Error::success();
-}
-
-} // end namespace wasm
-} // end namespace objcopy
-} // end namespace llvm
+//===- WasmObjcopy.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 "WasmObjcopy.h"
+#include "Buffer.h"
+#include "CopyConfig.h"
+#include "Object.h"
+#include "Reader.h"
+#include "Writer.h"
+#include "llvm/Support/Errc.h"
+
+namespace llvm {
+namespace objcopy {
+namespace wasm {
+
+using namespace object;
+
+static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
+ Object &Obj) {
+ for (const Section &Sec : Obj.Sections) {
+ if (Sec.Name == SecName) {
+ ArrayRef<uint8_t> Contents = Sec.Contents;
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(Filename, Contents.size());
+ if (!BufferOrErr)
+ return BufferOrErr.takeError();
+ std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
+ std::copy(Contents.begin(), Contents.end(), Buf->getBufferStart());
+ if (Error E = Buf->commit())
+ return E;
+ return Error::success();
+ }
+ }
+ return createStringError(errc::invalid_argument, "section '%s' not found",
+ SecName.str().c_str());
+}
+static Error handleArgs(const CopyConfig &Config, Object &Obj) {
+ // Only support AddSection, DumpSection, RemoveSection for now.
+ for (StringRef Flag : Config.DumpSection) {
+ StringRef SecName;
+ StringRef FileName;
+ std::tie(SecName, FileName) = Flag.split("=");
+ if (Error E = dumpSectionToFile(SecName, FileName, Obj))
+ return createFileError(FileName, std::move(E));
+ }
+
+ Obj.removeSections([&Config](const Section &Sec) {
+ if (Config.ToRemove.matches(Sec.Name))
+ return true;
+ return false;
+ });
+
+ for (StringRef Flag : Config.AddSection) {
+ StringRef SecName, FileName;
+ std::tie(SecName, FileName) = Flag.split("=");
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFile(FileName);
+ if (!BufOrErr)
+ return createFileError(FileName, errorCodeToError(BufOrErr.getError()));
+ Section Sec;
+ Sec.SectionType = llvm::wasm::WASM_SEC_CUSTOM;
+ Sec.Name = SecName;
+ std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
+ Sec.Contents = makeArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
+ Buf->getBufferSize());
+ Obj.addSectionWithOwnedContents(Sec, std::move(Buf));
+ }
+
+ if (!Config.AddGnuDebugLink.empty() || !Config.BuildIdLinkDir.empty() ||
+ Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
+ Config.ExtractPartition || !Config.SplitDWO.empty() ||
+ !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() ||
+ Config.DiscardMode != DiscardType::None || Config.NewSymbolVisibility ||
+ !Config.SymbolsToAdd.empty() || !Config.RPathToAdd.empty() ||
+ !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() ||
+ !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
+ !Config.SymbolsToRemove.empty() ||
+ !Config.UnneededSymbolsToRemove.empty() ||
+ !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
+ !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() ||
+ !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty()) {
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "only add-section, dump-section, and remove-section are supported");
+ }
+ return Error::success();
+}
+
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::WasmObjectFile &In, Buffer &Out) {
+ Reader TheReader(In);
+ Expected<std::unique_ptr<Object>> ObjOrErr = TheReader.create();
+ if (!ObjOrErr)
+ return createFileError(Config.InputFilename, ObjOrErr.takeError());
+ Object *Obj = ObjOrErr->get();
+ assert(Obj && "Unable to deserialize Wasm object");
+ if (Error E = handleArgs(Config, *Obj))
+ return E;
+ Writer TheWriter(*Obj, Out);
+ if (Error E = TheWriter.write())
+ return createFileError(Config.OutputFilename, std::move(E));
+ return Error::success();
+}
+
+} // end namespace wasm
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.h b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.h
index 3557d5c0a5..f0ded26911 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/WasmObjcopy.h
@@ -1,31 +1,31 @@
-//===- WasmObjcopy.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_LLVM_OBJCOPY_WASM_WASMOBJCOPY_H
-#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_WASMOBJCOPY_H
-
-namespace llvm {
-class Error;
-
-namespace object {
-class WasmObjectFile;
-} // end namespace object
-
-namespace objcopy {
-struct CopyConfig;
-class Buffer;
-
-namespace wasm {
-Error executeObjcopyOnBinary(const CopyConfig &Config,
- object::WasmObjectFile &In, Buffer &Out);
-
-} // end namespace wasm
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_WASMOBJCOPY_H
+//===- WasmObjcopy.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_LLVM_OBJCOPY_WASM_WASMOBJCOPY_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_WASMOBJCOPY_H
+
+namespace llvm {
+class Error;
+
+namespace object {
+class WasmObjectFile;
+} // end namespace object
+
+namespace objcopy {
+struct CopyConfig;
+class Buffer;
+
+namespace wasm {
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::WasmObjectFile &In, Buffer &Out);
+
+} // end namespace wasm
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_WASMOBJCOPY_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.cpp b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.cpp
index 50d26507b4..17a4e04835 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.cpp
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.cpp
@@ -1,78 +1,78 @@
-//===- Writer.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 "Writer.h"
-#include "llvm/BinaryFormat/Wasm.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace llvm {
-namespace objcopy {
-namespace wasm {
-
-using namespace object;
-using namespace llvm::wasm;
-
-Writer::SectionHeader Writer::createSectionHeader(const Section &S,
- size_t &SectionSize) {
- SectionHeader Header;
- raw_svector_ostream OS(Header);
- OS << S.SectionType;
- bool HasName = S.SectionType == WASM_SEC_CUSTOM;
- SectionSize = S.Contents.size();
- if (HasName)
- SectionSize += getULEB128Size(S.Name.size()) + S.Name.size();
- // Pad the LEB value out to 5 bytes to make it a predictable size, and
- // match the behavior of clang.
- encodeULEB128(SectionSize, OS, 5);
- if (HasName) {
- encodeULEB128(S.Name.size(), OS);
- OS << S.Name;
- }
- // Total section size is the content size plus 1 for the section type and
- // 5 for the LEB-encoded size.
- SectionSize = SectionSize + 1 + 5;
- return Header;
-}
-
-size_t Writer::finalize() {
- size_t ObjectSize = sizeof(WasmMagic) + sizeof(WasmVersion);
- SectionHeaders.reserve(Obj.Sections.size());
- // Finalize the headers of each section so we know the total size.
- for (const Section &S : Obj.Sections) {
- size_t SectionSize;
- SectionHeaders.push_back(createSectionHeader(S, SectionSize));
- ObjectSize += SectionSize;
- }
- return ObjectSize;
-}
-
-Error Writer::write() {
- size_t FileSize = finalize();
- if (Error E = Buf.allocate(FileSize))
- return E;
-
- // Write the header.
- uint8_t *Ptr = Buf.getBufferStart();
- Ptr = std::copy(Obj.Header.Magic.begin(), Obj.Header.Magic.end(), Ptr);
- support::endian::write32le(Ptr, Obj.Header.Version);
- Ptr += sizeof(Obj.Header.Version);
-
- // Write each section.
- for (size_t I = 0, S = SectionHeaders.size(); I < S; ++I) {
- Ptr = std::copy(SectionHeaders[I].begin(), SectionHeaders[I].end(), Ptr);
- ArrayRef<uint8_t> Contents = Obj.Sections[I].Contents;
- Ptr = std::copy(Contents.begin(), Contents.end(), Ptr);
- }
- return Buf.commit();
-}
-
-} // end namespace wasm
-} // end namespace objcopy
-} // end namespace llvm
+//===- Writer.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 "Writer.h"
+#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace objcopy {
+namespace wasm {
+
+using namespace object;
+using namespace llvm::wasm;
+
+Writer::SectionHeader Writer::createSectionHeader(const Section &S,
+ size_t &SectionSize) {
+ SectionHeader Header;
+ raw_svector_ostream OS(Header);
+ OS << S.SectionType;
+ bool HasName = S.SectionType == WASM_SEC_CUSTOM;
+ SectionSize = S.Contents.size();
+ if (HasName)
+ SectionSize += getULEB128Size(S.Name.size()) + S.Name.size();
+ // Pad the LEB value out to 5 bytes to make it a predictable size, and
+ // match the behavior of clang.
+ encodeULEB128(SectionSize, OS, 5);
+ if (HasName) {
+ encodeULEB128(S.Name.size(), OS);
+ OS << S.Name;
+ }
+ // Total section size is the content size plus 1 for the section type and
+ // 5 for the LEB-encoded size.
+ SectionSize = SectionSize + 1 + 5;
+ return Header;
+}
+
+size_t Writer::finalize() {
+ size_t ObjectSize = sizeof(WasmMagic) + sizeof(WasmVersion);
+ SectionHeaders.reserve(Obj.Sections.size());
+ // Finalize the headers of each section so we know the total size.
+ for (const Section &S : Obj.Sections) {
+ size_t SectionSize;
+ SectionHeaders.push_back(createSectionHeader(S, SectionSize));
+ ObjectSize += SectionSize;
+ }
+ return ObjectSize;
+}
+
+Error Writer::write() {
+ size_t FileSize = finalize();
+ if (Error E = Buf.allocate(FileSize))
+ return E;
+
+ // Write the header.
+ uint8_t *Ptr = Buf.getBufferStart();
+ Ptr = std::copy(Obj.Header.Magic.begin(), Obj.Header.Magic.end(), Ptr);
+ support::endian::write32le(Ptr, Obj.Header.Version);
+ Ptr += sizeof(Obj.Header.Version);
+
+ // Write each section.
+ for (size_t I = 0, S = SectionHeaders.size(); I < S; ++I) {
+ Ptr = std::copy(SectionHeaders[I].begin(), SectionHeaders[I].end(), Ptr);
+ ArrayRef<uint8_t> Contents = Obj.Sections[I].Contents;
+ Ptr = std::copy(Contents.begin(), Contents.end(), Ptr);
+ }
+ return Buf.commit();
+}
+
+} // end namespace wasm
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.h b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.h
index da48ee730c..5cfb04772e 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.h
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/wasm/Writer.h
@@ -1,50 +1,50 @@
-//===- Writer.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_LLVM_OBJCOPY_WASM_WRITER_H
-#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_WRITER_H
-
-#include "Buffer.h"
-#include "Object.h"
-#include <cstdint>
-#include <vector>
-
-namespace llvm {
-namespace objcopy {
-namespace wasm {
-
-class Writer {
-public:
- Writer(Object &Obj, Buffer &Buf) : Obj(Obj), Buf(Buf) {}
- Error write();
-
-private:
- using SectionHeader = SmallVector<char, 8>;
- Object &Obj;
- Buffer &Buf;
- std::vector<SectionHeader> SectionHeaders;
-
- /// Generate a wasm section section header for S.
- /// The header consists of
- /// * A one-byte section ID (aka the section type).
- /// * The size of the section contents, encoded as ULEB128.
- /// * If the section is a custom section (type 0) it also has a name, which is
- /// encoded as a length-prefixed string. The encoded section size *includes*
- /// this string.
- /// See https://webassembly.github.io/spec/core/binary/modules.html#sections
- /// Return the header and store the total size in SectionSize.
- static SectionHeader createSectionHeader(const Section &S,
- size_t &SectionSize);
- size_t finalize();
-};
-
-} // end namespace wasm
-} // end namespace objcopy
-} // end namespace llvm
-
-#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_WRITER_H
+//===- Writer.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_LLVM_OBJCOPY_WASM_WRITER_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_WRITER_H
+
+#include "Buffer.h"
+#include "Object.h"
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+namespace wasm {
+
+class Writer {
+public:
+ Writer(Object &Obj, Buffer &Buf) : Obj(Obj), Buf(Buf) {}
+ Error write();
+
+private:
+ using SectionHeader = SmallVector<char, 8>;
+ Object &Obj;
+ Buffer &Buf;
+ std::vector<SectionHeader> SectionHeaders;
+
+ /// Generate a wasm section section header for S.
+ /// The header consists of
+ /// * A one-byte section ID (aka the section type).
+ /// * The size of the section contents, encoded as ULEB128.
+ /// * If the section is a custom section (type 0) it also has a name, which is
+ /// encoded as a length-prefixed string. The encoded section size *includes*
+ /// this string.
+ /// See https://webassembly.github.io/spec/core/binary/modules.html#sections
+ /// Return the header and store the total size in SectionSize.
+ static SectionHeader createSectionHeader(const Section &S,
+ size_t &SectionSize);
+ size_t finalize();
+};
+
+} // end namespace wasm
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_OBJCOPY_WASM_WRITER_H
diff --git a/contrib/libs/llvm12/tools/llvm-objcopy/ya.make b/contrib/libs/llvm12/tools/llvm-objcopy/ya.make
index 13845f4bfa..f4f40719c9 100644
--- a/contrib/libs/llvm12/tools/llvm-objcopy/ya.make
+++ b/contrib/libs/llvm12/tools/llvm-objcopy/ya.make
@@ -1,17 +1,17 @@
-# Generated by devtools/yamaker.
-
-PROGRAM()
-
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
-
+
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/BinaryFormat
@@ -26,37 +26,37 @@ PEERDIR(
contrib/libs/llvm12/lib/Remarks
contrib/libs/llvm12/lib/Support
contrib/libs/llvm12/lib/TextAPI/MachO
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/llvm-objcopy
contrib/libs/llvm12/tools/llvm-objcopy
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- Buffer.cpp
- COFF/COFFObjcopy.cpp
- COFF/Object.cpp
- COFF/Reader.cpp
- COFF/Writer.cpp
- CopyConfig.cpp
- ELF/ELFConfig.cpp
- ELF/ELFObjcopy.cpp
- ELF/Object.cpp
- MachO/MachOLayoutBuilder.cpp
- MachO/MachOObjcopy.cpp
- MachO/MachOReader.cpp
- MachO/MachOWriter.cpp
- MachO/Object.cpp
- llvm-objcopy.cpp
- wasm/Object.cpp
- wasm/Reader.cpp
- wasm/WasmObjcopy.cpp
- wasm/Writer.cpp
-)
-
-END()
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ Buffer.cpp
+ COFF/COFFObjcopy.cpp
+ COFF/Object.cpp
+ COFF/Reader.cpp
+ COFF/Writer.cpp
+ CopyConfig.cpp
+ ELF/ELFConfig.cpp
+ ELF/ELFObjcopy.cpp
+ ELF/Object.cpp
+ MachO/MachOLayoutBuilder.cpp
+ MachO/MachOObjcopy.cpp
+ MachO/MachOReader.cpp
+ MachO/MachOWriter.cpp
+ MachO/Object.cpp
+ llvm-objcopy.cpp
+ wasm/Object.cpp
+ wasm/Reader.cpp
+ wasm/WasmObjcopy.cpp
+ wasm/Writer.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm12/tools/llvm-rc/Opts.td b/contrib/libs/llvm12/tools/llvm-rc/Opts.td
index 613f0a0db3..27b4f182a2 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/Opts.td
+++ b/contrib/libs/llvm12/tools/llvm-rc/Opts.td
@@ -1,55 +1,55 @@
-include "llvm/Option/OptParser.td"
-
-// All the switches can be preceded by either '/' or '-'.
-// These options seem to be important for the tool
-// and should be implemented.
-
+include "llvm/Option/OptParser.td"
+
+// All the switches can be preceded by either '/' or '-'.
+// These options seem to be important for the tool
+// and should be implemented.
+
def fileout : JoinedOrSeparate<[ "/", "-" ], "FO">,
- HelpText<"Change the output file location.">;
-
+ HelpText<"Change the output file location.">;
+
def define : Separate<[ "/", "-" ], "D">,
- HelpText<"Define a symbol for the C preprocessor.">;
+ HelpText<"Define a symbol for the C preprocessor.">;
def undef : Separate<[ "/", "-" ], "U">,
- HelpText<"Undefine a symbol for the C preprocessor.">;
-
+ HelpText<"Undefine a symbol for the C preprocessor.">;
+
def lang_id : JoinedOrSeparate<[ "/", "-" ], "L">,
- HelpText<"Set the default language identifier.">;
+ HelpText<"Set the default language identifier.">;
def lang_name : Separate<[ "/", "-" ], "LN">,
- HelpText<"Set the default language name.">;
-
+ HelpText<"Set the default language name.">;
+
def includepath : Separate<[ "/", "-" ], "I">, HelpText<"Add an include path.">;
def noinclude : Flag<[ "/", "-" ], "X">, HelpText<"Ignore 'include' variable.">;
-
+
def add_null : Flag<[ "/", "-" ], "N">,
- HelpText<"Null-terminate all strings in the string table.">;
-
+ HelpText<"Null-terminate all strings in the string table.">;
+
def dupid_nowarn : Flag<[ "/", "-" ], "Y">,
- HelpText<"Suppress warnings on duplicate resource IDs.">;
-
+ HelpText<"Suppress warnings on duplicate resource IDs.">;
+
def verbose : Flag<[ "/", "-" ], "V">, HelpText<"Be verbose.">;
def help : Flag<[ "/", "-" ], "?">, HelpText<"Display this help and exit.">;
def h : Flag<[ "/", "-" ], "H">,
Alias<help>,
- HelpText<"Display this help and exit.">;
-
+ HelpText<"Display this help and exit.">;
+
def dry_run : Flag<[ "/", "-" ], "dry-run">,
- HelpText<"Don't compile the input; only try to parse it.">;
-
+ HelpText<"Don't compile the input; only try to parse it.">;
+
def codepage : JoinedOrSeparate<[ "/", "-" ], "C">,
- HelpText<"Set the codepage used for input strings.">;
-
-// Unused switches (at least for now). These will stay unimplemented
-// in an early stage of development and can be ignored. However, we need to
-// parse them in order to preserve the compatibility with the original tool.
-
+ HelpText<"Set the codepage used for input strings.">;
+
+// Unused switches (at least for now). These will stay unimplemented
+// in an early stage of development and can be ignored. However, we need to
+// parse them in order to preserve the compatibility with the original tool.
+
def nologo : Flag<[ "/", "-" ], "NOLOGO">;
def r : Flag<[ "/", "-" ], "R">;
def sl : Flag<[ "/", "-" ], "SL">;
-
-// (Codepages support.)
+
+// (Codepages support.)
def w : Flag<[ "/", "-" ], "W">;
-
-// (Support of MUI and similar.)
+
+// (Support of MUI and similar.)
def fm : Separate<[ "/", "-" ], "FM">;
def q : Separate<[ "/", "-" ], "Q">;
def g : Flag<[ "/", "-" ], "G">;
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp
index 553bb754ae..a7418ba2f1 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp
@@ -1,1519 +1,1519 @@
-//===-- ResourceFileWriter.cpp --------------------------------*- 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
-//
-//===---------------------------------------------------------------------===//
-//
-// This implements the visitor serializing resources to a .res stream.
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceFileWriter.h"
-#include "llvm/Object/WindowsResource.h"
-#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/EndianStream.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-
-using namespace llvm::support;
-
-// Take an expression returning llvm::Error and forward the error if it exists.
-#define RETURN_IF_ERROR(Expr) \
- if (auto Err = (Expr)) \
- return Err;
-
-namespace llvm {
-namespace rc {
-
-// Class that employs RAII to save the current FileWriter object state
-// and revert to it as soon as we leave the scope. This is useful if resources
-// declare their own resource-local statements.
-class ContextKeeper {
- ResourceFileWriter *FileWriter;
- ResourceFileWriter::ObjectInfo SavedInfo;
-
-public:
- ContextKeeper(ResourceFileWriter *V)
- : FileWriter(V), SavedInfo(V->ObjectData) {}
- ~ContextKeeper() { FileWriter->ObjectData = SavedInfo; }
-};
-
-static Error createError(const Twine &Message,
- std::errc Type = std::errc::invalid_argument) {
- return make_error<StringError>(Message, std::make_error_code(Type));
-}
-
-static Error checkNumberFits(uint32_t Number, size_t MaxBits,
- const Twine &FieldName) {
- assert(1 <= MaxBits && MaxBits <= 32);
- if (!(Number >> MaxBits))
- return Error::success();
- return createError(FieldName + " (" + Twine(Number) + ") does not fit in " +
- Twine(MaxBits) + " bits.",
- std::errc::value_too_large);
-}
-
-template <typename FitType>
-static Error checkNumberFits(uint32_t Number, const Twine &FieldName) {
- return checkNumberFits(Number, sizeof(FitType) * 8, FieldName);
-}
-
-// A similar function for signed integers.
-template <typename FitType>
-static Error checkSignedNumberFits(uint32_t Number, const Twine &FieldName,
- bool CanBeNegative) {
- int32_t SignedNum = Number;
- if (SignedNum < std::numeric_limits<FitType>::min() ||
- SignedNum > std::numeric_limits<FitType>::max())
- return createError(FieldName + " (" + Twine(SignedNum) +
- ") does not fit in " + Twine(sizeof(FitType) * 8) +
- "-bit signed integer type.",
- std::errc::value_too_large);
-
- if (!CanBeNegative && SignedNum < 0)
- return createError(FieldName + " (" + Twine(SignedNum) +
- ") cannot be negative.");
-
- return Error::success();
-}
-
-static Error checkRCInt(RCInt Number, const Twine &FieldName) {
- if (Number.isLong())
- return Error::success();
- return checkNumberFits<uint16_t>(Number, FieldName);
-}
-
-static Error checkIntOrString(IntOrString Value, const Twine &FieldName) {
- if (!Value.isInt())
- return Error::success();
- return checkNumberFits<uint16_t>(Value.getInt(), FieldName);
-}
-
-static bool stripQuotes(StringRef &Str, bool &IsLongString) {
- if (!Str.contains('"'))
- return false;
-
- // Just take the contents of the string, checking if it's been marked long.
- IsLongString = Str.startswith_lower("L");
- if (IsLongString)
- Str = Str.drop_front();
-
- bool StripSuccess = Str.consume_front("\"") && Str.consume_back("\"");
- (void)StripSuccess;
- assert(StripSuccess && "Strings should be enclosed in quotes.");
- return true;
-}
-
-static UTF16 cp1252ToUnicode(unsigned char C) {
- static const UTF16 Map80[] = {
- 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
- 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
- 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
- 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178,
- };
- if (C >= 0x80 && C <= 0x9F)
- return Map80[C - 0x80];
- return C;
-}
-
-// Describes a way to handle '\0' characters when processing the string.
-// rc.exe tool sometimes behaves in a weird way in postprocessing.
-// If the string to be output is equivalent to a C-string (e.g. in MENU
-// titles), string is (predictably) truncated after first 0-byte.
-// When outputting a string table, the behavior is equivalent to appending
-// '\0\0' at the end of the string, and then stripping the string
-// before the first '\0\0' occurrence.
-// Finally, when handling strings in user-defined resources, 0-bytes
-// aren't stripped, nor do they terminate the string.
-
-enum class NullHandlingMethod {
- UserResource, // Don't terminate string on '\0'.
- CutAtNull, // Terminate string on '\0'.
- CutAtDoubleNull // Terminate string on '\0\0'; strip final '\0'.
-};
-
-// Parses an identifier or string and returns a processed version of it:
+//===-- ResourceFileWriter.cpp --------------------------------*- 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
+//
+//===---------------------------------------------------------------------===//
+//
+// This implements the visitor serializing resources to a .res stream.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceFileWriter.h"
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+
+using namespace llvm::support;
+
+// Take an expression returning llvm::Error and forward the error if it exists.
+#define RETURN_IF_ERROR(Expr) \
+ if (auto Err = (Expr)) \
+ return Err;
+
+namespace llvm {
+namespace rc {
+
+// Class that employs RAII to save the current FileWriter object state
+// and revert to it as soon as we leave the scope. This is useful if resources
+// declare their own resource-local statements.
+class ContextKeeper {
+ ResourceFileWriter *FileWriter;
+ ResourceFileWriter::ObjectInfo SavedInfo;
+
+public:
+ ContextKeeper(ResourceFileWriter *V)
+ : FileWriter(V), SavedInfo(V->ObjectData) {}
+ ~ContextKeeper() { FileWriter->ObjectData = SavedInfo; }
+};
+
+static Error createError(const Twine &Message,
+ std::errc Type = std::errc::invalid_argument) {
+ return make_error<StringError>(Message, std::make_error_code(Type));
+}
+
+static Error checkNumberFits(uint32_t Number, size_t MaxBits,
+ const Twine &FieldName) {
+ assert(1 <= MaxBits && MaxBits <= 32);
+ if (!(Number >> MaxBits))
+ return Error::success();
+ return createError(FieldName + " (" + Twine(Number) + ") does not fit in " +
+ Twine(MaxBits) + " bits.",
+ std::errc::value_too_large);
+}
+
+template <typename FitType>
+static Error checkNumberFits(uint32_t Number, const Twine &FieldName) {
+ return checkNumberFits(Number, sizeof(FitType) * 8, FieldName);
+}
+
+// A similar function for signed integers.
+template <typename FitType>
+static Error checkSignedNumberFits(uint32_t Number, const Twine &FieldName,
+ bool CanBeNegative) {
+ int32_t SignedNum = Number;
+ if (SignedNum < std::numeric_limits<FitType>::min() ||
+ SignedNum > std::numeric_limits<FitType>::max())
+ return createError(FieldName + " (" + Twine(SignedNum) +
+ ") does not fit in " + Twine(sizeof(FitType) * 8) +
+ "-bit signed integer type.",
+ std::errc::value_too_large);
+
+ if (!CanBeNegative && SignedNum < 0)
+ return createError(FieldName + " (" + Twine(SignedNum) +
+ ") cannot be negative.");
+
+ return Error::success();
+}
+
+static Error checkRCInt(RCInt Number, const Twine &FieldName) {
+ if (Number.isLong())
+ return Error::success();
+ return checkNumberFits<uint16_t>(Number, FieldName);
+}
+
+static Error checkIntOrString(IntOrString Value, const Twine &FieldName) {
+ if (!Value.isInt())
+ return Error::success();
+ return checkNumberFits<uint16_t>(Value.getInt(), FieldName);
+}
+
+static bool stripQuotes(StringRef &Str, bool &IsLongString) {
+ if (!Str.contains('"'))
+ return false;
+
+ // Just take the contents of the string, checking if it's been marked long.
+ IsLongString = Str.startswith_lower("L");
+ if (IsLongString)
+ Str = Str.drop_front();
+
+ bool StripSuccess = Str.consume_front("\"") && Str.consume_back("\"");
+ (void)StripSuccess;
+ assert(StripSuccess && "Strings should be enclosed in quotes.");
+ return true;
+}
+
+static UTF16 cp1252ToUnicode(unsigned char C) {
+ static const UTF16 Map80[] = {
+ 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
+ 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
+ 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
+ 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178,
+ };
+ if (C >= 0x80 && C <= 0x9F)
+ return Map80[C - 0x80];
+ return C;
+}
+
+// Describes a way to handle '\0' characters when processing the string.
+// rc.exe tool sometimes behaves in a weird way in postprocessing.
+// If the string to be output is equivalent to a C-string (e.g. in MENU
+// titles), string is (predictably) truncated after first 0-byte.
+// When outputting a string table, the behavior is equivalent to appending
+// '\0\0' at the end of the string, and then stripping the string
+// before the first '\0\0' occurrence.
+// Finally, when handling strings in user-defined resources, 0-bytes
+// aren't stripped, nor do they terminate the string.
+
+enum class NullHandlingMethod {
+ UserResource, // Don't terminate string on '\0'.
+ CutAtNull, // Terminate string on '\0'.
+ CutAtDoubleNull // Terminate string on '\0\0'; strip final '\0'.
+};
+
+// Parses an identifier or string and returns a processed version of it:
// * Strip the string boundary quotes.
// * Convert the input code page characters to UTF16.
-// * Squash "" to a single ".
-// * Replace the escape sequences with their processed version.
-// For identifiers, this is no-op.
-static Error processString(StringRef Str, NullHandlingMethod NullHandler,
- bool &IsLongString, SmallVectorImpl<UTF16> &Result,
- int CodePage) {
- bool IsString = stripQuotes(Str, IsLongString);
- SmallVector<UTF16, 128> Chars;
-
- // Convert the input bytes according to the chosen codepage.
- if (CodePage == CpUtf8) {
- convertUTF8ToUTF16String(Str, Chars);
- } else if (CodePage == CpWin1252) {
- for (char C : Str)
- Chars.push_back(cp1252ToUnicode((unsigned char)C));
- } else {
- // For other, unknown codepages, only allow plain ASCII input.
- for (char C : Str) {
- if ((unsigned char)C > 0x7F)
- return createError("Non-ASCII 8-bit codepoint (" + Twine(C) +
- ") can't be interpreted in the current codepage");
- Chars.push_back((unsigned char)C);
- }
- }
-
- if (!IsString) {
- // It's an identifier if it's not a string. Make all characters uppercase.
- for (UTF16 &Ch : Chars) {
- assert(Ch <= 0x7F && "We didn't allow identifiers to be non-ASCII");
- Ch = toupper(Ch);
- }
- Result.swap(Chars);
- return Error::success();
- }
- Result.reserve(Chars.size());
- size_t Pos = 0;
-
- auto AddRes = [&Result, NullHandler, IsLongString](UTF16 Char) -> Error {
- if (!IsLongString) {
- if (NullHandler == NullHandlingMethod::UserResource) {
- // Narrow strings in user-defined resources are *not* output in
- // UTF-16 format.
- if (Char > 0xFF)
- return createError("Non-8-bit codepoint (" + Twine(Char) +
- ") can't occur in a user-defined narrow string");
- }
- }
-
- Result.push_back(Char);
- return Error::success();
- };
- auto AddEscapedChar = [AddRes, IsLongString, CodePage](UTF16 Char) -> Error {
- if (!IsLongString) {
- // Escaped chars in narrow strings have to be interpreted according to
- // the chosen code page.
- if (Char > 0xFF)
- return createError("Non-8-bit escaped char (" + Twine(Char) +
- ") can't occur in narrow string");
- if (CodePage == CpUtf8) {
- if (Char >= 0x80)
- return createError("Unable to interpret single byte (" + Twine(Char) +
- ") as UTF-8");
- } else if (CodePage == CpWin1252) {
- Char = cp1252ToUnicode(Char);
- } else {
- // Unknown/unsupported codepage, only allow ASCII input.
- if (Char > 0x7F)
- return createError("Non-ASCII 8-bit codepoint (" + Twine(Char) +
- ") can't "
- "occur in a non-Unicode string");
- }
- }
-
- return AddRes(Char);
- };
-
- while (Pos < Chars.size()) {
- UTF16 CurChar = Chars[Pos];
- ++Pos;
-
- // Strip double "".
- if (CurChar == '"') {
- if (Pos == Chars.size() || Chars[Pos] != '"')
- return createError("Expected \"\"");
- ++Pos;
- RETURN_IF_ERROR(AddRes('"'));
- continue;
- }
-
- if (CurChar == '\\') {
- UTF16 TypeChar = Chars[Pos];
- ++Pos;
-
- if (TypeChar == 'x' || TypeChar == 'X') {
- // Read a hex number. Max number of characters to read differs between
- // narrow and wide strings.
- UTF16 ReadInt = 0;
- size_t RemainingChars = IsLongString ? 4 : 2;
- // We don't want to read non-ASCII hex digits. std:: functions past
- // 0xFF invoke UB.
- //
- // FIXME: actually, Microsoft version probably doesn't check this
- // condition and uses their Unicode version of 'isxdigit'. However,
- // there are some hex-digit Unicode character outside of ASCII, and
- // some of these are actually accepted by rc.exe, the notable example
- // being fullwidth forms (U+FF10..U+FF19 etc.) These can be written
- // instead of ASCII digits in \x... escape sequence and get accepted.
- // However, the resulting hexcodes seem totally unpredictable.
- // We think it's infeasible to try to reproduce this behavior, nor to
- // put effort in order to detect it.
- while (RemainingChars && Pos < Chars.size() && Chars[Pos] < 0x80) {
- if (!isxdigit(Chars[Pos]))
- break;
- char Digit = tolower(Chars[Pos]);
- ++Pos;
-
- ReadInt <<= 4;
- if (isdigit(Digit))
- ReadInt |= Digit - '0';
- else
- ReadInt |= Digit - 'a' + 10;
-
- --RemainingChars;
- }
-
- RETURN_IF_ERROR(AddEscapedChar(ReadInt));
- continue;
- }
-
- if (TypeChar >= '0' && TypeChar < '8') {
- // Read an octal number. Note that we've already read the first digit.
- UTF16 ReadInt = TypeChar - '0';
- size_t RemainingChars = IsLongString ? 6 : 2;
-
- while (RemainingChars && Pos < Chars.size() && Chars[Pos] >= '0' &&
- Chars[Pos] < '8') {
- ReadInt <<= 3;
- ReadInt |= Chars[Pos] - '0';
- --RemainingChars;
- ++Pos;
- }
-
- RETURN_IF_ERROR(AddEscapedChar(ReadInt));
-
- continue;
- }
-
- switch (TypeChar) {
- case 'A':
- case 'a':
- // Windows '\a' translates into '\b' (Backspace).
- RETURN_IF_ERROR(AddRes('\b'));
- break;
-
- case 'n': // Somehow, RC doesn't recognize '\N' and '\R'.
- RETURN_IF_ERROR(AddRes('\n'));
- break;
-
- case 'r':
- RETURN_IF_ERROR(AddRes('\r'));
- break;
-
- case 'T':
- case 't':
- RETURN_IF_ERROR(AddRes('\t'));
- break;
-
- case '\\':
- RETURN_IF_ERROR(AddRes('\\'));
- break;
-
- case '"':
- // RC accepts \" only if another " comes afterwards; then, \"" means
- // a single ".
- if (Pos == Chars.size() || Chars[Pos] != '"')
- return createError("Expected \\\"\"");
- ++Pos;
- RETURN_IF_ERROR(AddRes('"'));
- break;
-
- default:
- // If TypeChar means nothing, \ is should be output to stdout with
- // following char. However, rc.exe consumes these characters when
- // dealing with wide strings.
- if (!IsLongString) {
- RETURN_IF_ERROR(AddRes('\\'));
- RETURN_IF_ERROR(AddRes(TypeChar));
- }
- break;
- }
-
- continue;
- }
-
- // If nothing interesting happens, just output the character.
- RETURN_IF_ERROR(AddRes(CurChar));
- }
-
- switch (NullHandler) {
- case NullHandlingMethod::CutAtNull:
- for (size_t Pos = 0; Pos < Result.size(); ++Pos)
- if (Result[Pos] == '\0')
- Result.resize(Pos);
- break;
-
- case NullHandlingMethod::CutAtDoubleNull:
- for (size_t Pos = 0; Pos + 1 < Result.size(); ++Pos)
- if (Result[Pos] == '\0' && Result[Pos + 1] == '\0')
- Result.resize(Pos);
- if (Result.size() > 0 && Result.back() == '\0')
- Result.pop_back();
- break;
-
- case NullHandlingMethod::UserResource:
- break;
- }
-
- return Error::success();
-}
-
-uint64_t ResourceFileWriter::writeObject(const ArrayRef<uint8_t> Data) {
- uint64_t Result = tell();
- FS->write((const char *)Data.begin(), Data.size());
- return Result;
-}
-
-Error ResourceFileWriter::writeCString(StringRef Str, bool WriteTerminator) {
- SmallVector<UTF16, 128> ProcessedString;
- bool IsLongString;
- RETURN_IF_ERROR(processString(Str, NullHandlingMethod::CutAtNull,
- IsLongString, ProcessedString,
- Params.CodePage));
- for (auto Ch : ProcessedString)
- writeInt<uint16_t>(Ch);
- if (WriteTerminator)
- writeInt<uint16_t>(0);
- return Error::success();
-}
-
-Error ResourceFileWriter::writeIdentifier(const IntOrString &Ident) {
- return writeIntOrString(Ident);
-}
-
-Error ResourceFileWriter::writeIntOrString(const IntOrString &Value) {
- if (!Value.isInt())
- return writeCString(Value.getString());
-
- writeInt<uint16_t>(0xFFFF);
- writeInt<uint16_t>(Value.getInt());
- return Error::success();
-}
-
-void ResourceFileWriter::writeRCInt(RCInt Value) {
- if (Value.isLong())
- writeInt<uint32_t>(Value);
- else
- writeInt<uint16_t>(Value);
-}
-
-Error ResourceFileWriter::appendFile(StringRef Filename) {
- bool IsLong;
- stripQuotes(Filename, IsLong);
-
- auto File = loadFile(Filename);
- if (!File)
- return File.takeError();
-
- *FS << (*File)->getBuffer();
- return Error::success();
-}
-
-void ResourceFileWriter::padStream(uint64_t Length) {
- assert(Length > 0);
- uint64_t Location = tell();
- Location %= Length;
- uint64_t Pad = (Length - Location) % Length;
- for (uint64_t i = 0; i < Pad; ++i)
- writeInt<uint8_t>(0);
-}
-
-Error ResourceFileWriter::handleError(Error Err, const RCResource *Res) {
- if (Err)
- return joinErrors(createError("Error in " + Res->getResourceTypeName() +
- " statement (ID " + Twine(Res->ResName) +
- "): "),
- std::move(Err));
- return Error::success();
-}
-
-Error ResourceFileWriter::visitNullResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeNullBody);
-}
-
-Error ResourceFileWriter::visitAcceleratorsResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeAcceleratorsBody);
-}
-
-Error ResourceFileWriter::visitBitmapResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeBitmapBody);
-}
-
-Error ResourceFileWriter::visitCursorResource(const RCResource *Res) {
- return handleError(visitIconOrCursorResource(Res), Res);
-}
-
-Error ResourceFileWriter::visitDialogResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeDialogBody);
-}
-
-Error ResourceFileWriter::visitIconResource(const RCResource *Res) {
- return handleError(visitIconOrCursorResource(Res), Res);
-}
-
-Error ResourceFileWriter::visitCaptionStmt(const CaptionStmt *Stmt) {
- ObjectData.Caption = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitClassStmt(const ClassStmt *Stmt) {
- ObjectData.Class = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitHTMLResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeHTMLBody);
-}
-
-Error ResourceFileWriter::visitMenuResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeMenuBody);
-}
-
-Error ResourceFileWriter::visitStringTableResource(const RCResource *Base) {
- const auto *Res = cast<StringTableResource>(Base);
-
- ContextKeeper RAII(this);
- RETURN_IF_ERROR(Res->applyStmts(this));
-
- for (auto &String : Res->Table) {
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(String.first, "String ID"));
- uint16_t BundleID = String.first >> 4;
- StringTableInfo::BundleKey Key(BundleID, ObjectData.LanguageInfo);
- auto &BundleData = StringTableData.BundleData;
- auto Iter = BundleData.find(Key);
-
- if (Iter == BundleData.end()) {
- // Need to create a bundle.
- StringTableData.BundleList.push_back(Key);
- auto EmplaceResult = BundleData.emplace(
- Key, StringTableInfo::Bundle(ObjectData, Res->MemoryFlags));
- assert(EmplaceResult.second && "Could not create a bundle");
- Iter = EmplaceResult.first;
- }
-
- RETURN_IF_ERROR(
- insertStringIntoBundle(Iter->second, String.first, String.second));
- }
-
- return Error::success();
-}
-
-Error ResourceFileWriter::visitUserDefinedResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeUserDefinedBody);
-}
-
-Error ResourceFileWriter::visitVersionInfoResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeVersionInfoBody);
-}
-
-Error ResourceFileWriter::visitCharacteristicsStmt(
- const CharacteristicsStmt *Stmt) {
- ObjectData.Characteristics = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitExStyleStmt(const ExStyleStmt *Stmt) {
- ObjectData.ExStyle = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitFontStmt(const FontStmt *Stmt) {
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Size, "Font size"));
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Weight, "Font weight"));
- RETURN_IF_ERROR(checkNumberFits<uint8_t>(Stmt->Charset, "Font charset"));
- ObjectInfo::FontInfo Font{Stmt->Size, Stmt->Name, Stmt->Weight, Stmt->Italic,
- Stmt->Charset};
- ObjectData.Font.emplace(Font);
- return Error::success();
-}
-
-Error ResourceFileWriter::visitLanguageStmt(const LanguageResource *Stmt) {
- RETURN_IF_ERROR(checkNumberFits(Stmt->Lang, 10, "Primary language ID"));
- RETURN_IF_ERROR(checkNumberFits(Stmt->SubLang, 6, "Sublanguage ID"));
- ObjectData.LanguageInfo = Stmt->Lang | (Stmt->SubLang << 10);
- return Error::success();
-}
-
-Error ResourceFileWriter::visitStyleStmt(const StyleStmt *Stmt) {
- ObjectData.Style = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitVersionStmt(const VersionStmt *Stmt) {
- ObjectData.VersionInfo = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::writeResource(
- const RCResource *Res,
- Error (ResourceFileWriter::*BodyWriter)(const RCResource *)) {
- // We don't know the sizes yet.
- object::WinResHeaderPrefix HeaderPrefix{ulittle32_t(0U), ulittle32_t(0U)};
- uint64_t HeaderLoc = writeObject(HeaderPrefix);
-
- auto ResType = Res->getResourceType();
- RETURN_IF_ERROR(checkIntOrString(ResType, "Resource type"));
- RETURN_IF_ERROR(checkIntOrString(Res->ResName, "Resource ID"));
- RETURN_IF_ERROR(handleError(writeIdentifier(ResType), Res));
- RETURN_IF_ERROR(handleError(writeIdentifier(Res->ResName), Res));
-
- // Apply the resource-local optional statements.
- ContextKeeper RAII(this);
- RETURN_IF_ERROR(handleError(Res->applyStmts(this), Res));
-
- padStream(sizeof(uint32_t));
- object::WinResHeaderSuffix HeaderSuffix{
- ulittle32_t(0), // DataVersion; seems to always be 0
- ulittle16_t(Res->MemoryFlags), ulittle16_t(ObjectData.LanguageInfo),
- ulittle32_t(ObjectData.VersionInfo),
- ulittle32_t(ObjectData.Characteristics)};
- writeObject(HeaderSuffix);
-
- uint64_t DataLoc = tell();
- RETURN_IF_ERROR(handleError((this->*BodyWriter)(Res), Res));
- // RETURN_IF_ERROR(handleError(dumpResource(Ctx)));
-
- // Update the sizes.
- HeaderPrefix.DataSize = tell() - DataLoc;
- HeaderPrefix.HeaderSize = DataLoc - HeaderLoc;
- writeObjectAt(HeaderPrefix, HeaderLoc);
- padStream(sizeof(uint32_t));
-
- return Error::success();
-}
-
-// --- NullResource helpers. --- //
-
-Error ResourceFileWriter::writeNullBody(const RCResource *) {
- return Error::success();
-}
-
-// --- AcceleratorsResource helpers. --- //
-
-Error ResourceFileWriter::writeSingleAccelerator(
- const AcceleratorsResource::Accelerator &Obj, bool IsLastItem) {
- using Accelerator = AcceleratorsResource::Accelerator;
- using Opt = Accelerator::Options;
-
- struct AccelTableEntry {
- ulittle16_t Flags;
- ulittle16_t ANSICode;
- ulittle16_t Id;
- uint16_t Padding;
- } Entry{ulittle16_t(0), ulittle16_t(0), ulittle16_t(0), 0};
-
- bool IsASCII = Obj.Flags & Opt::ASCII, IsVirtKey = Obj.Flags & Opt::VIRTKEY;
-
- // Remove ASCII flags (which doesn't occur in .res files).
- Entry.Flags = Obj.Flags & ~Opt::ASCII;
-
- if (IsLastItem)
- Entry.Flags |= 0x80;
-
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(Obj.Id, "ACCELERATORS entry ID"));
- Entry.Id = ulittle16_t(Obj.Id);
-
- auto createAccError = [&Obj](const char *Msg) {
- return createError("Accelerator ID " + Twine(Obj.Id) + ": " + Msg);
- };
-
- if (IsASCII && IsVirtKey)
- return createAccError("Accelerator can't be both ASCII and VIRTKEY");
-
- if (!IsVirtKey && (Obj.Flags & (Opt::ALT | Opt::SHIFT | Opt::CONTROL)))
- return createAccError("Can only apply ALT, SHIFT or CONTROL to VIRTKEY"
- " accelerators");
-
- if (Obj.Event.isInt()) {
- if (!IsASCII && !IsVirtKey)
- return createAccError(
- "Accelerator with a numeric event must be either ASCII"
- " or VIRTKEY");
-
- uint32_t EventVal = Obj.Event.getInt();
- RETURN_IF_ERROR(
- checkNumberFits<uint16_t>(EventVal, "Numeric event key ID"));
- Entry.ANSICode = ulittle16_t(EventVal);
- writeObject(Entry);
- return Error::success();
- }
-
- StringRef Str = Obj.Event.getString();
- bool IsWide;
- stripQuotes(Str, IsWide);
-
- if (Str.size() == 0 || Str.size() > 2)
- return createAccError(
- "Accelerator string events should have length 1 or 2");
-
- if (Str[0] == '^') {
- if (Str.size() == 1)
- return createAccError("No character following '^' in accelerator event");
- if (IsVirtKey)
- return createAccError(
- "VIRTKEY accelerator events can't be preceded by '^'");
-
- char Ch = Str[1];
- if (Ch >= 'a' && Ch <= 'z')
- Entry.ANSICode = ulittle16_t(Ch - 'a' + 1);
- else if (Ch >= 'A' && Ch <= 'Z')
- Entry.ANSICode = ulittle16_t(Ch - 'A' + 1);
- else
- return createAccError("Control character accelerator event should be"
- " alphabetic");
-
- writeObject(Entry);
- return Error::success();
- }
-
- if (Str.size() == 2)
- return createAccError("Event string should be one-character, possibly"
- " preceded by '^'");
-
- uint8_t EventCh = Str[0];
- // The original tool just warns in this situation. We chose to fail.
- if (IsVirtKey && !isalnum(EventCh))
- return createAccError("Non-alphanumeric characters cannot describe virtual"
- " keys");
- if (EventCh > 0x7F)
- return createAccError("Non-ASCII description of accelerator");
-
- if (IsVirtKey)
- EventCh = toupper(EventCh);
- Entry.ANSICode = ulittle16_t(EventCh);
- writeObject(Entry);
- return Error::success();
-}
-
-Error ResourceFileWriter::writeAcceleratorsBody(const RCResource *Base) {
- auto *Res = cast<AcceleratorsResource>(Base);
- size_t AcceleratorId = 0;
- for (auto &Acc : Res->Accelerators) {
- ++AcceleratorId;
- RETURN_IF_ERROR(
- writeSingleAccelerator(Acc, AcceleratorId == Res->Accelerators.size()));
- }
- return Error::success();
-}
-
-// --- BitmapResource helpers. --- //
-
-Error ResourceFileWriter::writeBitmapBody(const RCResource *Base) {
- StringRef Filename = cast<BitmapResource>(Base)->BitmapLoc;
- bool IsLong;
- stripQuotes(Filename, IsLong);
-
- auto File = loadFile(Filename);
- if (!File)
- return File.takeError();
-
- StringRef Buffer = (*File)->getBuffer();
-
- // Skip the 14 byte BITMAPFILEHEADER.
- constexpr size_t BITMAPFILEHEADER_size = 14;
- if (Buffer.size() < BITMAPFILEHEADER_size || Buffer[0] != 'B' ||
- Buffer[1] != 'M')
- return createError("Incorrect bitmap file.");
-
- *FS << Buffer.substr(BITMAPFILEHEADER_size);
- return Error::success();
-}
-
-// --- CursorResource and IconResource helpers. --- //
-
-// ICONRESDIR structure. Describes a single icon in resource group.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648016.aspx
-struct IconResDir {
- uint8_t Width;
- uint8_t Height;
- uint8_t ColorCount;
- uint8_t Reserved;
-};
-
-// CURSORDIR structure. Describes a single cursor in resource group.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648011(v=vs.85).aspx
-struct CursorDir {
- ulittle16_t Width;
- ulittle16_t Height;
-};
-
-// RESDIRENTRY structure, stripped from the last item. Stripping made
-// for compatibility with RESDIR.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026(v=vs.85).aspx
-struct ResourceDirEntryStart {
- union {
- CursorDir Cursor; // Used in CURSOR resources.
- IconResDir Icon; // Used in .ico and .cur files, and ICON resources.
- };
- ulittle16_t Planes; // HotspotX (.cur files but not CURSOR resource).
- ulittle16_t BitCount; // HotspotY (.cur files but not CURSOR resource).
- ulittle32_t Size;
- // ulittle32_t ImageOffset; // Offset to image data (ICONDIRENTRY only).
- // ulittle16_t IconID; // Resource icon ID (RESDIR only).
-};
-
-// BITMAPINFOHEADER structure. Describes basic information about the bitmap
-// being read.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
-struct BitmapInfoHeader {
- ulittle32_t Size;
- ulittle32_t Width;
- ulittle32_t Height;
- ulittle16_t Planes;
- ulittle16_t BitCount;
- ulittle32_t Compression;
- ulittle32_t SizeImage;
- ulittle32_t XPelsPerMeter;
- ulittle32_t YPelsPerMeter;
- ulittle32_t ClrUsed;
- ulittle32_t ClrImportant;
-};
-
-// Group icon directory header. Called ICONDIR in .ico/.cur files and
-// NEWHEADER in .res files.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648023(v=vs.85).aspx
-struct GroupIconDir {
- ulittle16_t Reserved; // Always 0.
- ulittle16_t ResType; // 1 for icons, 2 for cursors.
- ulittle16_t ResCount; // Number of items.
-};
-
-enum class IconCursorGroupType { Icon, Cursor };
-
-class SingleIconCursorResource : public RCResource {
-public:
- IconCursorGroupType Type;
- const ResourceDirEntryStart &Header;
- ArrayRef<uint8_t> Image;
-
- SingleIconCursorResource(IconCursorGroupType ResourceType,
- const ResourceDirEntryStart &HeaderEntry,
- ArrayRef<uint8_t> ImageData, uint16_t Flags)
- : RCResource(Flags), Type(ResourceType), Header(HeaderEntry),
- Image(ImageData) {}
-
- Twine getResourceTypeName() const override { return "Icon/cursor image"; }
- IntOrString getResourceType() const override {
- return Type == IconCursorGroupType::Icon ? RkSingleIcon : RkSingleCursor;
- }
- ResourceKind getKind() const override { return RkSingleCursorOrIconRes; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkSingleCursorOrIconRes;
- }
-};
-
-class IconCursorGroupResource : public RCResource {
-public:
- IconCursorGroupType Type;
- GroupIconDir Header;
- std::vector<ResourceDirEntryStart> ItemEntries;
-
- IconCursorGroupResource(IconCursorGroupType ResourceType,
- const GroupIconDir &HeaderData,
- std::vector<ResourceDirEntryStart> &&Entries)
- : Type(ResourceType), Header(HeaderData),
- ItemEntries(std::move(Entries)) {}
-
- Twine getResourceTypeName() const override { return "Icon/cursor group"; }
- IntOrString getResourceType() const override {
- return Type == IconCursorGroupType::Icon ? RkIconGroup : RkCursorGroup;
- }
- ResourceKind getKind() const override { return RkCursorOrIconGroupRes; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkCursorOrIconGroupRes;
- }
-};
-
-Error ResourceFileWriter::writeSingleIconOrCursorBody(const RCResource *Base) {
- auto *Res = cast<SingleIconCursorResource>(Base);
- if (Res->Type == IconCursorGroupType::Cursor) {
- // In case of cursors, two WORDS are appended to the beginning
- // of the resource: HotspotX (Planes in RESDIRENTRY),
- // and HotspotY (BitCount).
- //
- // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026.aspx
- // (Remarks section).
- writeObject(Res->Header.Planes);
- writeObject(Res->Header.BitCount);
- }
-
- writeObject(Res->Image);
- return Error::success();
-}
-
-Error ResourceFileWriter::writeIconOrCursorGroupBody(const RCResource *Base) {
- auto *Res = cast<IconCursorGroupResource>(Base);
- writeObject(Res->Header);
- for (auto Item : Res->ItemEntries) {
- writeObject(Item);
- writeInt(IconCursorID++);
- }
- return Error::success();
-}
-
-Error ResourceFileWriter::visitSingleIconOrCursor(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeSingleIconOrCursorBody);
-}
-
-Error ResourceFileWriter::visitIconOrCursorGroup(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeIconOrCursorGroupBody);
-}
-
-Error ResourceFileWriter::visitIconOrCursorResource(const RCResource *Base) {
- IconCursorGroupType Type;
- StringRef FileStr;
- IntOrString ResName = Base->ResName;
-
- if (auto *IconRes = dyn_cast<IconResource>(Base)) {
- FileStr = IconRes->IconLoc;
- Type = IconCursorGroupType::Icon;
- } else {
- auto *CursorRes = dyn_cast<CursorResource>(Base);
- FileStr = CursorRes->CursorLoc;
- Type = IconCursorGroupType::Cursor;
- }
-
- bool IsLong;
- stripQuotes(FileStr, IsLong);
- auto File = loadFile(FileStr);
-
- if (!File)
- return File.takeError();
-
- BinaryStreamReader Reader((*File)->getBuffer(), support::little);
-
- // Read the file headers.
- // - At the beginning, ICONDIR/NEWHEADER header.
- // - Then, a number of RESDIR headers follow. These contain offsets
- // to data.
- const GroupIconDir *Header;
-
- RETURN_IF_ERROR(Reader.readObject(Header));
- if (Header->Reserved != 0)
- return createError("Incorrect icon/cursor Reserved field; should be 0.");
- uint16_t NeededType = Type == IconCursorGroupType::Icon ? 1 : 2;
- if (Header->ResType != NeededType)
- return createError("Incorrect icon/cursor ResType field; should be " +
- Twine(NeededType) + ".");
-
- uint16_t NumItems = Header->ResCount;
-
- // Read single ico/cur headers.
- std::vector<ResourceDirEntryStart> ItemEntries;
- ItemEntries.reserve(NumItems);
- std::vector<uint32_t> ItemOffsets(NumItems);
- for (size_t ID = 0; ID < NumItems; ++ID) {
- const ResourceDirEntryStart *Object;
- RETURN_IF_ERROR(Reader.readObject(Object));
- ItemEntries.push_back(*Object);
- RETURN_IF_ERROR(Reader.readInteger(ItemOffsets[ID]));
- }
-
- // Now write each icon/cursors one by one. At first, all the contents
- // without ICO/CUR header. This is described by SingleIconCursorResource.
- for (size_t ID = 0; ID < NumItems; ++ID) {
- // Load the fragment of file.
- Reader.setOffset(ItemOffsets[ID]);
- ArrayRef<uint8_t> Image;
- RETURN_IF_ERROR(Reader.readArray(Image, ItemEntries[ID].Size));
- SingleIconCursorResource SingleRes(Type, ItemEntries[ID], Image,
- Base->MemoryFlags);
- SingleRes.setName(IconCursorID + ID);
- RETURN_IF_ERROR(visitSingleIconOrCursor(&SingleRes));
- }
-
- // Now, write all the headers concatenated into a separate resource.
- for (size_t ID = 0; ID < NumItems; ++ID) {
- // We need to rewrite the cursor headers, and fetch actual values
- // for Planes/BitCount.
- const auto &OldHeader = ItemEntries[ID];
- ResourceDirEntryStart NewHeader = OldHeader;
-
- if (Type == IconCursorGroupType::Cursor) {
- NewHeader.Cursor.Width = OldHeader.Icon.Width;
- // Each cursor in fact stores two bitmaps, one under another.
- // Height provided in cursor definition describes the height of the
- // cursor, whereas the value existing in resource definition describes
- // the height of the bitmap. Therefore, we need to double this height.
- NewHeader.Cursor.Height = OldHeader.Icon.Height * 2;
-
- // Two WORDs were written at the beginning of the resource (hotspot
- // location). This is reflected in Size field.
- NewHeader.Size += 2 * sizeof(uint16_t);
- }
-
- // Now, we actually need to read the bitmap header to find
- // the number of planes and the number of bits per pixel.
- Reader.setOffset(ItemOffsets[ID]);
- const BitmapInfoHeader *BMPHeader;
- RETURN_IF_ERROR(Reader.readObject(BMPHeader));
- if (BMPHeader->Size == sizeof(BitmapInfoHeader)) {
- NewHeader.Planes = BMPHeader->Planes;
- NewHeader.BitCount = BMPHeader->BitCount;
- } else {
- // A PNG .ico file.
- // https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473
- // "The image must be in 32bpp"
- NewHeader.Planes = 1;
- NewHeader.BitCount = 32;
- }
-
- ItemEntries[ID] = NewHeader;
- }
-
- IconCursorGroupResource HeaderRes(Type, *Header, std::move(ItemEntries));
- HeaderRes.setName(ResName);
- if (Base->MemoryFlags & MfPreload) {
- HeaderRes.MemoryFlags |= MfPreload;
- HeaderRes.MemoryFlags &= ~MfPure;
- }
- RETURN_IF_ERROR(visitIconOrCursorGroup(&HeaderRes));
-
- return Error::success();
-}
-
-// --- DialogResource helpers. --- //
-
-Error ResourceFileWriter::writeSingleDialogControl(const Control &Ctl,
- bool IsExtended) {
- // Each control should be aligned to DWORD.
- padStream(sizeof(uint32_t));
-
- auto TypeInfo = Control::SupportedCtls.lookup(Ctl.Type);
- IntWithNotMask CtlStyle(TypeInfo.Style);
- CtlStyle |= Ctl.Style.getValueOr(RCInt(0));
- uint32_t CtlExtStyle = Ctl.ExtStyle.getValueOr(0);
-
- // DIALOG(EX) item header prefix.
- if (!IsExtended) {
- struct {
- ulittle32_t Style;
- ulittle32_t ExtStyle;
- } Prefix{ulittle32_t(CtlStyle.getValue()), ulittle32_t(CtlExtStyle)};
- writeObject(Prefix);
- } else {
- struct {
- ulittle32_t HelpID;
- ulittle32_t ExtStyle;
- ulittle32_t Style;
- } Prefix{ulittle32_t(Ctl.HelpID.getValueOr(0)), ulittle32_t(CtlExtStyle),
- ulittle32_t(CtlStyle.getValue())};
- writeObject(Prefix);
- }
-
- // Common fixed-length part.
- RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
- Ctl.X, "Dialog control x-coordinate", true));
- RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
- Ctl.Y, "Dialog control y-coordinate", true));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Ctl.Width, "Dialog control width", false));
- RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
- Ctl.Height, "Dialog control height", false));
- struct {
- ulittle16_t X;
- ulittle16_t Y;
- ulittle16_t Width;
- ulittle16_t Height;
- } Middle{ulittle16_t(Ctl.X), ulittle16_t(Ctl.Y), ulittle16_t(Ctl.Width),
- ulittle16_t(Ctl.Height)};
- writeObject(Middle);
-
- // ID; it's 16-bit in DIALOG and 32-bit in DIALOGEX.
- if (!IsExtended) {
- // It's common to use -1, i.e. UINT32_MAX, for controls one doesn't
- // want to refer to later.
- if (Ctl.ID != static_cast<uint32_t>(-1))
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(
- Ctl.ID, "Control ID in simple DIALOG resource"));
- writeInt<uint16_t>(Ctl.ID);
- } else {
- writeInt<uint32_t>(Ctl.ID);
- }
-
- // Window class - either 0xFFFF + 16-bit integer or a string.
- RETURN_IF_ERROR(writeIntOrString(Ctl.Class));
-
- // Element caption/reference ID. ID is preceded by 0xFFFF.
- RETURN_IF_ERROR(checkIntOrString(Ctl.Title, "Control reference ID"));
- RETURN_IF_ERROR(writeIntOrString(Ctl.Title));
-
- // # bytes of extra creation data count. Don't pass any.
- writeInt<uint16_t>(0);
-
- return Error::success();
-}
-
-Error ResourceFileWriter::writeDialogBody(const RCResource *Base) {
- auto *Res = cast<DialogResource>(Base);
-
- // Default style: WS_POPUP | WS_BORDER | WS_SYSMENU.
- const uint32_t DefaultStyle = 0x80880000;
- const uint32_t StyleFontFlag = 0x40;
- const uint32_t StyleCaptionFlag = 0x00C00000;
-
- uint32_t UsedStyle = ObjectData.Style.getValueOr(DefaultStyle);
- if (ObjectData.Font)
- UsedStyle |= StyleFontFlag;
- else
- UsedStyle &= ~StyleFontFlag;
-
- // Actually, in case of empty (but existent) caption, the examined field
- // is equal to "\"\"". That's why empty captions are still noticed.
- if (ObjectData.Caption != "")
- UsedStyle |= StyleCaptionFlag;
-
- const uint16_t DialogExMagic = 0xFFFF;
- uint32_t ExStyle = ObjectData.ExStyle.getValueOr(0);
-
- // Write DIALOG(EX) header prefix. These are pretty different.
- if (!Res->IsExtended) {
- // We cannot let the higher word of DefaultStyle be equal to 0xFFFF.
- // In such a case, whole object (in .res file) is equivalent to a
- // DIALOGEX. It might lead to access violation/segmentation fault in
- // resource readers. For example,
- // 1 DIALOG 0, 0, 0, 65432
- // STYLE 0xFFFF0001 {}
- // would be compiled to a DIALOGEX with 65432 controls.
- if ((UsedStyle >> 16) == DialogExMagic)
- return createError("16 higher bits of DIALOG resource style cannot be"
- " equal to 0xFFFF");
-
- struct {
- ulittle32_t Style;
- ulittle32_t ExtStyle;
- } Prefix{ulittle32_t(UsedStyle),
- ulittle32_t(ExStyle)};
-
- writeObject(Prefix);
- } else {
- struct {
- ulittle16_t Version;
- ulittle16_t Magic;
- ulittle32_t HelpID;
- ulittle32_t ExtStyle;
- ulittle32_t Style;
- } Prefix{ulittle16_t(1), ulittle16_t(DialogExMagic),
- ulittle32_t(Res->HelpID), ulittle32_t(ExStyle), ulittle32_t(UsedStyle)};
-
- writeObject(Prefix);
- }
-
- // Now, a common part. First, fixed-length fields.
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(Res->Controls.size(),
- "Number of dialog controls"));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Res->X, "Dialog x-coordinate", true));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Res->Y, "Dialog y-coordinate", true));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Res->Width, "Dialog width", false));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Res->Height, "Dialog height", false));
- struct {
- ulittle16_t Count;
- ulittle16_t PosX;
- ulittle16_t PosY;
- ulittle16_t DialogWidth;
- ulittle16_t DialogHeight;
- } Middle{ulittle16_t(Res->Controls.size()), ulittle16_t(Res->X),
- ulittle16_t(Res->Y), ulittle16_t(Res->Width),
- ulittle16_t(Res->Height)};
- writeObject(Middle);
-
- // MENU field. As of now, we don't keep them in the state and can peacefully
- // think there is no menu attached to the dialog.
- writeInt<uint16_t>(0);
-
- // Window CLASS field.
- RETURN_IF_ERROR(writeIntOrString(ObjectData.Class));
-
- // Window title or a single word equal to 0.
- RETURN_IF_ERROR(writeCString(ObjectData.Caption));
-
- // If there *is* a window font declared, output its data.
- auto &Font = ObjectData.Font;
- if (Font) {
- writeInt<uint16_t>(Font->Size);
- // Additional description occurs only in DIALOGEX.
- if (Res->IsExtended) {
- writeInt<uint16_t>(Font->Weight);
- writeInt<uint8_t>(Font->IsItalic);
- writeInt<uint8_t>(Font->Charset);
- }
- RETURN_IF_ERROR(writeCString(Font->Typeface));
- }
-
- auto handleCtlError = [&](Error &&Err, const Control &Ctl) -> Error {
- if (!Err)
- return Error::success();
- return joinErrors(createError("Error in " + Twine(Ctl.Type) +
- " control (ID " + Twine(Ctl.ID) + "):"),
- std::move(Err));
- };
-
- for (auto &Ctl : Res->Controls)
- RETURN_IF_ERROR(
- handleCtlError(writeSingleDialogControl(Ctl, Res->IsExtended), Ctl));
-
- return Error::success();
-}
-
-// --- HTMLResource helpers. --- //
-
-Error ResourceFileWriter::writeHTMLBody(const RCResource *Base) {
- return appendFile(cast<HTMLResource>(Base)->HTMLLoc);
-}
-
-// --- MenuResource helpers. --- //
-
-Error ResourceFileWriter::writeMenuDefinition(
- const std::unique_ptr<MenuDefinition> &Def, uint16_t Flags) {
- assert(Def);
- const MenuDefinition *DefPtr = Def.get();
-
- if (auto *MenuItemPtr = dyn_cast<MenuItem>(DefPtr)) {
- writeInt<uint16_t>(Flags);
- // Some resource files use -1, i.e. UINT32_MAX, for empty menu items.
- if (MenuItemPtr->Id != static_cast<uint32_t>(-1))
- RETURN_IF_ERROR(
- checkNumberFits<uint16_t>(MenuItemPtr->Id, "MENUITEM action ID"));
- writeInt<uint16_t>(MenuItemPtr->Id);
- RETURN_IF_ERROR(writeCString(MenuItemPtr->Name));
- return Error::success();
- }
-
- if (isa<MenuSeparator>(DefPtr)) {
- writeInt<uint16_t>(Flags);
- writeInt<uint32_t>(0);
- return Error::success();
- }
-
- auto *PopupPtr = cast<PopupItem>(DefPtr);
- writeInt<uint16_t>(Flags);
- RETURN_IF_ERROR(writeCString(PopupPtr->Name));
- return writeMenuDefinitionList(PopupPtr->SubItems);
-}
-
-Error ResourceFileWriter::writeMenuDefinitionList(
- const MenuDefinitionList &List) {
- for (auto &Def : List.Definitions) {
- uint16_t Flags = Def->getResFlags();
- // Last element receives an additional 0x80 flag.
- const uint16_t LastElementFlag = 0x0080;
- if (&Def == &List.Definitions.back())
- Flags |= LastElementFlag;
-
- RETURN_IF_ERROR(writeMenuDefinition(Def, Flags));
- }
- return Error::success();
-}
-
-Error ResourceFileWriter::writeMenuBody(const RCResource *Base) {
- // At first, MENUHEADER structure. In fact, these are two WORDs equal to 0.
- // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648018.aspx
- writeInt<uint32_t>(0);
-
- return writeMenuDefinitionList(cast<MenuResource>(Base)->Elements);
-}
-
-// --- StringTableResource helpers. --- //
-
-class BundleResource : public RCResource {
-public:
- using BundleType = ResourceFileWriter::StringTableInfo::Bundle;
- BundleType Bundle;
-
- BundleResource(const BundleType &StrBundle)
- : RCResource(StrBundle.MemoryFlags), Bundle(StrBundle) {}
- IntOrString getResourceType() const override { return 6; }
-
- ResourceKind getKind() const override { return RkStringTableBundle; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkStringTableBundle;
- }
- Twine getResourceTypeName() const override { return "STRINGTABLE"; }
-};
-
-Error ResourceFileWriter::visitStringTableBundle(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeStringTableBundleBody);
-}
-
-Error ResourceFileWriter::insertStringIntoBundle(
- StringTableInfo::Bundle &Bundle, uint16_t StringID,
- const std::vector<StringRef> &String) {
- uint16_t StringLoc = StringID & 15;
- if (Bundle.Data[StringLoc])
- return createError("Multiple STRINGTABLE strings located under ID " +
- Twine(StringID));
- Bundle.Data[StringLoc] = String;
- return Error::success();
-}
-
-Error ResourceFileWriter::writeStringTableBundleBody(const RCResource *Base) {
- auto *Res = cast<BundleResource>(Base);
- for (size_t ID = 0; ID < Res->Bundle.Data.size(); ++ID) {
- // The string format is a tiny bit different here. We
- // first output the size of the string, and then the string itself
- // (which is not null-terminated).
- SmallVector<UTF16, 128> Data;
- if (Res->Bundle.Data[ID]) {
- bool IsLongString;
- for (StringRef S : *Res->Bundle.Data[ID])
- RETURN_IF_ERROR(processString(S, NullHandlingMethod::CutAtDoubleNull,
- IsLongString, Data, Params.CodePage));
- if (AppendNull)
- Data.push_back('\0');
- }
- RETURN_IF_ERROR(
- checkNumberFits<uint16_t>(Data.size(), "STRINGTABLE string size"));
- writeInt<uint16_t>(Data.size());
- for (auto Char : Data)
- writeInt(Char);
- }
- return Error::success();
-}
-
-Error ResourceFileWriter::dumpAllStringTables() {
- for (auto Key : StringTableData.BundleList) {
- auto Iter = StringTableData.BundleData.find(Key);
- assert(Iter != StringTableData.BundleData.end());
-
- // For a moment, revert the context info to moment of bundle declaration.
- ContextKeeper RAII(this);
- ObjectData = Iter->second.DeclTimeInfo;
-
- BundleResource Res(Iter->second);
- // Bundle #(k+1) contains keys [16k, 16k + 15].
- Res.setName(Key.first + 1);
- RETURN_IF_ERROR(visitStringTableBundle(&Res));
- }
- return Error::success();
-}
-
-// --- UserDefinedResource helpers. --- //
-
-Error ResourceFileWriter::writeUserDefinedBody(const RCResource *Base) {
- auto *Res = cast<UserDefinedResource>(Base);
-
- if (Res->IsFileResource)
- return appendFile(Res->FileLoc);
-
- for (auto &Elem : Res->Contents) {
- if (Elem.isInt()) {
- RETURN_IF_ERROR(
- checkRCInt(Elem.getInt(), "Number in user-defined resource"));
- writeRCInt(Elem.getInt());
- continue;
- }
-
- SmallVector<UTF16, 128> ProcessedString;
- bool IsLongString;
- RETURN_IF_ERROR(
- processString(Elem.getString(), NullHandlingMethod::UserResource,
- IsLongString, ProcessedString, Params.CodePage));
-
- for (auto Ch : ProcessedString) {
- if (IsLongString) {
- writeInt(Ch);
- continue;
- }
-
- RETURN_IF_ERROR(checkNumberFits<uint8_t>(
- Ch, "Character in narrow string in user-defined resource"));
- writeInt<uint8_t>(Ch);
- }
- }
-
- return Error::success();
-}
-
-// --- VersionInfoResourceResource helpers. --- //
-
-Error ResourceFileWriter::writeVersionInfoBlock(const VersionInfoBlock &Blk) {
- // Output the header if the block has name.
- bool OutputHeader = Blk.Name != "";
- uint64_t LengthLoc;
-
- padStream(sizeof(uint32_t));
- if (OutputHeader) {
- LengthLoc = writeInt<uint16_t>(0);
- writeInt<uint16_t>(0);
- writeInt<uint16_t>(1); // true
- RETURN_IF_ERROR(writeCString(Blk.Name));
- padStream(sizeof(uint32_t));
- }
-
- for (const std::unique_ptr<VersionInfoStmt> &Item : Blk.Stmts) {
- VersionInfoStmt *ItemPtr = Item.get();
-
- if (auto *BlockPtr = dyn_cast<VersionInfoBlock>(ItemPtr)) {
- RETURN_IF_ERROR(writeVersionInfoBlock(*BlockPtr));
- continue;
- }
-
- auto *ValuePtr = cast<VersionInfoValue>(ItemPtr);
- RETURN_IF_ERROR(writeVersionInfoValue(*ValuePtr));
- }
-
- if (OutputHeader) {
- uint64_t CurLoc = tell();
- writeObjectAt(ulittle16_t(CurLoc - LengthLoc), LengthLoc);
- }
-
- return Error::success();
-}
-
-Error ResourceFileWriter::writeVersionInfoValue(const VersionInfoValue &Val) {
- // rc has a peculiar algorithm to output VERSIONINFO VALUEs. Each VALUE
- // is a mapping from the key (string) to the value (a sequence of ints or
- // a sequence of strings).
- //
- // If integers are to be written: width of each integer written depends on
- // whether it's been declared 'long' (it's DWORD then) or not (it's WORD).
- // ValueLength defined in structure referenced below is then the total
- // number of bytes taken by these integers.
- //
- // If strings are to be written: characters are always WORDs.
- // Moreover, '\0' character is written after the last string, and between
- // every two strings separated by comma (if strings are not comma-separated,
- // they're simply concatenated). ValueLength is equal to the number of WORDs
- // written (that is, half of the bytes written).
- //
- // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms646994.aspx
- bool HasStrings = false, HasInts = false;
- for (auto &Item : Val.Values)
- (Item.isInt() ? HasInts : HasStrings) = true;
-
- assert((HasStrings || HasInts) && "VALUE must have at least one argument");
- if (HasStrings && HasInts)
- return createError(Twine("VALUE ") + Val.Key +
- " cannot contain both strings and integers");
-
- padStream(sizeof(uint32_t));
- auto LengthLoc = writeInt<uint16_t>(0);
- auto ValLengthLoc = writeInt<uint16_t>(0);
- writeInt<uint16_t>(HasStrings);
- RETURN_IF_ERROR(writeCString(Val.Key));
- padStream(sizeof(uint32_t));
-
- auto DataLoc = tell();
- for (size_t Id = 0; Id < Val.Values.size(); ++Id) {
- auto &Item = Val.Values[Id];
- if (Item.isInt()) {
- auto Value = Item.getInt();
- RETURN_IF_ERROR(checkRCInt(Value, "VERSIONINFO integer value"));
- writeRCInt(Value);
- continue;
- }
-
- bool WriteTerminator =
- Id == Val.Values.size() - 1 || Val.HasPrecedingComma[Id + 1];
- RETURN_IF_ERROR(writeCString(Item.getString(), WriteTerminator));
- }
-
- auto CurLoc = tell();
- auto ValueLength = CurLoc - DataLoc;
- if (HasStrings) {
- assert(ValueLength % 2 == 0);
- ValueLength /= 2;
- }
- writeObjectAt(ulittle16_t(CurLoc - LengthLoc), LengthLoc);
- writeObjectAt(ulittle16_t(ValueLength), ValLengthLoc);
- return Error::success();
-}
-
-template <typename Ty>
-static Ty getWithDefault(const StringMap<Ty> &Map, StringRef Key,
- const Ty &Default) {
- auto Iter = Map.find(Key);
- if (Iter != Map.end())
- return Iter->getValue();
- return Default;
-}
-
-Error ResourceFileWriter::writeVersionInfoBody(const RCResource *Base) {
- auto *Res = cast<VersionInfoResource>(Base);
-
- const auto &FixedData = Res->FixedData;
-
- struct /* VS_FIXEDFILEINFO */ {
- ulittle32_t Signature = ulittle32_t(0xFEEF04BD);
- ulittle32_t StructVersion = ulittle32_t(0x10000);
- // It's weird to have most-significant DWORD first on the little-endian
- // machines, but let it be this way.
- ulittle32_t FileVersionMS;
- ulittle32_t FileVersionLS;
- ulittle32_t ProductVersionMS;
- ulittle32_t ProductVersionLS;
- ulittle32_t FileFlagsMask;
- ulittle32_t FileFlags;
- ulittle32_t FileOS;
- ulittle32_t FileType;
- ulittle32_t FileSubtype;
- // MS implementation seems to always set these fields to 0.
- ulittle32_t FileDateMS = ulittle32_t(0);
- ulittle32_t FileDateLS = ulittle32_t(0);
- } FixedInfo;
-
- // First, VS_VERSIONINFO.
- auto LengthLoc = writeInt<uint16_t>(0);
- writeInt<uint16_t>(sizeof(FixedInfo));
- writeInt<uint16_t>(0);
- cantFail(writeCString("VS_VERSION_INFO"));
- padStream(sizeof(uint32_t));
-
- using VersionInfoFixed = VersionInfoResource::VersionInfoFixed;
- auto GetField = [&](VersionInfoFixed::VersionInfoFixedType Type) {
- static const SmallVector<uint32_t, 4> DefaultOut{0, 0, 0, 0};
- if (!FixedData.IsTypePresent[(int)Type])
- return DefaultOut;
- return FixedData.FixedInfo[(int)Type];
- };
-
- auto FileVer = GetField(VersionInfoFixed::FtFileVersion);
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(
- *std::max_element(FileVer.begin(), FileVer.end()), "FILEVERSION fields"));
- FixedInfo.FileVersionMS = (FileVer[0] << 16) | FileVer[1];
- FixedInfo.FileVersionLS = (FileVer[2] << 16) | FileVer[3];
-
- auto ProdVer = GetField(VersionInfoFixed::FtProductVersion);
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(
- *std::max_element(ProdVer.begin(), ProdVer.end()),
- "PRODUCTVERSION fields"));
- FixedInfo.ProductVersionMS = (ProdVer[0] << 16) | ProdVer[1];
- FixedInfo.ProductVersionLS = (ProdVer[2] << 16) | ProdVer[3];
-
- FixedInfo.FileFlagsMask = GetField(VersionInfoFixed::FtFileFlagsMask)[0];
- FixedInfo.FileFlags = GetField(VersionInfoFixed::FtFileFlags)[0];
- FixedInfo.FileOS = GetField(VersionInfoFixed::FtFileOS)[0];
- FixedInfo.FileType = GetField(VersionInfoFixed::FtFileType)[0];
- FixedInfo.FileSubtype = GetField(VersionInfoFixed::FtFileSubtype)[0];
-
- writeObject(FixedInfo);
- padStream(sizeof(uint32_t));
-
- RETURN_IF_ERROR(writeVersionInfoBlock(Res->MainBlock));
-
- // FIXME: check overflow?
- writeObjectAt(ulittle16_t(tell() - LengthLoc), LengthLoc);
-
- return Error::success();
-}
-
-Expected<std::unique_ptr<MemoryBuffer>>
-ResourceFileWriter::loadFile(StringRef File) const {
- SmallString<128> Path;
- SmallString<128> Cwd;
- std::unique_ptr<MemoryBuffer> Result;
-
+// * Squash "" to a single ".
+// * Replace the escape sequences with their processed version.
+// For identifiers, this is no-op.
+static Error processString(StringRef Str, NullHandlingMethod NullHandler,
+ bool &IsLongString, SmallVectorImpl<UTF16> &Result,
+ int CodePage) {
+ bool IsString = stripQuotes(Str, IsLongString);
+ SmallVector<UTF16, 128> Chars;
+
+ // Convert the input bytes according to the chosen codepage.
+ if (CodePage == CpUtf8) {
+ convertUTF8ToUTF16String(Str, Chars);
+ } else if (CodePage == CpWin1252) {
+ for (char C : Str)
+ Chars.push_back(cp1252ToUnicode((unsigned char)C));
+ } else {
+ // For other, unknown codepages, only allow plain ASCII input.
+ for (char C : Str) {
+ if ((unsigned char)C > 0x7F)
+ return createError("Non-ASCII 8-bit codepoint (" + Twine(C) +
+ ") can't be interpreted in the current codepage");
+ Chars.push_back((unsigned char)C);
+ }
+ }
+
+ if (!IsString) {
+ // It's an identifier if it's not a string. Make all characters uppercase.
+ for (UTF16 &Ch : Chars) {
+ assert(Ch <= 0x7F && "We didn't allow identifiers to be non-ASCII");
+ Ch = toupper(Ch);
+ }
+ Result.swap(Chars);
+ return Error::success();
+ }
+ Result.reserve(Chars.size());
+ size_t Pos = 0;
+
+ auto AddRes = [&Result, NullHandler, IsLongString](UTF16 Char) -> Error {
+ if (!IsLongString) {
+ if (NullHandler == NullHandlingMethod::UserResource) {
+ // Narrow strings in user-defined resources are *not* output in
+ // UTF-16 format.
+ if (Char > 0xFF)
+ return createError("Non-8-bit codepoint (" + Twine(Char) +
+ ") can't occur in a user-defined narrow string");
+ }
+ }
+
+ Result.push_back(Char);
+ return Error::success();
+ };
+ auto AddEscapedChar = [AddRes, IsLongString, CodePage](UTF16 Char) -> Error {
+ if (!IsLongString) {
+ // Escaped chars in narrow strings have to be interpreted according to
+ // the chosen code page.
+ if (Char > 0xFF)
+ return createError("Non-8-bit escaped char (" + Twine(Char) +
+ ") can't occur in narrow string");
+ if (CodePage == CpUtf8) {
+ if (Char >= 0x80)
+ return createError("Unable to interpret single byte (" + Twine(Char) +
+ ") as UTF-8");
+ } else if (CodePage == CpWin1252) {
+ Char = cp1252ToUnicode(Char);
+ } else {
+ // Unknown/unsupported codepage, only allow ASCII input.
+ if (Char > 0x7F)
+ return createError("Non-ASCII 8-bit codepoint (" + Twine(Char) +
+ ") can't "
+ "occur in a non-Unicode string");
+ }
+ }
+
+ return AddRes(Char);
+ };
+
+ while (Pos < Chars.size()) {
+ UTF16 CurChar = Chars[Pos];
+ ++Pos;
+
+ // Strip double "".
+ if (CurChar == '"') {
+ if (Pos == Chars.size() || Chars[Pos] != '"')
+ return createError("Expected \"\"");
+ ++Pos;
+ RETURN_IF_ERROR(AddRes('"'));
+ continue;
+ }
+
+ if (CurChar == '\\') {
+ UTF16 TypeChar = Chars[Pos];
+ ++Pos;
+
+ if (TypeChar == 'x' || TypeChar == 'X') {
+ // Read a hex number. Max number of characters to read differs between
+ // narrow and wide strings.
+ UTF16 ReadInt = 0;
+ size_t RemainingChars = IsLongString ? 4 : 2;
+ // We don't want to read non-ASCII hex digits. std:: functions past
+ // 0xFF invoke UB.
+ //
+ // FIXME: actually, Microsoft version probably doesn't check this
+ // condition and uses their Unicode version of 'isxdigit'. However,
+ // there are some hex-digit Unicode character outside of ASCII, and
+ // some of these are actually accepted by rc.exe, the notable example
+ // being fullwidth forms (U+FF10..U+FF19 etc.) These can be written
+ // instead of ASCII digits in \x... escape sequence and get accepted.
+ // However, the resulting hexcodes seem totally unpredictable.
+ // We think it's infeasible to try to reproduce this behavior, nor to
+ // put effort in order to detect it.
+ while (RemainingChars && Pos < Chars.size() && Chars[Pos] < 0x80) {
+ if (!isxdigit(Chars[Pos]))
+ break;
+ char Digit = tolower(Chars[Pos]);
+ ++Pos;
+
+ ReadInt <<= 4;
+ if (isdigit(Digit))
+ ReadInt |= Digit - '0';
+ else
+ ReadInt |= Digit - 'a' + 10;
+
+ --RemainingChars;
+ }
+
+ RETURN_IF_ERROR(AddEscapedChar(ReadInt));
+ continue;
+ }
+
+ if (TypeChar >= '0' && TypeChar < '8') {
+ // Read an octal number. Note that we've already read the first digit.
+ UTF16 ReadInt = TypeChar - '0';
+ size_t RemainingChars = IsLongString ? 6 : 2;
+
+ while (RemainingChars && Pos < Chars.size() && Chars[Pos] >= '0' &&
+ Chars[Pos] < '8') {
+ ReadInt <<= 3;
+ ReadInt |= Chars[Pos] - '0';
+ --RemainingChars;
+ ++Pos;
+ }
+
+ RETURN_IF_ERROR(AddEscapedChar(ReadInt));
+
+ continue;
+ }
+
+ switch (TypeChar) {
+ case 'A':
+ case 'a':
+ // Windows '\a' translates into '\b' (Backspace).
+ RETURN_IF_ERROR(AddRes('\b'));
+ break;
+
+ case 'n': // Somehow, RC doesn't recognize '\N' and '\R'.
+ RETURN_IF_ERROR(AddRes('\n'));
+ break;
+
+ case 'r':
+ RETURN_IF_ERROR(AddRes('\r'));
+ break;
+
+ case 'T':
+ case 't':
+ RETURN_IF_ERROR(AddRes('\t'));
+ break;
+
+ case '\\':
+ RETURN_IF_ERROR(AddRes('\\'));
+ break;
+
+ case '"':
+ // RC accepts \" only if another " comes afterwards; then, \"" means
+ // a single ".
+ if (Pos == Chars.size() || Chars[Pos] != '"')
+ return createError("Expected \\\"\"");
+ ++Pos;
+ RETURN_IF_ERROR(AddRes('"'));
+ break;
+
+ default:
+ // If TypeChar means nothing, \ is should be output to stdout with
+ // following char. However, rc.exe consumes these characters when
+ // dealing with wide strings.
+ if (!IsLongString) {
+ RETURN_IF_ERROR(AddRes('\\'));
+ RETURN_IF_ERROR(AddRes(TypeChar));
+ }
+ break;
+ }
+
+ continue;
+ }
+
+ // If nothing interesting happens, just output the character.
+ RETURN_IF_ERROR(AddRes(CurChar));
+ }
+
+ switch (NullHandler) {
+ case NullHandlingMethod::CutAtNull:
+ for (size_t Pos = 0; Pos < Result.size(); ++Pos)
+ if (Result[Pos] == '\0')
+ Result.resize(Pos);
+ break;
+
+ case NullHandlingMethod::CutAtDoubleNull:
+ for (size_t Pos = 0; Pos + 1 < Result.size(); ++Pos)
+ if (Result[Pos] == '\0' && Result[Pos + 1] == '\0')
+ Result.resize(Pos);
+ if (Result.size() > 0 && Result.back() == '\0')
+ Result.pop_back();
+ break;
+
+ case NullHandlingMethod::UserResource:
+ break;
+ }
+
+ return Error::success();
+}
+
+uint64_t ResourceFileWriter::writeObject(const ArrayRef<uint8_t> Data) {
+ uint64_t Result = tell();
+ FS->write((const char *)Data.begin(), Data.size());
+ return Result;
+}
+
+Error ResourceFileWriter::writeCString(StringRef Str, bool WriteTerminator) {
+ SmallVector<UTF16, 128> ProcessedString;
+ bool IsLongString;
+ RETURN_IF_ERROR(processString(Str, NullHandlingMethod::CutAtNull,
+ IsLongString, ProcessedString,
+ Params.CodePage));
+ for (auto Ch : ProcessedString)
+ writeInt<uint16_t>(Ch);
+ if (WriteTerminator)
+ writeInt<uint16_t>(0);
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeIdentifier(const IntOrString &Ident) {
+ return writeIntOrString(Ident);
+}
+
+Error ResourceFileWriter::writeIntOrString(const IntOrString &Value) {
+ if (!Value.isInt())
+ return writeCString(Value.getString());
+
+ writeInt<uint16_t>(0xFFFF);
+ writeInt<uint16_t>(Value.getInt());
+ return Error::success();
+}
+
+void ResourceFileWriter::writeRCInt(RCInt Value) {
+ if (Value.isLong())
+ writeInt<uint32_t>(Value);
+ else
+ writeInt<uint16_t>(Value);
+}
+
+Error ResourceFileWriter::appendFile(StringRef Filename) {
+ bool IsLong;
+ stripQuotes(Filename, IsLong);
+
+ auto File = loadFile(Filename);
+ if (!File)
+ return File.takeError();
+
+ *FS << (*File)->getBuffer();
+ return Error::success();
+}
+
+void ResourceFileWriter::padStream(uint64_t Length) {
+ assert(Length > 0);
+ uint64_t Location = tell();
+ Location %= Length;
+ uint64_t Pad = (Length - Location) % Length;
+ for (uint64_t i = 0; i < Pad; ++i)
+ writeInt<uint8_t>(0);
+}
+
+Error ResourceFileWriter::handleError(Error Err, const RCResource *Res) {
+ if (Err)
+ return joinErrors(createError("Error in " + Res->getResourceTypeName() +
+ " statement (ID " + Twine(Res->ResName) +
+ "): "),
+ std::move(Err));
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitNullResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeNullBody);
+}
+
+Error ResourceFileWriter::visitAcceleratorsResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeAcceleratorsBody);
+}
+
+Error ResourceFileWriter::visitBitmapResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeBitmapBody);
+}
+
+Error ResourceFileWriter::visitCursorResource(const RCResource *Res) {
+ return handleError(visitIconOrCursorResource(Res), Res);
+}
+
+Error ResourceFileWriter::visitDialogResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeDialogBody);
+}
+
+Error ResourceFileWriter::visitIconResource(const RCResource *Res) {
+ return handleError(visitIconOrCursorResource(Res), Res);
+}
+
+Error ResourceFileWriter::visitCaptionStmt(const CaptionStmt *Stmt) {
+ ObjectData.Caption = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitClassStmt(const ClassStmt *Stmt) {
+ ObjectData.Class = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitHTMLResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeHTMLBody);
+}
+
+Error ResourceFileWriter::visitMenuResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeMenuBody);
+}
+
+Error ResourceFileWriter::visitStringTableResource(const RCResource *Base) {
+ const auto *Res = cast<StringTableResource>(Base);
+
+ ContextKeeper RAII(this);
+ RETURN_IF_ERROR(Res->applyStmts(this));
+
+ for (auto &String : Res->Table) {
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(String.first, "String ID"));
+ uint16_t BundleID = String.first >> 4;
+ StringTableInfo::BundleKey Key(BundleID, ObjectData.LanguageInfo);
+ auto &BundleData = StringTableData.BundleData;
+ auto Iter = BundleData.find(Key);
+
+ if (Iter == BundleData.end()) {
+ // Need to create a bundle.
+ StringTableData.BundleList.push_back(Key);
+ auto EmplaceResult = BundleData.emplace(
+ Key, StringTableInfo::Bundle(ObjectData, Res->MemoryFlags));
+ assert(EmplaceResult.second && "Could not create a bundle");
+ Iter = EmplaceResult.first;
+ }
+
+ RETURN_IF_ERROR(
+ insertStringIntoBundle(Iter->second, String.first, String.second));
+ }
+
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitUserDefinedResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeUserDefinedBody);
+}
+
+Error ResourceFileWriter::visitVersionInfoResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeVersionInfoBody);
+}
+
+Error ResourceFileWriter::visitCharacteristicsStmt(
+ const CharacteristicsStmt *Stmt) {
+ ObjectData.Characteristics = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitExStyleStmt(const ExStyleStmt *Stmt) {
+ ObjectData.ExStyle = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitFontStmt(const FontStmt *Stmt) {
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Size, "Font size"));
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Weight, "Font weight"));
+ RETURN_IF_ERROR(checkNumberFits<uint8_t>(Stmt->Charset, "Font charset"));
+ ObjectInfo::FontInfo Font{Stmt->Size, Stmt->Name, Stmt->Weight, Stmt->Italic,
+ Stmt->Charset};
+ ObjectData.Font.emplace(Font);
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitLanguageStmt(const LanguageResource *Stmt) {
+ RETURN_IF_ERROR(checkNumberFits(Stmt->Lang, 10, "Primary language ID"));
+ RETURN_IF_ERROR(checkNumberFits(Stmt->SubLang, 6, "Sublanguage ID"));
+ ObjectData.LanguageInfo = Stmt->Lang | (Stmt->SubLang << 10);
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitStyleStmt(const StyleStmt *Stmt) {
+ ObjectData.Style = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitVersionStmt(const VersionStmt *Stmt) {
+ ObjectData.VersionInfo = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeResource(
+ const RCResource *Res,
+ Error (ResourceFileWriter::*BodyWriter)(const RCResource *)) {
+ // We don't know the sizes yet.
+ object::WinResHeaderPrefix HeaderPrefix{ulittle32_t(0U), ulittle32_t(0U)};
+ uint64_t HeaderLoc = writeObject(HeaderPrefix);
+
+ auto ResType = Res->getResourceType();
+ RETURN_IF_ERROR(checkIntOrString(ResType, "Resource type"));
+ RETURN_IF_ERROR(checkIntOrString(Res->ResName, "Resource ID"));
+ RETURN_IF_ERROR(handleError(writeIdentifier(ResType), Res));
+ RETURN_IF_ERROR(handleError(writeIdentifier(Res->ResName), Res));
+
+ // Apply the resource-local optional statements.
+ ContextKeeper RAII(this);
+ RETURN_IF_ERROR(handleError(Res->applyStmts(this), Res));
+
+ padStream(sizeof(uint32_t));
+ object::WinResHeaderSuffix HeaderSuffix{
+ ulittle32_t(0), // DataVersion; seems to always be 0
+ ulittle16_t(Res->MemoryFlags), ulittle16_t(ObjectData.LanguageInfo),
+ ulittle32_t(ObjectData.VersionInfo),
+ ulittle32_t(ObjectData.Characteristics)};
+ writeObject(HeaderSuffix);
+
+ uint64_t DataLoc = tell();
+ RETURN_IF_ERROR(handleError((this->*BodyWriter)(Res), Res));
+ // RETURN_IF_ERROR(handleError(dumpResource(Ctx)));
+
+ // Update the sizes.
+ HeaderPrefix.DataSize = tell() - DataLoc;
+ HeaderPrefix.HeaderSize = DataLoc - HeaderLoc;
+ writeObjectAt(HeaderPrefix, HeaderLoc);
+ padStream(sizeof(uint32_t));
+
+ return Error::success();
+}
+
+// --- NullResource helpers. --- //
+
+Error ResourceFileWriter::writeNullBody(const RCResource *) {
+ return Error::success();
+}
+
+// --- AcceleratorsResource helpers. --- //
+
+Error ResourceFileWriter::writeSingleAccelerator(
+ const AcceleratorsResource::Accelerator &Obj, bool IsLastItem) {
+ using Accelerator = AcceleratorsResource::Accelerator;
+ using Opt = Accelerator::Options;
+
+ struct AccelTableEntry {
+ ulittle16_t Flags;
+ ulittle16_t ANSICode;
+ ulittle16_t Id;
+ uint16_t Padding;
+ } Entry{ulittle16_t(0), ulittle16_t(0), ulittle16_t(0), 0};
+
+ bool IsASCII = Obj.Flags & Opt::ASCII, IsVirtKey = Obj.Flags & Opt::VIRTKEY;
+
+ // Remove ASCII flags (which doesn't occur in .res files).
+ Entry.Flags = Obj.Flags & ~Opt::ASCII;
+
+ if (IsLastItem)
+ Entry.Flags |= 0x80;
+
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(Obj.Id, "ACCELERATORS entry ID"));
+ Entry.Id = ulittle16_t(Obj.Id);
+
+ auto createAccError = [&Obj](const char *Msg) {
+ return createError("Accelerator ID " + Twine(Obj.Id) + ": " + Msg);
+ };
+
+ if (IsASCII && IsVirtKey)
+ return createAccError("Accelerator can't be both ASCII and VIRTKEY");
+
+ if (!IsVirtKey && (Obj.Flags & (Opt::ALT | Opt::SHIFT | Opt::CONTROL)))
+ return createAccError("Can only apply ALT, SHIFT or CONTROL to VIRTKEY"
+ " accelerators");
+
+ if (Obj.Event.isInt()) {
+ if (!IsASCII && !IsVirtKey)
+ return createAccError(
+ "Accelerator with a numeric event must be either ASCII"
+ " or VIRTKEY");
+
+ uint32_t EventVal = Obj.Event.getInt();
+ RETURN_IF_ERROR(
+ checkNumberFits<uint16_t>(EventVal, "Numeric event key ID"));
+ Entry.ANSICode = ulittle16_t(EventVal);
+ writeObject(Entry);
+ return Error::success();
+ }
+
+ StringRef Str = Obj.Event.getString();
+ bool IsWide;
+ stripQuotes(Str, IsWide);
+
+ if (Str.size() == 0 || Str.size() > 2)
+ return createAccError(
+ "Accelerator string events should have length 1 or 2");
+
+ if (Str[0] == '^') {
+ if (Str.size() == 1)
+ return createAccError("No character following '^' in accelerator event");
+ if (IsVirtKey)
+ return createAccError(
+ "VIRTKEY accelerator events can't be preceded by '^'");
+
+ char Ch = Str[1];
+ if (Ch >= 'a' && Ch <= 'z')
+ Entry.ANSICode = ulittle16_t(Ch - 'a' + 1);
+ else if (Ch >= 'A' && Ch <= 'Z')
+ Entry.ANSICode = ulittle16_t(Ch - 'A' + 1);
+ else
+ return createAccError("Control character accelerator event should be"
+ " alphabetic");
+
+ writeObject(Entry);
+ return Error::success();
+ }
+
+ if (Str.size() == 2)
+ return createAccError("Event string should be one-character, possibly"
+ " preceded by '^'");
+
+ uint8_t EventCh = Str[0];
+ // The original tool just warns in this situation. We chose to fail.
+ if (IsVirtKey && !isalnum(EventCh))
+ return createAccError("Non-alphanumeric characters cannot describe virtual"
+ " keys");
+ if (EventCh > 0x7F)
+ return createAccError("Non-ASCII description of accelerator");
+
+ if (IsVirtKey)
+ EventCh = toupper(EventCh);
+ Entry.ANSICode = ulittle16_t(EventCh);
+ writeObject(Entry);
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeAcceleratorsBody(const RCResource *Base) {
+ auto *Res = cast<AcceleratorsResource>(Base);
+ size_t AcceleratorId = 0;
+ for (auto &Acc : Res->Accelerators) {
+ ++AcceleratorId;
+ RETURN_IF_ERROR(
+ writeSingleAccelerator(Acc, AcceleratorId == Res->Accelerators.size()));
+ }
+ return Error::success();
+}
+
+// --- BitmapResource helpers. --- //
+
+Error ResourceFileWriter::writeBitmapBody(const RCResource *Base) {
+ StringRef Filename = cast<BitmapResource>(Base)->BitmapLoc;
+ bool IsLong;
+ stripQuotes(Filename, IsLong);
+
+ auto File = loadFile(Filename);
+ if (!File)
+ return File.takeError();
+
+ StringRef Buffer = (*File)->getBuffer();
+
+ // Skip the 14 byte BITMAPFILEHEADER.
+ constexpr size_t BITMAPFILEHEADER_size = 14;
+ if (Buffer.size() < BITMAPFILEHEADER_size || Buffer[0] != 'B' ||
+ Buffer[1] != 'M')
+ return createError("Incorrect bitmap file.");
+
+ *FS << Buffer.substr(BITMAPFILEHEADER_size);
+ return Error::success();
+}
+
+// --- CursorResource and IconResource helpers. --- //
+
+// ICONRESDIR structure. Describes a single icon in resource group.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648016.aspx
+struct IconResDir {
+ uint8_t Width;
+ uint8_t Height;
+ uint8_t ColorCount;
+ uint8_t Reserved;
+};
+
+// CURSORDIR structure. Describes a single cursor in resource group.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648011(v=vs.85).aspx
+struct CursorDir {
+ ulittle16_t Width;
+ ulittle16_t Height;
+};
+
+// RESDIRENTRY structure, stripped from the last item. Stripping made
+// for compatibility with RESDIR.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026(v=vs.85).aspx
+struct ResourceDirEntryStart {
+ union {
+ CursorDir Cursor; // Used in CURSOR resources.
+ IconResDir Icon; // Used in .ico and .cur files, and ICON resources.
+ };
+ ulittle16_t Planes; // HotspotX (.cur files but not CURSOR resource).
+ ulittle16_t BitCount; // HotspotY (.cur files but not CURSOR resource).
+ ulittle32_t Size;
+ // ulittle32_t ImageOffset; // Offset to image data (ICONDIRENTRY only).
+ // ulittle16_t IconID; // Resource icon ID (RESDIR only).
+};
+
+// BITMAPINFOHEADER structure. Describes basic information about the bitmap
+// being read.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
+struct BitmapInfoHeader {
+ ulittle32_t Size;
+ ulittle32_t Width;
+ ulittle32_t Height;
+ ulittle16_t Planes;
+ ulittle16_t BitCount;
+ ulittle32_t Compression;
+ ulittle32_t SizeImage;
+ ulittle32_t XPelsPerMeter;
+ ulittle32_t YPelsPerMeter;
+ ulittle32_t ClrUsed;
+ ulittle32_t ClrImportant;
+};
+
+// Group icon directory header. Called ICONDIR in .ico/.cur files and
+// NEWHEADER in .res files.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648023(v=vs.85).aspx
+struct GroupIconDir {
+ ulittle16_t Reserved; // Always 0.
+ ulittle16_t ResType; // 1 for icons, 2 for cursors.
+ ulittle16_t ResCount; // Number of items.
+};
+
+enum class IconCursorGroupType { Icon, Cursor };
+
+class SingleIconCursorResource : public RCResource {
+public:
+ IconCursorGroupType Type;
+ const ResourceDirEntryStart &Header;
+ ArrayRef<uint8_t> Image;
+
+ SingleIconCursorResource(IconCursorGroupType ResourceType,
+ const ResourceDirEntryStart &HeaderEntry,
+ ArrayRef<uint8_t> ImageData, uint16_t Flags)
+ : RCResource(Flags), Type(ResourceType), Header(HeaderEntry),
+ Image(ImageData) {}
+
+ Twine getResourceTypeName() const override { return "Icon/cursor image"; }
+ IntOrString getResourceType() const override {
+ return Type == IconCursorGroupType::Icon ? RkSingleIcon : RkSingleCursor;
+ }
+ ResourceKind getKind() const override { return RkSingleCursorOrIconRes; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkSingleCursorOrIconRes;
+ }
+};
+
+class IconCursorGroupResource : public RCResource {
+public:
+ IconCursorGroupType Type;
+ GroupIconDir Header;
+ std::vector<ResourceDirEntryStart> ItemEntries;
+
+ IconCursorGroupResource(IconCursorGroupType ResourceType,
+ const GroupIconDir &HeaderData,
+ std::vector<ResourceDirEntryStart> &&Entries)
+ : Type(ResourceType), Header(HeaderData),
+ ItemEntries(std::move(Entries)) {}
+
+ Twine getResourceTypeName() const override { return "Icon/cursor group"; }
+ IntOrString getResourceType() const override {
+ return Type == IconCursorGroupType::Icon ? RkIconGroup : RkCursorGroup;
+ }
+ ResourceKind getKind() const override { return RkCursorOrIconGroupRes; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkCursorOrIconGroupRes;
+ }
+};
+
+Error ResourceFileWriter::writeSingleIconOrCursorBody(const RCResource *Base) {
+ auto *Res = cast<SingleIconCursorResource>(Base);
+ if (Res->Type == IconCursorGroupType::Cursor) {
+ // In case of cursors, two WORDS are appended to the beginning
+ // of the resource: HotspotX (Planes in RESDIRENTRY),
+ // and HotspotY (BitCount).
+ //
+ // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026.aspx
+ // (Remarks section).
+ writeObject(Res->Header.Planes);
+ writeObject(Res->Header.BitCount);
+ }
+
+ writeObject(Res->Image);
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeIconOrCursorGroupBody(const RCResource *Base) {
+ auto *Res = cast<IconCursorGroupResource>(Base);
+ writeObject(Res->Header);
+ for (auto Item : Res->ItemEntries) {
+ writeObject(Item);
+ writeInt(IconCursorID++);
+ }
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitSingleIconOrCursor(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeSingleIconOrCursorBody);
+}
+
+Error ResourceFileWriter::visitIconOrCursorGroup(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeIconOrCursorGroupBody);
+}
+
+Error ResourceFileWriter::visitIconOrCursorResource(const RCResource *Base) {
+ IconCursorGroupType Type;
+ StringRef FileStr;
+ IntOrString ResName = Base->ResName;
+
+ if (auto *IconRes = dyn_cast<IconResource>(Base)) {
+ FileStr = IconRes->IconLoc;
+ Type = IconCursorGroupType::Icon;
+ } else {
+ auto *CursorRes = dyn_cast<CursorResource>(Base);
+ FileStr = CursorRes->CursorLoc;
+ Type = IconCursorGroupType::Cursor;
+ }
+
+ bool IsLong;
+ stripQuotes(FileStr, IsLong);
+ auto File = loadFile(FileStr);
+
+ if (!File)
+ return File.takeError();
+
+ BinaryStreamReader Reader((*File)->getBuffer(), support::little);
+
+ // Read the file headers.
+ // - At the beginning, ICONDIR/NEWHEADER header.
+ // - Then, a number of RESDIR headers follow. These contain offsets
+ // to data.
+ const GroupIconDir *Header;
+
+ RETURN_IF_ERROR(Reader.readObject(Header));
+ if (Header->Reserved != 0)
+ return createError("Incorrect icon/cursor Reserved field; should be 0.");
+ uint16_t NeededType = Type == IconCursorGroupType::Icon ? 1 : 2;
+ if (Header->ResType != NeededType)
+ return createError("Incorrect icon/cursor ResType field; should be " +
+ Twine(NeededType) + ".");
+
+ uint16_t NumItems = Header->ResCount;
+
+ // Read single ico/cur headers.
+ std::vector<ResourceDirEntryStart> ItemEntries;
+ ItemEntries.reserve(NumItems);
+ std::vector<uint32_t> ItemOffsets(NumItems);
+ for (size_t ID = 0; ID < NumItems; ++ID) {
+ const ResourceDirEntryStart *Object;
+ RETURN_IF_ERROR(Reader.readObject(Object));
+ ItemEntries.push_back(*Object);
+ RETURN_IF_ERROR(Reader.readInteger(ItemOffsets[ID]));
+ }
+
+ // Now write each icon/cursors one by one. At first, all the contents
+ // without ICO/CUR header. This is described by SingleIconCursorResource.
+ for (size_t ID = 0; ID < NumItems; ++ID) {
+ // Load the fragment of file.
+ Reader.setOffset(ItemOffsets[ID]);
+ ArrayRef<uint8_t> Image;
+ RETURN_IF_ERROR(Reader.readArray(Image, ItemEntries[ID].Size));
+ SingleIconCursorResource SingleRes(Type, ItemEntries[ID], Image,
+ Base->MemoryFlags);
+ SingleRes.setName(IconCursorID + ID);
+ RETURN_IF_ERROR(visitSingleIconOrCursor(&SingleRes));
+ }
+
+ // Now, write all the headers concatenated into a separate resource.
+ for (size_t ID = 0; ID < NumItems; ++ID) {
+ // We need to rewrite the cursor headers, and fetch actual values
+ // for Planes/BitCount.
+ const auto &OldHeader = ItemEntries[ID];
+ ResourceDirEntryStart NewHeader = OldHeader;
+
+ if (Type == IconCursorGroupType::Cursor) {
+ NewHeader.Cursor.Width = OldHeader.Icon.Width;
+ // Each cursor in fact stores two bitmaps, one under another.
+ // Height provided in cursor definition describes the height of the
+ // cursor, whereas the value existing in resource definition describes
+ // the height of the bitmap. Therefore, we need to double this height.
+ NewHeader.Cursor.Height = OldHeader.Icon.Height * 2;
+
+ // Two WORDs were written at the beginning of the resource (hotspot
+ // location). This is reflected in Size field.
+ NewHeader.Size += 2 * sizeof(uint16_t);
+ }
+
+ // Now, we actually need to read the bitmap header to find
+ // the number of planes and the number of bits per pixel.
+ Reader.setOffset(ItemOffsets[ID]);
+ const BitmapInfoHeader *BMPHeader;
+ RETURN_IF_ERROR(Reader.readObject(BMPHeader));
+ if (BMPHeader->Size == sizeof(BitmapInfoHeader)) {
+ NewHeader.Planes = BMPHeader->Planes;
+ NewHeader.BitCount = BMPHeader->BitCount;
+ } else {
+ // A PNG .ico file.
+ // https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473
+ // "The image must be in 32bpp"
+ NewHeader.Planes = 1;
+ NewHeader.BitCount = 32;
+ }
+
+ ItemEntries[ID] = NewHeader;
+ }
+
+ IconCursorGroupResource HeaderRes(Type, *Header, std::move(ItemEntries));
+ HeaderRes.setName(ResName);
+ if (Base->MemoryFlags & MfPreload) {
+ HeaderRes.MemoryFlags |= MfPreload;
+ HeaderRes.MemoryFlags &= ~MfPure;
+ }
+ RETURN_IF_ERROR(visitIconOrCursorGroup(&HeaderRes));
+
+ return Error::success();
+}
+
+// --- DialogResource helpers. --- //
+
+Error ResourceFileWriter::writeSingleDialogControl(const Control &Ctl,
+ bool IsExtended) {
+ // Each control should be aligned to DWORD.
+ padStream(sizeof(uint32_t));
+
+ auto TypeInfo = Control::SupportedCtls.lookup(Ctl.Type);
+ IntWithNotMask CtlStyle(TypeInfo.Style);
+ CtlStyle |= Ctl.Style.getValueOr(RCInt(0));
+ uint32_t CtlExtStyle = Ctl.ExtStyle.getValueOr(0);
+
+ // DIALOG(EX) item header prefix.
+ if (!IsExtended) {
+ struct {
+ ulittle32_t Style;
+ ulittle32_t ExtStyle;
+ } Prefix{ulittle32_t(CtlStyle.getValue()), ulittle32_t(CtlExtStyle)};
+ writeObject(Prefix);
+ } else {
+ struct {
+ ulittle32_t HelpID;
+ ulittle32_t ExtStyle;
+ ulittle32_t Style;
+ } Prefix{ulittle32_t(Ctl.HelpID.getValueOr(0)), ulittle32_t(CtlExtStyle),
+ ulittle32_t(CtlStyle.getValue())};
+ writeObject(Prefix);
+ }
+
+ // Common fixed-length part.
+ RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
+ Ctl.X, "Dialog control x-coordinate", true));
+ RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
+ Ctl.Y, "Dialog control y-coordinate", true));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Ctl.Width, "Dialog control width", false));
+ RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
+ Ctl.Height, "Dialog control height", false));
+ struct {
+ ulittle16_t X;
+ ulittle16_t Y;
+ ulittle16_t Width;
+ ulittle16_t Height;
+ } Middle{ulittle16_t(Ctl.X), ulittle16_t(Ctl.Y), ulittle16_t(Ctl.Width),
+ ulittle16_t(Ctl.Height)};
+ writeObject(Middle);
+
+ // ID; it's 16-bit in DIALOG and 32-bit in DIALOGEX.
+ if (!IsExtended) {
+ // It's common to use -1, i.e. UINT32_MAX, for controls one doesn't
+ // want to refer to later.
+ if (Ctl.ID != static_cast<uint32_t>(-1))
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(
+ Ctl.ID, "Control ID in simple DIALOG resource"));
+ writeInt<uint16_t>(Ctl.ID);
+ } else {
+ writeInt<uint32_t>(Ctl.ID);
+ }
+
+ // Window class - either 0xFFFF + 16-bit integer or a string.
+ RETURN_IF_ERROR(writeIntOrString(Ctl.Class));
+
+ // Element caption/reference ID. ID is preceded by 0xFFFF.
+ RETURN_IF_ERROR(checkIntOrString(Ctl.Title, "Control reference ID"));
+ RETURN_IF_ERROR(writeIntOrString(Ctl.Title));
+
+ // # bytes of extra creation data count. Don't pass any.
+ writeInt<uint16_t>(0);
+
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeDialogBody(const RCResource *Base) {
+ auto *Res = cast<DialogResource>(Base);
+
+ // Default style: WS_POPUP | WS_BORDER | WS_SYSMENU.
+ const uint32_t DefaultStyle = 0x80880000;
+ const uint32_t StyleFontFlag = 0x40;
+ const uint32_t StyleCaptionFlag = 0x00C00000;
+
+ uint32_t UsedStyle = ObjectData.Style.getValueOr(DefaultStyle);
+ if (ObjectData.Font)
+ UsedStyle |= StyleFontFlag;
+ else
+ UsedStyle &= ~StyleFontFlag;
+
+ // Actually, in case of empty (but existent) caption, the examined field
+ // is equal to "\"\"". That's why empty captions are still noticed.
+ if (ObjectData.Caption != "")
+ UsedStyle |= StyleCaptionFlag;
+
+ const uint16_t DialogExMagic = 0xFFFF;
+ uint32_t ExStyle = ObjectData.ExStyle.getValueOr(0);
+
+ // Write DIALOG(EX) header prefix. These are pretty different.
+ if (!Res->IsExtended) {
+ // We cannot let the higher word of DefaultStyle be equal to 0xFFFF.
+ // In such a case, whole object (in .res file) is equivalent to a
+ // DIALOGEX. It might lead to access violation/segmentation fault in
+ // resource readers. For example,
+ // 1 DIALOG 0, 0, 0, 65432
+ // STYLE 0xFFFF0001 {}
+ // would be compiled to a DIALOGEX with 65432 controls.
+ if ((UsedStyle >> 16) == DialogExMagic)
+ return createError("16 higher bits of DIALOG resource style cannot be"
+ " equal to 0xFFFF");
+
+ struct {
+ ulittle32_t Style;
+ ulittle32_t ExtStyle;
+ } Prefix{ulittle32_t(UsedStyle),
+ ulittle32_t(ExStyle)};
+
+ writeObject(Prefix);
+ } else {
+ struct {
+ ulittle16_t Version;
+ ulittle16_t Magic;
+ ulittle32_t HelpID;
+ ulittle32_t ExtStyle;
+ ulittle32_t Style;
+ } Prefix{ulittle16_t(1), ulittle16_t(DialogExMagic),
+ ulittle32_t(Res->HelpID), ulittle32_t(ExStyle), ulittle32_t(UsedStyle)};
+
+ writeObject(Prefix);
+ }
+
+ // Now, a common part. First, fixed-length fields.
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(Res->Controls.size(),
+ "Number of dialog controls"));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Res->X, "Dialog x-coordinate", true));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Res->Y, "Dialog y-coordinate", true));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Res->Width, "Dialog width", false));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Res->Height, "Dialog height", false));
+ struct {
+ ulittle16_t Count;
+ ulittle16_t PosX;
+ ulittle16_t PosY;
+ ulittle16_t DialogWidth;
+ ulittle16_t DialogHeight;
+ } Middle{ulittle16_t(Res->Controls.size()), ulittle16_t(Res->X),
+ ulittle16_t(Res->Y), ulittle16_t(Res->Width),
+ ulittle16_t(Res->Height)};
+ writeObject(Middle);
+
+ // MENU field. As of now, we don't keep them in the state and can peacefully
+ // think there is no menu attached to the dialog.
+ writeInt<uint16_t>(0);
+
+ // Window CLASS field.
+ RETURN_IF_ERROR(writeIntOrString(ObjectData.Class));
+
+ // Window title or a single word equal to 0.
+ RETURN_IF_ERROR(writeCString(ObjectData.Caption));
+
+ // If there *is* a window font declared, output its data.
+ auto &Font = ObjectData.Font;
+ if (Font) {
+ writeInt<uint16_t>(Font->Size);
+ // Additional description occurs only in DIALOGEX.
+ if (Res->IsExtended) {
+ writeInt<uint16_t>(Font->Weight);
+ writeInt<uint8_t>(Font->IsItalic);
+ writeInt<uint8_t>(Font->Charset);
+ }
+ RETURN_IF_ERROR(writeCString(Font->Typeface));
+ }
+
+ auto handleCtlError = [&](Error &&Err, const Control &Ctl) -> Error {
+ if (!Err)
+ return Error::success();
+ return joinErrors(createError("Error in " + Twine(Ctl.Type) +
+ " control (ID " + Twine(Ctl.ID) + "):"),
+ std::move(Err));
+ };
+
+ for (auto &Ctl : Res->Controls)
+ RETURN_IF_ERROR(
+ handleCtlError(writeSingleDialogControl(Ctl, Res->IsExtended), Ctl));
+
+ return Error::success();
+}
+
+// --- HTMLResource helpers. --- //
+
+Error ResourceFileWriter::writeHTMLBody(const RCResource *Base) {
+ return appendFile(cast<HTMLResource>(Base)->HTMLLoc);
+}
+
+// --- MenuResource helpers. --- //
+
+Error ResourceFileWriter::writeMenuDefinition(
+ const std::unique_ptr<MenuDefinition> &Def, uint16_t Flags) {
+ assert(Def);
+ const MenuDefinition *DefPtr = Def.get();
+
+ if (auto *MenuItemPtr = dyn_cast<MenuItem>(DefPtr)) {
+ writeInt<uint16_t>(Flags);
+ // Some resource files use -1, i.e. UINT32_MAX, for empty menu items.
+ if (MenuItemPtr->Id != static_cast<uint32_t>(-1))
+ RETURN_IF_ERROR(
+ checkNumberFits<uint16_t>(MenuItemPtr->Id, "MENUITEM action ID"));
+ writeInt<uint16_t>(MenuItemPtr->Id);
+ RETURN_IF_ERROR(writeCString(MenuItemPtr->Name));
+ return Error::success();
+ }
+
+ if (isa<MenuSeparator>(DefPtr)) {
+ writeInt<uint16_t>(Flags);
+ writeInt<uint32_t>(0);
+ return Error::success();
+ }
+
+ auto *PopupPtr = cast<PopupItem>(DefPtr);
+ writeInt<uint16_t>(Flags);
+ RETURN_IF_ERROR(writeCString(PopupPtr->Name));
+ return writeMenuDefinitionList(PopupPtr->SubItems);
+}
+
+Error ResourceFileWriter::writeMenuDefinitionList(
+ const MenuDefinitionList &List) {
+ for (auto &Def : List.Definitions) {
+ uint16_t Flags = Def->getResFlags();
+ // Last element receives an additional 0x80 flag.
+ const uint16_t LastElementFlag = 0x0080;
+ if (&Def == &List.Definitions.back())
+ Flags |= LastElementFlag;
+
+ RETURN_IF_ERROR(writeMenuDefinition(Def, Flags));
+ }
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeMenuBody(const RCResource *Base) {
+ // At first, MENUHEADER structure. In fact, these are two WORDs equal to 0.
+ // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648018.aspx
+ writeInt<uint32_t>(0);
+
+ return writeMenuDefinitionList(cast<MenuResource>(Base)->Elements);
+}
+
+// --- StringTableResource helpers. --- //
+
+class BundleResource : public RCResource {
+public:
+ using BundleType = ResourceFileWriter::StringTableInfo::Bundle;
+ BundleType Bundle;
+
+ BundleResource(const BundleType &StrBundle)
+ : RCResource(StrBundle.MemoryFlags), Bundle(StrBundle) {}
+ IntOrString getResourceType() const override { return 6; }
+
+ ResourceKind getKind() const override { return RkStringTableBundle; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkStringTableBundle;
+ }
+ Twine getResourceTypeName() const override { return "STRINGTABLE"; }
+};
+
+Error ResourceFileWriter::visitStringTableBundle(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeStringTableBundleBody);
+}
+
+Error ResourceFileWriter::insertStringIntoBundle(
+ StringTableInfo::Bundle &Bundle, uint16_t StringID,
+ const std::vector<StringRef> &String) {
+ uint16_t StringLoc = StringID & 15;
+ if (Bundle.Data[StringLoc])
+ return createError("Multiple STRINGTABLE strings located under ID " +
+ Twine(StringID));
+ Bundle.Data[StringLoc] = String;
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeStringTableBundleBody(const RCResource *Base) {
+ auto *Res = cast<BundleResource>(Base);
+ for (size_t ID = 0; ID < Res->Bundle.Data.size(); ++ID) {
+ // The string format is a tiny bit different here. We
+ // first output the size of the string, and then the string itself
+ // (which is not null-terminated).
+ SmallVector<UTF16, 128> Data;
+ if (Res->Bundle.Data[ID]) {
+ bool IsLongString;
+ for (StringRef S : *Res->Bundle.Data[ID])
+ RETURN_IF_ERROR(processString(S, NullHandlingMethod::CutAtDoubleNull,
+ IsLongString, Data, Params.CodePage));
+ if (AppendNull)
+ Data.push_back('\0');
+ }
+ RETURN_IF_ERROR(
+ checkNumberFits<uint16_t>(Data.size(), "STRINGTABLE string size"));
+ writeInt<uint16_t>(Data.size());
+ for (auto Char : Data)
+ writeInt(Char);
+ }
+ return Error::success();
+}
+
+Error ResourceFileWriter::dumpAllStringTables() {
+ for (auto Key : StringTableData.BundleList) {
+ auto Iter = StringTableData.BundleData.find(Key);
+ assert(Iter != StringTableData.BundleData.end());
+
+ // For a moment, revert the context info to moment of bundle declaration.
+ ContextKeeper RAII(this);
+ ObjectData = Iter->second.DeclTimeInfo;
+
+ BundleResource Res(Iter->second);
+ // Bundle #(k+1) contains keys [16k, 16k + 15].
+ Res.setName(Key.first + 1);
+ RETURN_IF_ERROR(visitStringTableBundle(&Res));
+ }
+ return Error::success();
+}
+
+// --- UserDefinedResource helpers. --- //
+
+Error ResourceFileWriter::writeUserDefinedBody(const RCResource *Base) {
+ auto *Res = cast<UserDefinedResource>(Base);
+
+ if (Res->IsFileResource)
+ return appendFile(Res->FileLoc);
+
+ for (auto &Elem : Res->Contents) {
+ if (Elem.isInt()) {
+ RETURN_IF_ERROR(
+ checkRCInt(Elem.getInt(), "Number in user-defined resource"));
+ writeRCInt(Elem.getInt());
+ continue;
+ }
+
+ SmallVector<UTF16, 128> ProcessedString;
+ bool IsLongString;
+ RETURN_IF_ERROR(
+ processString(Elem.getString(), NullHandlingMethod::UserResource,
+ IsLongString, ProcessedString, Params.CodePage));
+
+ for (auto Ch : ProcessedString) {
+ if (IsLongString) {
+ writeInt(Ch);
+ continue;
+ }
+
+ RETURN_IF_ERROR(checkNumberFits<uint8_t>(
+ Ch, "Character in narrow string in user-defined resource"));
+ writeInt<uint8_t>(Ch);
+ }
+ }
+
+ return Error::success();
+}
+
+// --- VersionInfoResourceResource helpers. --- //
+
+Error ResourceFileWriter::writeVersionInfoBlock(const VersionInfoBlock &Blk) {
+ // Output the header if the block has name.
+ bool OutputHeader = Blk.Name != "";
+ uint64_t LengthLoc;
+
+ padStream(sizeof(uint32_t));
+ if (OutputHeader) {
+ LengthLoc = writeInt<uint16_t>(0);
+ writeInt<uint16_t>(0);
+ writeInt<uint16_t>(1); // true
+ RETURN_IF_ERROR(writeCString(Blk.Name));
+ padStream(sizeof(uint32_t));
+ }
+
+ for (const std::unique_ptr<VersionInfoStmt> &Item : Blk.Stmts) {
+ VersionInfoStmt *ItemPtr = Item.get();
+
+ if (auto *BlockPtr = dyn_cast<VersionInfoBlock>(ItemPtr)) {
+ RETURN_IF_ERROR(writeVersionInfoBlock(*BlockPtr));
+ continue;
+ }
+
+ auto *ValuePtr = cast<VersionInfoValue>(ItemPtr);
+ RETURN_IF_ERROR(writeVersionInfoValue(*ValuePtr));
+ }
+
+ if (OutputHeader) {
+ uint64_t CurLoc = tell();
+ writeObjectAt(ulittle16_t(CurLoc - LengthLoc), LengthLoc);
+ }
+
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeVersionInfoValue(const VersionInfoValue &Val) {
+ // rc has a peculiar algorithm to output VERSIONINFO VALUEs. Each VALUE
+ // is a mapping from the key (string) to the value (a sequence of ints or
+ // a sequence of strings).
+ //
+ // If integers are to be written: width of each integer written depends on
+ // whether it's been declared 'long' (it's DWORD then) or not (it's WORD).
+ // ValueLength defined in structure referenced below is then the total
+ // number of bytes taken by these integers.
+ //
+ // If strings are to be written: characters are always WORDs.
+ // Moreover, '\0' character is written after the last string, and between
+ // every two strings separated by comma (if strings are not comma-separated,
+ // they're simply concatenated). ValueLength is equal to the number of WORDs
+ // written (that is, half of the bytes written).
+ //
+ // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms646994.aspx
+ bool HasStrings = false, HasInts = false;
+ for (auto &Item : Val.Values)
+ (Item.isInt() ? HasInts : HasStrings) = true;
+
+ assert((HasStrings || HasInts) && "VALUE must have at least one argument");
+ if (HasStrings && HasInts)
+ return createError(Twine("VALUE ") + Val.Key +
+ " cannot contain both strings and integers");
+
+ padStream(sizeof(uint32_t));
+ auto LengthLoc = writeInt<uint16_t>(0);
+ auto ValLengthLoc = writeInt<uint16_t>(0);
+ writeInt<uint16_t>(HasStrings);
+ RETURN_IF_ERROR(writeCString(Val.Key));
+ padStream(sizeof(uint32_t));
+
+ auto DataLoc = tell();
+ for (size_t Id = 0; Id < Val.Values.size(); ++Id) {
+ auto &Item = Val.Values[Id];
+ if (Item.isInt()) {
+ auto Value = Item.getInt();
+ RETURN_IF_ERROR(checkRCInt(Value, "VERSIONINFO integer value"));
+ writeRCInt(Value);
+ continue;
+ }
+
+ bool WriteTerminator =
+ Id == Val.Values.size() - 1 || Val.HasPrecedingComma[Id + 1];
+ RETURN_IF_ERROR(writeCString(Item.getString(), WriteTerminator));
+ }
+
+ auto CurLoc = tell();
+ auto ValueLength = CurLoc - DataLoc;
+ if (HasStrings) {
+ assert(ValueLength % 2 == 0);
+ ValueLength /= 2;
+ }
+ writeObjectAt(ulittle16_t(CurLoc - LengthLoc), LengthLoc);
+ writeObjectAt(ulittle16_t(ValueLength), ValLengthLoc);
+ return Error::success();
+}
+
+template <typename Ty>
+static Ty getWithDefault(const StringMap<Ty> &Map, StringRef Key,
+ const Ty &Default) {
+ auto Iter = Map.find(Key);
+ if (Iter != Map.end())
+ return Iter->getValue();
+ return Default;
+}
+
+Error ResourceFileWriter::writeVersionInfoBody(const RCResource *Base) {
+ auto *Res = cast<VersionInfoResource>(Base);
+
+ const auto &FixedData = Res->FixedData;
+
+ struct /* VS_FIXEDFILEINFO */ {
+ ulittle32_t Signature = ulittle32_t(0xFEEF04BD);
+ ulittle32_t StructVersion = ulittle32_t(0x10000);
+ // It's weird to have most-significant DWORD first on the little-endian
+ // machines, but let it be this way.
+ ulittle32_t FileVersionMS;
+ ulittle32_t FileVersionLS;
+ ulittle32_t ProductVersionMS;
+ ulittle32_t ProductVersionLS;
+ ulittle32_t FileFlagsMask;
+ ulittle32_t FileFlags;
+ ulittle32_t FileOS;
+ ulittle32_t FileType;
+ ulittle32_t FileSubtype;
+ // MS implementation seems to always set these fields to 0.
+ ulittle32_t FileDateMS = ulittle32_t(0);
+ ulittle32_t FileDateLS = ulittle32_t(0);
+ } FixedInfo;
+
+ // First, VS_VERSIONINFO.
+ auto LengthLoc = writeInt<uint16_t>(0);
+ writeInt<uint16_t>(sizeof(FixedInfo));
+ writeInt<uint16_t>(0);
+ cantFail(writeCString("VS_VERSION_INFO"));
+ padStream(sizeof(uint32_t));
+
+ using VersionInfoFixed = VersionInfoResource::VersionInfoFixed;
+ auto GetField = [&](VersionInfoFixed::VersionInfoFixedType Type) {
+ static const SmallVector<uint32_t, 4> DefaultOut{0, 0, 0, 0};
+ if (!FixedData.IsTypePresent[(int)Type])
+ return DefaultOut;
+ return FixedData.FixedInfo[(int)Type];
+ };
+
+ auto FileVer = GetField(VersionInfoFixed::FtFileVersion);
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(
+ *std::max_element(FileVer.begin(), FileVer.end()), "FILEVERSION fields"));
+ FixedInfo.FileVersionMS = (FileVer[0] << 16) | FileVer[1];
+ FixedInfo.FileVersionLS = (FileVer[2] << 16) | FileVer[3];
+
+ auto ProdVer = GetField(VersionInfoFixed::FtProductVersion);
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(
+ *std::max_element(ProdVer.begin(), ProdVer.end()),
+ "PRODUCTVERSION fields"));
+ FixedInfo.ProductVersionMS = (ProdVer[0] << 16) | ProdVer[1];
+ FixedInfo.ProductVersionLS = (ProdVer[2] << 16) | ProdVer[3];
+
+ FixedInfo.FileFlagsMask = GetField(VersionInfoFixed::FtFileFlagsMask)[0];
+ FixedInfo.FileFlags = GetField(VersionInfoFixed::FtFileFlags)[0];
+ FixedInfo.FileOS = GetField(VersionInfoFixed::FtFileOS)[0];
+ FixedInfo.FileType = GetField(VersionInfoFixed::FtFileType)[0];
+ FixedInfo.FileSubtype = GetField(VersionInfoFixed::FtFileSubtype)[0];
+
+ writeObject(FixedInfo);
+ padStream(sizeof(uint32_t));
+
+ RETURN_IF_ERROR(writeVersionInfoBlock(Res->MainBlock));
+
+ // FIXME: check overflow?
+ writeObjectAt(ulittle16_t(tell() - LengthLoc), LengthLoc);
+
+ return Error::success();
+}
+
+Expected<std::unique_ptr<MemoryBuffer>>
+ResourceFileWriter::loadFile(StringRef File) const {
+ SmallString<128> Path;
+ SmallString<128> Cwd;
+ std::unique_ptr<MemoryBuffer> Result;
+
// 0. The file path is absolute or has a root directory, so we shouldn't
// try to append it on top of other base directories. (An absolute path
// must have a root directory, but e.g. the path "\dir\file" on windows
@@ -1524,38 +1524,38 @@ ResourceFileWriter::loadFile(StringRef File) const {
// properly though, so if using that to append paths below, this early
// exception case could be removed.)
if (sys::path::has_root_directory(File))
- return errorOrToExpected(MemoryBuffer::getFile(File, -1, false));
-
- // 1. The current working directory.
- sys::fs::current_path(Cwd);
- Path.assign(Cwd.begin(), Cwd.end());
- sys::path::append(Path, File);
- if (sys::fs::exists(Path))
- return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
-
- // 2. The directory of the input resource file, if it is different from the
- // current working directory.
- StringRef InputFileDir = sys::path::parent_path(Params.InputFilePath);
- Path.assign(InputFileDir.begin(), InputFileDir.end());
- sys::path::append(Path, File);
- if (sys::fs::exists(Path))
- return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
-
- // 3. All of the include directories specified on the command line.
- for (StringRef ForceInclude : Params.Include) {
- Path.assign(ForceInclude.begin(), ForceInclude.end());
- sys::path::append(Path, File);
- if (sys::fs::exists(Path))
- return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
- }
-
- if (auto Result =
- llvm::sys::Process::FindInEnvPath("INCLUDE", File, Params.NoInclude))
- return errorOrToExpected(MemoryBuffer::getFile(*Result, -1, false));
-
- return make_error<StringError>("error : file not found : " + Twine(File),
- inconvertibleErrorCode());
-}
-
-} // namespace rc
-} // namespace llvm
+ return errorOrToExpected(MemoryBuffer::getFile(File, -1, false));
+
+ // 1. The current working directory.
+ sys::fs::current_path(Cwd);
+ Path.assign(Cwd.begin(), Cwd.end());
+ sys::path::append(Path, File);
+ if (sys::fs::exists(Path))
+ return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
+
+ // 2. The directory of the input resource file, if it is different from the
+ // current working directory.
+ StringRef InputFileDir = sys::path::parent_path(Params.InputFilePath);
+ Path.assign(InputFileDir.begin(), InputFileDir.end());
+ sys::path::append(Path, File);
+ if (sys::fs::exists(Path))
+ return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
+
+ // 3. All of the include directories specified on the command line.
+ for (StringRef ForceInclude : Params.Include) {
+ Path.assign(ForceInclude.begin(), ForceInclude.end());
+ sys::path::append(Path, File);
+ if (sys::fs::exists(Path))
+ return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
+ }
+
+ if (auto Result =
+ llvm::sys::Process::FindInEnvPath("INCLUDE", File, Params.NoInclude))
+ return errorOrToExpected(MemoryBuffer::getFile(*Result, -1, false));
+
+ return make_error<StringError>("error : file not found : " + Twine(File),
+ inconvertibleErrorCode());
+}
+
+} // namespace rc
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h
index d545a7a9ca..a8802d2220 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h
@@ -1,217 +1,217 @@
-//===-- ResourceSerializator.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
-//
-//===---------------------------------------------------------------------===//
-//
-// This defines a visitor serializing resources to a .res stream.
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H
-
-#include "ResourceScriptStmt.h"
-#include "ResourceVisitor.h"
-
-#include "llvm/Support/Endian.h"
-
-namespace llvm {
-
-class MemoryBuffer;
-
-namespace rc {
-
-enum CodePage {
- CpAcp = 0, // The current used codepage. Since there's no such
- // notion in LLVM what codepage it actually means,
- // this only allows ASCII.
- CpWin1252 = 1252, // A codepage where most 8 bit values correspond to
- // unicode code points with the same value.
- CpUtf8 = 65001, // UTF-8.
-};
-
-struct WriterParams {
- std::vector<std::string> Include; // Additional folders to search for files.
- std::vector<std::string> NoInclude; // Folders to exclude from file search.
- StringRef InputFilePath; // The full path of the input file.
- int CodePage = CpAcp; // The codepage for interpreting characters.
-};
-
-class ResourceFileWriter : public Visitor {
-public:
- ResourceFileWriter(const WriterParams &Params,
- std::unique_ptr<raw_fd_ostream> Stream)
- : Params(Params), FS(std::move(Stream)), IconCursorID(1) {
- assert(FS && "Output stream needs to be provided to the serializator");
- }
-
- Error visitNullResource(const RCResource *) override;
- Error visitAcceleratorsResource(const RCResource *) override;
- Error visitCursorResource(const RCResource *) override;
- Error visitDialogResource(const RCResource *) override;
- Error visitHTMLResource(const RCResource *) override;
- Error visitIconResource(const RCResource *) override;
- Error visitMenuResource(const RCResource *) override;
- Error visitVersionInfoResource(const RCResource *) override;
- Error visitStringTableResource(const RCResource *) override;
- Error visitUserDefinedResource(const RCResource *) override;
-
- Error visitCaptionStmt(const CaptionStmt *) override;
- Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
- Error visitClassStmt(const ClassStmt *) override;
- Error visitExStyleStmt(const ExStyleStmt *) override;
- Error visitFontStmt(const FontStmt *) override;
- Error visitLanguageStmt(const LanguageResource *) override;
- Error visitStyleStmt(const StyleStmt *) override;
- Error visitVersionStmt(const VersionStmt *) override;
-
- // Stringtables are output at the end of .res file. We need a separate
- // function to do it.
- Error dumpAllStringTables();
-
- bool AppendNull = false; // Append '\0' to each existing STRINGTABLE element?
-
- struct ObjectInfo {
- uint16_t LanguageInfo;
- uint32_t Characteristics;
- uint32_t VersionInfo;
-
- Optional<uint32_t> Style;
- Optional<uint32_t> ExStyle;
- StringRef Caption;
- struct FontInfo {
- uint32_t Size;
- StringRef Typeface;
- uint32_t Weight;
- bool IsItalic;
- uint32_t Charset;
- };
- Optional<FontInfo> Font;
- IntOrString Class;
-
- ObjectInfo()
- : LanguageInfo(0), Characteristics(0), VersionInfo(0),
- Class(StringRef()) {}
- } ObjectData;
-
- struct StringTableInfo {
- // Each STRINGTABLE bundle depends on ID of the bundle and language
- // description.
- using BundleKey = std::pair<uint16_t, uint16_t>;
- // Each bundle is in fact an array of 16 strings.
- struct Bundle {
- std::array<Optional<std::vector<StringRef>>, 16> Data;
- ObjectInfo DeclTimeInfo;
- uint16_t MemoryFlags;
- Bundle(const ObjectInfo &Info, uint16_t Flags)
- : DeclTimeInfo(Info), MemoryFlags(Flags) {}
- };
- std::map<BundleKey, Bundle> BundleData;
- // Bundles are listed in the order of their first occurrence.
- std::vector<BundleKey> BundleList;
- } StringTableData;
-
-private:
- Error handleError(Error Err, const RCResource *Res);
-
- Error
- writeResource(const RCResource *Res,
- Error (ResourceFileWriter::*BodyWriter)(const RCResource *));
-
- // NullResource
- Error writeNullBody(const RCResource *);
-
- // AcceleratorsResource
- Error writeSingleAccelerator(const AcceleratorsResource::Accelerator &,
- bool IsLastItem);
- Error writeAcceleratorsBody(const RCResource *);
-
- // BitmapResource
- Error visitBitmapResource(const RCResource *) override;
- Error writeBitmapBody(const RCResource *);
-
- // CursorResource and IconResource
- Error visitIconOrCursorResource(const RCResource *);
- Error visitIconOrCursorGroup(const RCResource *);
- Error visitSingleIconOrCursor(const RCResource *);
- Error writeSingleIconOrCursorBody(const RCResource *);
- Error writeIconOrCursorGroupBody(const RCResource *);
-
- // DialogResource
- Error writeSingleDialogControl(const Control &, bool IsExtended);
- Error writeDialogBody(const RCResource *);
-
- // HTMLResource
- Error writeHTMLBody(const RCResource *);
-
- // MenuResource
- Error writeMenuDefinition(const std::unique_ptr<MenuDefinition> &,
- uint16_t Flags);
- Error writeMenuDefinitionList(const MenuDefinitionList &List);
- Error writeMenuBody(const RCResource *);
-
- // StringTableResource
- Error visitStringTableBundle(const RCResource *);
- Error writeStringTableBundleBody(const RCResource *);
- Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle,
- uint16_t StringID,
- const std::vector<StringRef> &String);
-
- // User defined resource
- Error writeUserDefinedBody(const RCResource *);
-
- // VersionInfoResource
- Error writeVersionInfoBody(const RCResource *);
- Error writeVersionInfoBlock(const VersionInfoBlock &);
- Error writeVersionInfoValue(const VersionInfoValue &);
-
- const WriterParams &Params;
-
- // Output stream handling.
- std::unique_ptr<raw_fd_ostream> FS;
-
- uint64_t tell() const { return FS->tell(); }
-
- uint64_t writeObject(const ArrayRef<uint8_t> Data);
-
- template <typename T> uint64_t writeInt(const T &Value) {
- support::detail::packed_endian_specific_integral<T, support::little,
- support::unaligned>
- Object(Value);
- return writeObject(Object);
- }
-
- template <typename T> uint64_t writeObject(const T &Value) {
- return writeObject(ArrayRef<uint8_t>(
- reinterpret_cast<const uint8_t *>(&Value), sizeof(T)));
- }
-
- template <typename T> void writeObjectAt(const T &Value, uint64_t Position) {
- FS->pwrite((const char *)&Value, sizeof(T), Position);
- }
-
- Error writeCString(StringRef Str, bool WriteTerminator = true);
-
- Error writeIdentifier(const IntOrString &Ident);
- Error writeIntOrString(const IntOrString &Data);
-
- void writeRCInt(RCInt);
-
- Error appendFile(StringRef Filename);
-
- void padStream(uint64_t Length);
-
- Expected<std::unique_ptr<MemoryBuffer>> loadFile(StringRef File) const;
-
- // Icon and cursor IDs are allocated starting from 1 and increasing for
- // each icon/cursor dumped. This maintains the current ID to be allocated.
- uint16_t IconCursorID;
-};
-
-} // namespace rc
-} // namespace llvm
-
-#endif
+//===-- ResourceSerializator.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
+//
+//===---------------------------------------------------------------------===//
+//
+// This defines a visitor serializing resources to a .res stream.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H
+
+#include "ResourceScriptStmt.h"
+#include "ResourceVisitor.h"
+
+#include "llvm/Support/Endian.h"
+
+namespace llvm {
+
+class MemoryBuffer;
+
+namespace rc {
+
+enum CodePage {
+ CpAcp = 0, // The current used codepage. Since there's no such
+ // notion in LLVM what codepage it actually means,
+ // this only allows ASCII.
+ CpWin1252 = 1252, // A codepage where most 8 bit values correspond to
+ // unicode code points with the same value.
+ CpUtf8 = 65001, // UTF-8.
+};
+
+struct WriterParams {
+ std::vector<std::string> Include; // Additional folders to search for files.
+ std::vector<std::string> NoInclude; // Folders to exclude from file search.
+ StringRef InputFilePath; // The full path of the input file.
+ int CodePage = CpAcp; // The codepage for interpreting characters.
+};
+
+class ResourceFileWriter : public Visitor {
+public:
+ ResourceFileWriter(const WriterParams &Params,
+ std::unique_ptr<raw_fd_ostream> Stream)
+ : Params(Params), FS(std::move(Stream)), IconCursorID(1) {
+ assert(FS && "Output stream needs to be provided to the serializator");
+ }
+
+ Error visitNullResource(const RCResource *) override;
+ Error visitAcceleratorsResource(const RCResource *) override;
+ Error visitCursorResource(const RCResource *) override;
+ Error visitDialogResource(const RCResource *) override;
+ Error visitHTMLResource(const RCResource *) override;
+ Error visitIconResource(const RCResource *) override;
+ Error visitMenuResource(const RCResource *) override;
+ Error visitVersionInfoResource(const RCResource *) override;
+ Error visitStringTableResource(const RCResource *) override;
+ Error visitUserDefinedResource(const RCResource *) override;
+
+ Error visitCaptionStmt(const CaptionStmt *) override;
+ Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
+ Error visitClassStmt(const ClassStmt *) override;
+ Error visitExStyleStmt(const ExStyleStmt *) override;
+ Error visitFontStmt(const FontStmt *) override;
+ Error visitLanguageStmt(const LanguageResource *) override;
+ Error visitStyleStmt(const StyleStmt *) override;
+ Error visitVersionStmt(const VersionStmt *) override;
+
+ // Stringtables are output at the end of .res file. We need a separate
+ // function to do it.
+ Error dumpAllStringTables();
+
+ bool AppendNull = false; // Append '\0' to each existing STRINGTABLE element?
+
+ struct ObjectInfo {
+ uint16_t LanguageInfo;
+ uint32_t Characteristics;
+ uint32_t VersionInfo;
+
+ Optional<uint32_t> Style;
+ Optional<uint32_t> ExStyle;
+ StringRef Caption;
+ struct FontInfo {
+ uint32_t Size;
+ StringRef Typeface;
+ uint32_t Weight;
+ bool IsItalic;
+ uint32_t Charset;
+ };
+ Optional<FontInfo> Font;
+ IntOrString Class;
+
+ ObjectInfo()
+ : LanguageInfo(0), Characteristics(0), VersionInfo(0),
+ Class(StringRef()) {}
+ } ObjectData;
+
+ struct StringTableInfo {
+ // Each STRINGTABLE bundle depends on ID of the bundle and language
+ // description.
+ using BundleKey = std::pair<uint16_t, uint16_t>;
+ // Each bundle is in fact an array of 16 strings.
+ struct Bundle {
+ std::array<Optional<std::vector<StringRef>>, 16> Data;
+ ObjectInfo DeclTimeInfo;
+ uint16_t MemoryFlags;
+ Bundle(const ObjectInfo &Info, uint16_t Flags)
+ : DeclTimeInfo(Info), MemoryFlags(Flags) {}
+ };
+ std::map<BundleKey, Bundle> BundleData;
+ // Bundles are listed in the order of their first occurrence.
+ std::vector<BundleKey> BundleList;
+ } StringTableData;
+
+private:
+ Error handleError(Error Err, const RCResource *Res);
+
+ Error
+ writeResource(const RCResource *Res,
+ Error (ResourceFileWriter::*BodyWriter)(const RCResource *));
+
+ // NullResource
+ Error writeNullBody(const RCResource *);
+
+ // AcceleratorsResource
+ Error writeSingleAccelerator(const AcceleratorsResource::Accelerator &,
+ bool IsLastItem);
+ Error writeAcceleratorsBody(const RCResource *);
+
+ // BitmapResource
+ Error visitBitmapResource(const RCResource *) override;
+ Error writeBitmapBody(const RCResource *);
+
+ // CursorResource and IconResource
+ Error visitIconOrCursorResource(const RCResource *);
+ Error visitIconOrCursorGroup(const RCResource *);
+ Error visitSingleIconOrCursor(const RCResource *);
+ Error writeSingleIconOrCursorBody(const RCResource *);
+ Error writeIconOrCursorGroupBody(const RCResource *);
+
+ // DialogResource
+ Error writeSingleDialogControl(const Control &, bool IsExtended);
+ Error writeDialogBody(const RCResource *);
+
+ // HTMLResource
+ Error writeHTMLBody(const RCResource *);
+
+ // MenuResource
+ Error writeMenuDefinition(const std::unique_ptr<MenuDefinition> &,
+ uint16_t Flags);
+ Error writeMenuDefinitionList(const MenuDefinitionList &List);
+ Error writeMenuBody(const RCResource *);
+
+ // StringTableResource
+ Error visitStringTableBundle(const RCResource *);
+ Error writeStringTableBundleBody(const RCResource *);
+ Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle,
+ uint16_t StringID,
+ const std::vector<StringRef> &String);
+
+ // User defined resource
+ Error writeUserDefinedBody(const RCResource *);
+
+ // VersionInfoResource
+ Error writeVersionInfoBody(const RCResource *);
+ Error writeVersionInfoBlock(const VersionInfoBlock &);
+ Error writeVersionInfoValue(const VersionInfoValue &);
+
+ const WriterParams &Params;
+
+ // Output stream handling.
+ std::unique_ptr<raw_fd_ostream> FS;
+
+ uint64_t tell() const { return FS->tell(); }
+
+ uint64_t writeObject(const ArrayRef<uint8_t> Data);
+
+ template <typename T> uint64_t writeInt(const T &Value) {
+ support::detail::packed_endian_specific_integral<T, support::little,
+ support::unaligned>
+ Object(Value);
+ return writeObject(Object);
+ }
+
+ template <typename T> uint64_t writeObject(const T &Value) {
+ return writeObject(ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(&Value), sizeof(T)));
+ }
+
+ template <typename T> void writeObjectAt(const T &Value, uint64_t Position) {
+ FS->pwrite((const char *)&Value, sizeof(T), Position);
+ }
+
+ Error writeCString(StringRef Str, bool WriteTerminator = true);
+
+ Error writeIdentifier(const IntOrString &Ident);
+ Error writeIntOrString(const IntOrString &Data);
+
+ void writeRCInt(RCInt);
+
+ Error appendFile(StringRef Filename);
+
+ void padStream(uint64_t Length);
+
+ Expected<std::unique_ptr<MemoryBuffer>> loadFile(StringRef File) const;
+
+ // Icon and cursor IDs are allocated starting from 1 and increasing for
+ // each icon/cursor dumped. This maintains the current ID to be allocated.
+ uint16_t IconCursorID;
+};
+
+} // namespace rc
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp
index e610be99df..826b212db9 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp
@@ -1,111 +1,111 @@
-//===-- ResourceScriptCppFilter.cpp ----------------------------*- 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
-//
-//===---------------------------------------------------------------------===//
-//
-// This file implements an interface defined in ResourceScriptCppFilter.h.
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceScriptCppFilter.h"
-#include "llvm/ADT/StringExtras.h"
-
-#include <vector>
-
-using namespace llvm;
-
-namespace {
-
-class Filter {
-public:
- explicit Filter(StringRef Input) : Data(Input), DataLength(Input.size()) {}
-
- std::string run();
-
-private:
- // Parse the line, returning whether the line should be included in
- // the output.
- bool parseLine(StringRef Line);
-
- bool streamEof() const;
-
- StringRef Data;
- size_t DataLength;
-
- size_t Pos = 0;
- bool Outputting = true;
-};
-
-std::string Filter::run() {
- std::vector<StringRef> Output;
-
- while (!streamEof() && Pos != StringRef::npos) {
- size_t LineStart = Pos;
- Pos = Data.find_first_of("\r\n", Pos);
- Pos = Data.find_first_not_of("\r\n", Pos);
- StringRef Line = Data.take_front(Pos).drop_front(LineStart);
-
- if (parseLine(Line))
- Output.push_back(Line);
- }
-
- return llvm::join(Output, "");
-}
-
-bool Filter::parseLine(StringRef Line) {
- Line = Line.ltrim();
-
- if (!Line.consume_front("#")) {
- // A normal content line, filtered according to the current mode.
- return Outputting;
- }
-
- // Found a preprocessing directive line. From here on, we always return
- // false since the preprocessing directives should be filtered out.
-
- Line.consume_front("line");
- if (!Line.startswith(" "))
- return false; // Not a line directive (pragma etc).
-
- // #line 123 "path/file.h"
- // # 123 "path/file.h" 1
-
- Line =
- Line.ltrim(); // There could be multiple spaces after the #line directive
-
- size_t N;
- if (Line.consumeInteger(10, N)) // Returns true to signify an error
- return false;
-
- Line = Line.ltrim();
-
- if (!Line.consume_front("\""))
- return false; // Malformed line, no quote found.
-
- // Split the string at the last quote (in case the path name had
- // escaped quotes as well).
- Line = Line.rsplit('"').first;
-
- StringRef Ext = Line.rsplit('.').second;
-
- if (Ext.equals_lower("h") || Ext.equals_lower("c")) {
- Outputting = false;
- } else {
- Outputting = true;
- }
-
- return false;
-}
-
-bool Filter::streamEof() const { return Pos == DataLength; }
-
-} // anonymous namespace
-
-namespace llvm {
-
-std::string filterCppOutput(StringRef Input) { return Filter(Input).run(); }
-
-} // namespace llvm
+//===-- ResourceScriptCppFilter.cpp ----------------------------*- 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
+//
+//===---------------------------------------------------------------------===//
+//
+// This file implements an interface defined in ResourceScriptCppFilter.h.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceScriptCppFilter.h"
+#include "llvm/ADT/StringExtras.h"
+
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+class Filter {
+public:
+ explicit Filter(StringRef Input) : Data(Input), DataLength(Input.size()) {}
+
+ std::string run();
+
+private:
+ // Parse the line, returning whether the line should be included in
+ // the output.
+ bool parseLine(StringRef Line);
+
+ bool streamEof() const;
+
+ StringRef Data;
+ size_t DataLength;
+
+ size_t Pos = 0;
+ bool Outputting = true;
+};
+
+std::string Filter::run() {
+ std::vector<StringRef> Output;
+
+ while (!streamEof() && Pos != StringRef::npos) {
+ size_t LineStart = Pos;
+ Pos = Data.find_first_of("\r\n", Pos);
+ Pos = Data.find_first_not_of("\r\n", Pos);
+ StringRef Line = Data.take_front(Pos).drop_front(LineStart);
+
+ if (parseLine(Line))
+ Output.push_back(Line);
+ }
+
+ return llvm::join(Output, "");
+}
+
+bool Filter::parseLine(StringRef Line) {
+ Line = Line.ltrim();
+
+ if (!Line.consume_front("#")) {
+ // A normal content line, filtered according to the current mode.
+ return Outputting;
+ }
+
+ // Found a preprocessing directive line. From here on, we always return
+ // false since the preprocessing directives should be filtered out.
+
+ Line.consume_front("line");
+ if (!Line.startswith(" "))
+ return false; // Not a line directive (pragma etc).
+
+ // #line 123 "path/file.h"
+ // # 123 "path/file.h" 1
+
+ Line =
+ Line.ltrim(); // There could be multiple spaces after the #line directive
+
+ size_t N;
+ if (Line.consumeInteger(10, N)) // Returns true to signify an error
+ return false;
+
+ Line = Line.ltrim();
+
+ if (!Line.consume_front("\""))
+ return false; // Malformed line, no quote found.
+
+ // Split the string at the last quote (in case the path name had
+ // escaped quotes as well).
+ Line = Line.rsplit('"').first;
+
+ StringRef Ext = Line.rsplit('.').second;
+
+ if (Ext.equals_lower("h") || Ext.equals_lower("c")) {
+ Outputting = false;
+ } else {
+ Outputting = true;
+ }
+
+ return false;
+}
+
+bool Filter::streamEof() const { return Pos == DataLength; }
+
+} // anonymous namespace
+
+namespace llvm {
+
+std::string filterCppOutput(StringRef Input) { return Filter(Input).run(); }
+
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h
index 780db317c9..754dace070 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h
@@ -1,34 +1,34 @@
-//===-- ResourceScriptCppFilter.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
-//
-//===---------------------------------------------------------------------===//
-//
-// This filters the input to llvm-rc for preprocessor markers, removing
-// preprocessing directives that a preprocessor can output or leave behind.
-//
-// It also filters out any contribution from files named *.h or *.c, based
-// on preprocessor line markers. When preprocessing RC files, the included
-// headers can leave behind C declarations, that RC doesn't understand.
-// Rc.exe simply discards anything that comes from files named *.h or *.h.
-//
-// https://msdn.microsoft.com/en-us/library/windows/desktop/aa381033(v=vs.85).aspx
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTCPPFILTER_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTCPPFILTER_H
-
-#include "llvm/ADT/StringRef.h"
-
-#include <string>
-
-namespace llvm {
-
-std::string filterCppOutput(StringRef Input);
-
-} // namespace llvm
-
-#endif
+//===-- ResourceScriptCppFilter.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
+//
+//===---------------------------------------------------------------------===//
+//
+// This filters the input to llvm-rc for preprocessor markers, removing
+// preprocessing directives that a preprocessor can output or leave behind.
+//
+// It also filters out any contribution from files named *.h or *.c, based
+// on preprocessor line markers. When preprocessing RC files, the included
+// headers can leave behind C declarations, that RC doesn't understand.
+// Rc.exe simply discards anything that comes from files named *.h or *.h.
+//
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa381033(v=vs.85).aspx
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTCPPFILTER_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTCPPFILTER_H
+
+#include "llvm/ADT/StringRef.h"
+
+#include <string>
+
+namespace llvm {
+
+std::string filterCppOutput(StringRef Input);
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp
index 5141ac0c38..1dbfc5e8bf 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp
@@ -1,857 +1,857 @@
-//===-- ResourceScriptParser.cpp --------------------------------*- 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
-//
-//===---------------------------------------------------------------------===//
-//
-// This implements the parser defined in ResourceScriptParser.h.
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceScriptParser.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-
-// Take an expression returning llvm::Error and forward the error if it exists.
-#define RETURN_IF_ERROR(Expr) \
- if (auto Err = (Expr)) \
- return std::move(Err);
-
-// Take an expression returning llvm::Expected<T> and assign it to Var or
-// forward the error out of the function.
-#define ASSIGN_OR_RETURN(Var, Expr) \
- auto Var = (Expr); \
- if (!Var) \
- return Var.takeError();
-
-namespace llvm {
-namespace rc {
-
-RCParser::ParserError::ParserError(const Twine &Expected, const LocIter CurLoc,
- const LocIter End)
- : ErrorLoc(CurLoc), FileEnd(End) {
- CurMessage = "Error parsing file: expected " + Expected.str() + ", got " +
- (CurLoc == End ? "<EOF>" : CurLoc->value()).str();
-}
-
-char RCParser::ParserError::ID = 0;
-
-RCParser::RCParser(std::vector<RCToken> TokenList)
- : Tokens(std::move(TokenList)), CurLoc(Tokens.begin()), End(Tokens.end()) {}
-
-bool RCParser::isEof() const { return CurLoc == End; }
-
-RCParser::ParseType RCParser::parseSingleResource() {
- // The first thing we read is usually a resource's name. However, in some
- // cases (LANGUAGE and STRINGTABLE) the resources don't have their names
- // and the first token to be read is the type.
- ASSIGN_OR_RETURN(NameToken, readTypeOrName());
-
- if (NameToken->equalsLower("LANGUAGE"))
- return parseLanguageResource();
- else if (NameToken->equalsLower("STRINGTABLE"))
- return parseStringTableResource();
-
- // If it's not an unnamed resource, what we've just read is a name. Now,
- // read resource type;
- ASSIGN_OR_RETURN(TypeToken, readTypeOrName());
-
- ParseType Result = std::unique_ptr<RCResource>();
- (void)!Result;
-
- if (TypeToken->equalsLower("ACCELERATORS"))
- Result = parseAcceleratorsResource();
- else if (TypeToken->equalsLower("BITMAP"))
- Result = parseBitmapResource();
- else if (TypeToken->equalsLower("CURSOR"))
- Result = parseCursorResource();
- else if (TypeToken->equalsLower("DIALOG"))
- Result = parseDialogResource(false);
- else if (TypeToken->equalsLower("DIALOGEX"))
- Result = parseDialogResource(true);
- else if (TypeToken->equalsLower("HTML"))
- Result = parseHTMLResource();
- else if (TypeToken->equalsLower("ICON"))
- Result = parseIconResource();
- else if (TypeToken->equalsLower("MENU"))
- Result = parseMenuResource();
- else if (TypeToken->equalsLower("RCDATA"))
- Result = parseUserDefinedResource(RkRcData);
- else if (TypeToken->equalsLower("VERSIONINFO"))
- Result = parseVersionInfoResource();
- else
- Result = parseUserDefinedResource(*TypeToken);
-
- if (Result)
- (*Result)->setName(*NameToken);
-
- return Result;
-}
-
-bool RCParser::isNextTokenKind(Kind TokenKind) const {
- return !isEof() && look().kind() == TokenKind;
-}
-
-const RCToken &RCParser::look() const {
- assert(!isEof());
- return *CurLoc;
-}
-
-const RCToken &RCParser::read() {
- assert(!isEof());
- return *CurLoc++;
-}
-
-void RCParser::consume() {
- assert(!isEof());
- CurLoc++;
-}
-
-// An integer description might consist of a single integer or
-// an arithmetic expression evaluating to the integer. The expressions
-// can contain the following tokens: <int> ( ) + - | & ~ not. Their meaning
-// is the same as in C++ except for 'not' expression.
-// The operators in the original RC implementation have the following
-// precedence:
-// 1) Unary operators (- ~ not),
-// 2) Binary operators (+ - & |), with no precedence.
-//
-// 'not' expression is mostly useful for style values. It evaluates to 0,
-// but value given to the operator is stored separately from integer value.
-// It's mostly useful for control style expressions and causes bits from
-// default control style to be excluded from generated style. For binary
-// operators the mask from the right operand is applied to the left operand
-// and masks from both operands are combined in operator result.
-//
-// The following grammar is used to parse the expressions Exp1:
-// Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2
-// Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
-// (More conveniently, Exp1 is a non-empty sequence of Exp2 expressions,
-// separated by binary operators.)
-//
-// Expressions of type Exp1 are read by parseIntExpr1(Inner) method, while Exp2
-// is read by parseIntExpr2().
-//
-// The original Microsoft tool handles multiple unary operators incorrectly.
-// For example, in 16-bit little-endian integers:
-// 1 => 01 00, -1 => ff ff, --1 => ff ff, ---1 => 01 00;
-// 1 => 01 00, ~1 => fe ff, ~~1 => fd ff, ~~~1 => fc ff.
-// Our implementation differs from the original one and handles these
-// operators correctly:
-// 1 => 01 00, -1 => ff ff, --1 => 01 00, ---1 => ff ff;
-// 1 => 01 00, ~1 => fe ff, ~~1 => 01 00, ~~~1 => fe ff.
-
-Expected<RCInt> RCParser::readInt() {
- ASSIGN_OR_RETURN(Value, parseIntExpr1());
- return (*Value).getValue();
-}
-
-Expected<IntWithNotMask> RCParser::parseIntExpr1() {
- // Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2.
- ASSIGN_OR_RETURN(FirstResult, parseIntExpr2());
- IntWithNotMask Result = *FirstResult;
-
- while (!isEof() && look().isBinaryOp()) {
- auto OpToken = read();
- ASSIGN_OR_RETURN(NextResult, parseIntExpr2());
-
- switch (OpToken.kind()) {
- case Kind::Plus:
- Result += *NextResult;
- break;
-
- case Kind::Minus:
- Result -= *NextResult;
- break;
-
- case Kind::Pipe:
- Result |= *NextResult;
- break;
-
- case Kind::Amp:
- Result &= *NextResult;
- break;
-
- default:
- llvm_unreachable("Already processed all binary ops.");
- }
- }
-
- return Result;
-}
-
-Expected<IntWithNotMask> RCParser::parseIntExpr2() {
- // Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
- static const char ErrorMsg[] = "'-', '~', integer or '('";
-
- if (isEof())
- return getExpectedError(ErrorMsg);
-
- switch (look().kind()) {
- case Kind::Minus: {
- consume();
- ASSIGN_OR_RETURN(Result, parseIntExpr2());
- return -(*Result);
- }
-
- case Kind::Tilde: {
- consume();
- ASSIGN_OR_RETURN(Result, parseIntExpr2());
- return ~(*Result);
- }
-
- case Kind::Int:
- return RCInt(read());
-
- case Kind::LeftParen: {
- consume();
- ASSIGN_OR_RETURN(Result, parseIntExpr1());
- RETURN_IF_ERROR(consumeType(Kind::RightParen));
- return *Result;
- }
-
- case Kind::Identifier: {
- if (!read().value().equals_lower("not"))
- return getExpectedError(ErrorMsg, true);
- ASSIGN_OR_RETURN(Result, parseIntExpr2());
- return IntWithNotMask(0, (*Result).getValue());
- }
-
- default:
- return getExpectedError(ErrorMsg);
- }
-}
-
-Expected<StringRef> RCParser::readString() {
- if (!isNextTokenKind(Kind::String))
- return getExpectedError("string");
- return read().value();
-}
-
-Expected<StringRef> RCParser::readFilename() {
- if (!isNextTokenKind(Kind::String) && !isNextTokenKind(Kind::Identifier))
- return getExpectedError("string");
- return read().value();
-}
-
-Expected<StringRef> RCParser::readIdentifier() {
- if (!isNextTokenKind(Kind::Identifier))
- return getExpectedError("identifier");
- return read().value();
-}
-
-Expected<IntOrString> RCParser::readIntOrString() {
- if (!isNextTokenKind(Kind::Int) && !isNextTokenKind(Kind::String))
- return getExpectedError("int or string");
- return IntOrString(read());
-}
-
-Expected<IntOrString> RCParser::readTypeOrName() {
- // We suggest that the correct resource name or type should be either an
- // identifier or an integer. The original RC tool is much more liberal.
- if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int))
- return getExpectedError("int or identifier");
- return IntOrString(read());
-}
-
-Error RCParser::consumeType(Kind TokenKind) {
- if (isNextTokenKind(TokenKind)) {
- consume();
- return Error::success();
- }
-
- switch (TokenKind) {
-#define TOKEN(TokenName) \
- case Kind::TokenName: \
- return getExpectedError(#TokenName);
-#define SHORT_TOKEN(TokenName, TokenCh) \
- case Kind::TokenName: \
- return getExpectedError(#TokenCh);
-#include "ResourceScriptTokenList.def"
- }
-
- llvm_unreachable("All case options exhausted.");
-}
-
-bool RCParser::consumeOptionalType(Kind TokenKind) {
- if (isNextTokenKind(TokenKind)) {
- consume();
- return true;
- }
-
- return false;
-}
-
-Expected<SmallVector<RCInt, 8>> RCParser::readIntsWithCommas(size_t MinCount,
- size_t MaxCount) {
- assert(MinCount <= MaxCount);
-
- SmallVector<RCInt, 8> Result;
-
- auto FailureHandler =
- [&](llvm::Error Err) -> Expected<SmallVector<RCInt, 8>> {
- if (Result.size() < MinCount)
- return std::move(Err);
- consumeError(std::move(Err));
- return Result;
- };
-
- for (size_t i = 0; i < MaxCount; ++i) {
- // Try to read a comma unless we read the first token.
- // Sometimes RC tool requires them and sometimes not. We decide to
- // always require them.
- if (i >= 1) {
- if (auto CommaError = consumeType(Kind::Comma))
- return FailureHandler(std::move(CommaError));
- }
-
- if (auto IntResult = readInt())
- Result.push_back(*IntResult);
- else
- return FailureHandler(IntResult.takeError());
- }
-
- return std::move(Result);
-}
-
-Expected<uint32_t> RCParser::parseFlags(ArrayRef<StringRef> FlagDesc,
- ArrayRef<uint32_t> FlagValues) {
- assert(!FlagDesc.empty());
- assert(FlagDesc.size() == FlagValues.size());
-
- uint32_t Result = 0;
- while (isNextTokenKind(Kind::Comma)) {
- consume();
- ASSIGN_OR_RETURN(FlagResult, readIdentifier());
- bool FoundFlag = false;
-
- for (size_t FlagId = 0; FlagId < FlagDesc.size(); ++FlagId) {
- if (!FlagResult->equals_lower(FlagDesc[FlagId]))
- continue;
-
- Result |= FlagValues[FlagId];
- FoundFlag = true;
- break;
- }
-
- if (!FoundFlag)
- return getExpectedError(join(FlagDesc, "/"), true);
- }
-
- return Result;
-}
-
-uint16_t RCParser::parseMemoryFlags(uint16_t Flags) {
- while (!isEof()) {
- const RCToken &Token = look();
- if (Token.kind() != Kind::Identifier)
- return Flags;
- const StringRef Ident = Token.value();
- if (Ident.equals_lower("PRELOAD"))
- Flags |= MfPreload;
- else if (Ident.equals_lower("LOADONCALL"))
- Flags &= ~MfPreload;
- else if (Ident.equals_lower("FIXED"))
- Flags &= ~(MfMoveable | MfDiscardable);
- else if (Ident.equals_lower("MOVEABLE"))
- Flags |= MfMoveable;
- else if (Ident.equals_lower("DISCARDABLE"))
- Flags |= MfDiscardable | MfMoveable | MfPure;
- else if (Ident.equals_lower("PURE"))
- Flags |= MfPure;
- else if (Ident.equals_lower("IMPURE"))
- Flags &= ~(MfPure | MfDiscardable);
- else if (Ident.equals_lower("SHARED"))
- Flags |= MfPure;
- else if (Ident.equals_lower("NONSHARED"))
- Flags &= ~(MfPure | MfDiscardable);
- else
- return Flags;
- consume();
- }
- return Flags;
-}
-
-Expected<OptionalStmtList>
-RCParser::parseOptionalStatements(OptStmtType StmtsType) {
- OptionalStmtList Result;
-
- // The last statement is always followed by the start of the block.
- while (!isNextTokenKind(Kind::BlockBegin)) {
- ASSIGN_OR_RETURN(SingleParse, parseSingleOptionalStatement(StmtsType));
- Result.addStmt(std::move(*SingleParse));
- }
-
- return std::move(Result);
-}
-
-Expected<std::unique_ptr<OptionalStmt>>
-RCParser::parseSingleOptionalStatement(OptStmtType StmtsType) {
- ASSIGN_OR_RETURN(TypeToken, readIdentifier());
- if (TypeToken->equals_lower("CHARACTERISTICS"))
- return parseCharacteristicsStmt();
- if (TypeToken->equals_lower("LANGUAGE"))
- return parseLanguageStmt();
- if (TypeToken->equals_lower("VERSION"))
- return parseVersionStmt();
-
- if (StmtsType != OptStmtType::BasicStmt) {
- if (TypeToken->equals_lower("CAPTION"))
- return parseCaptionStmt();
- if (TypeToken->equals_lower("CLASS"))
- return parseClassStmt();
- if (TypeToken->equals_lower("EXSTYLE"))
- return parseExStyleStmt();
- if (TypeToken->equals_lower("FONT"))
- return parseFontStmt(StmtsType);
- if (TypeToken->equals_lower("STYLE"))
- return parseStyleStmt();
- }
-
- return getExpectedError("optional statement type, BEGIN or '{'",
- /* IsAlreadyRead = */ true);
-}
-
-RCParser::ParseType RCParser::parseLanguageResource() {
- // Read LANGUAGE as an optional statement. If it's read correctly, we can
- // upcast it to RCResource.
- return parseLanguageStmt();
-}
-
-RCParser::ParseType RCParser::parseAcceleratorsResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(AcceleratorsResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
- RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
-
- auto Accels = std::make_unique<AcceleratorsResource>(
- std::move(*OptStatements), MemoryFlags);
-
- while (!consumeOptionalType(Kind::BlockEnd)) {
- ASSIGN_OR_RETURN(EventResult, readIntOrString());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- ASSIGN_OR_RETURN(IDResult, readInt());
- ASSIGN_OR_RETURN(
- FlagsResult,
- parseFlags(AcceleratorsResource::Accelerator::OptionsStr,
- AcceleratorsResource::Accelerator::OptionsFlags));
- Accels->addAccelerator(*EventResult, *IDResult, *FlagsResult);
- }
-
- return std::move(Accels);
-}
-
-RCParser::ParseType RCParser::parseCursorResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(CursorResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(Arg, readFilename());
- return std::make_unique<CursorResource>(*Arg, MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
- uint16_t MemoryFlags =
- parseMemoryFlags(DialogResource::getDefaultMemoryFlags());
- // Dialog resources have the following format of the arguments:
- // DIALOG: x, y, width, height [opt stmts...] {controls...}
- // DIALOGEX: x, y, width, height [, helpID] [opt stmts...] {controls...}
- // These are very similar, so we parse them together.
- ASSIGN_OR_RETURN(LocResult, readIntsWithCommas(4, 4));
-
- uint32_t HelpID = 0; // When HelpID is unset, it's assumed to be 0.
- if (IsExtended && consumeOptionalType(Kind::Comma)) {
- ASSIGN_OR_RETURN(HelpIDResult, readInt());
- HelpID = *HelpIDResult;
- }
-
- ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements(
- IsExtended ? OptStmtType::DialogExStmt
- : OptStmtType::DialogStmt));
-
- assert(isNextTokenKind(Kind::BlockBegin) &&
- "parseOptionalStatements, when successful, halts on BlockBegin.");
- consume();
-
- auto Dialog = std::make_unique<DialogResource>(
- (*LocResult)[0], (*LocResult)[1], (*LocResult)[2], (*LocResult)[3],
- HelpID, std::move(*OptStatements), IsExtended, MemoryFlags);
-
- while (!consumeOptionalType(Kind::BlockEnd)) {
- ASSIGN_OR_RETURN(ControlDefResult, parseControl());
- Dialog->addControl(std::move(*ControlDefResult));
- }
-
- return std::move(Dialog);
-}
-
-RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
- uint16_t MemoryFlags =
- parseMemoryFlags(UserDefinedResource::getDefaultMemoryFlags());
- if (isEof())
- return getExpectedError("filename, '{' or BEGIN");
-
- // Check if this is a file resource.
- switch (look().kind()) {
- case Kind::String:
- case Kind::Identifier:
- return std::make_unique<UserDefinedResource>(Type, read().value(),
- MemoryFlags);
- default:
- break;
- }
-
- RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
- std::vector<IntOrString> Data;
-
- // Consume comma before each consecutive token except the first one.
- bool ConsumeComma = false;
- while (!consumeOptionalType(Kind::BlockEnd)) {
- if (ConsumeComma)
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- ConsumeComma = true;
-
- ASSIGN_OR_RETURN(Item, readIntOrString());
- Data.push_back(*Item);
- }
-
- return std::make_unique<UserDefinedResource>(Type, std::move(Data),
- MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseVersionInfoResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(VersionInfoResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed());
- ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef()));
- return std::make_unique<VersionInfoResource>(
- std::move(**BlockResult), std::move(*FixedResult), MemoryFlags);
-}
-
-Expected<Control> RCParser::parseControl() {
- // Each control definition (except CONTROL) follows one of the schemes below
- // depending on the control class:
- // [class] text, id, x, y, width, height [, style] [, exstyle] [, helpID]
- // [class] id, x, y, width, height [, style] [, exstyle] [, helpID]
- // Note that control ids must be integers.
- // Text might be either a string or an integer pointing to resource ID.
- ASSIGN_OR_RETURN(ClassResult, readIdentifier());
- std::string ClassUpper = ClassResult->upper();
- auto CtlInfo = Control::SupportedCtls.find(ClassUpper);
- if (CtlInfo == Control::SupportedCtls.end())
- return getExpectedError("control type, END or '}'", true);
-
- // Read caption if necessary.
- IntOrString Caption{StringRef()};
- if (CtlInfo->getValue().HasTitle) {
- ASSIGN_OR_RETURN(CaptionResult, readIntOrString());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- Caption = *CaptionResult;
- }
-
- ASSIGN_OR_RETURN(ID, readInt());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
-
- IntOrString Class;
- Optional<IntWithNotMask> Style;
- if (ClassUpper == "CONTROL") {
- // CONTROL text, id, class, style, x, y, width, height [, exstyle] [, helpID]
- ASSIGN_OR_RETURN(ClassStr, readString());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- Class = *ClassStr;
- ASSIGN_OR_RETURN(StyleVal, parseIntExpr1());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- Style = *StyleVal;
- } else {
- Class = CtlInfo->getValue().CtlClass;
- }
-
- // x, y, width, height
- ASSIGN_OR_RETURN(Args, readIntsWithCommas(4, 4));
-
- if (ClassUpper != "CONTROL") {
- if (consumeOptionalType(Kind::Comma)) {
- ASSIGN_OR_RETURN(Val, parseIntExpr1());
- Style = *Val;
- }
- }
-
- Optional<uint32_t> ExStyle;
- if (consumeOptionalType(Kind::Comma)) {
- ASSIGN_OR_RETURN(Val, readInt());
- ExStyle = *Val;
- }
- Optional<uint32_t> HelpID;
- if (consumeOptionalType(Kind::Comma)) {
- ASSIGN_OR_RETURN(Val, readInt());
- HelpID = *Val;
- }
-
- return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1],
- (*Args)[2], (*Args)[3], Style, ExStyle, HelpID, Class);
-}
-
-RCParser::ParseType RCParser::parseBitmapResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(BitmapResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(Arg, readFilename());
- return std::make_unique<BitmapResource>(*Arg, MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseIconResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(IconResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(Arg, readFilename());
- return std::make_unique<IconResource>(*Arg, MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseHTMLResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(HTMLResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(Arg, readFilename());
- return std::make_unique<HTMLResource>(*Arg, MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseMenuResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(MenuResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
- ASSIGN_OR_RETURN(Items, parseMenuItemsList());
- return std::make_unique<MenuResource>(std::move(*OptStatements),
- std::move(*Items), MemoryFlags);
-}
-
-Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
- RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
-
- MenuDefinitionList List;
-
- // Read a set of items. Each item is of one of three kinds:
- // MENUITEM SEPARATOR
- // MENUITEM caption:String, result:Int [, menu flags]...
- // POPUP caption:String [, menu flags]... { items... }
- while (!consumeOptionalType(Kind::BlockEnd)) {
- ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier());
-
- bool IsMenuItem = ItemTypeResult->equals_lower("MENUITEM");
- bool IsPopup = ItemTypeResult->equals_lower("POPUP");
- if (!IsMenuItem && !IsPopup)
- return getExpectedError("MENUITEM, POPUP, END or '}'", true);
-
- if (IsMenuItem && isNextTokenKind(Kind::Identifier)) {
- // Now, expecting SEPARATOR.
- ASSIGN_OR_RETURN(SeparatorResult, readIdentifier());
- if (SeparatorResult->equals_lower("SEPARATOR")) {
- List.addDefinition(std::make_unique<MenuSeparator>());
- continue;
- }
-
- return getExpectedError("SEPARATOR or string", true);
- }
-
- // Not a separator. Read the caption.
- ASSIGN_OR_RETURN(CaptionResult, readString());
-
- // If MENUITEM, expect also a comma and an integer.
- uint32_t MenuResult = -1;
-
- if (IsMenuItem) {
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- ASSIGN_OR_RETURN(IntResult, readInt());
- MenuResult = *IntResult;
- }
-
- ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr,
- MenuDefinition::OptionsFlags));
-
- if (IsPopup) {
- // If POPUP, read submenu items recursively.
- ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList());
- List.addDefinition(std::make_unique<PopupItem>(
- *CaptionResult, *FlagsResult, std::move(*SubMenuResult)));
- continue;
- }
-
- assert(IsMenuItem);
- List.addDefinition(
- std::make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult));
- }
-
- return std::move(List);
-}
-
-RCParser::ParseType RCParser::parseStringTableResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(StringTableResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
- RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
-
- auto Table = std::make_unique<StringTableResource>(std::move(*OptStatements),
- MemoryFlags);
-
- // Read strings until we reach the end of the block.
- while (!consumeOptionalType(Kind::BlockEnd)) {
- // Each definition consists of string's ID (an integer) and a string.
- // Some examples in documentation suggest that there might be a comma in
- // between, however we strictly adhere to the single statement definition.
- ASSIGN_OR_RETURN(IDResult, readInt());
- consumeOptionalType(Kind::Comma);
-
- std::vector<StringRef> Strings;
- ASSIGN_OR_RETURN(StrResult, readString());
- Strings.push_back(*StrResult);
- while (isNextTokenKind(Kind::String))
- Strings.push_back(read().value());
-
- Table->addStrings(*IDResult, std::move(Strings));
- }
-
- return std::move(Table);
-}
-
-Expected<std::unique_ptr<VersionInfoBlock>>
-RCParser::parseVersionInfoBlockContents(StringRef BlockName) {
- RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
-
- auto Contents = std::make_unique<VersionInfoBlock>(BlockName);
-
- while (!isNextTokenKind(Kind::BlockEnd)) {
- ASSIGN_OR_RETURN(Stmt, parseVersionInfoStmt());
- Contents->addStmt(std::move(*Stmt));
- }
-
- consume(); // Consume BlockEnd.
-
- return std::move(Contents);
-}
-
-Expected<std::unique_ptr<VersionInfoStmt>> RCParser::parseVersionInfoStmt() {
- // Expect either BLOCK or VALUE, then a name or a key (a string).
- ASSIGN_OR_RETURN(TypeResult, readIdentifier());
-
- if (TypeResult->equals_lower("BLOCK")) {
- ASSIGN_OR_RETURN(NameResult, readString());
- return parseVersionInfoBlockContents(*NameResult);
- }
-
- if (TypeResult->equals_lower("VALUE")) {
- ASSIGN_OR_RETURN(KeyResult, readString());
- // Read a non-empty list of strings and/or ints, each
- // possibly preceded by a comma. Unfortunately, the tool behavior depends
- // on them existing or not, so we need to memorize where we found them.
- std::vector<IntOrString> Values;
- std::vector<bool> PrecedingCommas;
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- while (!isNextTokenKind(Kind::Identifier) &&
- !isNextTokenKind(Kind::BlockEnd)) {
- // Try to eat a comma if it's not the first statement.
- bool HadComma = Values.size() > 0 && consumeOptionalType(Kind::Comma);
- ASSIGN_OR_RETURN(ValueResult, readIntOrString());
- Values.push_back(*ValueResult);
- PrecedingCommas.push_back(HadComma);
- }
- return std::make_unique<VersionInfoValue>(*KeyResult, std::move(Values),
- std::move(PrecedingCommas));
- }
-
- return getExpectedError("BLOCK or VALUE", true);
-}
-
-Expected<VersionInfoResource::VersionInfoFixed>
-RCParser::parseVersionInfoFixed() {
- using RetType = VersionInfoResource::VersionInfoFixed;
- RetType Result;
-
- // Read until the beginning of the block.
- while (!isNextTokenKind(Kind::BlockBegin)) {
- ASSIGN_OR_RETURN(TypeResult, readIdentifier());
- auto FixedType = RetType::getFixedType(*TypeResult);
-
- if (!RetType::isTypeSupported(FixedType))
- return getExpectedError("fixed VERSIONINFO statement type", true);
- if (Result.IsTypePresent[FixedType])
- return getExpectedError("yet unread fixed VERSIONINFO statement type",
- true);
-
- // VERSION variations take multiple integers.
- size_t NumInts = RetType::isVersionType(FixedType) ? 4 : 1;
+//===-- ResourceScriptParser.cpp --------------------------------*- 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
+//
+//===---------------------------------------------------------------------===//
+//
+// This implements the parser defined in ResourceScriptParser.h.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceScriptParser.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+
+// Take an expression returning llvm::Error and forward the error if it exists.
+#define RETURN_IF_ERROR(Expr) \
+ if (auto Err = (Expr)) \
+ return std::move(Err);
+
+// Take an expression returning llvm::Expected<T> and assign it to Var or
+// forward the error out of the function.
+#define ASSIGN_OR_RETURN(Var, Expr) \
+ auto Var = (Expr); \
+ if (!Var) \
+ return Var.takeError();
+
+namespace llvm {
+namespace rc {
+
+RCParser::ParserError::ParserError(const Twine &Expected, const LocIter CurLoc,
+ const LocIter End)
+ : ErrorLoc(CurLoc), FileEnd(End) {
+ CurMessage = "Error parsing file: expected " + Expected.str() + ", got " +
+ (CurLoc == End ? "<EOF>" : CurLoc->value()).str();
+}
+
+char RCParser::ParserError::ID = 0;
+
+RCParser::RCParser(std::vector<RCToken> TokenList)
+ : Tokens(std::move(TokenList)), CurLoc(Tokens.begin()), End(Tokens.end()) {}
+
+bool RCParser::isEof() const { return CurLoc == End; }
+
+RCParser::ParseType RCParser::parseSingleResource() {
+ // The first thing we read is usually a resource's name. However, in some
+ // cases (LANGUAGE and STRINGTABLE) the resources don't have their names
+ // and the first token to be read is the type.
+ ASSIGN_OR_RETURN(NameToken, readTypeOrName());
+
+ if (NameToken->equalsLower("LANGUAGE"))
+ return parseLanguageResource();
+ else if (NameToken->equalsLower("STRINGTABLE"))
+ return parseStringTableResource();
+
+ // If it's not an unnamed resource, what we've just read is a name. Now,
+ // read resource type;
+ ASSIGN_OR_RETURN(TypeToken, readTypeOrName());
+
+ ParseType Result = std::unique_ptr<RCResource>();
+ (void)!Result;
+
+ if (TypeToken->equalsLower("ACCELERATORS"))
+ Result = parseAcceleratorsResource();
+ else if (TypeToken->equalsLower("BITMAP"))
+ Result = parseBitmapResource();
+ else if (TypeToken->equalsLower("CURSOR"))
+ Result = parseCursorResource();
+ else if (TypeToken->equalsLower("DIALOG"))
+ Result = parseDialogResource(false);
+ else if (TypeToken->equalsLower("DIALOGEX"))
+ Result = parseDialogResource(true);
+ else if (TypeToken->equalsLower("HTML"))
+ Result = parseHTMLResource();
+ else if (TypeToken->equalsLower("ICON"))
+ Result = parseIconResource();
+ else if (TypeToken->equalsLower("MENU"))
+ Result = parseMenuResource();
+ else if (TypeToken->equalsLower("RCDATA"))
+ Result = parseUserDefinedResource(RkRcData);
+ else if (TypeToken->equalsLower("VERSIONINFO"))
+ Result = parseVersionInfoResource();
+ else
+ Result = parseUserDefinedResource(*TypeToken);
+
+ if (Result)
+ (*Result)->setName(*NameToken);
+
+ return Result;
+}
+
+bool RCParser::isNextTokenKind(Kind TokenKind) const {
+ return !isEof() && look().kind() == TokenKind;
+}
+
+const RCToken &RCParser::look() const {
+ assert(!isEof());
+ return *CurLoc;
+}
+
+const RCToken &RCParser::read() {
+ assert(!isEof());
+ return *CurLoc++;
+}
+
+void RCParser::consume() {
+ assert(!isEof());
+ CurLoc++;
+}
+
+// An integer description might consist of a single integer or
+// an arithmetic expression evaluating to the integer. The expressions
+// can contain the following tokens: <int> ( ) + - | & ~ not. Their meaning
+// is the same as in C++ except for 'not' expression.
+// The operators in the original RC implementation have the following
+// precedence:
+// 1) Unary operators (- ~ not),
+// 2) Binary operators (+ - & |), with no precedence.
+//
+// 'not' expression is mostly useful for style values. It evaluates to 0,
+// but value given to the operator is stored separately from integer value.
+// It's mostly useful for control style expressions and causes bits from
+// default control style to be excluded from generated style. For binary
+// operators the mask from the right operand is applied to the left operand
+// and masks from both operands are combined in operator result.
+//
+// The following grammar is used to parse the expressions Exp1:
+// Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2
+// Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
+// (More conveniently, Exp1 is a non-empty sequence of Exp2 expressions,
+// separated by binary operators.)
+//
+// Expressions of type Exp1 are read by parseIntExpr1(Inner) method, while Exp2
+// is read by parseIntExpr2().
+//
+// The original Microsoft tool handles multiple unary operators incorrectly.
+// For example, in 16-bit little-endian integers:
+// 1 => 01 00, -1 => ff ff, --1 => ff ff, ---1 => 01 00;
+// 1 => 01 00, ~1 => fe ff, ~~1 => fd ff, ~~~1 => fc ff.
+// Our implementation differs from the original one and handles these
+// operators correctly:
+// 1 => 01 00, -1 => ff ff, --1 => 01 00, ---1 => ff ff;
+// 1 => 01 00, ~1 => fe ff, ~~1 => 01 00, ~~~1 => fe ff.
+
+Expected<RCInt> RCParser::readInt() {
+ ASSIGN_OR_RETURN(Value, parseIntExpr1());
+ return (*Value).getValue();
+}
+
+Expected<IntWithNotMask> RCParser::parseIntExpr1() {
+ // Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2.
+ ASSIGN_OR_RETURN(FirstResult, parseIntExpr2());
+ IntWithNotMask Result = *FirstResult;
+
+ while (!isEof() && look().isBinaryOp()) {
+ auto OpToken = read();
+ ASSIGN_OR_RETURN(NextResult, parseIntExpr2());
+
+ switch (OpToken.kind()) {
+ case Kind::Plus:
+ Result += *NextResult;
+ break;
+
+ case Kind::Minus:
+ Result -= *NextResult;
+ break;
+
+ case Kind::Pipe:
+ Result |= *NextResult;
+ break;
+
+ case Kind::Amp:
+ Result &= *NextResult;
+ break;
+
+ default:
+ llvm_unreachable("Already processed all binary ops.");
+ }
+ }
+
+ return Result;
+}
+
+Expected<IntWithNotMask> RCParser::parseIntExpr2() {
+ // Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
+ static const char ErrorMsg[] = "'-', '~', integer or '('";
+
+ if (isEof())
+ return getExpectedError(ErrorMsg);
+
+ switch (look().kind()) {
+ case Kind::Minus: {
+ consume();
+ ASSIGN_OR_RETURN(Result, parseIntExpr2());
+ return -(*Result);
+ }
+
+ case Kind::Tilde: {
+ consume();
+ ASSIGN_OR_RETURN(Result, parseIntExpr2());
+ return ~(*Result);
+ }
+
+ case Kind::Int:
+ return RCInt(read());
+
+ case Kind::LeftParen: {
+ consume();
+ ASSIGN_OR_RETURN(Result, parseIntExpr1());
+ RETURN_IF_ERROR(consumeType(Kind::RightParen));
+ return *Result;
+ }
+
+ case Kind::Identifier: {
+ if (!read().value().equals_lower("not"))
+ return getExpectedError(ErrorMsg, true);
+ ASSIGN_OR_RETURN(Result, parseIntExpr2());
+ return IntWithNotMask(0, (*Result).getValue());
+ }
+
+ default:
+ return getExpectedError(ErrorMsg);
+ }
+}
+
+Expected<StringRef> RCParser::readString() {
+ if (!isNextTokenKind(Kind::String))
+ return getExpectedError("string");
+ return read().value();
+}
+
+Expected<StringRef> RCParser::readFilename() {
+ if (!isNextTokenKind(Kind::String) && !isNextTokenKind(Kind::Identifier))
+ return getExpectedError("string");
+ return read().value();
+}
+
+Expected<StringRef> RCParser::readIdentifier() {
+ if (!isNextTokenKind(Kind::Identifier))
+ return getExpectedError("identifier");
+ return read().value();
+}
+
+Expected<IntOrString> RCParser::readIntOrString() {
+ if (!isNextTokenKind(Kind::Int) && !isNextTokenKind(Kind::String))
+ return getExpectedError("int or string");
+ return IntOrString(read());
+}
+
+Expected<IntOrString> RCParser::readTypeOrName() {
+ // We suggest that the correct resource name or type should be either an
+ // identifier or an integer. The original RC tool is much more liberal.
+ if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int))
+ return getExpectedError("int or identifier");
+ return IntOrString(read());
+}
+
+Error RCParser::consumeType(Kind TokenKind) {
+ if (isNextTokenKind(TokenKind)) {
+ consume();
+ return Error::success();
+ }
+
+ switch (TokenKind) {
+#define TOKEN(TokenName) \
+ case Kind::TokenName: \
+ return getExpectedError(#TokenName);
+#define SHORT_TOKEN(TokenName, TokenCh) \
+ case Kind::TokenName: \
+ return getExpectedError(#TokenCh);
+#include "ResourceScriptTokenList.def"
+ }
+
+ llvm_unreachable("All case options exhausted.");
+}
+
+bool RCParser::consumeOptionalType(Kind TokenKind) {
+ if (isNextTokenKind(TokenKind)) {
+ consume();
+ return true;
+ }
+
+ return false;
+}
+
+Expected<SmallVector<RCInt, 8>> RCParser::readIntsWithCommas(size_t MinCount,
+ size_t MaxCount) {
+ assert(MinCount <= MaxCount);
+
+ SmallVector<RCInt, 8> Result;
+
+ auto FailureHandler =
+ [&](llvm::Error Err) -> Expected<SmallVector<RCInt, 8>> {
+ if (Result.size() < MinCount)
+ return std::move(Err);
+ consumeError(std::move(Err));
+ return Result;
+ };
+
+ for (size_t i = 0; i < MaxCount; ++i) {
+ // Try to read a comma unless we read the first token.
+ // Sometimes RC tool requires them and sometimes not. We decide to
+ // always require them.
+ if (i >= 1) {
+ if (auto CommaError = consumeType(Kind::Comma))
+ return FailureHandler(std::move(CommaError));
+ }
+
+ if (auto IntResult = readInt())
+ Result.push_back(*IntResult);
+ else
+ return FailureHandler(IntResult.takeError());
+ }
+
+ return std::move(Result);
+}
+
+Expected<uint32_t> RCParser::parseFlags(ArrayRef<StringRef> FlagDesc,
+ ArrayRef<uint32_t> FlagValues) {
+ assert(!FlagDesc.empty());
+ assert(FlagDesc.size() == FlagValues.size());
+
+ uint32_t Result = 0;
+ while (isNextTokenKind(Kind::Comma)) {
+ consume();
+ ASSIGN_OR_RETURN(FlagResult, readIdentifier());
+ bool FoundFlag = false;
+
+ for (size_t FlagId = 0; FlagId < FlagDesc.size(); ++FlagId) {
+ if (!FlagResult->equals_lower(FlagDesc[FlagId]))
+ continue;
+
+ Result |= FlagValues[FlagId];
+ FoundFlag = true;
+ break;
+ }
+
+ if (!FoundFlag)
+ return getExpectedError(join(FlagDesc, "/"), true);
+ }
+
+ return Result;
+}
+
+uint16_t RCParser::parseMemoryFlags(uint16_t Flags) {
+ while (!isEof()) {
+ const RCToken &Token = look();
+ if (Token.kind() != Kind::Identifier)
+ return Flags;
+ const StringRef Ident = Token.value();
+ if (Ident.equals_lower("PRELOAD"))
+ Flags |= MfPreload;
+ else if (Ident.equals_lower("LOADONCALL"))
+ Flags &= ~MfPreload;
+ else if (Ident.equals_lower("FIXED"))
+ Flags &= ~(MfMoveable | MfDiscardable);
+ else if (Ident.equals_lower("MOVEABLE"))
+ Flags |= MfMoveable;
+ else if (Ident.equals_lower("DISCARDABLE"))
+ Flags |= MfDiscardable | MfMoveable | MfPure;
+ else if (Ident.equals_lower("PURE"))
+ Flags |= MfPure;
+ else if (Ident.equals_lower("IMPURE"))
+ Flags &= ~(MfPure | MfDiscardable);
+ else if (Ident.equals_lower("SHARED"))
+ Flags |= MfPure;
+ else if (Ident.equals_lower("NONSHARED"))
+ Flags &= ~(MfPure | MfDiscardable);
+ else
+ return Flags;
+ consume();
+ }
+ return Flags;
+}
+
+Expected<OptionalStmtList>
+RCParser::parseOptionalStatements(OptStmtType StmtsType) {
+ OptionalStmtList Result;
+
+ // The last statement is always followed by the start of the block.
+ while (!isNextTokenKind(Kind::BlockBegin)) {
+ ASSIGN_OR_RETURN(SingleParse, parseSingleOptionalStatement(StmtsType));
+ Result.addStmt(std::move(*SingleParse));
+ }
+
+ return std::move(Result);
+}
+
+Expected<std::unique_ptr<OptionalStmt>>
+RCParser::parseSingleOptionalStatement(OptStmtType StmtsType) {
+ ASSIGN_OR_RETURN(TypeToken, readIdentifier());
+ if (TypeToken->equals_lower("CHARACTERISTICS"))
+ return parseCharacteristicsStmt();
+ if (TypeToken->equals_lower("LANGUAGE"))
+ return parseLanguageStmt();
+ if (TypeToken->equals_lower("VERSION"))
+ return parseVersionStmt();
+
+ if (StmtsType != OptStmtType::BasicStmt) {
+ if (TypeToken->equals_lower("CAPTION"))
+ return parseCaptionStmt();
+ if (TypeToken->equals_lower("CLASS"))
+ return parseClassStmt();
+ if (TypeToken->equals_lower("EXSTYLE"))
+ return parseExStyleStmt();
+ if (TypeToken->equals_lower("FONT"))
+ return parseFontStmt(StmtsType);
+ if (TypeToken->equals_lower("STYLE"))
+ return parseStyleStmt();
+ }
+
+ return getExpectedError("optional statement type, BEGIN or '{'",
+ /* IsAlreadyRead = */ true);
+}
+
+RCParser::ParseType RCParser::parseLanguageResource() {
+ // Read LANGUAGE as an optional statement. If it's read correctly, we can
+ // upcast it to RCResource.
+ return parseLanguageStmt();
+}
+
+RCParser::ParseType RCParser::parseAcceleratorsResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(AcceleratorsResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+ auto Accels = std::make_unique<AcceleratorsResource>(
+ std::move(*OptStatements), MemoryFlags);
+
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ ASSIGN_OR_RETURN(EventResult, readIntOrString());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ ASSIGN_OR_RETURN(IDResult, readInt());
+ ASSIGN_OR_RETURN(
+ FlagsResult,
+ parseFlags(AcceleratorsResource::Accelerator::OptionsStr,
+ AcceleratorsResource::Accelerator::OptionsFlags));
+ Accels->addAccelerator(*EventResult, *IDResult, *FlagsResult);
+ }
+
+ return std::move(Accels);
+}
+
+RCParser::ParseType RCParser::parseCursorResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(CursorResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(Arg, readFilename());
+ return std::make_unique<CursorResource>(*Arg, MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(DialogResource::getDefaultMemoryFlags());
+ // Dialog resources have the following format of the arguments:
+ // DIALOG: x, y, width, height [opt stmts...] {controls...}
+ // DIALOGEX: x, y, width, height [, helpID] [opt stmts...] {controls...}
+ // These are very similar, so we parse them together.
+ ASSIGN_OR_RETURN(LocResult, readIntsWithCommas(4, 4));
+
+ uint32_t HelpID = 0; // When HelpID is unset, it's assumed to be 0.
+ if (IsExtended && consumeOptionalType(Kind::Comma)) {
+ ASSIGN_OR_RETURN(HelpIDResult, readInt());
+ HelpID = *HelpIDResult;
+ }
+
+ ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements(
+ IsExtended ? OptStmtType::DialogExStmt
+ : OptStmtType::DialogStmt));
+
+ assert(isNextTokenKind(Kind::BlockBegin) &&
+ "parseOptionalStatements, when successful, halts on BlockBegin.");
+ consume();
+
+ auto Dialog = std::make_unique<DialogResource>(
+ (*LocResult)[0], (*LocResult)[1], (*LocResult)[2], (*LocResult)[3],
+ HelpID, std::move(*OptStatements), IsExtended, MemoryFlags);
+
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ ASSIGN_OR_RETURN(ControlDefResult, parseControl());
+ Dialog->addControl(std::move(*ControlDefResult));
+ }
+
+ return std::move(Dialog);
+}
+
+RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(UserDefinedResource::getDefaultMemoryFlags());
+ if (isEof())
+ return getExpectedError("filename, '{' or BEGIN");
+
+ // Check if this is a file resource.
+ switch (look().kind()) {
+ case Kind::String:
+ case Kind::Identifier:
+ return std::make_unique<UserDefinedResource>(Type, read().value(),
+ MemoryFlags);
+ default:
+ break;
+ }
+
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+ std::vector<IntOrString> Data;
+
+ // Consume comma before each consecutive token except the first one.
+ bool ConsumeComma = false;
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ if (ConsumeComma)
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ ConsumeComma = true;
+
+ ASSIGN_OR_RETURN(Item, readIntOrString());
+ Data.push_back(*Item);
+ }
+
+ return std::make_unique<UserDefinedResource>(Type, std::move(Data),
+ MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseVersionInfoResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(VersionInfoResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed());
+ ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef()));
+ return std::make_unique<VersionInfoResource>(
+ std::move(**BlockResult), std::move(*FixedResult), MemoryFlags);
+}
+
+Expected<Control> RCParser::parseControl() {
+ // Each control definition (except CONTROL) follows one of the schemes below
+ // depending on the control class:
+ // [class] text, id, x, y, width, height [, style] [, exstyle] [, helpID]
+ // [class] id, x, y, width, height [, style] [, exstyle] [, helpID]
+ // Note that control ids must be integers.
+ // Text might be either a string or an integer pointing to resource ID.
+ ASSIGN_OR_RETURN(ClassResult, readIdentifier());
+ std::string ClassUpper = ClassResult->upper();
+ auto CtlInfo = Control::SupportedCtls.find(ClassUpper);
+ if (CtlInfo == Control::SupportedCtls.end())
+ return getExpectedError("control type, END or '}'", true);
+
+ // Read caption if necessary.
+ IntOrString Caption{StringRef()};
+ if (CtlInfo->getValue().HasTitle) {
+ ASSIGN_OR_RETURN(CaptionResult, readIntOrString());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ Caption = *CaptionResult;
+ }
+
+ ASSIGN_OR_RETURN(ID, readInt());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+
+ IntOrString Class;
+ Optional<IntWithNotMask> Style;
+ if (ClassUpper == "CONTROL") {
+ // CONTROL text, id, class, style, x, y, width, height [, exstyle] [, helpID]
+ ASSIGN_OR_RETURN(ClassStr, readString());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ Class = *ClassStr;
+ ASSIGN_OR_RETURN(StyleVal, parseIntExpr1());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ Style = *StyleVal;
+ } else {
+ Class = CtlInfo->getValue().CtlClass;
+ }
+
+ // x, y, width, height
+ ASSIGN_OR_RETURN(Args, readIntsWithCommas(4, 4));
+
+ if (ClassUpper != "CONTROL") {
+ if (consumeOptionalType(Kind::Comma)) {
+ ASSIGN_OR_RETURN(Val, parseIntExpr1());
+ Style = *Val;
+ }
+ }
+
+ Optional<uint32_t> ExStyle;
+ if (consumeOptionalType(Kind::Comma)) {
+ ASSIGN_OR_RETURN(Val, readInt());
+ ExStyle = *Val;
+ }
+ Optional<uint32_t> HelpID;
+ if (consumeOptionalType(Kind::Comma)) {
+ ASSIGN_OR_RETURN(Val, readInt());
+ HelpID = *Val;
+ }
+
+ return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1],
+ (*Args)[2], (*Args)[3], Style, ExStyle, HelpID, Class);
+}
+
+RCParser::ParseType RCParser::parseBitmapResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(BitmapResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(Arg, readFilename());
+ return std::make_unique<BitmapResource>(*Arg, MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseIconResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(IconResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(Arg, readFilename());
+ return std::make_unique<IconResource>(*Arg, MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseHTMLResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(HTMLResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(Arg, readFilename());
+ return std::make_unique<HTMLResource>(*Arg, MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseMenuResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(MenuResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
+ ASSIGN_OR_RETURN(Items, parseMenuItemsList());
+ return std::make_unique<MenuResource>(std::move(*OptStatements),
+ std::move(*Items), MemoryFlags);
+}
+
+Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+ MenuDefinitionList List;
+
+ // Read a set of items. Each item is of one of three kinds:
+ // MENUITEM SEPARATOR
+ // MENUITEM caption:String, result:Int [, menu flags]...
+ // POPUP caption:String [, menu flags]... { items... }
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier());
+
+ bool IsMenuItem = ItemTypeResult->equals_lower("MENUITEM");
+ bool IsPopup = ItemTypeResult->equals_lower("POPUP");
+ if (!IsMenuItem && !IsPopup)
+ return getExpectedError("MENUITEM, POPUP, END or '}'", true);
+
+ if (IsMenuItem && isNextTokenKind(Kind::Identifier)) {
+ // Now, expecting SEPARATOR.
+ ASSIGN_OR_RETURN(SeparatorResult, readIdentifier());
+ if (SeparatorResult->equals_lower("SEPARATOR")) {
+ List.addDefinition(std::make_unique<MenuSeparator>());
+ continue;
+ }
+
+ return getExpectedError("SEPARATOR or string", true);
+ }
+
+ // Not a separator. Read the caption.
+ ASSIGN_OR_RETURN(CaptionResult, readString());
+
+ // If MENUITEM, expect also a comma and an integer.
+ uint32_t MenuResult = -1;
+
+ if (IsMenuItem) {
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ ASSIGN_OR_RETURN(IntResult, readInt());
+ MenuResult = *IntResult;
+ }
+
+ ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr,
+ MenuDefinition::OptionsFlags));
+
+ if (IsPopup) {
+ // If POPUP, read submenu items recursively.
+ ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList());
+ List.addDefinition(std::make_unique<PopupItem>(
+ *CaptionResult, *FlagsResult, std::move(*SubMenuResult)));
+ continue;
+ }
+
+ assert(IsMenuItem);
+ List.addDefinition(
+ std::make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult));
+ }
+
+ return std::move(List);
+}
+
+RCParser::ParseType RCParser::parseStringTableResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(StringTableResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+ auto Table = std::make_unique<StringTableResource>(std::move(*OptStatements),
+ MemoryFlags);
+
+ // Read strings until we reach the end of the block.
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ // Each definition consists of string's ID (an integer) and a string.
+ // Some examples in documentation suggest that there might be a comma in
+ // between, however we strictly adhere to the single statement definition.
+ ASSIGN_OR_RETURN(IDResult, readInt());
+ consumeOptionalType(Kind::Comma);
+
+ std::vector<StringRef> Strings;
+ ASSIGN_OR_RETURN(StrResult, readString());
+ Strings.push_back(*StrResult);
+ while (isNextTokenKind(Kind::String))
+ Strings.push_back(read().value());
+
+ Table->addStrings(*IDResult, std::move(Strings));
+ }
+
+ return std::move(Table);
+}
+
+Expected<std::unique_ptr<VersionInfoBlock>>
+RCParser::parseVersionInfoBlockContents(StringRef BlockName) {
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+ auto Contents = std::make_unique<VersionInfoBlock>(BlockName);
+
+ while (!isNextTokenKind(Kind::BlockEnd)) {
+ ASSIGN_OR_RETURN(Stmt, parseVersionInfoStmt());
+ Contents->addStmt(std::move(*Stmt));
+ }
+
+ consume(); // Consume BlockEnd.
+
+ return std::move(Contents);
+}
+
+Expected<std::unique_ptr<VersionInfoStmt>> RCParser::parseVersionInfoStmt() {
+ // Expect either BLOCK or VALUE, then a name or a key (a string).
+ ASSIGN_OR_RETURN(TypeResult, readIdentifier());
+
+ if (TypeResult->equals_lower("BLOCK")) {
+ ASSIGN_OR_RETURN(NameResult, readString());
+ return parseVersionInfoBlockContents(*NameResult);
+ }
+
+ if (TypeResult->equals_lower("VALUE")) {
+ ASSIGN_OR_RETURN(KeyResult, readString());
+ // Read a non-empty list of strings and/or ints, each
+ // possibly preceded by a comma. Unfortunately, the tool behavior depends
+ // on them existing or not, so we need to memorize where we found them.
+ std::vector<IntOrString> Values;
+ std::vector<bool> PrecedingCommas;
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ while (!isNextTokenKind(Kind::Identifier) &&
+ !isNextTokenKind(Kind::BlockEnd)) {
+ // Try to eat a comma if it's not the first statement.
+ bool HadComma = Values.size() > 0 && consumeOptionalType(Kind::Comma);
+ ASSIGN_OR_RETURN(ValueResult, readIntOrString());
+ Values.push_back(*ValueResult);
+ PrecedingCommas.push_back(HadComma);
+ }
+ return std::make_unique<VersionInfoValue>(*KeyResult, std::move(Values),
+ std::move(PrecedingCommas));
+ }
+
+ return getExpectedError("BLOCK or VALUE", true);
+}
+
+Expected<VersionInfoResource::VersionInfoFixed>
+RCParser::parseVersionInfoFixed() {
+ using RetType = VersionInfoResource::VersionInfoFixed;
+ RetType Result;
+
+ // Read until the beginning of the block.
+ while (!isNextTokenKind(Kind::BlockBegin)) {
+ ASSIGN_OR_RETURN(TypeResult, readIdentifier());
+ auto FixedType = RetType::getFixedType(*TypeResult);
+
+ if (!RetType::isTypeSupported(FixedType))
+ return getExpectedError("fixed VERSIONINFO statement type", true);
+ if (Result.IsTypePresent[FixedType])
+ return getExpectedError("yet unread fixed VERSIONINFO statement type",
+ true);
+
+ // VERSION variations take multiple integers.
+ size_t NumInts = RetType::isVersionType(FixedType) ? 4 : 1;
ASSIGN_OR_RETURN(ArgsResult, readIntsWithCommas(1, NumInts));
- SmallVector<uint32_t, 4> ArgInts(ArgsResult->begin(), ArgsResult->end());
+ SmallVector<uint32_t, 4> ArgInts(ArgsResult->begin(), ArgsResult->end());
while (ArgInts.size() < NumInts)
ArgInts.push_back(0);
- Result.setValue(FixedType, ArgInts);
- }
-
- return Result;
-}
-
-RCParser::ParseOptionType RCParser::parseLanguageStmt() {
- ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2));
- return std::make_unique<LanguageResource>((*Args)[0], (*Args)[1]);
-}
-
-RCParser::ParseOptionType RCParser::parseCharacteristicsStmt() {
- ASSIGN_OR_RETURN(Arg, readInt());
- return std::make_unique<CharacteristicsStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseVersionStmt() {
- ASSIGN_OR_RETURN(Arg, readInt());
- return std::make_unique<VersionStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseCaptionStmt() {
- ASSIGN_OR_RETURN(Arg, readString());
- return std::make_unique<CaptionStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseClassStmt() {
- ASSIGN_OR_RETURN(Arg, readIntOrString());
- return std::make_unique<ClassStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseFontStmt(OptStmtType DialogType) {
- assert(DialogType != OptStmtType::BasicStmt);
-
- ASSIGN_OR_RETURN(SizeResult, readInt());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- ASSIGN_OR_RETURN(NameResult, readString());
-
- // Default values for the optional arguments.
- uint32_t FontWeight = 0;
- bool FontItalic = false;
- uint32_t FontCharset = 1;
- if (DialogType == OptStmtType::DialogExStmt) {
- if (consumeOptionalType(Kind::Comma)) {
- ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 0, /* max = */ 3));
- if (Args->size() >= 1)
- FontWeight = (*Args)[0];
- if (Args->size() >= 2)
- FontItalic = (*Args)[1] != 0;
- if (Args->size() >= 3)
- FontCharset = (*Args)[2];
- }
- }
- return std::make_unique<FontStmt>(*SizeResult, *NameResult, FontWeight,
- FontItalic, FontCharset);
-}
-
-RCParser::ParseOptionType RCParser::parseStyleStmt() {
- ASSIGN_OR_RETURN(Arg, readInt());
- return std::make_unique<StyleStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseExStyleStmt() {
- ASSIGN_OR_RETURN(Arg, readInt());
- return std::make_unique<ExStyleStmt>(*Arg);
-}
-
-Error RCParser::getExpectedError(const Twine &Message, bool IsAlreadyRead) {
- return make_error<ParserError>(
- Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End);
-}
-
-} // namespace rc
-} // namespace llvm
+ Result.setValue(FixedType, ArgInts);
+ }
+
+ return Result;
+}
+
+RCParser::ParseOptionType RCParser::parseLanguageStmt() {
+ ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2));
+ return std::make_unique<LanguageResource>((*Args)[0], (*Args)[1]);
+}
+
+RCParser::ParseOptionType RCParser::parseCharacteristicsStmt() {
+ ASSIGN_OR_RETURN(Arg, readInt());
+ return std::make_unique<CharacteristicsStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseVersionStmt() {
+ ASSIGN_OR_RETURN(Arg, readInt());
+ return std::make_unique<VersionStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseCaptionStmt() {
+ ASSIGN_OR_RETURN(Arg, readString());
+ return std::make_unique<CaptionStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseClassStmt() {
+ ASSIGN_OR_RETURN(Arg, readIntOrString());
+ return std::make_unique<ClassStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseFontStmt(OptStmtType DialogType) {
+ assert(DialogType != OptStmtType::BasicStmt);
+
+ ASSIGN_OR_RETURN(SizeResult, readInt());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ ASSIGN_OR_RETURN(NameResult, readString());
+
+ // Default values for the optional arguments.
+ uint32_t FontWeight = 0;
+ bool FontItalic = false;
+ uint32_t FontCharset = 1;
+ if (DialogType == OptStmtType::DialogExStmt) {
+ if (consumeOptionalType(Kind::Comma)) {
+ ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 0, /* max = */ 3));
+ if (Args->size() >= 1)
+ FontWeight = (*Args)[0];
+ if (Args->size() >= 2)
+ FontItalic = (*Args)[1] != 0;
+ if (Args->size() >= 3)
+ FontCharset = (*Args)[2];
+ }
+ }
+ return std::make_unique<FontStmt>(*SizeResult, *NameResult, FontWeight,
+ FontItalic, FontCharset);
+}
+
+RCParser::ParseOptionType RCParser::parseStyleStmt() {
+ ASSIGN_OR_RETURN(Arg, readInt());
+ return std::make_unique<StyleStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseExStyleStmt() {
+ ASSIGN_OR_RETURN(Arg, readInt());
+ return std::make_unique<ExStyleStmt>(*Arg);
+}
+
+Error RCParser::getExpectedError(const Twine &Message, bool IsAlreadyRead) {
+ return make_error<ParserError>(
+ Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End);
+}
+
+} // namespace rc
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h
index fe202073b6..4887b0d5db 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h
@@ -1,192 +1,192 @@
-//===-- ResourceScriptParser.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
-//
-//===---------------------------------------------------------------------===//
-//
-// This defines the RC scripts parser. It takes a sequence of RC tokens
-// and then provides the method to parse the resources one by one.
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H
-
-#include "ResourceScriptStmt.h"
-#include "ResourceScriptToken.h"
-
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <system_error>
-#include <vector>
-
-namespace llvm {
-namespace opt {
-class InputArgList;
-}
-namespace rc {
-
-class RCParser {
-public:
- using LocIter = std::vector<RCToken>::iterator;
- using ParseType = Expected<std::unique_ptr<RCResource>>;
- using ParseOptionType = Expected<std::unique_ptr<OptionalStmt>>;
-
- // Class describing a single failure of parser.
- class ParserError : public ErrorInfo<ParserError> {
- public:
- ParserError(const Twine &Expected, const LocIter CurLoc, const LocIter End);
-
- void log(raw_ostream &OS) const override { OS << CurMessage; }
- std::error_code convertToErrorCode() const override {
- return std::make_error_code(std::errc::invalid_argument);
- }
- const std::string &getMessage() const { return CurMessage; }
-
- static char ID; // Keep llvm::Error happy.
-
- private:
- std::string CurMessage;
- LocIter ErrorLoc, FileEnd;
- };
-
- explicit RCParser(std::vector<RCToken> TokenList);
-
- // Reads and returns a single resource definition, or error message if any
- // occurred.
- ParseType parseSingleResource();
-
- bool isEof() const;
-
-private:
- using Kind = RCToken::Kind;
-
- // Checks if the current parser state points to the token of type TokenKind.
- bool isNextTokenKind(Kind TokenKind) const;
-
- // These methods assume that the parser is not in EOF state.
-
- // Take a look at the current token. Do not fetch it.
- const RCToken &look() const;
- // Read the current token and advance the state by one token.
- const RCToken &read();
- // Advance the state by one token, discarding the current token.
- void consume();
-
- // The following methods try to read a single token, check if it has the
- // correct type and then parse it.
- // Each integer can be written as an arithmetic expression producing an
- // unsigned 32-bit integer.
- Expected<RCInt> readInt(); // Parse an integer.
- Expected<StringRef> readString(); // Parse a string.
- Expected<StringRef> readIdentifier(); // Parse an identifier.
- Expected<StringRef> readFilename(); // Parse a filename.
- Expected<IntOrString> readIntOrString(); // Parse an integer or a string.
- Expected<IntOrString> readTypeOrName(); // Parse an integer or an identifier.
-
- // Helper integer expression parsing methods.
- Expected<IntWithNotMask> parseIntExpr1();
- Expected<IntWithNotMask> parseIntExpr2();
-
- // Advance the state by one, discarding the current token.
- // If the discarded token had an incorrect type, fail.
- Error consumeType(Kind TokenKind);
-
- // Check the current token type. If it's TokenKind, discard it.
- // Return true if the parser consumed this token successfully.
- bool consumeOptionalType(Kind TokenKind);
-
- // Read at least MinCount, and at most MaxCount integers separated by
- // commas. The parser stops reading after fetching MaxCount integers
- // or after an error occurs. Whenever the parser reads a comma, it
- // expects an integer to follow.
- Expected<SmallVector<RCInt, 8>> readIntsWithCommas(size_t MinCount,
- size_t MaxCount);
-
- // Read an unknown number of flags preceded by commas. Each correct flag
- // has an entry in FlagDesc array of length NumFlags. In case i-th
- // flag (0-based) has been read, the result is OR-ed with FlagValues[i].
- // As long as parser has a comma to read, it expects to be fed with
- // a correct flag afterwards.
- Expected<uint32_t> parseFlags(ArrayRef<StringRef> FlagDesc,
- ArrayRef<uint32_t> FlagValues);
-
- // Reads a set of optional statements. These can change the behavior of
- // a number of resource types (e.g. STRINGTABLE, MENU or DIALOG) if provided
- // before the main block with the contents of the resource.
- // Usually, resources use a basic set of optional statements:
- // CHARACTERISTICS, LANGUAGE, VERSION
- // However, DIALOG and DIALOGEX extend this list by the following items:
- // CAPTION, CLASS, EXSTYLE, FONT, MENU, STYLE
- // UseExtendedStatements flag (off by default) allows the parser to read
- // the additional types of statements.
- //
- // Ref (to the list of all optional statements):
- // msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
- enum class OptStmtType { BasicStmt, DialogStmt, DialogExStmt };
-
- uint16_t parseMemoryFlags(uint16_t DefaultFlags);
-
- Expected<OptionalStmtList>
- parseOptionalStatements(OptStmtType StmtsType = OptStmtType::BasicStmt);
-
- // Read a single optional statement.
- Expected<std::unique_ptr<OptionalStmt>>
- parseSingleOptionalStatement(OptStmtType StmtsType = OptStmtType::BasicStmt);
-
- // Top-level resource parsers.
- ParseType parseLanguageResource();
- ParseType parseAcceleratorsResource();
- ParseType parseBitmapResource();
- ParseType parseCursorResource();
- ParseType parseDialogResource(bool IsExtended);
- ParseType parseIconResource();
- ParseType parseHTMLResource();
- ParseType parseMenuResource();
- ParseType parseStringTableResource();
- ParseType parseUserDefinedResource(IntOrString Type);
- ParseType parseVersionInfoResource();
-
- // Helper DIALOG parser - a single control.
- Expected<Control> parseControl();
-
- // Helper MENU parser.
- Expected<MenuDefinitionList> parseMenuItemsList();
-
- // Helper VERSIONINFO parser - read the contents of a single BLOCK statement,
- // from BEGIN to END.
- Expected<std::unique_ptr<VersionInfoBlock>>
- parseVersionInfoBlockContents(StringRef BlockName);
- // Helper VERSIONINFO parser - read either VALUE or BLOCK statement.
- Expected<std::unique_ptr<VersionInfoStmt>> parseVersionInfoStmt();
- // Helper VERSIONINFO parser - read fixed VERSIONINFO statements.
- Expected<VersionInfoResource::VersionInfoFixed> parseVersionInfoFixed();
-
- // Optional statement parsers.
- ParseOptionType parseLanguageStmt();
- ParseOptionType parseCharacteristicsStmt();
- ParseOptionType parseVersionStmt();
- ParseOptionType parseCaptionStmt();
- ParseOptionType parseClassStmt();
- ParseOptionType parseExStyleStmt();
- ParseOptionType parseFontStmt(OptStmtType DialogType);
- ParseOptionType parseStyleStmt();
-
- // Raises an error. If IsAlreadyRead = false (default), this complains about
- // the token that couldn't be parsed. If the flag is on, this complains about
- // the correctly read token that makes no sense (that is, the current parser
- // state is beyond the erroneous token.)
- Error getExpectedError(const Twine &Message, bool IsAlreadyRead = false);
-
- std::vector<RCToken> Tokens;
- LocIter CurLoc;
- const LocIter End;
-};
-
-} // namespace rc
-} // namespace llvm
-
-#endif
+//===-- ResourceScriptParser.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
+//
+//===---------------------------------------------------------------------===//
+//
+// This defines the RC scripts parser. It takes a sequence of RC tokens
+// and then provides the method to parse the resources one by one.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H
+
+#include "ResourceScriptStmt.h"
+#include "ResourceScriptToken.h"
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <system_error>
+#include <vector>
+
+namespace llvm {
+namespace opt {
+class InputArgList;
+}
+namespace rc {
+
+class RCParser {
+public:
+ using LocIter = std::vector<RCToken>::iterator;
+ using ParseType = Expected<std::unique_ptr<RCResource>>;
+ using ParseOptionType = Expected<std::unique_ptr<OptionalStmt>>;
+
+ // Class describing a single failure of parser.
+ class ParserError : public ErrorInfo<ParserError> {
+ public:
+ ParserError(const Twine &Expected, const LocIter CurLoc, const LocIter End);
+
+ void log(raw_ostream &OS) const override { OS << CurMessage; }
+ std::error_code convertToErrorCode() const override {
+ return std::make_error_code(std::errc::invalid_argument);
+ }
+ const std::string &getMessage() const { return CurMessage; }
+
+ static char ID; // Keep llvm::Error happy.
+
+ private:
+ std::string CurMessage;
+ LocIter ErrorLoc, FileEnd;
+ };
+
+ explicit RCParser(std::vector<RCToken> TokenList);
+
+ // Reads and returns a single resource definition, or error message if any
+ // occurred.
+ ParseType parseSingleResource();
+
+ bool isEof() const;
+
+private:
+ using Kind = RCToken::Kind;
+
+ // Checks if the current parser state points to the token of type TokenKind.
+ bool isNextTokenKind(Kind TokenKind) const;
+
+ // These methods assume that the parser is not in EOF state.
+
+ // Take a look at the current token. Do not fetch it.
+ const RCToken &look() const;
+ // Read the current token and advance the state by one token.
+ const RCToken &read();
+ // Advance the state by one token, discarding the current token.
+ void consume();
+
+ // The following methods try to read a single token, check if it has the
+ // correct type and then parse it.
+ // Each integer can be written as an arithmetic expression producing an
+ // unsigned 32-bit integer.
+ Expected<RCInt> readInt(); // Parse an integer.
+ Expected<StringRef> readString(); // Parse a string.
+ Expected<StringRef> readIdentifier(); // Parse an identifier.
+ Expected<StringRef> readFilename(); // Parse a filename.
+ Expected<IntOrString> readIntOrString(); // Parse an integer or a string.
+ Expected<IntOrString> readTypeOrName(); // Parse an integer or an identifier.
+
+ // Helper integer expression parsing methods.
+ Expected<IntWithNotMask> parseIntExpr1();
+ Expected<IntWithNotMask> parseIntExpr2();
+
+ // Advance the state by one, discarding the current token.
+ // If the discarded token had an incorrect type, fail.
+ Error consumeType(Kind TokenKind);
+
+ // Check the current token type. If it's TokenKind, discard it.
+ // Return true if the parser consumed this token successfully.
+ bool consumeOptionalType(Kind TokenKind);
+
+ // Read at least MinCount, and at most MaxCount integers separated by
+ // commas. The parser stops reading after fetching MaxCount integers
+ // or after an error occurs. Whenever the parser reads a comma, it
+ // expects an integer to follow.
+ Expected<SmallVector<RCInt, 8>> readIntsWithCommas(size_t MinCount,
+ size_t MaxCount);
+
+ // Read an unknown number of flags preceded by commas. Each correct flag
+ // has an entry in FlagDesc array of length NumFlags. In case i-th
+ // flag (0-based) has been read, the result is OR-ed with FlagValues[i].
+ // As long as parser has a comma to read, it expects to be fed with
+ // a correct flag afterwards.
+ Expected<uint32_t> parseFlags(ArrayRef<StringRef> FlagDesc,
+ ArrayRef<uint32_t> FlagValues);
+
+ // Reads a set of optional statements. These can change the behavior of
+ // a number of resource types (e.g. STRINGTABLE, MENU or DIALOG) if provided
+ // before the main block with the contents of the resource.
+ // Usually, resources use a basic set of optional statements:
+ // CHARACTERISTICS, LANGUAGE, VERSION
+ // However, DIALOG and DIALOGEX extend this list by the following items:
+ // CAPTION, CLASS, EXSTYLE, FONT, MENU, STYLE
+ // UseExtendedStatements flag (off by default) allows the parser to read
+ // the additional types of statements.
+ //
+ // Ref (to the list of all optional statements):
+ // msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
+ enum class OptStmtType { BasicStmt, DialogStmt, DialogExStmt };
+
+ uint16_t parseMemoryFlags(uint16_t DefaultFlags);
+
+ Expected<OptionalStmtList>
+ parseOptionalStatements(OptStmtType StmtsType = OptStmtType::BasicStmt);
+
+ // Read a single optional statement.
+ Expected<std::unique_ptr<OptionalStmt>>
+ parseSingleOptionalStatement(OptStmtType StmtsType = OptStmtType::BasicStmt);
+
+ // Top-level resource parsers.
+ ParseType parseLanguageResource();
+ ParseType parseAcceleratorsResource();
+ ParseType parseBitmapResource();
+ ParseType parseCursorResource();
+ ParseType parseDialogResource(bool IsExtended);
+ ParseType parseIconResource();
+ ParseType parseHTMLResource();
+ ParseType parseMenuResource();
+ ParseType parseStringTableResource();
+ ParseType parseUserDefinedResource(IntOrString Type);
+ ParseType parseVersionInfoResource();
+
+ // Helper DIALOG parser - a single control.
+ Expected<Control> parseControl();
+
+ // Helper MENU parser.
+ Expected<MenuDefinitionList> parseMenuItemsList();
+
+ // Helper VERSIONINFO parser - read the contents of a single BLOCK statement,
+ // from BEGIN to END.
+ Expected<std::unique_ptr<VersionInfoBlock>>
+ parseVersionInfoBlockContents(StringRef BlockName);
+ // Helper VERSIONINFO parser - read either VALUE or BLOCK statement.
+ Expected<std::unique_ptr<VersionInfoStmt>> parseVersionInfoStmt();
+ // Helper VERSIONINFO parser - read fixed VERSIONINFO statements.
+ Expected<VersionInfoResource::VersionInfoFixed> parseVersionInfoFixed();
+
+ // Optional statement parsers.
+ ParseOptionType parseLanguageStmt();
+ ParseOptionType parseCharacteristicsStmt();
+ ParseOptionType parseVersionStmt();
+ ParseOptionType parseCaptionStmt();
+ ParseOptionType parseClassStmt();
+ ParseOptionType parseExStyleStmt();
+ ParseOptionType parseFontStmt(OptStmtType DialogType);
+ ParseOptionType parseStyleStmt();
+
+ // Raises an error. If IsAlreadyRead = false (default), this complains about
+ // the token that couldn't be parsed. If the flag is on, this complains about
+ // the correctly read token that makes no sense (that is, the current parser
+ // state is beyond the erroneous token.)
+ Error getExpectedError(const Twine &Message, bool IsAlreadyRead = false);
+
+ std::vector<RCToken> Tokens;
+ LocIter CurLoc;
+ const LocIter End;
+};
+
+} // namespace rc
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp
index ef8c345418..eaf9711af6 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp
@@ -1,294 +1,294 @@
-//
-// 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 implements methods defined in ResourceScriptStmt.h.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380599(v=vs.85).aspx
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceScriptStmt.h"
-
-namespace llvm {
-namespace rc {
-
-raw_ostream &operator<<(raw_ostream &OS, const IntOrString &Item) {
- if (Item.IsInt)
- return OS << Item.Data.Int;
- else
- return OS << Item.Data.String;
-}
-
-raw_ostream &OptionalStmtList::log(raw_ostream &OS) const {
- for (const auto &Stmt : Statements) {
- OS << " Option: ";
- Stmt->log(OS);
- }
- return OS;
-}
-
-raw_ostream &LanguageResource::log(raw_ostream &OS) const {
- return OS << "Language: " << Lang << ", Sublanguage: " << SubLang << "\n";
-}
-
-StringRef AcceleratorsResource::Accelerator::OptionsStr
- [AcceleratorsResource::Accelerator::NumFlags] = {
- "ASCII", "VIRTKEY", "NOINVERT", "ALT", "SHIFT", "CONTROL"};
-
-uint32_t AcceleratorsResource::Accelerator::OptionsFlags
- [AcceleratorsResource::Accelerator::NumFlags] = {ASCII, VIRTKEY, NOINVERT,
- ALT, SHIFT, CONTROL};
-
-raw_ostream &AcceleratorsResource::log(raw_ostream &OS) const {
- OS << "Accelerators (" << ResName << "): \n";
- OptStatements->log(OS);
- for (const auto &Acc : Accelerators) {
- OS << " Accelerator: " << Acc.Event << " " << Acc.Id;
- for (size_t i = 0; i < Accelerator::NumFlags; ++i)
- if (Acc.Flags & Accelerator::OptionsFlags[i])
- OS << " " << Accelerator::OptionsStr[i];
- OS << "\n";
- }
- return OS;
-}
-
-raw_ostream &BitmapResource::log(raw_ostream &OS) const {
- return OS << "Bitmap (" << ResName << "): " << BitmapLoc << "\n";
-}
-
-raw_ostream &CursorResource::log(raw_ostream &OS) const {
- return OS << "Cursor (" << ResName << "): " << CursorLoc << "\n";
-}
-
-raw_ostream &IconResource::log(raw_ostream &OS) const {
- return OS << "Icon (" << ResName << "): " << IconLoc << "\n";
-}
-
-raw_ostream &HTMLResource::log(raw_ostream &OS) const {
- return OS << "HTML (" << ResName << "): " << HTMLLoc << "\n";
-}
-
-StringRef MenuDefinition::OptionsStr[MenuDefinition::NumFlags] = {
- "CHECKED", "GRAYED", "HELP", "INACTIVE", "MENUBARBREAK", "MENUBREAK"};
-
-uint32_t MenuDefinition::OptionsFlags[MenuDefinition::NumFlags] = {
- CHECKED, GRAYED, HELP, INACTIVE, MENUBARBREAK, MENUBREAK};
-
-raw_ostream &MenuDefinition::logFlags(raw_ostream &OS, uint16_t Flags) {
- for (size_t i = 0; i < NumFlags; ++i)
- if (Flags & OptionsFlags[i])
- OS << " " << OptionsStr[i];
- return OS;
-}
-
-raw_ostream &MenuDefinitionList::log(raw_ostream &OS) const {
- OS << " Menu list starts\n";
- for (auto &Item : Definitions)
- Item->log(OS);
- return OS << " Menu list ends\n";
-}
-
-raw_ostream &MenuItem::log(raw_ostream &OS) const {
- OS << " MenuItem (" << Name << "), ID = " << Id;
- logFlags(OS, Flags);
- return OS << "\n";
-}
-
-raw_ostream &MenuSeparator::log(raw_ostream &OS) const {
- return OS << " Menu separator\n";
-}
-
-raw_ostream &PopupItem::log(raw_ostream &OS) const {
- OS << " Popup (" << Name << ")";
- logFlags(OS, Flags);
- OS << ":\n";
- return SubItems.log(OS);
-}
-
-raw_ostream &MenuResource::log(raw_ostream &OS) const {
- OS << "Menu (" << ResName << "):\n";
- OptStatements->log(OS);
- return Elements.log(OS);
-}
-
-raw_ostream &StringTableResource::log(raw_ostream &OS) const {
- OS << "StringTable:\n";
- OptStatements->log(OS);
- for (const auto &String : Table) {
- OS << " " << String.first << " =>";
- for (const auto &S : String.second)
- OS << " " << S;
- OS << "\n";
- }
- return OS;
-}
-
-const StringMap<Control::CtlInfo> Control::SupportedCtls = {
- {"LTEXT", CtlInfo{0x50020000, ClsStatic, true}},
- {"CTEXT", CtlInfo{0x50020001, ClsStatic, true}},
- {"RTEXT", CtlInfo{0x50020002, ClsStatic, true}},
- {"ICON", CtlInfo{0x50000003, ClsStatic, true}},
- {"PUSHBUTTON", CtlInfo{0x50010000, ClsButton, true}},
- {"DEFPUSHBUTTON", CtlInfo{0x50010001, ClsButton, true}},
- {"AUTO3STATE", CtlInfo{0x50010006, ClsButton, true}},
- {"AUTOCHECKBOX", CtlInfo{0x50010003, ClsButton, true}},
- {"AUTORADIOBUTTON", CtlInfo{0x50000009, ClsButton, true}},
- {"CHECKBOX", CtlInfo{0x50010002, ClsButton, true}},
- {"GROUPBOX", CtlInfo{0x50000007, ClsButton, true}},
- {"RADIOBUTTON", CtlInfo{0x50000004, ClsButton, true}},
- {"STATE3", CtlInfo{0x50010005, ClsButton, true}},
- {"PUSHBOX", CtlInfo{0x5001000A, ClsButton, true}},
- {"EDITTEXT", CtlInfo{0x50810000, ClsEdit, false}},
- {"COMBOBOX", CtlInfo{0x50000000, ClsComboBox, false}},
- {"LISTBOX", CtlInfo{0x50800001, ClsListBox, false}},
- {"SCROLLBAR", CtlInfo{0x50000000, ClsScrollBar, false}},
- {"CONTROL", CtlInfo{0x50000000, 0, true}},
-};
-
-raw_ostream &Control::log(raw_ostream &OS) const {
- OS << " Control (" << ID << "): " << Type << ", title: " << Title
- << ", loc: (" << X << ", " << Y << "), size: [" << Width << ", " << Height
- << "]";
- if (Style)
- OS << ", style: " << (*Style).getValue();
- if (ExtStyle)
- OS << ", ext. style: " << *ExtStyle;
- if (HelpID)
- OS << ", help ID: " << *HelpID;
- return OS << "\n";
-}
-
-raw_ostream &DialogResource::log(raw_ostream &OS) const {
- OS << "Dialog" << (IsExtended ? "Ex" : "") << " (" << ResName << "): loc: ("
- << X << ", " << Y << "), size: [" << Width << ", " << Height
- << "], help ID: " << HelpID << "\n";
- OptStatements->log(OS);
- for (auto &Ctl : Controls)
- Ctl.log(OS);
- return OS;
-}
-
-raw_ostream &VersionInfoBlock::log(raw_ostream &OS) const {
- OS << " Start of block (name: " << Name << ")\n";
- for (auto &Stmt : Stmts)
- Stmt->log(OS);
- return OS << " End of block\n";
-}
-
-raw_ostream &VersionInfoValue::log(raw_ostream &OS) const {
- OS << " " << Key << " =>";
- size_t NumValues = Values.size();
- for (size_t Id = 0; Id < NumValues; ++Id) {
- if (Id > 0 && HasPrecedingComma[Id])
- OS << ",";
- OS << " " << Values[Id];
- }
- return OS << "\n";
-}
-
-using VersionInfoFixed = VersionInfoResource::VersionInfoFixed;
-using VersionInfoFixedType = VersionInfoFixed::VersionInfoFixedType;
-
-const StringRef
- VersionInfoFixed::FixedFieldsNames[VersionInfoFixed::FtNumTypes] = {
- "", "FILEVERSION", "PRODUCTVERSION", "FILEFLAGSMASK",
- "FILEFLAGS", "FILEOS", "FILETYPE", "FILESUBTYPE"};
-
-const StringMap<VersionInfoFixedType> VersionInfoFixed::FixedFieldsInfoMap = {
- {FixedFieldsNames[FtFileVersion], FtFileVersion},
- {FixedFieldsNames[FtProductVersion], FtProductVersion},
- {FixedFieldsNames[FtFileFlagsMask], FtFileFlagsMask},
- {FixedFieldsNames[FtFileFlags], FtFileFlags},
- {FixedFieldsNames[FtFileOS], FtFileOS},
- {FixedFieldsNames[FtFileType], FtFileType},
- {FixedFieldsNames[FtFileSubtype], FtFileSubtype}};
-
-VersionInfoFixedType VersionInfoFixed::getFixedType(StringRef Type) {
- auto UpperType = Type.upper();
- auto Iter = FixedFieldsInfoMap.find(UpperType);
- if (Iter != FixedFieldsInfoMap.end())
- return Iter->getValue();
- return FtUnknown;
-}
-
-bool VersionInfoFixed::isTypeSupported(VersionInfoFixedType Type) {
- return FtUnknown < Type && Type < FtNumTypes;
-}
-
-bool VersionInfoFixed::isVersionType(VersionInfoFixedType Type) {
- switch (Type) {
- case FtFileVersion:
- case FtProductVersion:
- return true;
-
- default:
- return false;
- }
-}
-
-raw_ostream &VersionInfoFixed::log(raw_ostream &OS) const {
- for (int Type = FtUnknown; Type < FtNumTypes; ++Type) {
- if (!isTypeSupported((VersionInfoFixedType)Type))
- continue;
- OS << " Fixed: " << FixedFieldsNames[Type] << ":";
- for (uint32_t Val : FixedInfo[Type])
- OS << " " << Val;
- OS << "\n";
- }
- return OS;
-}
-
-raw_ostream &VersionInfoResource::log(raw_ostream &OS) const {
- OS << "VersionInfo (" << ResName << "):\n";
- FixedData.log(OS);
- return MainBlock.log(OS);
-}
-
-raw_ostream &UserDefinedResource::log(raw_ostream &OS) const {
- OS << "User-defined (type: " << Type << ", name: " << ResName << "): ";
- if (IsFileResource)
- return OS << FileLoc << "\n";
- OS << "data = ";
- for (auto &Item : Contents)
- OS << Item << " ";
- return OS << "\n";
-}
-
-raw_ostream &CharacteristicsStmt::log(raw_ostream &OS) const {
- return OS << "Characteristics: " << Value << "\n";
-}
-
-raw_ostream &VersionStmt::log(raw_ostream &OS) const {
- return OS << "Version: " << Value << "\n";
-}
-
-raw_ostream &CaptionStmt::log(raw_ostream &OS) const {
- return OS << "Caption: " << Value << "\n";
-}
-
-raw_ostream &ClassStmt::log(raw_ostream &OS) const {
- return OS << "Class: " << Value << "\n";
-}
-
-raw_ostream &FontStmt::log(raw_ostream &OS) const {
- OS << "Font: size = " << Size << ", face = " << Name
- << ", weight = " << Weight;
- if (Italic)
- OS << ", italic";
- return OS << ", charset = " << Charset << "\n";
-}
-
-raw_ostream &StyleStmt::log(raw_ostream &OS) const {
- return OS << "Style: " << Value << "\n";
-}
-
-raw_ostream &ExStyleStmt::log(raw_ostream &OS) const {
- return OS << "ExStyle: " << Value << "\n";
-}
-
-} // namespace rc
-} // namespace 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 implements methods defined in ResourceScriptStmt.h.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380599(v=vs.85).aspx
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceScriptStmt.h"
+
+namespace llvm {
+namespace rc {
+
+raw_ostream &operator<<(raw_ostream &OS, const IntOrString &Item) {
+ if (Item.IsInt)
+ return OS << Item.Data.Int;
+ else
+ return OS << Item.Data.String;
+}
+
+raw_ostream &OptionalStmtList::log(raw_ostream &OS) const {
+ for (const auto &Stmt : Statements) {
+ OS << " Option: ";
+ Stmt->log(OS);
+ }
+ return OS;
+}
+
+raw_ostream &LanguageResource::log(raw_ostream &OS) const {
+ return OS << "Language: " << Lang << ", Sublanguage: " << SubLang << "\n";
+}
+
+StringRef AcceleratorsResource::Accelerator::OptionsStr
+ [AcceleratorsResource::Accelerator::NumFlags] = {
+ "ASCII", "VIRTKEY", "NOINVERT", "ALT", "SHIFT", "CONTROL"};
+
+uint32_t AcceleratorsResource::Accelerator::OptionsFlags
+ [AcceleratorsResource::Accelerator::NumFlags] = {ASCII, VIRTKEY, NOINVERT,
+ ALT, SHIFT, CONTROL};
+
+raw_ostream &AcceleratorsResource::log(raw_ostream &OS) const {
+ OS << "Accelerators (" << ResName << "): \n";
+ OptStatements->log(OS);
+ for (const auto &Acc : Accelerators) {
+ OS << " Accelerator: " << Acc.Event << " " << Acc.Id;
+ for (size_t i = 0; i < Accelerator::NumFlags; ++i)
+ if (Acc.Flags & Accelerator::OptionsFlags[i])
+ OS << " " << Accelerator::OptionsStr[i];
+ OS << "\n";
+ }
+ return OS;
+}
+
+raw_ostream &BitmapResource::log(raw_ostream &OS) const {
+ return OS << "Bitmap (" << ResName << "): " << BitmapLoc << "\n";
+}
+
+raw_ostream &CursorResource::log(raw_ostream &OS) const {
+ return OS << "Cursor (" << ResName << "): " << CursorLoc << "\n";
+}
+
+raw_ostream &IconResource::log(raw_ostream &OS) const {
+ return OS << "Icon (" << ResName << "): " << IconLoc << "\n";
+}
+
+raw_ostream &HTMLResource::log(raw_ostream &OS) const {
+ return OS << "HTML (" << ResName << "): " << HTMLLoc << "\n";
+}
+
+StringRef MenuDefinition::OptionsStr[MenuDefinition::NumFlags] = {
+ "CHECKED", "GRAYED", "HELP", "INACTIVE", "MENUBARBREAK", "MENUBREAK"};
+
+uint32_t MenuDefinition::OptionsFlags[MenuDefinition::NumFlags] = {
+ CHECKED, GRAYED, HELP, INACTIVE, MENUBARBREAK, MENUBREAK};
+
+raw_ostream &MenuDefinition::logFlags(raw_ostream &OS, uint16_t Flags) {
+ for (size_t i = 0; i < NumFlags; ++i)
+ if (Flags & OptionsFlags[i])
+ OS << " " << OptionsStr[i];
+ return OS;
+}
+
+raw_ostream &MenuDefinitionList::log(raw_ostream &OS) const {
+ OS << " Menu list starts\n";
+ for (auto &Item : Definitions)
+ Item->log(OS);
+ return OS << " Menu list ends\n";
+}
+
+raw_ostream &MenuItem::log(raw_ostream &OS) const {
+ OS << " MenuItem (" << Name << "), ID = " << Id;
+ logFlags(OS, Flags);
+ return OS << "\n";
+}
+
+raw_ostream &MenuSeparator::log(raw_ostream &OS) const {
+ return OS << " Menu separator\n";
+}
+
+raw_ostream &PopupItem::log(raw_ostream &OS) const {
+ OS << " Popup (" << Name << ")";
+ logFlags(OS, Flags);
+ OS << ":\n";
+ return SubItems.log(OS);
+}
+
+raw_ostream &MenuResource::log(raw_ostream &OS) const {
+ OS << "Menu (" << ResName << "):\n";
+ OptStatements->log(OS);
+ return Elements.log(OS);
+}
+
+raw_ostream &StringTableResource::log(raw_ostream &OS) const {
+ OS << "StringTable:\n";
+ OptStatements->log(OS);
+ for (const auto &String : Table) {
+ OS << " " << String.first << " =>";
+ for (const auto &S : String.second)
+ OS << " " << S;
+ OS << "\n";
+ }
+ return OS;
+}
+
+const StringMap<Control::CtlInfo> Control::SupportedCtls = {
+ {"LTEXT", CtlInfo{0x50020000, ClsStatic, true}},
+ {"CTEXT", CtlInfo{0x50020001, ClsStatic, true}},
+ {"RTEXT", CtlInfo{0x50020002, ClsStatic, true}},
+ {"ICON", CtlInfo{0x50000003, ClsStatic, true}},
+ {"PUSHBUTTON", CtlInfo{0x50010000, ClsButton, true}},
+ {"DEFPUSHBUTTON", CtlInfo{0x50010001, ClsButton, true}},
+ {"AUTO3STATE", CtlInfo{0x50010006, ClsButton, true}},
+ {"AUTOCHECKBOX", CtlInfo{0x50010003, ClsButton, true}},
+ {"AUTORADIOBUTTON", CtlInfo{0x50000009, ClsButton, true}},
+ {"CHECKBOX", CtlInfo{0x50010002, ClsButton, true}},
+ {"GROUPBOX", CtlInfo{0x50000007, ClsButton, true}},
+ {"RADIOBUTTON", CtlInfo{0x50000004, ClsButton, true}},
+ {"STATE3", CtlInfo{0x50010005, ClsButton, true}},
+ {"PUSHBOX", CtlInfo{0x5001000A, ClsButton, true}},
+ {"EDITTEXT", CtlInfo{0x50810000, ClsEdit, false}},
+ {"COMBOBOX", CtlInfo{0x50000000, ClsComboBox, false}},
+ {"LISTBOX", CtlInfo{0x50800001, ClsListBox, false}},
+ {"SCROLLBAR", CtlInfo{0x50000000, ClsScrollBar, false}},
+ {"CONTROL", CtlInfo{0x50000000, 0, true}},
+};
+
+raw_ostream &Control::log(raw_ostream &OS) const {
+ OS << " Control (" << ID << "): " << Type << ", title: " << Title
+ << ", loc: (" << X << ", " << Y << "), size: [" << Width << ", " << Height
+ << "]";
+ if (Style)
+ OS << ", style: " << (*Style).getValue();
+ if (ExtStyle)
+ OS << ", ext. style: " << *ExtStyle;
+ if (HelpID)
+ OS << ", help ID: " << *HelpID;
+ return OS << "\n";
+}
+
+raw_ostream &DialogResource::log(raw_ostream &OS) const {
+ OS << "Dialog" << (IsExtended ? "Ex" : "") << " (" << ResName << "): loc: ("
+ << X << ", " << Y << "), size: [" << Width << ", " << Height
+ << "], help ID: " << HelpID << "\n";
+ OptStatements->log(OS);
+ for (auto &Ctl : Controls)
+ Ctl.log(OS);
+ return OS;
+}
+
+raw_ostream &VersionInfoBlock::log(raw_ostream &OS) const {
+ OS << " Start of block (name: " << Name << ")\n";
+ for (auto &Stmt : Stmts)
+ Stmt->log(OS);
+ return OS << " End of block\n";
+}
+
+raw_ostream &VersionInfoValue::log(raw_ostream &OS) const {
+ OS << " " << Key << " =>";
+ size_t NumValues = Values.size();
+ for (size_t Id = 0; Id < NumValues; ++Id) {
+ if (Id > 0 && HasPrecedingComma[Id])
+ OS << ",";
+ OS << " " << Values[Id];
+ }
+ return OS << "\n";
+}
+
+using VersionInfoFixed = VersionInfoResource::VersionInfoFixed;
+using VersionInfoFixedType = VersionInfoFixed::VersionInfoFixedType;
+
+const StringRef
+ VersionInfoFixed::FixedFieldsNames[VersionInfoFixed::FtNumTypes] = {
+ "", "FILEVERSION", "PRODUCTVERSION", "FILEFLAGSMASK",
+ "FILEFLAGS", "FILEOS", "FILETYPE", "FILESUBTYPE"};
+
+const StringMap<VersionInfoFixedType> VersionInfoFixed::FixedFieldsInfoMap = {
+ {FixedFieldsNames[FtFileVersion], FtFileVersion},
+ {FixedFieldsNames[FtProductVersion], FtProductVersion},
+ {FixedFieldsNames[FtFileFlagsMask], FtFileFlagsMask},
+ {FixedFieldsNames[FtFileFlags], FtFileFlags},
+ {FixedFieldsNames[FtFileOS], FtFileOS},
+ {FixedFieldsNames[FtFileType], FtFileType},
+ {FixedFieldsNames[FtFileSubtype], FtFileSubtype}};
+
+VersionInfoFixedType VersionInfoFixed::getFixedType(StringRef Type) {
+ auto UpperType = Type.upper();
+ auto Iter = FixedFieldsInfoMap.find(UpperType);
+ if (Iter != FixedFieldsInfoMap.end())
+ return Iter->getValue();
+ return FtUnknown;
+}
+
+bool VersionInfoFixed::isTypeSupported(VersionInfoFixedType Type) {
+ return FtUnknown < Type && Type < FtNumTypes;
+}
+
+bool VersionInfoFixed::isVersionType(VersionInfoFixedType Type) {
+ switch (Type) {
+ case FtFileVersion:
+ case FtProductVersion:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+raw_ostream &VersionInfoFixed::log(raw_ostream &OS) const {
+ for (int Type = FtUnknown; Type < FtNumTypes; ++Type) {
+ if (!isTypeSupported((VersionInfoFixedType)Type))
+ continue;
+ OS << " Fixed: " << FixedFieldsNames[Type] << ":";
+ for (uint32_t Val : FixedInfo[Type])
+ OS << " " << Val;
+ OS << "\n";
+ }
+ return OS;
+}
+
+raw_ostream &VersionInfoResource::log(raw_ostream &OS) const {
+ OS << "VersionInfo (" << ResName << "):\n";
+ FixedData.log(OS);
+ return MainBlock.log(OS);
+}
+
+raw_ostream &UserDefinedResource::log(raw_ostream &OS) const {
+ OS << "User-defined (type: " << Type << ", name: " << ResName << "): ";
+ if (IsFileResource)
+ return OS << FileLoc << "\n";
+ OS << "data = ";
+ for (auto &Item : Contents)
+ OS << Item << " ";
+ return OS << "\n";
+}
+
+raw_ostream &CharacteristicsStmt::log(raw_ostream &OS) const {
+ return OS << "Characteristics: " << Value << "\n";
+}
+
+raw_ostream &VersionStmt::log(raw_ostream &OS) const {
+ return OS << "Version: " << Value << "\n";
+}
+
+raw_ostream &CaptionStmt::log(raw_ostream &OS) const {
+ return OS << "Caption: " << Value << "\n";
+}
+
+raw_ostream &ClassStmt::log(raw_ostream &OS) const {
+ return OS << "Class: " << Value << "\n";
+}
+
+raw_ostream &FontStmt::log(raw_ostream &OS) const {
+ OS << "Font: size = " << Size << ", face = " << Name
+ << ", weight = " << Weight;
+ if (Italic)
+ OS << ", italic";
+ return OS << ", charset = " << Charset << "\n";
+}
+
+raw_ostream &StyleStmt::log(raw_ostream &OS) const {
+ return OS << "Style: " << Value << "\n";
+}
+
+raw_ostream &ExStyleStmt::log(raw_ostream &OS) const {
+ return OS << "ExStyle: " << Value << "\n";
+}
+
+} // namespace rc
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h
index 27fbea3ae8..0b56f39f83 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h
@@ -1,953 +1,953 @@
-//===-- ResourceScriptStmt.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
-//
-//===---------------------------------------------------------------------===//
-//
-// This lists all the resource and statement types occurring in RC scripts.
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
-
-#include "ResourceScriptToken.h"
-#include "ResourceVisitor.h"
-
-#include "llvm/ADT/StringSet.h"
-
-namespace llvm {
-namespace rc {
-
-// Integer wrapper that also holds information whether the user declared
-// the integer to be long (by appending L to the end of the integer) or not.
-// It allows to be implicitly cast from and to uint32_t in order
-// to be compatible with the parts of code that don't care about the integers
-// being marked long.
-class RCInt {
- uint32_t Val;
- bool Long;
-
-public:
- RCInt(const RCToken &Token)
- : Val(Token.intValue()), Long(Token.isLongInt()) {}
- RCInt(uint32_t Value) : Val(Value), Long(false) {}
- RCInt(uint32_t Value, bool IsLong) : Val(Value), Long(IsLong) {}
- operator uint32_t() const { return Val; }
- bool isLong() const { return Long; }
-
- RCInt &operator+=(const RCInt &Rhs) {
- std::tie(Val, Long) = std::make_pair(Val + Rhs.Val, Long | Rhs.Long);
- return *this;
- }
-
- RCInt &operator-=(const RCInt &Rhs) {
- std::tie(Val, Long) = std::make_pair(Val - Rhs.Val, Long | Rhs.Long);
- return *this;
- }
-
- RCInt &operator|=(const RCInt &Rhs) {
- std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long);
- return *this;
- }
-
- RCInt &operator&=(const RCInt &Rhs) {
- std::tie(Val, Long) = std::make_pair(Val & Rhs.Val, Long | Rhs.Long);
- return *this;
- }
-
- RCInt operator-() const { return {-Val, Long}; }
- RCInt operator~() const { return {~Val, Long}; }
-
- friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) {
- return OS << Int.Val << (Int.Long ? "L" : "");
- }
-};
-
-class IntWithNotMask {
-private:
- RCInt Value;
- int32_t NotMask;
-
-public:
- IntWithNotMask() : IntWithNotMask(RCInt(0)) {}
- IntWithNotMask(RCInt Value, int32_t NotMask = 0) : Value(Value), NotMask(NotMask) {}
-
- RCInt getValue() const {
- return Value;
- }
-
- uint32_t getNotMask() const {
- return NotMask;
- }
-
- IntWithNotMask &operator+=(const IntWithNotMask &Rhs) {
- Value &= ~Rhs.NotMask;
- Value += Rhs.Value;
- NotMask |= Rhs.NotMask;
- return *this;
- }
-
- IntWithNotMask &operator-=(const IntWithNotMask &Rhs) {
- Value &= ~Rhs.NotMask;
- Value -= Rhs.Value;
- NotMask |= Rhs.NotMask;
- return *this;
- }
-
- IntWithNotMask &operator|=(const IntWithNotMask &Rhs) {
- Value &= ~Rhs.NotMask;
- Value |= Rhs.Value;
- NotMask |= Rhs.NotMask;
- return *this;
- }
-
- IntWithNotMask &operator&=(const IntWithNotMask &Rhs) {
- Value &= ~Rhs.NotMask;
- Value &= Rhs.Value;
- NotMask |= Rhs.NotMask;
- return *this;
- }
-
- IntWithNotMask operator-() const { return {-Value, NotMask}; }
- IntWithNotMask operator~() const { return {~Value, 0}; }
-
- friend raw_ostream &operator<<(raw_ostream &OS, const IntWithNotMask &Int) {
- return OS << Int.Value;
- }
-};
-
-// A class holding a name - either an integer or a reference to the string.
-class IntOrString {
-private:
- union Data {
- RCInt Int;
- StringRef String;
- Data(RCInt Value) : Int(Value) {}
- Data(const StringRef Value) : String(Value) {}
- Data(const RCToken &Token) {
- if (Token.kind() == RCToken::Kind::Int)
- Int = RCInt(Token);
- else
- String = Token.value();
- }
- } Data;
- bool IsInt;
-
-public:
- IntOrString() : IntOrString(RCInt(0)) {}
- IntOrString(uint32_t Value) : Data(Value), IsInt(1) {}
- IntOrString(RCInt Value) : Data(Value), IsInt(1) {}
- IntOrString(StringRef Value) : Data(Value), IsInt(0) {}
- IntOrString(const RCToken &Token)
- : Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {}
-
- bool equalsLower(const char *Str) {
- return !IsInt && Data.String.equals_lower(Str);
- }
-
- bool isInt() const { return IsInt; }
-
- RCInt getInt() const {
- assert(IsInt);
- return Data.Int;
- }
-
- const StringRef &getString() const {
- assert(!IsInt);
- return Data.String;
- }
-
- operator Twine() const {
- return isInt() ? Twine(getInt()) : Twine(getString());
- }
-
- friend raw_ostream &operator<<(raw_ostream &, const IntOrString &);
-};
-
-enum ResourceKind {
- // These resource kinds have corresponding .res resource type IDs
- // (TYPE in RESOURCEHEADER structure). The numeric value assigned to each
- // kind is equal to this type ID.
- RkNull = 0,
- RkSingleCursor = 1,
- RkBitmap = 2,
- RkSingleIcon = 3,
- RkMenu = 4,
- RkDialog = 5,
- RkStringTableBundle = 6,
- RkAccelerators = 9,
- RkRcData = 10,
- RkCursorGroup = 12,
- RkIconGroup = 14,
- RkVersionInfo = 16,
- RkHTML = 23,
-
- // These kinds don't have assigned type IDs (they might be the resources
- // of invalid kind, expand to many resource structures in .res files,
- // or have variable type ID). In order to avoid ID clashes with IDs above,
- // we assign the kinds the values 256 and larger.
- RkInvalid = 256,
- RkBase,
- RkCursor,
- RkIcon,
- RkStringTable,
- RkUser,
- RkSingleCursorOrIconRes,
- RkCursorOrIconGroupRes,
-};
-
-// Non-zero memory flags.
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
-enum MemoryFlags {
- MfMoveable = 0x10,
- MfPure = 0x20,
- MfPreload = 0x40,
- MfDiscardable = 0x1000
-};
-
-// Base resource. All the resources should derive from this base.
-class RCResource {
-public:
- IntOrString ResName;
- uint16_t MemoryFlags = getDefaultMemoryFlags();
- void setName(const IntOrString &Name) { ResName = Name; }
- virtual raw_ostream &log(raw_ostream &OS) const {
- return OS << "Base statement\n";
- };
- RCResource() {}
- RCResource(uint16_t Flags) : MemoryFlags(Flags) {}
- virtual ~RCResource() {}
-
- virtual Error visit(Visitor *) const {
- llvm_unreachable("This is unable to call methods from Visitor base");
- }
-
- // Apply the statements attached to this resource. Generic resources
- // don't have any.
- virtual Error applyStmts(Visitor *) const { return Error::success(); }
-
- // By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
- static uint16_t getDefaultMemoryFlags() {
- return MfDiscardable | MfPure | MfMoveable;
- }
-
- virtual ResourceKind getKind() const { return RkBase; }
- static bool classof(const RCResource *Res) { return true; }
-
- virtual IntOrString getResourceType() const {
- llvm_unreachable("This cannot be called on objects without types.");
- }
- virtual Twine getResourceTypeName() const {
- llvm_unreachable("This cannot be called on objects without types.");
- };
-};
-
-// An empty resource. It has no content, type 0, ID 0 and all of its
-// characteristics are equal to 0.
-class NullResource : public RCResource {
-public:
- NullResource() : RCResource(0) {}
- raw_ostream &log(raw_ostream &OS) const override {
- return OS << "Null resource\n";
- }
- Error visit(Visitor *V) const override { return V->visitNullResource(this); }
- IntOrString getResourceType() const override { return 0; }
- Twine getResourceTypeName() const override { return "(NULL)"; }
-};
-
-// Optional statement base. All such statements should derive from this base.
-class OptionalStmt : public RCResource {};
-
-class OptionalStmtList : public OptionalStmt {
- std::vector<std::unique_ptr<OptionalStmt>> Statements;
-
-public:
- OptionalStmtList() {}
- raw_ostream &log(raw_ostream &OS) const override;
-
- void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
- Statements.push_back(std::move(Stmt));
- }
-
- Error visit(Visitor *V) const override {
- for (auto &StmtPtr : Statements)
- if (auto Err = StmtPtr->visit(V))
- return Err;
- return Error::success();
- }
-};
-
-class OptStatementsRCResource : public RCResource {
-public:
- std::unique_ptr<OptionalStmtList> OptStatements;
-
- OptStatementsRCResource(OptionalStmtList &&Stmts,
- uint16_t Flags = RCResource::getDefaultMemoryFlags())
- : RCResource(Flags),
- OptStatements(std::make_unique<OptionalStmtList>(std::move(Stmts))) {}
-
+//===-- ResourceScriptStmt.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
+//
+//===---------------------------------------------------------------------===//
+//
+// This lists all the resource and statement types occurring in RC scripts.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
+
+#include "ResourceScriptToken.h"
+#include "ResourceVisitor.h"
+
+#include "llvm/ADT/StringSet.h"
+
+namespace llvm {
+namespace rc {
+
+// Integer wrapper that also holds information whether the user declared
+// the integer to be long (by appending L to the end of the integer) or not.
+// It allows to be implicitly cast from and to uint32_t in order
+// to be compatible with the parts of code that don't care about the integers
+// being marked long.
+class RCInt {
+ uint32_t Val;
+ bool Long;
+
+public:
+ RCInt(const RCToken &Token)
+ : Val(Token.intValue()), Long(Token.isLongInt()) {}
+ RCInt(uint32_t Value) : Val(Value), Long(false) {}
+ RCInt(uint32_t Value, bool IsLong) : Val(Value), Long(IsLong) {}
+ operator uint32_t() const { return Val; }
+ bool isLong() const { return Long; }
+
+ RCInt &operator+=(const RCInt &Rhs) {
+ std::tie(Val, Long) = std::make_pair(Val + Rhs.Val, Long | Rhs.Long);
+ return *this;
+ }
+
+ RCInt &operator-=(const RCInt &Rhs) {
+ std::tie(Val, Long) = std::make_pair(Val - Rhs.Val, Long | Rhs.Long);
+ return *this;
+ }
+
+ RCInt &operator|=(const RCInt &Rhs) {
+ std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long);
+ return *this;
+ }
+
+ RCInt &operator&=(const RCInt &Rhs) {
+ std::tie(Val, Long) = std::make_pair(Val & Rhs.Val, Long | Rhs.Long);
+ return *this;
+ }
+
+ RCInt operator-() const { return {-Val, Long}; }
+ RCInt operator~() const { return {~Val, Long}; }
+
+ friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) {
+ return OS << Int.Val << (Int.Long ? "L" : "");
+ }
+};
+
+class IntWithNotMask {
+private:
+ RCInt Value;
+ int32_t NotMask;
+
+public:
+ IntWithNotMask() : IntWithNotMask(RCInt(0)) {}
+ IntWithNotMask(RCInt Value, int32_t NotMask = 0) : Value(Value), NotMask(NotMask) {}
+
+ RCInt getValue() const {
+ return Value;
+ }
+
+ uint32_t getNotMask() const {
+ return NotMask;
+ }
+
+ IntWithNotMask &operator+=(const IntWithNotMask &Rhs) {
+ Value &= ~Rhs.NotMask;
+ Value += Rhs.Value;
+ NotMask |= Rhs.NotMask;
+ return *this;
+ }
+
+ IntWithNotMask &operator-=(const IntWithNotMask &Rhs) {
+ Value &= ~Rhs.NotMask;
+ Value -= Rhs.Value;
+ NotMask |= Rhs.NotMask;
+ return *this;
+ }
+
+ IntWithNotMask &operator|=(const IntWithNotMask &Rhs) {
+ Value &= ~Rhs.NotMask;
+ Value |= Rhs.Value;
+ NotMask |= Rhs.NotMask;
+ return *this;
+ }
+
+ IntWithNotMask &operator&=(const IntWithNotMask &Rhs) {
+ Value &= ~Rhs.NotMask;
+ Value &= Rhs.Value;
+ NotMask |= Rhs.NotMask;
+ return *this;
+ }
+
+ IntWithNotMask operator-() const { return {-Value, NotMask}; }
+ IntWithNotMask operator~() const { return {~Value, 0}; }
+
+ friend raw_ostream &operator<<(raw_ostream &OS, const IntWithNotMask &Int) {
+ return OS << Int.Value;
+ }
+};
+
+// A class holding a name - either an integer or a reference to the string.
+class IntOrString {
+private:
+ union Data {
+ RCInt Int;
+ StringRef String;
+ Data(RCInt Value) : Int(Value) {}
+ Data(const StringRef Value) : String(Value) {}
+ Data(const RCToken &Token) {
+ if (Token.kind() == RCToken::Kind::Int)
+ Int = RCInt(Token);
+ else
+ String = Token.value();
+ }
+ } Data;
+ bool IsInt;
+
+public:
+ IntOrString() : IntOrString(RCInt(0)) {}
+ IntOrString(uint32_t Value) : Data(Value), IsInt(1) {}
+ IntOrString(RCInt Value) : Data(Value), IsInt(1) {}
+ IntOrString(StringRef Value) : Data(Value), IsInt(0) {}
+ IntOrString(const RCToken &Token)
+ : Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {}
+
+ bool equalsLower(const char *Str) {
+ return !IsInt && Data.String.equals_lower(Str);
+ }
+
+ bool isInt() const { return IsInt; }
+
+ RCInt getInt() const {
+ assert(IsInt);
+ return Data.Int;
+ }
+
+ const StringRef &getString() const {
+ assert(!IsInt);
+ return Data.String;
+ }
+
+ operator Twine() const {
+ return isInt() ? Twine(getInt()) : Twine(getString());
+ }
+
+ friend raw_ostream &operator<<(raw_ostream &, const IntOrString &);
+};
+
+enum ResourceKind {
+ // These resource kinds have corresponding .res resource type IDs
+ // (TYPE in RESOURCEHEADER structure). The numeric value assigned to each
+ // kind is equal to this type ID.
+ RkNull = 0,
+ RkSingleCursor = 1,
+ RkBitmap = 2,
+ RkSingleIcon = 3,
+ RkMenu = 4,
+ RkDialog = 5,
+ RkStringTableBundle = 6,
+ RkAccelerators = 9,
+ RkRcData = 10,
+ RkCursorGroup = 12,
+ RkIconGroup = 14,
+ RkVersionInfo = 16,
+ RkHTML = 23,
+
+ // These kinds don't have assigned type IDs (they might be the resources
+ // of invalid kind, expand to many resource structures in .res files,
+ // or have variable type ID). In order to avoid ID clashes with IDs above,
+ // we assign the kinds the values 256 and larger.
+ RkInvalid = 256,
+ RkBase,
+ RkCursor,
+ RkIcon,
+ RkStringTable,
+ RkUser,
+ RkSingleCursorOrIconRes,
+ RkCursorOrIconGroupRes,
+};
+
+// Non-zero memory flags.
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
+enum MemoryFlags {
+ MfMoveable = 0x10,
+ MfPure = 0x20,
+ MfPreload = 0x40,
+ MfDiscardable = 0x1000
+};
+
+// Base resource. All the resources should derive from this base.
+class RCResource {
+public:
+ IntOrString ResName;
+ uint16_t MemoryFlags = getDefaultMemoryFlags();
+ void setName(const IntOrString &Name) { ResName = Name; }
+ virtual raw_ostream &log(raw_ostream &OS) const {
+ return OS << "Base statement\n";
+ };
+ RCResource() {}
+ RCResource(uint16_t Flags) : MemoryFlags(Flags) {}
+ virtual ~RCResource() {}
+
+ virtual Error visit(Visitor *) const {
+ llvm_unreachable("This is unable to call methods from Visitor base");
+ }
+
+ // Apply the statements attached to this resource. Generic resources
+ // don't have any.
+ virtual Error applyStmts(Visitor *) const { return Error::success(); }
+
+ // By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
+ static uint16_t getDefaultMemoryFlags() {
+ return MfDiscardable | MfPure | MfMoveable;
+ }
+
+ virtual ResourceKind getKind() const { return RkBase; }
+ static bool classof(const RCResource *Res) { return true; }
+
+ virtual IntOrString getResourceType() const {
+ llvm_unreachable("This cannot be called on objects without types.");
+ }
+ virtual Twine getResourceTypeName() const {
+ llvm_unreachable("This cannot be called on objects without types.");
+ };
+};
+
+// An empty resource. It has no content, type 0, ID 0 and all of its
+// characteristics are equal to 0.
+class NullResource : public RCResource {
+public:
+ NullResource() : RCResource(0) {}
+ raw_ostream &log(raw_ostream &OS) const override {
+ return OS << "Null resource\n";
+ }
+ Error visit(Visitor *V) const override { return V->visitNullResource(this); }
+ IntOrString getResourceType() const override { return 0; }
+ Twine getResourceTypeName() const override { return "(NULL)"; }
+};
+
+// Optional statement base. All such statements should derive from this base.
+class OptionalStmt : public RCResource {};
+
+class OptionalStmtList : public OptionalStmt {
+ std::vector<std::unique_ptr<OptionalStmt>> Statements;
+
+public:
+ OptionalStmtList() {}
+ raw_ostream &log(raw_ostream &OS) const override;
+
+ void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
+ Statements.push_back(std::move(Stmt));
+ }
+
+ Error visit(Visitor *V) const override {
+ for (auto &StmtPtr : Statements)
+ if (auto Err = StmtPtr->visit(V))
+ return Err;
+ return Error::success();
+ }
+};
+
+class OptStatementsRCResource : public RCResource {
+public:
+ std::unique_ptr<OptionalStmtList> OptStatements;
+
+ OptStatementsRCResource(OptionalStmtList &&Stmts,
+ uint16_t Flags = RCResource::getDefaultMemoryFlags())
+ : RCResource(Flags),
+ OptStatements(std::make_unique<OptionalStmtList>(std::move(Stmts))) {}
+
Error applyStmts(Visitor *V) const override {
return OptStatements->visit(V);
}
-};
-
-// LANGUAGE statement. It can occur both as a top-level statement (in such
-// a situation, it changes the default language until the end of the file)
-// and as an optional resource statement (then it changes the language
-// of a single resource).
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx
-class LanguageResource : public OptionalStmt {
-public:
- uint32_t Lang, SubLang;
-
- LanguageResource(uint32_t LangId, uint32_t SubLangId)
- : Lang(LangId), SubLang(SubLangId) {}
- raw_ostream &log(raw_ostream &) const override;
-
- // This is not a regular top-level statement; when it occurs, it just
- // modifies the language context.
- Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
- Twine getResourceTypeName() const override { return "LANGUAGE"; }
-};
-
-// ACCELERATORS resource. Defines a named table of accelerators for the app.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx
-class AcceleratorsResource : public OptStatementsRCResource {
-public:
- class Accelerator {
- public:
- IntOrString Event;
- uint32_t Id;
- uint16_t Flags;
-
- enum Options {
- // This is actually 0x0000 (accelerator is assumed to be ASCII if it's
- // not VIRTKEY). However, rc.exe behavior is different in situations
- // "only ASCII defined" and "neither ASCII nor VIRTKEY defined".
- // Therefore, we include ASCII as another flag. This must be zeroed
- // when serialized.
- ASCII = 0x8000,
- VIRTKEY = 0x0001,
- NOINVERT = 0x0002,
- ALT = 0x0010,
- SHIFT = 0x0004,
- CONTROL = 0x0008
- };
-
- static constexpr size_t NumFlags = 6;
- static StringRef OptionsStr[NumFlags];
- static uint32_t OptionsFlags[NumFlags];
- };
-
- AcceleratorsResource(OptionalStmtList &&List, uint16_t Flags)
- : OptStatementsRCResource(std::move(List), Flags) {}
-
- std::vector<Accelerator> Accelerators;
-
- void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
- Accelerators.push_back(Accelerator{Event, Id, Flags});
- }
- raw_ostream &log(raw_ostream &) const override;
-
- IntOrString getResourceType() const override { return RkAccelerators; }
- static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
- Twine getResourceTypeName() const override { return "ACCELERATORS"; }
-
- Error visit(Visitor *V) const override {
- return V->visitAcceleratorsResource(this);
- }
- ResourceKind getKind() const override { return RkAccelerators; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkAccelerators;
- }
-};
-
-// BITMAP resource. Represents a bitmap (".bmp") file.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx
-class BitmapResource : public RCResource {
-public:
- StringRef BitmapLoc;
-
- BitmapResource(StringRef Location, uint16_t Flags)
- : RCResource(Flags), BitmapLoc(Location) {}
- raw_ostream &log(raw_ostream &) const override;
-
- IntOrString getResourceType() const override { return RkBitmap; }
- static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
-
- Twine getResourceTypeName() const override { return "BITMAP"; }
- Error visit(Visitor *V) const override {
- return V->visitBitmapResource(this);
- }
- ResourceKind getKind() const override { return RkBitmap; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkBitmap;
- }
-};
-
-// CURSOR resource. Represents a single cursor (".cur") file.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
-class CursorResource : public RCResource {
-public:
- StringRef CursorLoc;
-
- CursorResource(StringRef Location, uint16_t Flags)
- : RCResource(Flags), CursorLoc(Location) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Twine getResourceTypeName() const override { return "CURSOR"; }
- static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
- Error visit(Visitor *V) const override {
- return V->visitCursorResource(this);
- }
- ResourceKind getKind() const override { return RkCursor; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkCursor;
- }
-};
-
-// ICON resource. Represents a single ".ico" file containing a group of icons.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
-class IconResource : public RCResource {
-public:
- StringRef IconLoc;
-
- IconResource(StringRef Location, uint16_t Flags)
- : RCResource(Flags), IconLoc(Location) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Twine getResourceTypeName() const override { return "ICON"; }
- static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
- Error visit(Visitor *V) const override { return V->visitIconResource(this); }
- ResourceKind getKind() const override { return RkIcon; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkIcon;
- }
-};
-
-// HTML resource. Represents a local webpage that is to be embedded into the
-// resulting resource file. It embeds a file only - no additional resources
-// (images etc.) are included with this resource.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx
-class HTMLResource : public RCResource {
-public:
- StringRef HTMLLoc;
-
- HTMLResource(StringRef Location, uint16_t Flags)
- : RCResource(Flags), HTMLLoc(Location) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
-
- // Curiously, file resources don't have DISCARDABLE flag set.
- static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
- IntOrString getResourceType() const override { return RkHTML; }
- Twine getResourceTypeName() const override { return "HTML"; }
- ResourceKind getKind() const override { return RkHTML; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkHTML;
- }
-};
-
-// -- MENU resource and its helper classes --
-// This resource describes the contents of an application menu
-// (usually located in the upper part of the dialog.)
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx
-
-// Description of a single submenu item.
-class MenuDefinition {
-public:
- enum Options {
- CHECKED = 0x0008,
- GRAYED = 0x0001,
- HELP = 0x4000,
- INACTIVE = 0x0002,
- MENUBARBREAK = 0x0020,
- MENUBREAK = 0x0040
- };
-
- enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
-
- static constexpr size_t NumFlags = 6;
- static StringRef OptionsStr[NumFlags];
- static uint32_t OptionsFlags[NumFlags];
- static raw_ostream &logFlags(raw_ostream &, uint16_t Flags);
- virtual raw_ostream &log(raw_ostream &OS) const {
- return OS << "Base menu definition\n";
- }
- virtual ~MenuDefinition() {}
-
- virtual uint16_t getResFlags() const { return 0; }
- virtual MenuDefKind getKind() const { return MkBase; }
-};
-
-// Recursive description of a whole submenu.
-class MenuDefinitionList : public MenuDefinition {
-public:
- std::vector<std::unique_ptr<MenuDefinition>> Definitions;
-
- void addDefinition(std::unique_ptr<MenuDefinition> Def) {
- Definitions.push_back(std::move(Def));
- }
- raw_ostream &log(raw_ostream &) const override;
-};
-
-// Separator in MENU definition (MENUITEM SEPARATOR).
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
-class MenuSeparator : public MenuDefinition {
-public:
- raw_ostream &log(raw_ostream &) const override;
-
- MenuDefKind getKind() const override { return MkSeparator; }
- static bool classof(const MenuDefinition *D) {
- return D->getKind() == MkSeparator;
- }
-};
-
-// MENUITEM statement definition.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
-class MenuItem : public MenuDefinition {
-public:
- StringRef Name;
- uint32_t Id;
- uint16_t Flags;
-
- MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
- : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
- raw_ostream &log(raw_ostream &) const override;
-
- uint16_t getResFlags() const override { return Flags; }
- MenuDefKind getKind() const override { return MkMenuItem; }
- static bool classof(const MenuDefinition *D) {
- return D->getKind() == MkMenuItem;
- }
-};
-
-// POPUP statement definition.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
-class PopupItem : public MenuDefinition {
-public:
- StringRef Name;
- uint16_t Flags;
- MenuDefinitionList SubItems;
-
- PopupItem(StringRef Caption, uint16_t ItemFlags,
- MenuDefinitionList &&SubItemsList)
- : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
- raw_ostream &log(raw_ostream &) const override;
-
- // This has an additional (0x10) flag. It doesn't match with documented
- // 0x01 flag, though.
- uint16_t getResFlags() const override { return Flags | 0x10; }
- MenuDefKind getKind() const override { return MkPopup; }
- static bool classof(const MenuDefinition *D) {
- return D->getKind() == MkPopup;
- }
-};
-
-// Menu resource definition.
-class MenuResource : public OptStatementsRCResource {
-public:
- MenuDefinitionList Elements;
-
- MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
- uint16_t Flags)
- : OptStatementsRCResource(std::move(OptStmts), Flags),
- Elements(std::move(Items)) {}
- raw_ostream &log(raw_ostream &) const override;
-
- IntOrString getResourceType() const override { return RkMenu; }
- Twine getResourceTypeName() const override { return "MENU"; }
- Error visit(Visitor *V) const override { return V->visitMenuResource(this); }
- ResourceKind getKind() const override { return RkMenu; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkMenu;
- }
-};
-
-// STRINGTABLE resource. Contains a list of strings, each having its unique ID.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
-class StringTableResource : public OptStatementsRCResource {
-public:
- std::vector<std::pair<uint32_t, std::vector<StringRef>>> Table;
-
- StringTableResource(OptionalStmtList &&List, uint16_t Flags)
- : OptStatementsRCResource(std::move(List), Flags) {}
- void addStrings(uint32_t ID, std::vector<StringRef> &&Strings) {
- Table.emplace_back(ID, Strings);
- }
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "STRINGTABLE"; }
- Error visit(Visitor *V) const override {
- return V->visitStringTableResource(this);
- }
-};
-
-// -- DIALOG(EX) resource and its helper classes --
-//
-// This resource describes dialog boxes and controls residing inside them.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
-
-// Single control definition.
-class Control {
-public:
- StringRef Type;
- IntOrString Title;
- uint32_t ID, X, Y, Width, Height;
- Optional<IntWithNotMask> Style;
- Optional<uint32_t> ExtStyle, HelpID;
- IntOrString Class;
-
- // Control classes as described in DLGITEMTEMPLATEEX documentation.
- //
- // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx
- enum CtlClasses {
- ClsButton = 0x80,
- ClsEdit = 0x81,
- ClsStatic = 0x82,
- ClsListBox = 0x83,
- ClsScrollBar = 0x84,
- ClsComboBox = 0x85
- };
-
- // Simple information about a single control type.
- struct CtlInfo {
- uint32_t Style;
- uint16_t CtlClass;
- bool HasTitle;
- };
-
- Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
- uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
- Optional<IntWithNotMask> ItemStyle, Optional<uint32_t> ExtItemStyle,
- Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
- : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
- Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
- ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
-
- static const StringMap<CtlInfo> SupportedCtls;
-
- raw_ostream &log(raw_ostream &) const;
-};
-
-// Single dialog definition. We don't create distinct classes for DIALOG and
-// DIALOGEX because of their being too similar to each other. We only have a
-// flag determining the type of the dialog box.
-class DialogResource : public OptStatementsRCResource {
-public:
- uint32_t X, Y, Width, Height, HelpID;
- std::vector<Control> Controls;
- bool IsExtended;
-
- DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
- uint32_t DlgHeight, uint32_t DlgHelpID,
- OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
- : OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
- Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
- IsExtended(IsDialogEx) {}
-
- void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
-
- raw_ostream &log(raw_ostream &) const override;
-
- // It was a weird design decision to assign the same resource type number
- // both for DIALOG and DIALOGEX (and the same structure version number).
- // It makes it possible for DIALOG to be mistaken for DIALOGEX.
- IntOrString getResourceType() const override { return RkDialog; }
- Twine getResourceTypeName() const override {
- return "DIALOG" + Twine(IsExtended ? "EX" : "");
- }
- Error visit(Visitor *V) const override {
- return V->visitDialogResource(this);
- }
- ResourceKind getKind() const override { return RkDialog; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkDialog;
- }
-};
-
-// User-defined resource. It is either:
-// * a link to the file, e.g. NAME TYPE "filename",
-// * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}.
-class UserDefinedResource : public RCResource {
-public:
- IntOrString Type;
- StringRef FileLoc;
- std::vector<IntOrString> Contents;
- bool IsFileResource;
-
- UserDefinedResource(IntOrString ResourceType, StringRef FileLocation,
- uint16_t Flags)
- : RCResource(Flags), Type(ResourceType), FileLoc(FileLocation),
- IsFileResource(true) {}
- UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data,
- uint16_t Flags)
- : RCResource(Flags), Type(ResourceType), Contents(std::move(Data)),
- IsFileResource(false) {}
-
- raw_ostream &log(raw_ostream &) const override;
- IntOrString getResourceType() const override { return Type; }
- Twine getResourceTypeName() const override { return Type; }
- static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
-
- Error visit(Visitor *V) const override {
- return V->visitUserDefinedResource(this);
- }
- ResourceKind getKind() const override { return RkUser; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkUser;
- }
-};
-
-// -- VERSIONINFO resource and its helper classes --
-//
-// This resource lists the version information on the executable/library.
-// The declaration consists of the following items:
-// * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS)
-// * BEGIN
-// * A number of BLOCK and/or VALUE statements. BLOCK recursively defines
-// another block of version information, whereas VALUE defines a
-// key -> value correspondence. There might be more than one value
-// corresponding to the single key.
-// * END
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
-
-// A single VERSIONINFO statement;
-class VersionInfoStmt {
-public:
- enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
-
- virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
- virtual ~VersionInfoStmt() {}
-
- virtual StmtKind getKind() const { return StBase; }
- static bool classof(const VersionInfoStmt *S) {
- return S->getKind() == StBase;
- }
-};
-
-// BLOCK definition; also the main VERSIONINFO declaration is considered a
-// BLOCK, although it has no name.
-// The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
-// care about them at the parsing phase.
-class VersionInfoBlock : public VersionInfoStmt {
-public:
- std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
- StringRef Name;
-
- VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
- void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
- Stmts.push_back(std::move(Stmt));
- }
- raw_ostream &log(raw_ostream &) const override;
-
- StmtKind getKind() const override { return StBlock; }
- static bool classof(const VersionInfoStmt *S) {
- return S->getKind() == StBlock;
- }
-};
-
-class VersionInfoValue : public VersionInfoStmt {
-public:
- StringRef Key;
- std::vector<IntOrString> Values;
- std::vector<bool> HasPrecedingComma;
-
- VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
- std::vector<bool> &&CommasBeforeVals)
- : Key(InfoKey), Values(std::move(Vals)),
- HasPrecedingComma(std::move(CommasBeforeVals)) {}
- raw_ostream &log(raw_ostream &) const override;
-
- StmtKind getKind() const override { return StValue; }
- static bool classof(const VersionInfoStmt *S) {
- return S->getKind() == StValue;
- }
-};
-
-class VersionInfoResource : public RCResource {
-public:
- // A class listing fixed VERSIONINFO statements (occuring before main BEGIN).
- // If any of these is not specified, it is assumed by the original tool to
- // be equal to 0.
- class VersionInfoFixed {
- public:
- enum VersionInfoFixedType {
- FtUnknown,
- FtFileVersion,
- FtProductVersion,
- FtFileFlagsMask,
- FtFileFlags,
- FtFileOS,
- FtFileType,
- FtFileSubtype,
- FtNumTypes
- };
-
- private:
- static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
- static const StringRef FixedFieldsNames[FtNumTypes];
-
- public:
- SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
- SmallVector<bool, FtNumTypes> IsTypePresent;
-
- static VersionInfoFixedType getFixedType(StringRef Type);
- static bool isTypeSupported(VersionInfoFixedType Type);
- static bool isVersionType(VersionInfoFixedType Type);
-
- VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
-
- void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
- FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end());
- IsTypePresent[Type] = true;
- }
-
- raw_ostream &log(raw_ostream &) const;
- };
-
- VersionInfoBlock MainBlock;
- VersionInfoFixed FixedData;
-
- VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
- VersionInfoFixed &&FixedInfo, uint16_t Flags)
- : RCResource(Flags), MainBlock(std::move(TopLevelBlock)),
- FixedData(std::move(FixedInfo)) {}
-
- raw_ostream &log(raw_ostream &) const override;
- IntOrString getResourceType() const override { return RkVersionInfo; }
- static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
- Twine getResourceTypeName() const override { return "VERSIONINFO"; }
- Error visit(Visitor *V) const override {
- return V->visitVersionInfoResource(this);
- }
- ResourceKind getKind() const override { return RkVersionInfo; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkVersionInfo;
- }
-};
-
-// CHARACTERISTICS optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
-class CharacteristicsStmt : public OptionalStmt {
-public:
- uint32_t Value;
-
- CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
- Error visit(Visitor *V) const override {
- return V->visitCharacteristicsStmt(this);
- }
-};
-
-// VERSION optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
-class VersionStmt : public OptionalStmt {
-public:
- uint32_t Value;
-
- VersionStmt(uint32_t Version) : Value(Version) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Twine getResourceTypeName() const override { return "VERSION"; }
- Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
-};
-
-// CAPTION optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
-class CaptionStmt : public OptionalStmt {
-public:
- StringRef Value;
-
- CaptionStmt(StringRef Caption) : Value(Caption) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "CAPTION"; }
- Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
-};
-
-// FONT optional statement.
-// Note that the documentation is inaccurate: it expects five arguments to be
-// given, however the example provides only two. In fact, the original tool
-// expects two arguments - point size and name of the typeface.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx
-class FontStmt : public OptionalStmt {
-public:
- uint32_t Size, Weight, Charset;
- StringRef Name;
- bool Italic;
-
- FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
- bool FontItalic, uint32_t FontCharset)
- : Size(FontSize), Weight(FontWeight), Charset(FontCharset),
- Name(FontName), Italic(FontItalic) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "FONT"; }
- Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
-};
-
-// STYLE optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
-class StyleStmt : public OptionalStmt {
-public:
- uint32_t Value;
-
- StyleStmt(uint32_t Style) : Value(Style) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "STYLE"; }
- Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
-};
-
-// EXSTYLE optional statement.
-//
-// Ref: docs.microsoft.com/en-us/windows/desktop/menurc/exstyle-statement
-class ExStyleStmt : public OptionalStmt {
-public:
- uint32_t Value;
-
- ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "EXSTYLE"; }
- Error visit(Visitor *V) const override { return V->visitExStyleStmt(this); }
-};
-
-// CLASS optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380883(v=vs.85).aspx
-class ClassStmt : public OptionalStmt {
-public:
- IntOrString Value;
-
- ClassStmt(IntOrString Class) : Value(Class) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "CLASS"; }
- Error visit(Visitor *V) const override { return V->visitClassStmt(this); }
-};
-
-} // namespace rc
-} // namespace llvm
-
-#endif
+};
+
+// LANGUAGE statement. It can occur both as a top-level statement (in such
+// a situation, it changes the default language until the end of the file)
+// and as an optional resource statement (then it changes the language
+// of a single resource).
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx
+class LanguageResource : public OptionalStmt {
+public:
+ uint32_t Lang, SubLang;
+
+ LanguageResource(uint32_t LangId, uint32_t SubLangId)
+ : Lang(LangId), SubLang(SubLangId) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ // This is not a regular top-level statement; when it occurs, it just
+ // modifies the language context.
+ Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
+ Twine getResourceTypeName() const override { return "LANGUAGE"; }
+};
+
+// ACCELERATORS resource. Defines a named table of accelerators for the app.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx
+class AcceleratorsResource : public OptStatementsRCResource {
+public:
+ class Accelerator {
+ public:
+ IntOrString Event;
+ uint32_t Id;
+ uint16_t Flags;
+
+ enum Options {
+ // This is actually 0x0000 (accelerator is assumed to be ASCII if it's
+ // not VIRTKEY). However, rc.exe behavior is different in situations
+ // "only ASCII defined" and "neither ASCII nor VIRTKEY defined".
+ // Therefore, we include ASCII as another flag. This must be zeroed
+ // when serialized.
+ ASCII = 0x8000,
+ VIRTKEY = 0x0001,
+ NOINVERT = 0x0002,
+ ALT = 0x0010,
+ SHIFT = 0x0004,
+ CONTROL = 0x0008
+ };
+
+ static constexpr size_t NumFlags = 6;
+ static StringRef OptionsStr[NumFlags];
+ static uint32_t OptionsFlags[NumFlags];
+ };
+
+ AcceleratorsResource(OptionalStmtList &&List, uint16_t Flags)
+ : OptStatementsRCResource(std::move(List), Flags) {}
+
+ std::vector<Accelerator> Accelerators;
+
+ void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
+ Accelerators.push_back(Accelerator{Event, Id, Flags});
+ }
+ raw_ostream &log(raw_ostream &) const override;
+
+ IntOrString getResourceType() const override { return RkAccelerators; }
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
+ Twine getResourceTypeName() const override { return "ACCELERATORS"; }
+
+ Error visit(Visitor *V) const override {
+ return V->visitAcceleratorsResource(this);
+ }
+ ResourceKind getKind() const override { return RkAccelerators; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkAccelerators;
+ }
+};
+
+// BITMAP resource. Represents a bitmap (".bmp") file.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx
+class BitmapResource : public RCResource {
+public:
+ StringRef BitmapLoc;
+
+ BitmapResource(StringRef Location, uint16_t Flags)
+ : RCResource(Flags), BitmapLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ IntOrString getResourceType() const override { return RkBitmap; }
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
+
+ Twine getResourceTypeName() const override { return "BITMAP"; }
+ Error visit(Visitor *V) const override {
+ return V->visitBitmapResource(this);
+ }
+ ResourceKind getKind() const override { return RkBitmap; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkBitmap;
+ }
+};
+
+// CURSOR resource. Represents a single cursor (".cur") file.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
+class CursorResource : public RCResource {
+public:
+ StringRef CursorLoc;
+
+ CursorResource(StringRef Location, uint16_t Flags)
+ : RCResource(Flags), CursorLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "CURSOR"; }
+ static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
+ Error visit(Visitor *V) const override {
+ return V->visitCursorResource(this);
+ }
+ ResourceKind getKind() const override { return RkCursor; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkCursor;
+ }
+};
+
+// ICON resource. Represents a single ".ico" file containing a group of icons.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
+class IconResource : public RCResource {
+public:
+ StringRef IconLoc;
+
+ IconResource(StringRef Location, uint16_t Flags)
+ : RCResource(Flags), IconLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "ICON"; }
+ static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
+ Error visit(Visitor *V) const override { return V->visitIconResource(this); }
+ ResourceKind getKind() const override { return RkIcon; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkIcon;
+ }
+};
+
+// HTML resource. Represents a local webpage that is to be embedded into the
+// resulting resource file. It embeds a file only - no additional resources
+// (images etc.) are included with this resource.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx
+class HTMLResource : public RCResource {
+public:
+ StringRef HTMLLoc;
+
+ HTMLResource(StringRef Location, uint16_t Flags)
+ : RCResource(Flags), HTMLLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
+
+ // Curiously, file resources don't have DISCARDABLE flag set.
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
+ IntOrString getResourceType() const override { return RkHTML; }
+ Twine getResourceTypeName() const override { return "HTML"; }
+ ResourceKind getKind() const override { return RkHTML; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkHTML;
+ }
+};
+
+// -- MENU resource and its helper classes --
+// This resource describes the contents of an application menu
+// (usually located in the upper part of the dialog.)
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx
+
+// Description of a single submenu item.
+class MenuDefinition {
+public:
+ enum Options {
+ CHECKED = 0x0008,
+ GRAYED = 0x0001,
+ HELP = 0x4000,
+ INACTIVE = 0x0002,
+ MENUBARBREAK = 0x0020,
+ MENUBREAK = 0x0040
+ };
+
+ enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
+
+ static constexpr size_t NumFlags = 6;
+ static StringRef OptionsStr[NumFlags];
+ static uint32_t OptionsFlags[NumFlags];
+ static raw_ostream &logFlags(raw_ostream &, uint16_t Flags);
+ virtual raw_ostream &log(raw_ostream &OS) const {
+ return OS << "Base menu definition\n";
+ }
+ virtual ~MenuDefinition() {}
+
+ virtual uint16_t getResFlags() const { return 0; }
+ virtual MenuDefKind getKind() const { return MkBase; }
+};
+
+// Recursive description of a whole submenu.
+class MenuDefinitionList : public MenuDefinition {
+public:
+ std::vector<std::unique_ptr<MenuDefinition>> Definitions;
+
+ void addDefinition(std::unique_ptr<MenuDefinition> Def) {
+ Definitions.push_back(std::move(Def));
+ }
+ raw_ostream &log(raw_ostream &) const override;
+};
+
+// Separator in MENU definition (MENUITEM SEPARATOR).
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
+class MenuSeparator : public MenuDefinition {
+public:
+ raw_ostream &log(raw_ostream &) const override;
+
+ MenuDefKind getKind() const override { return MkSeparator; }
+ static bool classof(const MenuDefinition *D) {
+ return D->getKind() == MkSeparator;
+ }
+};
+
+// MENUITEM statement definition.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
+class MenuItem : public MenuDefinition {
+public:
+ StringRef Name;
+ uint32_t Id;
+ uint16_t Flags;
+
+ MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
+ : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ uint16_t getResFlags() const override { return Flags; }
+ MenuDefKind getKind() const override { return MkMenuItem; }
+ static bool classof(const MenuDefinition *D) {
+ return D->getKind() == MkMenuItem;
+ }
+};
+
+// POPUP statement definition.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
+class PopupItem : public MenuDefinition {
+public:
+ StringRef Name;
+ uint16_t Flags;
+ MenuDefinitionList SubItems;
+
+ PopupItem(StringRef Caption, uint16_t ItemFlags,
+ MenuDefinitionList &&SubItemsList)
+ : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ // This has an additional (0x10) flag. It doesn't match with documented
+ // 0x01 flag, though.
+ uint16_t getResFlags() const override { return Flags | 0x10; }
+ MenuDefKind getKind() const override { return MkPopup; }
+ static bool classof(const MenuDefinition *D) {
+ return D->getKind() == MkPopup;
+ }
+};
+
+// Menu resource definition.
+class MenuResource : public OptStatementsRCResource {
+public:
+ MenuDefinitionList Elements;
+
+ MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
+ uint16_t Flags)
+ : OptStatementsRCResource(std::move(OptStmts), Flags),
+ Elements(std::move(Items)) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ IntOrString getResourceType() const override { return RkMenu; }
+ Twine getResourceTypeName() const override { return "MENU"; }
+ Error visit(Visitor *V) const override { return V->visitMenuResource(this); }
+ ResourceKind getKind() const override { return RkMenu; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkMenu;
+ }
+};
+
+// STRINGTABLE resource. Contains a list of strings, each having its unique ID.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
+class StringTableResource : public OptStatementsRCResource {
+public:
+ std::vector<std::pair<uint32_t, std::vector<StringRef>>> Table;
+
+ StringTableResource(OptionalStmtList &&List, uint16_t Flags)
+ : OptStatementsRCResource(std::move(List), Flags) {}
+ void addStrings(uint32_t ID, std::vector<StringRef> &&Strings) {
+ Table.emplace_back(ID, Strings);
+ }
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "STRINGTABLE"; }
+ Error visit(Visitor *V) const override {
+ return V->visitStringTableResource(this);
+ }
+};
+
+// -- DIALOG(EX) resource and its helper classes --
+//
+// This resource describes dialog boxes and controls residing inside them.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
+
+// Single control definition.
+class Control {
+public:
+ StringRef Type;
+ IntOrString Title;
+ uint32_t ID, X, Y, Width, Height;
+ Optional<IntWithNotMask> Style;
+ Optional<uint32_t> ExtStyle, HelpID;
+ IntOrString Class;
+
+ // Control classes as described in DLGITEMTEMPLATEEX documentation.
+ //
+ // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx
+ enum CtlClasses {
+ ClsButton = 0x80,
+ ClsEdit = 0x81,
+ ClsStatic = 0x82,
+ ClsListBox = 0x83,
+ ClsScrollBar = 0x84,
+ ClsComboBox = 0x85
+ };
+
+ // Simple information about a single control type.
+ struct CtlInfo {
+ uint32_t Style;
+ uint16_t CtlClass;
+ bool HasTitle;
+ };
+
+ Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
+ uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
+ Optional<IntWithNotMask> ItemStyle, Optional<uint32_t> ExtItemStyle,
+ Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
+ : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
+ Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
+ ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
+
+ static const StringMap<CtlInfo> SupportedCtls;
+
+ raw_ostream &log(raw_ostream &) const;
+};
+
+// Single dialog definition. We don't create distinct classes for DIALOG and
+// DIALOGEX because of their being too similar to each other. We only have a
+// flag determining the type of the dialog box.
+class DialogResource : public OptStatementsRCResource {
+public:
+ uint32_t X, Y, Width, Height, HelpID;
+ std::vector<Control> Controls;
+ bool IsExtended;
+
+ DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
+ uint32_t DlgHeight, uint32_t DlgHelpID,
+ OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
+ : OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
+ Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
+ IsExtended(IsDialogEx) {}
+
+ void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
+
+ raw_ostream &log(raw_ostream &) const override;
+
+ // It was a weird design decision to assign the same resource type number
+ // both for DIALOG and DIALOGEX (and the same structure version number).
+ // It makes it possible for DIALOG to be mistaken for DIALOGEX.
+ IntOrString getResourceType() const override { return RkDialog; }
+ Twine getResourceTypeName() const override {
+ return "DIALOG" + Twine(IsExtended ? "EX" : "");
+ }
+ Error visit(Visitor *V) const override {
+ return V->visitDialogResource(this);
+ }
+ ResourceKind getKind() const override { return RkDialog; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkDialog;
+ }
+};
+
+// User-defined resource. It is either:
+// * a link to the file, e.g. NAME TYPE "filename",
+// * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}.
+class UserDefinedResource : public RCResource {
+public:
+ IntOrString Type;
+ StringRef FileLoc;
+ std::vector<IntOrString> Contents;
+ bool IsFileResource;
+
+ UserDefinedResource(IntOrString ResourceType, StringRef FileLocation,
+ uint16_t Flags)
+ : RCResource(Flags), Type(ResourceType), FileLoc(FileLocation),
+ IsFileResource(true) {}
+ UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data,
+ uint16_t Flags)
+ : RCResource(Flags), Type(ResourceType), Contents(std::move(Data)),
+ IsFileResource(false) {}
+
+ raw_ostream &log(raw_ostream &) const override;
+ IntOrString getResourceType() const override { return Type; }
+ Twine getResourceTypeName() const override { return Type; }
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
+
+ Error visit(Visitor *V) const override {
+ return V->visitUserDefinedResource(this);
+ }
+ ResourceKind getKind() const override { return RkUser; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkUser;
+ }
+};
+
+// -- VERSIONINFO resource and its helper classes --
+//
+// This resource lists the version information on the executable/library.
+// The declaration consists of the following items:
+// * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS)
+// * BEGIN
+// * A number of BLOCK and/or VALUE statements. BLOCK recursively defines
+// another block of version information, whereas VALUE defines a
+// key -> value correspondence. There might be more than one value
+// corresponding to the single key.
+// * END
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
+
+// A single VERSIONINFO statement;
+class VersionInfoStmt {
+public:
+ enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
+
+ virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
+ virtual ~VersionInfoStmt() {}
+
+ virtual StmtKind getKind() const { return StBase; }
+ static bool classof(const VersionInfoStmt *S) {
+ return S->getKind() == StBase;
+ }
+};
+
+// BLOCK definition; also the main VERSIONINFO declaration is considered a
+// BLOCK, although it has no name.
+// The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
+// care about them at the parsing phase.
+class VersionInfoBlock : public VersionInfoStmt {
+public:
+ std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
+ StringRef Name;
+
+ VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
+ void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
+ Stmts.push_back(std::move(Stmt));
+ }
+ raw_ostream &log(raw_ostream &) const override;
+
+ StmtKind getKind() const override { return StBlock; }
+ static bool classof(const VersionInfoStmt *S) {
+ return S->getKind() == StBlock;
+ }
+};
+
+class VersionInfoValue : public VersionInfoStmt {
+public:
+ StringRef Key;
+ std::vector<IntOrString> Values;
+ std::vector<bool> HasPrecedingComma;
+
+ VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
+ std::vector<bool> &&CommasBeforeVals)
+ : Key(InfoKey), Values(std::move(Vals)),
+ HasPrecedingComma(std::move(CommasBeforeVals)) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ StmtKind getKind() const override { return StValue; }
+ static bool classof(const VersionInfoStmt *S) {
+ return S->getKind() == StValue;
+ }
+};
+
+class VersionInfoResource : public RCResource {
+public:
+ // A class listing fixed VERSIONINFO statements (occuring before main BEGIN).
+ // If any of these is not specified, it is assumed by the original tool to
+ // be equal to 0.
+ class VersionInfoFixed {
+ public:
+ enum VersionInfoFixedType {
+ FtUnknown,
+ FtFileVersion,
+ FtProductVersion,
+ FtFileFlagsMask,
+ FtFileFlags,
+ FtFileOS,
+ FtFileType,
+ FtFileSubtype,
+ FtNumTypes
+ };
+
+ private:
+ static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
+ static const StringRef FixedFieldsNames[FtNumTypes];
+
+ public:
+ SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
+ SmallVector<bool, FtNumTypes> IsTypePresent;
+
+ static VersionInfoFixedType getFixedType(StringRef Type);
+ static bool isTypeSupported(VersionInfoFixedType Type);
+ static bool isVersionType(VersionInfoFixedType Type);
+
+ VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
+
+ void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
+ FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end());
+ IsTypePresent[Type] = true;
+ }
+
+ raw_ostream &log(raw_ostream &) const;
+ };
+
+ VersionInfoBlock MainBlock;
+ VersionInfoFixed FixedData;
+
+ VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
+ VersionInfoFixed &&FixedInfo, uint16_t Flags)
+ : RCResource(Flags), MainBlock(std::move(TopLevelBlock)),
+ FixedData(std::move(FixedInfo)) {}
+
+ raw_ostream &log(raw_ostream &) const override;
+ IntOrString getResourceType() const override { return RkVersionInfo; }
+ static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
+ Twine getResourceTypeName() const override { return "VERSIONINFO"; }
+ Error visit(Visitor *V) const override {
+ return V->visitVersionInfoResource(this);
+ }
+ ResourceKind getKind() const override { return RkVersionInfo; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkVersionInfo;
+ }
+};
+
+// CHARACTERISTICS optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
+class CharacteristicsStmt : public OptionalStmt {
+public:
+ uint32_t Value;
+
+ CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
+ Error visit(Visitor *V) const override {
+ return V->visitCharacteristicsStmt(this);
+ }
+};
+
+// VERSION optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
+class VersionStmt : public OptionalStmt {
+public:
+ uint32_t Value;
+
+ VersionStmt(uint32_t Version) : Value(Version) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "VERSION"; }
+ Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
+};
+
+// CAPTION optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
+class CaptionStmt : public OptionalStmt {
+public:
+ StringRef Value;
+
+ CaptionStmt(StringRef Caption) : Value(Caption) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "CAPTION"; }
+ Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
+};
+
+// FONT optional statement.
+// Note that the documentation is inaccurate: it expects five arguments to be
+// given, however the example provides only two. In fact, the original tool
+// expects two arguments - point size and name of the typeface.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx
+class FontStmt : public OptionalStmt {
+public:
+ uint32_t Size, Weight, Charset;
+ StringRef Name;
+ bool Italic;
+
+ FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
+ bool FontItalic, uint32_t FontCharset)
+ : Size(FontSize), Weight(FontWeight), Charset(FontCharset),
+ Name(FontName), Italic(FontItalic) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "FONT"; }
+ Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
+};
+
+// STYLE optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
+class StyleStmt : public OptionalStmt {
+public:
+ uint32_t Value;
+
+ StyleStmt(uint32_t Style) : Value(Style) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "STYLE"; }
+ Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
+};
+
+// EXSTYLE optional statement.
+//
+// Ref: docs.microsoft.com/en-us/windows/desktop/menurc/exstyle-statement
+class ExStyleStmt : public OptionalStmt {
+public:
+ uint32_t Value;
+
+ ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "EXSTYLE"; }
+ Error visit(Visitor *V) const override { return V->visitExStyleStmt(this); }
+};
+
+// CLASS optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380883(v=vs.85).aspx
+class ClassStmt : public OptionalStmt {
+public:
+ IntOrString Value;
+
+ ClassStmt(IntOrString Class) : Value(Class) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "CLASS"; }
+ Error visit(Visitor *V) const override { return V->visitClassStmt(this); }
+};
+
+} // namespace rc
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp
index 2e21f675b9..b9699d2b2e 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp
@@ -1,367 +1,367 @@
-//===-- ResourceScriptToken.cpp ---------------------------------*- 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
-//
-//===---------------------------------------------------------------------===//
-//
-// This file implements an interface defined in ResourceScriptToken.h.
-// In particular, it defines an .rc script tokenizer.
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceScriptToken.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <algorithm>
-#include <cassert>
-#include <cctype>
-#include <cstdlib>
-#include <utility>
-
-using namespace llvm;
-
-using Kind = RCToken::Kind;
-
-// Checks if Representation is a correct description of an RC integer.
-// It should be a 32-bit unsigned integer, either decimal, octal (0[0-7]+),
-// or hexadecimal (0x[0-9a-f]+). It might be followed by a single 'L'
-// character (that is the difference between our representation and
-// StringRef's one). If Representation is correct, 'true' is returned and
-// the return value is put back in Num.
-static bool rcGetAsInteger(StringRef Representation, uint32_t &Num) {
- size_t Length = Representation.size();
- if (Length == 0)
- return false;
- // Strip the last 'L' if unnecessary.
- if (std::toupper(Representation.back()) == 'L')
- Representation = Representation.drop_back(1);
-
- return !Representation.getAsInteger<uint32_t>(0, Num);
-}
-
-RCToken::RCToken(RCToken::Kind RCTokenKind, StringRef Value)
- : TokenKind(RCTokenKind), TokenValue(Value) {}
-
-uint32_t RCToken::intValue() const {
- assert(TokenKind == Kind::Int);
- // We assume that the token already is a correct integer (checked by
- // rcGetAsInteger).
- uint32_t Result;
- bool IsSuccess = rcGetAsInteger(TokenValue, Result);
- assert(IsSuccess);
- (void)IsSuccess; // Silence the compiler warning when -DNDEBUG flag is on.
- return Result;
-}
-
-bool RCToken::isLongInt() const {
- return TokenKind == Kind::Int && std::toupper(TokenValue.back()) == 'L';
-}
-
-StringRef RCToken::value() const { return TokenValue; }
-
-Kind RCToken::kind() const { return TokenKind; }
-
-bool RCToken::isBinaryOp() const {
- switch (TokenKind) {
- case Kind::Plus:
- case Kind::Minus:
- case Kind::Pipe:
- case Kind::Amp:
- return true;
- default:
- return false;
- }
-}
-
-static Error getStringError(const Twine &message) {
- return make_error<StringError>("Error parsing file: " + message,
- inconvertibleErrorCode());
-}
-
-namespace {
-
-class Tokenizer {
-public:
- Tokenizer(StringRef Input) : Data(Input), DataLength(Input.size()), Pos(0) {}
-
- Expected<std::vector<RCToken>> run();
-
-private:
- // All 'advancing' methods return boolean values; if they're equal to false,
- // the stream has ended or failed.
- bool advance(size_t Amount = 1);
- bool skipWhitespaces();
-
- // Consumes a token. If any problem occurred, a non-empty Error is returned.
- Error consumeToken(const Kind TokenKind);
-
- // Check if tokenizer is about to read FollowingChars.
- bool willNowRead(StringRef FollowingChars) const;
-
- // Check if tokenizer can start reading an identifier at current position.
- // The original tool did non specify the rules to determine what is a correct
- // identifier. We assume they should follow the C convention:
- // [a-zA-Z_][a-zA-Z0-9_]*.
- bool canStartIdentifier() const;
- // Check if tokenizer can continue reading an identifier.
- bool canContinueIdentifier() const;
-
- // Check if tokenizer can start reading an integer.
- // A correct integer always starts with a 0-9 digit,
- // can contain characters 0-9A-Fa-f (digits),
- // Ll (marking the integer is 32-bit), Xx (marking the representation
- // is hexadecimal). As some kind of separator should come after the
- // integer, we can consume the integer until a non-alphanumeric
- // character.
- bool canStartInt() const;
- bool canContinueInt() const;
-
- bool canStartString() const;
-
- // Check if tokenizer can start reading a single line comment (e.g. a comment
- // that begins with '//')
- bool canStartLineComment() const;
-
- // Check if tokenizer can start or finish reading a block comment (e.g. a
- // comment that begins with '/*' and ends with '*/')
- bool canStartBlockComment() const;
-
- // Throw away all remaining characters on the current line.
- void skipCurrentLine();
-
- bool streamEof() const;
-
- // Classify the token that is about to be read from the current position.
- Kind classifyCurrentToken() const;
-
- // Process the Kind::Identifier token - check if it is
- // an identifier describing a block start or end.
- void processIdentifier(RCToken &token) const;
-
- StringRef Data;
- size_t DataLength, Pos;
-};
-
-void Tokenizer::skipCurrentLine() {
- Pos = Data.find_first_of("\r\n", Pos);
- Pos = Data.find_first_not_of("\r\n", Pos);
-
- if (Pos == StringRef::npos)
- Pos = DataLength;
-}
-
-Expected<std::vector<RCToken>> Tokenizer::run() {
- Pos = 0;
- std::vector<RCToken> Result;
-
- // Consume an optional UTF-8 Byte Order Mark.
- if (willNowRead("\xef\xbb\xbf"))
- advance(3);
-
- while (!streamEof()) {
- if (!skipWhitespaces())
- break;
-
- Kind TokenKind = classifyCurrentToken();
- if (TokenKind == Kind::Invalid)
- return getStringError("Invalid token found at position " + Twine(Pos));
-
- const size_t TokenStart = Pos;
- if (Error TokenError = consumeToken(TokenKind))
- return std::move(TokenError);
-
- // Comments are just deleted, don't bother saving them.
- if (TokenKind == Kind::LineComment || TokenKind == Kind::StartComment)
- continue;
-
- RCToken Token(TokenKind, Data.take_front(Pos).drop_front(TokenStart));
- if (TokenKind == Kind::Identifier) {
- processIdentifier(Token);
- } else if (TokenKind == Kind::Int) {
- uint32_t TokenInt;
- if (!rcGetAsInteger(Token.value(), TokenInt)) {
- // The integer has incorrect format or cannot be represented in
- // a 32-bit integer.
- return getStringError("Integer invalid or too large: " +
- Token.value().str());
- }
- }
-
- Result.push_back(Token);
- }
-
- return Result;
-}
-
-bool Tokenizer::advance(size_t Amount) {
- Pos += Amount;
- return !streamEof();
-}
-
-bool Tokenizer::skipWhitespaces() {
- while (!streamEof() && isSpace(Data[Pos]))
- advance();
- return !streamEof();
-}
-
-Error Tokenizer::consumeToken(const Kind TokenKind) {
- switch (TokenKind) {
- // One-character token consumption.
-#define TOKEN(Name)
-#define SHORT_TOKEN(Name, Ch) case Kind::Name:
-#include "ResourceScriptTokenList.def"
- advance();
- return Error::success();
-
- case Kind::LineComment:
- advance(2);
- skipCurrentLine();
- return Error::success();
-
- case Kind::StartComment: {
- advance(2);
- auto EndPos = Data.find("*/", Pos);
- if (EndPos == StringRef::npos)
- return getStringError(
- "Unclosed multi-line comment beginning at position " + Twine(Pos));
- advance(EndPos - Pos);
- advance(2);
- return Error::success();
- }
- case Kind::Identifier:
- while (!streamEof() && canContinueIdentifier())
- advance();
- return Error::success();
-
- case Kind::Int:
- while (!streamEof() && canContinueInt())
- advance();
- return Error::success();
-
- case Kind::String:
- // Consume the preceding 'L', if there is any.
- if (std::toupper(Data[Pos]) == 'L')
- advance();
- // Consume the double-quote.
- advance();
-
- // Consume the characters until the end of the file, line or string.
- while (true) {
- if (streamEof()) {
- return getStringError("Unterminated string literal.");
- } else if (Data[Pos] == '"') {
- // Consume the ending double-quote.
- advance();
- // However, if another '"' follows this double-quote, the string didn't
- // end and we just included '"' into the string.
- if (!willNowRead("\""))
- return Error::success();
- } else if (Data[Pos] == '\n') {
- return getStringError("String literal not terminated in the line.");
- }
-
- advance();
- }
-
- case Kind::Invalid:
- assert(false && "Cannot consume an invalid token.");
- }
-
- llvm_unreachable("Unknown RCToken::Kind");
-}
-
-bool Tokenizer::willNowRead(StringRef FollowingChars) const {
- return Data.drop_front(Pos).startswith(FollowingChars);
-}
-
-bool Tokenizer::canStartIdentifier() const {
- assert(!streamEof());
-
- const char CurChar = Data[Pos];
- return std::isalpha(CurChar) || CurChar == '_' || CurChar == '.';
-}
-
-bool Tokenizer::canContinueIdentifier() const {
- assert(!streamEof());
- const char CurChar = Data[Pos];
- return std::isalnum(CurChar) || CurChar == '_' || CurChar == '.' ||
- CurChar == '/' || CurChar == '\\';
-}
-
-bool Tokenizer::canStartInt() const {
- assert(!streamEof());
- return std::isdigit(Data[Pos]);
-}
-
-bool Tokenizer::canStartBlockComment() const {
- assert(!streamEof());
- return Data.drop_front(Pos).startswith("/*");
-}
-
-bool Tokenizer::canStartLineComment() const {
- assert(!streamEof());
- return Data.drop_front(Pos).startswith("//");
-}
-
-bool Tokenizer::canContinueInt() const {
- assert(!streamEof());
- return std::isalnum(Data[Pos]);
-}
-
-bool Tokenizer::canStartString() const {
- return willNowRead("\"") || willNowRead("L\"") || willNowRead("l\"");
-}
-
-bool Tokenizer::streamEof() const { return Pos == DataLength; }
-
-Kind Tokenizer::classifyCurrentToken() const {
- if (canStartBlockComment())
- return Kind::StartComment;
- if (canStartLineComment())
- return Kind::LineComment;
-
- if (canStartInt())
- return Kind::Int;
- if (canStartString())
- return Kind::String;
- // BEGIN and END are at this point of lexing recognized as identifiers.
- if (canStartIdentifier())
- return Kind::Identifier;
-
- const char CurChar = Data[Pos];
-
- switch (CurChar) {
- // One-character token classification.
-#define TOKEN(Name)
-#define SHORT_TOKEN(Name, Ch) \
- case Ch: \
- return Kind::Name;
-#include "ResourceScriptTokenList.def"
-
- default:
- return Kind::Invalid;
- }
-}
-
-void Tokenizer::processIdentifier(RCToken &Token) const {
- assert(Token.kind() == Kind::Identifier);
- StringRef Name = Token.value();
-
- if (Name.equals_lower("begin"))
- Token = RCToken(Kind::BlockBegin, Name);
- else if (Name.equals_lower("end"))
- Token = RCToken(Kind::BlockEnd, Name);
-}
-
-} // anonymous namespace
-
-namespace llvm {
-
-Expected<std::vector<RCToken>> tokenizeRC(StringRef Input) {
- return Tokenizer(Input).run();
-}
-
-} // namespace llvm
+//===-- ResourceScriptToken.cpp ---------------------------------*- 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
+//
+//===---------------------------------------------------------------------===//
+//
+// This file implements an interface defined in ResourceScriptToken.h.
+// In particular, it defines an .rc script tokenizer.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceScriptToken.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cstdlib>
+#include <utility>
+
+using namespace llvm;
+
+using Kind = RCToken::Kind;
+
+// Checks if Representation is a correct description of an RC integer.
+// It should be a 32-bit unsigned integer, either decimal, octal (0[0-7]+),
+// or hexadecimal (0x[0-9a-f]+). It might be followed by a single 'L'
+// character (that is the difference between our representation and
+// StringRef's one). If Representation is correct, 'true' is returned and
+// the return value is put back in Num.
+static bool rcGetAsInteger(StringRef Representation, uint32_t &Num) {
+ size_t Length = Representation.size();
+ if (Length == 0)
+ return false;
+ // Strip the last 'L' if unnecessary.
+ if (std::toupper(Representation.back()) == 'L')
+ Representation = Representation.drop_back(1);
+
+ return !Representation.getAsInteger<uint32_t>(0, Num);
+}
+
+RCToken::RCToken(RCToken::Kind RCTokenKind, StringRef Value)
+ : TokenKind(RCTokenKind), TokenValue(Value) {}
+
+uint32_t RCToken::intValue() const {
+ assert(TokenKind == Kind::Int);
+ // We assume that the token already is a correct integer (checked by
+ // rcGetAsInteger).
+ uint32_t Result;
+ bool IsSuccess = rcGetAsInteger(TokenValue, Result);
+ assert(IsSuccess);
+ (void)IsSuccess; // Silence the compiler warning when -DNDEBUG flag is on.
+ return Result;
+}
+
+bool RCToken::isLongInt() const {
+ return TokenKind == Kind::Int && std::toupper(TokenValue.back()) == 'L';
+}
+
+StringRef RCToken::value() const { return TokenValue; }
+
+Kind RCToken::kind() const { return TokenKind; }
+
+bool RCToken::isBinaryOp() const {
+ switch (TokenKind) {
+ case Kind::Plus:
+ case Kind::Minus:
+ case Kind::Pipe:
+ case Kind::Amp:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static Error getStringError(const Twine &message) {
+ return make_error<StringError>("Error parsing file: " + message,
+ inconvertibleErrorCode());
+}
+
+namespace {
+
+class Tokenizer {
+public:
+ Tokenizer(StringRef Input) : Data(Input), DataLength(Input.size()), Pos(0) {}
+
+ Expected<std::vector<RCToken>> run();
+
+private:
+ // All 'advancing' methods return boolean values; if they're equal to false,
+ // the stream has ended or failed.
+ bool advance(size_t Amount = 1);
+ bool skipWhitespaces();
+
+ // Consumes a token. If any problem occurred, a non-empty Error is returned.
+ Error consumeToken(const Kind TokenKind);
+
+ // Check if tokenizer is about to read FollowingChars.
+ bool willNowRead(StringRef FollowingChars) const;
+
+ // Check if tokenizer can start reading an identifier at current position.
+ // The original tool did non specify the rules to determine what is a correct
+ // identifier. We assume they should follow the C convention:
+ // [a-zA-Z_][a-zA-Z0-9_]*.
+ bool canStartIdentifier() const;
+ // Check if tokenizer can continue reading an identifier.
+ bool canContinueIdentifier() const;
+
+ // Check if tokenizer can start reading an integer.
+ // A correct integer always starts with a 0-9 digit,
+ // can contain characters 0-9A-Fa-f (digits),
+ // Ll (marking the integer is 32-bit), Xx (marking the representation
+ // is hexadecimal). As some kind of separator should come after the
+ // integer, we can consume the integer until a non-alphanumeric
+ // character.
+ bool canStartInt() const;
+ bool canContinueInt() const;
+
+ bool canStartString() const;
+
+ // Check if tokenizer can start reading a single line comment (e.g. a comment
+ // that begins with '//')
+ bool canStartLineComment() const;
+
+ // Check if tokenizer can start or finish reading a block comment (e.g. a
+ // comment that begins with '/*' and ends with '*/')
+ bool canStartBlockComment() const;
+
+ // Throw away all remaining characters on the current line.
+ void skipCurrentLine();
+
+ bool streamEof() const;
+
+ // Classify the token that is about to be read from the current position.
+ Kind classifyCurrentToken() const;
+
+ // Process the Kind::Identifier token - check if it is
+ // an identifier describing a block start or end.
+ void processIdentifier(RCToken &token) const;
+
+ StringRef Data;
+ size_t DataLength, Pos;
+};
+
+void Tokenizer::skipCurrentLine() {
+ Pos = Data.find_first_of("\r\n", Pos);
+ Pos = Data.find_first_not_of("\r\n", Pos);
+
+ if (Pos == StringRef::npos)
+ Pos = DataLength;
+}
+
+Expected<std::vector<RCToken>> Tokenizer::run() {
+ Pos = 0;
+ std::vector<RCToken> Result;
+
+ // Consume an optional UTF-8 Byte Order Mark.
+ if (willNowRead("\xef\xbb\xbf"))
+ advance(3);
+
+ while (!streamEof()) {
+ if (!skipWhitespaces())
+ break;
+
+ Kind TokenKind = classifyCurrentToken();
+ if (TokenKind == Kind::Invalid)
+ return getStringError("Invalid token found at position " + Twine(Pos));
+
+ const size_t TokenStart = Pos;
+ if (Error TokenError = consumeToken(TokenKind))
+ return std::move(TokenError);
+
+ // Comments are just deleted, don't bother saving them.
+ if (TokenKind == Kind::LineComment || TokenKind == Kind::StartComment)
+ continue;
+
+ RCToken Token(TokenKind, Data.take_front(Pos).drop_front(TokenStart));
+ if (TokenKind == Kind::Identifier) {
+ processIdentifier(Token);
+ } else if (TokenKind == Kind::Int) {
+ uint32_t TokenInt;
+ if (!rcGetAsInteger(Token.value(), TokenInt)) {
+ // The integer has incorrect format or cannot be represented in
+ // a 32-bit integer.
+ return getStringError("Integer invalid or too large: " +
+ Token.value().str());
+ }
+ }
+
+ Result.push_back(Token);
+ }
+
+ return Result;
+}
+
+bool Tokenizer::advance(size_t Amount) {
+ Pos += Amount;
+ return !streamEof();
+}
+
+bool Tokenizer::skipWhitespaces() {
+ while (!streamEof() && isSpace(Data[Pos]))
+ advance();
+ return !streamEof();
+}
+
+Error Tokenizer::consumeToken(const Kind TokenKind) {
+ switch (TokenKind) {
+ // One-character token consumption.
+#define TOKEN(Name)
+#define SHORT_TOKEN(Name, Ch) case Kind::Name:
+#include "ResourceScriptTokenList.def"
+ advance();
+ return Error::success();
+
+ case Kind::LineComment:
+ advance(2);
+ skipCurrentLine();
+ return Error::success();
+
+ case Kind::StartComment: {
+ advance(2);
+ auto EndPos = Data.find("*/", Pos);
+ if (EndPos == StringRef::npos)
+ return getStringError(
+ "Unclosed multi-line comment beginning at position " + Twine(Pos));
+ advance(EndPos - Pos);
+ advance(2);
+ return Error::success();
+ }
+ case Kind::Identifier:
+ while (!streamEof() && canContinueIdentifier())
+ advance();
+ return Error::success();
+
+ case Kind::Int:
+ while (!streamEof() && canContinueInt())
+ advance();
+ return Error::success();
+
+ case Kind::String:
+ // Consume the preceding 'L', if there is any.
+ if (std::toupper(Data[Pos]) == 'L')
+ advance();
+ // Consume the double-quote.
+ advance();
+
+ // Consume the characters until the end of the file, line or string.
+ while (true) {
+ if (streamEof()) {
+ return getStringError("Unterminated string literal.");
+ } else if (Data[Pos] == '"') {
+ // Consume the ending double-quote.
+ advance();
+ // However, if another '"' follows this double-quote, the string didn't
+ // end and we just included '"' into the string.
+ if (!willNowRead("\""))
+ return Error::success();
+ } else if (Data[Pos] == '\n') {
+ return getStringError("String literal not terminated in the line.");
+ }
+
+ advance();
+ }
+
+ case Kind::Invalid:
+ assert(false && "Cannot consume an invalid token.");
+ }
+
+ llvm_unreachable("Unknown RCToken::Kind");
+}
+
+bool Tokenizer::willNowRead(StringRef FollowingChars) const {
+ return Data.drop_front(Pos).startswith(FollowingChars);
+}
+
+bool Tokenizer::canStartIdentifier() const {
+ assert(!streamEof());
+
+ const char CurChar = Data[Pos];
+ return std::isalpha(CurChar) || CurChar == '_' || CurChar == '.';
+}
+
+bool Tokenizer::canContinueIdentifier() const {
+ assert(!streamEof());
+ const char CurChar = Data[Pos];
+ return std::isalnum(CurChar) || CurChar == '_' || CurChar == '.' ||
+ CurChar == '/' || CurChar == '\\';
+}
+
+bool Tokenizer::canStartInt() const {
+ assert(!streamEof());
+ return std::isdigit(Data[Pos]);
+}
+
+bool Tokenizer::canStartBlockComment() const {
+ assert(!streamEof());
+ return Data.drop_front(Pos).startswith("/*");
+}
+
+bool Tokenizer::canStartLineComment() const {
+ assert(!streamEof());
+ return Data.drop_front(Pos).startswith("//");
+}
+
+bool Tokenizer::canContinueInt() const {
+ assert(!streamEof());
+ return std::isalnum(Data[Pos]);
+}
+
+bool Tokenizer::canStartString() const {
+ return willNowRead("\"") || willNowRead("L\"") || willNowRead("l\"");
+}
+
+bool Tokenizer::streamEof() const { return Pos == DataLength; }
+
+Kind Tokenizer::classifyCurrentToken() const {
+ if (canStartBlockComment())
+ return Kind::StartComment;
+ if (canStartLineComment())
+ return Kind::LineComment;
+
+ if (canStartInt())
+ return Kind::Int;
+ if (canStartString())
+ return Kind::String;
+ // BEGIN and END are at this point of lexing recognized as identifiers.
+ if (canStartIdentifier())
+ return Kind::Identifier;
+
+ const char CurChar = Data[Pos];
+
+ switch (CurChar) {
+ // One-character token classification.
+#define TOKEN(Name)
+#define SHORT_TOKEN(Name, Ch) \
+ case Ch: \
+ return Kind::Name;
+#include "ResourceScriptTokenList.def"
+
+ default:
+ return Kind::Invalid;
+ }
+}
+
+void Tokenizer::processIdentifier(RCToken &Token) const {
+ assert(Token.kind() == Kind::Identifier);
+ StringRef Name = Token.value();
+
+ if (Name.equals_lower("begin"))
+ Token = RCToken(Kind::BlockBegin, Name);
+ else if (Name.equals_lower("end"))
+ Token = RCToken(Kind::BlockEnd, Name);
+}
+
+} // anonymous namespace
+
+namespace llvm {
+
+Expected<std::vector<RCToken>> tokenizeRC(StringRef Input) {
+ return Tokenizer(Input).run();
+}
+
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h
index cc8ca48b49..d821f10138 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h
@@ -1,81 +1,81 @@
-//===-- ResourceScriptToken.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
-//
-//===---------------------------------------------------------------------===//
-//
-// This declares the .rc script tokens and defines an interface for tokenizing
-// the input data. The list of available tokens is located at
-// ResourceScriptTokenList.def.
-//
-// Note that the tokenizer does not support preprocessor directives. The
-// preprocessor should do its work on the .rc file before running llvm-rc.
-//
-// As for now, it is possible to parse ASCII files only (the behavior on
-// UTF files might be undefined). However, it already consumes UTF-8 BOM, if
-// there is any. Thus, ASCII-compatible UTF-8 files are tokenized correctly.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380599(v=vs.85).aspx
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTTOKEN_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTTOKEN_H
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-
-#include <cstdint>
-#include <map>
-#include <string>
-#include <vector>
-
-namespace llvm {
-
-// A definition of a single resource script token. Each token has its kind
-// (declared in ResourceScriptTokenList) and holds a value - a reference
-// representation of the token.
-// RCToken does not claim ownership on its value. A memory buffer containing
-// the token value should be stored in a safe place and cannot be freed
-// nor reallocated.
-class RCToken {
-public:
- enum class Kind {
-#define TOKEN(Name) Name,
-#define SHORT_TOKEN(Name, Ch) Name,
-#include "ResourceScriptTokenList.def"
- };
-
- RCToken(RCToken::Kind RCTokenKind, StringRef Value);
-
- // Get an integer value of the integer token.
- uint32_t intValue() const;
- bool isLongInt() const;
-
- StringRef value() const;
- Kind kind() const;
-
- // Check if a token describes a binary operator.
- bool isBinaryOp() const;
-
-private:
- Kind TokenKind;
- StringRef TokenValue;
-};
-
-// Tokenize Input.
-// In case no error occurred, the return value contains
-// tokens in order they were in the input file.
-// In case of any error, the return value contains
-// a textual representation of error.
-//
-// Tokens returned by this function hold only references to the parts
-// of the Input. Memory buffer containing Input cannot be freed,
-// modified or reallocated.
-Expected<std::vector<RCToken>> tokenizeRC(StringRef Input);
-
-} // namespace llvm
-
-#endif
+//===-- ResourceScriptToken.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
+//
+//===---------------------------------------------------------------------===//
+//
+// This declares the .rc script tokens and defines an interface for tokenizing
+// the input data. The list of available tokens is located at
+// ResourceScriptTokenList.def.
+//
+// Note that the tokenizer does not support preprocessor directives. The
+// preprocessor should do its work on the .rc file before running llvm-rc.
+//
+// As for now, it is possible to parse ASCII files only (the behavior on
+// UTF files might be undefined). However, it already consumes UTF-8 BOM, if
+// there is any. Thus, ASCII-compatible UTF-8 files are tokenized correctly.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380599(v=vs.85).aspx
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTTOKEN_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTTOKEN_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+// A definition of a single resource script token. Each token has its kind
+// (declared in ResourceScriptTokenList) and holds a value - a reference
+// representation of the token.
+// RCToken does not claim ownership on its value. A memory buffer containing
+// the token value should be stored in a safe place and cannot be freed
+// nor reallocated.
+class RCToken {
+public:
+ enum class Kind {
+#define TOKEN(Name) Name,
+#define SHORT_TOKEN(Name, Ch) Name,
+#include "ResourceScriptTokenList.def"
+ };
+
+ RCToken(RCToken::Kind RCTokenKind, StringRef Value);
+
+ // Get an integer value of the integer token.
+ uint32_t intValue() const;
+ bool isLongInt() const;
+
+ StringRef value() const;
+ Kind kind() const;
+
+ // Check if a token describes a binary operator.
+ bool isBinaryOp() const;
+
+private:
+ Kind TokenKind;
+ StringRef TokenValue;
+};
+
+// Tokenize Input.
+// In case no error occurred, the return value contains
+// tokens in order they were in the input file.
+// In case of any error, the return value contains
+// a textual representation of error.
+//
+// Tokens returned by this function hold only references to the parts
+// of the Input. Memory buffer containing Input cannot be freed,
+// modified or reallocated.
+Expected<std::vector<RCToken>> tokenizeRC(StringRef Input);
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def
index a61a96461f..e0ea32f940 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def
@@ -1,39 +1,39 @@
-//===-- ResourceScriptTokenList.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
-//
-//===---------------------------------------------------------------------===//
-//
-// This is a part of llvm-rc tokenizer. It lists all the possible tokens
-// that might occur in a correct .rc script.
-//
-//===---------------------------------------------------------------------===//
-
-
-// Long tokens. They might consist of more than one character.
-TOKEN(Invalid) // Invalid token. Should not occur in a valid script.
-TOKEN(Int) // Integer (decimal, octal or hexadecimal).
-TOKEN(String) // String value.
-TOKEN(Identifier) // Script identifier (resource name or type).
-TOKEN(LineComment) // Beginning of single-line comment.
-TOKEN(StartComment) // Beginning of multi-line comment.
-
-// Short tokens. They usually consist of exactly one character.
-// The definitions are of the form SHORT_TOKEN(TokenName, TokenChar).
-// TokenChar is the one-character token representation occuring in the correct
-// .rc scripts.
-SHORT_TOKEN(BlockBegin, '{') // Start of the script block; can also be BEGIN.
-SHORT_TOKEN(BlockEnd, '}') // End of the block; can also be END.
-SHORT_TOKEN(Comma, ',') // Comma - resource arguments separator.
-SHORT_TOKEN(Plus, '+') // Addition operator.
-SHORT_TOKEN(Minus, '-') // Subtraction operator.
-SHORT_TOKEN(Pipe, '|') // Bitwise-OR operator.
-SHORT_TOKEN(Amp, '&') // Bitwise-AND operator.
-SHORT_TOKEN(Tilde, '~') // Bitwise-NOT operator.
-SHORT_TOKEN(LeftParen, '(') // Left parenthesis in the script expressions.
-SHORT_TOKEN(RightParen, ')') // Right parenthesis.
-
-#undef TOKEN
-#undef SHORT_TOKEN
+//===-- ResourceScriptTokenList.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
+//
+//===---------------------------------------------------------------------===//
+//
+// This is a part of llvm-rc tokenizer. It lists all the possible tokens
+// that might occur in a correct .rc script.
+//
+//===---------------------------------------------------------------------===//
+
+
+// Long tokens. They might consist of more than one character.
+TOKEN(Invalid) // Invalid token. Should not occur in a valid script.
+TOKEN(Int) // Integer (decimal, octal or hexadecimal).
+TOKEN(String) // String value.
+TOKEN(Identifier) // Script identifier (resource name or type).
+TOKEN(LineComment) // Beginning of single-line comment.
+TOKEN(StartComment) // Beginning of multi-line comment.
+
+// Short tokens. They usually consist of exactly one character.
+// The definitions are of the form SHORT_TOKEN(TokenName, TokenChar).
+// TokenChar is the one-character token representation occuring in the correct
+// .rc scripts.
+SHORT_TOKEN(BlockBegin, '{') // Start of the script block; can also be BEGIN.
+SHORT_TOKEN(BlockEnd, '}') // End of the block; can also be END.
+SHORT_TOKEN(Comma, ',') // Comma - resource arguments separator.
+SHORT_TOKEN(Plus, '+') // Addition operator.
+SHORT_TOKEN(Minus, '-') // Subtraction operator.
+SHORT_TOKEN(Pipe, '|') // Bitwise-OR operator.
+SHORT_TOKEN(Amp, '&') // Bitwise-AND operator.
+SHORT_TOKEN(Tilde, '~') // Bitwise-NOT operator.
+SHORT_TOKEN(LeftParen, '(') // Left parenthesis in the script expressions.
+SHORT_TOKEN(RightParen, ')') // Right parenthesis.
+
+#undef TOKEN
+#undef SHORT_TOKEN
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h
index 843c8d898a..f45154ddd4 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h
@@ -1,61 +1,61 @@
-//===-- ResourceVisitor.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
-//
-//===---------------------------------------------------------------------===//
-//
-// This defines a base class visiting resource script resources.
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCEVISITOR_H
-#define LLVM_TOOLS_LLVMRC_RESOURCEVISITOR_H
-
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-namespace rc {
-
-class RCResource;
-
-class CaptionStmt;
-class ClassStmt;
-class CharacteristicsStmt;
-class ExStyleStmt;
-class FontStmt;
-class LanguageResource;
-class StyleStmt;
-class VersionStmt;
-
-class Visitor {
-public:
- virtual Error visitNullResource(const RCResource *) = 0;
- virtual Error visitAcceleratorsResource(const RCResource *) = 0;
- virtual Error visitBitmapResource(const RCResource *) = 0;
- virtual Error visitCursorResource(const RCResource *) = 0;
- virtual Error visitDialogResource(const RCResource *) = 0;
- virtual Error visitHTMLResource(const RCResource *) = 0;
- virtual Error visitIconResource(const RCResource *) = 0;
- virtual Error visitMenuResource(const RCResource *) = 0;
- virtual Error visitStringTableResource(const RCResource *) = 0;
- virtual Error visitUserDefinedResource(const RCResource *) = 0;
- virtual Error visitVersionInfoResource(const RCResource *) = 0;
-
- virtual Error visitCaptionStmt(const CaptionStmt *) = 0;
- virtual Error visitClassStmt(const ClassStmt *) = 0;
- virtual Error visitCharacteristicsStmt(const CharacteristicsStmt *) = 0;
- virtual Error visitExStyleStmt(const ExStyleStmt *) = 0;
- virtual Error visitFontStmt(const FontStmt *) = 0;
- virtual Error visitLanguageStmt(const LanguageResource *) = 0;
- virtual Error visitStyleStmt(const StyleStmt *) = 0;
- virtual Error visitVersionStmt(const VersionStmt *) = 0;
-
- virtual ~Visitor() {}
-};
-
-} // namespace rc
-} // namespace llvm
-
-#endif
+//===-- ResourceVisitor.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
+//
+//===---------------------------------------------------------------------===//
+//
+// This defines a base class visiting resource script resources.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCEVISITOR_H
+#define LLVM_TOOLS_LLVMRC_RESOURCEVISITOR_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace rc {
+
+class RCResource;
+
+class CaptionStmt;
+class ClassStmt;
+class CharacteristicsStmt;
+class ExStyleStmt;
+class FontStmt;
+class LanguageResource;
+class StyleStmt;
+class VersionStmt;
+
+class Visitor {
+public:
+ virtual Error visitNullResource(const RCResource *) = 0;
+ virtual Error visitAcceleratorsResource(const RCResource *) = 0;
+ virtual Error visitBitmapResource(const RCResource *) = 0;
+ virtual Error visitCursorResource(const RCResource *) = 0;
+ virtual Error visitDialogResource(const RCResource *) = 0;
+ virtual Error visitHTMLResource(const RCResource *) = 0;
+ virtual Error visitIconResource(const RCResource *) = 0;
+ virtual Error visitMenuResource(const RCResource *) = 0;
+ virtual Error visitStringTableResource(const RCResource *) = 0;
+ virtual Error visitUserDefinedResource(const RCResource *) = 0;
+ virtual Error visitVersionInfoResource(const RCResource *) = 0;
+
+ virtual Error visitCaptionStmt(const CaptionStmt *) = 0;
+ virtual Error visitClassStmt(const ClassStmt *) = 0;
+ virtual Error visitCharacteristicsStmt(const CharacteristicsStmt *) = 0;
+ virtual Error visitExStyleStmt(const ExStyleStmt *) = 0;
+ virtual Error visitFontStmt(const FontStmt *) = 0;
+ virtual Error visitLanguageStmt(const LanguageResource *) = 0;
+ virtual Error visitStyleStmt(const StyleStmt *) = 0;
+ virtual Error visitVersionStmt(const VersionStmt *) = 0;
+
+ virtual ~Visitor() {}
+};
+
+} // namespace rc
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp b/contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp
index e9027a21d4..ced68a3727 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp
@@ -1,216 +1,216 @@
-//===-- llvm-rc.cpp - Compile .rc scripts into .res -------------*- 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
-//
-//===----------------------------------------------------------------------===//
-//
-// Compile .rc scripts into .res files. This is intended to be a
-// platform-independent port of Microsoft's rc.exe tool.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ResourceFileWriter.h"
-#include "ResourceScriptCppFilter.h"
-#include "ResourceScriptParser.h"
-#include "ResourceScriptStmt.h"
-#include "ResourceScriptToken.h"
-
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <algorithm>
-#include <system_error>
-
-using namespace llvm;
-using namespace llvm::rc;
-
-namespace {
-
-// Input options tables.
-
-enum ID {
- OPT_INVALID = 0, // This is not a correct option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
-#include "Opts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#include "Opts.inc"
-#undef PREFIX
-
-static 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 "Opts.inc"
-#undef OPTION
-};
-
-class RcOptTable : public opt::OptTable {
-public:
- RcOptTable() : OptTable(InfoTable, /* IgnoreCase = */ true) {}
-};
-
-static ExitOnError ExitOnErr;
-
-LLVM_ATTRIBUTE_NORETURN static void fatalError(const Twine &Message) {
- errs() << Message << "\n";
- exit(1);
-}
-
-} // anonymous namespace
-
-int main(int Argc, const char **Argv) {
- InitLLVM X(Argc, Argv);
- ExitOnErr.setBanner("llvm-rc: ");
-
- RcOptTable T;
- unsigned MAI, MAC;
- const char **DashDash = std::find_if(
- Argv + 1, Argv + Argc, [](StringRef Str) { return Str == "--"; });
- ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, DashDash);
-
- opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
-
- // The tool prints nothing when invoked with no command-line arguments.
+//===-- llvm-rc.cpp - Compile .rc scripts into .res -------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Compile .rc scripts into .res files. This is intended to be a
+// platform-independent port of Microsoft's rc.exe tool.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ResourceFileWriter.h"
+#include "ResourceScriptCppFilter.h"
+#include "ResourceScriptParser.h"
+#include "ResourceScriptStmt.h"
+#include "ResourceScriptToken.h"
+
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <system_error>
+
+using namespace llvm;
+using namespace llvm::rc;
+
+namespace {
+
+// Input options tables.
+
+enum ID {
+ OPT_INVALID = 0, // This is not a correct option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
+#include "Opts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Opts.inc"
+#undef PREFIX
+
+static 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 "Opts.inc"
+#undef OPTION
+};
+
+class RcOptTable : public opt::OptTable {
+public:
+ RcOptTable() : OptTable(InfoTable, /* IgnoreCase = */ true) {}
+};
+
+static ExitOnError ExitOnErr;
+
+LLVM_ATTRIBUTE_NORETURN static void fatalError(const Twine &Message) {
+ errs() << Message << "\n";
+ exit(1);
+}
+
+} // anonymous namespace
+
+int main(int Argc, const char **Argv) {
+ InitLLVM X(Argc, Argv);
+ ExitOnErr.setBanner("llvm-rc: ");
+
+ RcOptTable T;
+ unsigned MAI, MAC;
+ const char **DashDash = std::find_if(
+ Argv + 1, Argv + Argc, [](StringRef Str) { return Str == "--"; });
+ ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, DashDash);
+
+ opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
+
+ // The tool prints nothing when invoked with no command-line arguments.
if (InputArgs.hasArg(OPT_help)) {
- T.PrintHelp(outs(), "rc [options] file...", "Resource Converter", false);
- return 0;
- }
-
+ T.PrintHelp(outs(), "rc [options] file...", "Resource Converter", false);
+ return 0;
+ }
+
const bool BeVerbose = InputArgs.hasArg(OPT_verbose);
-
- std::vector<std::string> InArgsInfo = InputArgs.getAllArgValues(OPT_INPUT);
- if (DashDash != Argv + Argc)
- InArgsInfo.insert(InArgsInfo.end(), DashDash + 1, Argv + Argc);
- if (InArgsInfo.size() != 1) {
- fatalError("Exactly one input file should be provided.");
- }
-
- // Read and tokenize the input file.
- ErrorOr<std::unique_ptr<MemoryBuffer>> File =
- MemoryBuffer::getFile(InArgsInfo[0]);
- if (!File) {
- fatalError("Error opening file '" + Twine(InArgsInfo[0]) +
- "': " + File.getError().message());
- }
-
- std::unique_ptr<MemoryBuffer> FileContents = std::move(*File);
- StringRef Contents = FileContents->getBuffer();
-
- std::string FilteredContents = filterCppOutput(Contents);
- std::vector<RCToken> Tokens = ExitOnErr(tokenizeRC(FilteredContents));
-
- if (BeVerbose) {
- const Twine TokenNames[] = {
-#define TOKEN(Name) #Name,
-#define SHORT_TOKEN(Name, Ch) #Name,
-#include "ResourceScriptTokenList.def"
- };
-
- for (const RCToken &Token : Tokens) {
- outs() << TokenNames[static_cast<int>(Token.kind())] << ": "
- << Token.value();
- if (Token.kind() == RCToken::Kind::Int)
- outs() << "; int value = " << Token.intValue();
-
- outs() << "\n";
- }
- }
-
- WriterParams Params;
- SmallString<128> InputFile(InArgsInfo[0]);
- llvm::sys::fs::make_absolute(InputFile);
- Params.InputFilePath = InputFile;
+
+ std::vector<std::string> InArgsInfo = InputArgs.getAllArgValues(OPT_INPUT);
+ if (DashDash != Argv + Argc)
+ InArgsInfo.insert(InArgsInfo.end(), DashDash + 1, Argv + Argc);
+ if (InArgsInfo.size() != 1) {
+ fatalError("Exactly one input file should be provided.");
+ }
+
+ // Read and tokenize the input file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> File =
+ MemoryBuffer::getFile(InArgsInfo[0]);
+ if (!File) {
+ fatalError("Error opening file '" + Twine(InArgsInfo[0]) +
+ "': " + File.getError().message());
+ }
+
+ std::unique_ptr<MemoryBuffer> FileContents = std::move(*File);
+ StringRef Contents = FileContents->getBuffer();
+
+ std::string FilteredContents = filterCppOutput(Contents);
+ std::vector<RCToken> Tokens = ExitOnErr(tokenizeRC(FilteredContents));
+
+ if (BeVerbose) {
+ const Twine TokenNames[] = {
+#define TOKEN(Name) #Name,
+#define SHORT_TOKEN(Name, Ch) #Name,
+#include "ResourceScriptTokenList.def"
+ };
+
+ for (const RCToken &Token : Tokens) {
+ outs() << TokenNames[static_cast<int>(Token.kind())] << ": "
+ << Token.value();
+ if (Token.kind() == RCToken::Kind::Int)
+ outs() << "; int value = " << Token.intValue();
+
+ outs() << "\n";
+ }
+ }
+
+ WriterParams Params;
+ SmallString<128> InputFile(InArgsInfo[0]);
+ llvm::sys::fs::make_absolute(InputFile);
+ Params.InputFilePath = InputFile;
Params.Include = InputArgs.getAllArgValues(OPT_includepath);
Params.NoInclude = InputArgs.getAllArgValues(OPT_noinclude);
-
+
if (InputArgs.hasArg(OPT_codepage)) {
if (InputArgs.getLastArgValue(OPT_codepage)
- .getAsInteger(10, Params.CodePage))
- fatalError("Invalid code page: " +
+ .getAsInteger(10, Params.CodePage))
+ fatalError("Invalid code page: " +
InputArgs.getLastArgValue(OPT_codepage));
- switch (Params.CodePage) {
- case CpAcp:
- case CpWin1252:
- case CpUtf8:
- break;
- default:
- fatalError(
- "Unsupported code page, only 0, 1252 and 65001 are supported!");
- }
- }
-
- std::unique_ptr<ResourceFileWriter> Visitor;
+ switch (Params.CodePage) {
+ case CpAcp:
+ case CpWin1252:
+ case CpUtf8:
+ break;
+ default:
+ fatalError(
+ "Unsupported code page, only 0, 1252 and 65001 are supported!");
+ }
+ }
+
+ std::unique_ptr<ResourceFileWriter> Visitor;
bool IsDryRun = InputArgs.hasArg(OPT_dry_run);
-
- if (!IsDryRun) {
+
+ if (!IsDryRun) {
auto OutArgsInfo = InputArgs.getAllArgValues(OPT_fileout);
- if (OutArgsInfo.empty()) {
- SmallString<128> OutputFile = InputFile;
- llvm::sys::path::replace_extension(OutputFile, "res");
- OutArgsInfo.push_back(std::string(OutputFile.str()));
- }
-
- if (OutArgsInfo.size() != 1)
- fatalError(
- "No more than one output file should be provided (using /FO flag).");
-
- std::error_code EC;
- auto FOut = std::make_unique<raw_fd_ostream>(
- OutArgsInfo[0], EC, sys::fs::FA_Read | sys::fs::FA_Write);
- if (EC)
- fatalError("Error opening output file '" + OutArgsInfo[0] +
- "': " + EC.message());
- Visitor = std::make_unique<ResourceFileWriter>(Params, std::move(FOut));
+ if (OutArgsInfo.empty()) {
+ SmallString<128> OutputFile = InputFile;
+ llvm::sys::path::replace_extension(OutputFile, "res");
+ OutArgsInfo.push_back(std::string(OutputFile.str()));
+ }
+
+ if (OutArgsInfo.size() != 1)
+ fatalError(
+ "No more than one output file should be provided (using /FO flag).");
+
+ std::error_code EC;
+ auto FOut = std::make_unique<raw_fd_ostream>(
+ OutArgsInfo[0], EC, sys::fs::FA_Read | sys::fs::FA_Write);
+ if (EC)
+ fatalError("Error opening output file '" + OutArgsInfo[0] +
+ "': " + EC.message());
+ Visitor = std::make_unique<ResourceFileWriter>(Params, std::move(FOut));
Visitor->AppendNull = InputArgs.hasArg(OPT_add_null);
-
- ExitOnErr(NullResource().visit(Visitor.get()));
-
- // Set the default language; choose en-US arbitrarily.
- unsigned PrimaryLangId = 0x09, SubLangId = 0x01;
+
+ ExitOnErr(NullResource().visit(Visitor.get()));
+
+ // Set the default language; choose en-US arbitrarily.
+ unsigned PrimaryLangId = 0x09, SubLangId = 0x01;
if (InputArgs.hasArg(OPT_lang_id)) {
- unsigned LangId;
+ unsigned LangId;
if (InputArgs.getLastArgValue(OPT_lang_id).getAsInteger(16, LangId))
- fatalError("Invalid language id: " +
+ fatalError("Invalid language id: " +
InputArgs.getLastArgValue(OPT_lang_id));
- PrimaryLangId = LangId & 0x3ff;
- SubLangId = LangId >> 10;
- }
- ExitOnErr(LanguageResource(PrimaryLangId, SubLangId).visit(Visitor.get()));
- }
-
- rc::RCParser Parser{std::move(Tokens)};
- while (!Parser.isEof()) {
- auto Resource = ExitOnErr(Parser.parseSingleResource());
- if (BeVerbose)
- Resource->log(outs());
- if (!IsDryRun)
- ExitOnErr(Resource->visit(Visitor.get()));
- }
-
- // STRINGTABLE resources come at the very end.
- if (!IsDryRun)
- ExitOnErr(Visitor->dumpAllStringTables());
-
- return 0;
-}
+ PrimaryLangId = LangId & 0x3ff;
+ SubLangId = LangId >> 10;
+ }
+ ExitOnErr(LanguageResource(PrimaryLangId, SubLangId).visit(Visitor.get()));
+ }
+
+ rc::RCParser Parser{std::move(Tokens)};
+ while (!Parser.isEof()) {
+ auto Resource = ExitOnErr(Parser.parseSingleResource());
+ if (BeVerbose)
+ Resource->log(outs());
+ if (!IsDryRun)
+ ExitOnErr(Resource->visit(Visitor.get()));
+ }
+
+ // STRINGTABLE resources come at the very end.
+ if (!IsDryRun)
+ ExitOnErr(Visitor->dumpAllStringTables());
+
+ return 0;
+}
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ya.make b/contrib/libs/llvm12/tools/llvm-rc/ya.make
index e69f41f542..e1f1b87aec 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ya.make
+++ b/contrib/libs/llvm12/tools/llvm-rc/ya.make
@@ -1,40 +1,40 @@
-# Generated by devtools/yamaker.
-
-PROGRAM()
-
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
-
+
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/Demangle
contrib/libs/llvm12/lib/Option
contrib/libs/llvm12/lib/Support
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/llvm-rc
contrib/libs/llvm12/tools/llvm-rc
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- ResourceFileWriter.cpp
- ResourceScriptCppFilter.cpp
- ResourceScriptParser.cpp
- ResourceScriptStmt.cpp
- ResourceScriptToken.cpp
- llvm-rc.cpp
-)
-
-END()
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ ResourceFileWriter.cpp
+ ResourceScriptCppFilter.cpp
+ ResourceScriptParser.cpp
+ ResourceScriptStmt.cpp
+ ResourceScriptToken.cpp
+ llvm-rc.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm12/tools/llvm-symbolizer/llvm-symbolizer.cpp b/contrib/libs/llvm12/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 8734c2d740..394fc5d1a7 100644
--- a/contrib/libs/llvm12/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/contrib/libs/llvm12/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -1,43 +1,43 @@
-//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
-//
-// 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 utility works much like "addr2line". It is able of transforming
-// tuples (module name, module offset) to code locations (function name,
-// file, line number, column number). It is targeted for compiler-rt tools
-// (especially AddressSanitizer and ThreadSanitizer) that can use it
-// to symbolize stack traces in their error reports.
-//
-//===----------------------------------------------------------------------===//
-
+//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
+//
+// 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 utility works much like "addr2line". It is able of transforming
+// tuples (module name, module offset) to code locations (function name,
+// file, line number, column number). It is targeted for compiler-rt tools
+// (especially AddressSanitizer and ThreadSanitizer) that can use it
+// to symbolize stack traces in their error reports.
+//
+//===----------------------------------------------------------------------===//
+
#include "Opts.inc"
-#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
-#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
-#include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
+#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
-#include "llvm/Support/COM.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/Path.h"
+#include "llvm/Support/COM.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cstdio>
-#include <cstring>
-#include <string>
-
-using namespace llvm;
-using namespace symbolize;
-
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+using namespace llvm;
+using namespace symbolize;
+
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
@@ -47,11 +47,11 @@ enum ID {
#include "Opts.inc"
#undef OPTION
};
-
+
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Opts.inc"
#undef PREFIX
-
+
static const opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
@@ -63,139 +63,139 @@ static const opt::OptTable::Info InfoTable[] = {
#include "Opts.inc"
#undef OPTION
};
-
+
class SymbolizerOptTable : public opt::OptTable {
public:
SymbolizerOptTable() : OptTable(InfoTable, true) {}
};
} // namespace
-
-static cl::list<std::string> ClInputAddresses(cl::Positional,
- cl::desc("<input addresses>..."),
- cl::ZeroOrMore);
-
-template<typename T>
-static bool error(Expected<T> &ResOrErr) {
- if (ResOrErr)
- return false;
- logAllUnhandledErrors(ResOrErr.takeError(), errs(),
- "LLVMSymbolizer: error reading file: ");
- return true;
-}
-
-enum class Command {
- Code,
- Data,
- Frame,
-};
-
+
+static cl::list<std::string> ClInputAddresses(cl::Positional,
+ cl::desc("<input addresses>..."),
+ cl::ZeroOrMore);
+
+template<typename T>
+static bool error(Expected<T> &ResOrErr) {
+ if (ResOrErr)
+ return false;
+ logAllUnhandledErrors(ResOrErr.takeError(), errs(),
+ "LLVMSymbolizer: error reading file: ");
+ return true;
+}
+
+enum class Command {
+ Code,
+ Data,
+ Frame,
+};
+
static bool parseCommand(StringRef BinaryName, bool IsAddr2Line,
StringRef InputString, Command &Cmd,
- std::string &ModuleName, uint64_t &ModuleOffset) {
- const char kDelimiters[] = " \n\r";
- ModuleName = "";
- if (InputString.consume_front("CODE ")) {
- Cmd = Command::Code;
- } else if (InputString.consume_front("DATA ")) {
- Cmd = Command::Data;
- } else if (InputString.consume_front("FRAME ")) {
- Cmd = Command::Frame;
- } else {
- // If no cmd, assume it's CODE.
- Cmd = Command::Code;
- }
- const char *Pos = InputString.data();
- // Skip delimiters and parse input filename (if needed).
+ std::string &ModuleName, uint64_t &ModuleOffset) {
+ const char kDelimiters[] = " \n\r";
+ ModuleName = "";
+ if (InputString.consume_front("CODE ")) {
+ Cmd = Command::Code;
+ } else if (InputString.consume_front("DATA ")) {
+ Cmd = Command::Data;
+ } else if (InputString.consume_front("FRAME ")) {
+ Cmd = Command::Frame;
+ } else {
+ // If no cmd, assume it's CODE.
+ Cmd = Command::Code;
+ }
+ const char *Pos = InputString.data();
+ // Skip delimiters and parse input filename (if needed).
if (BinaryName.empty()) {
- Pos += strspn(Pos, kDelimiters);
- if (*Pos == '"' || *Pos == '\'') {
- char Quote = *Pos;
- Pos++;
- const char *End = strchr(Pos, Quote);
- if (!End)
- return false;
- ModuleName = std::string(Pos, End - Pos);
- Pos = End + 1;
- } else {
- int NameLength = strcspn(Pos, kDelimiters);
- ModuleName = std::string(Pos, NameLength);
- Pos += NameLength;
- }
- } else {
+ Pos += strspn(Pos, kDelimiters);
+ if (*Pos == '"' || *Pos == '\'') {
+ char Quote = *Pos;
+ Pos++;
+ const char *End = strchr(Pos, Quote);
+ if (!End)
+ return false;
+ ModuleName = std::string(Pos, End - Pos);
+ Pos = End + 1;
+ } else {
+ int NameLength = strcspn(Pos, kDelimiters);
+ ModuleName = std::string(Pos, NameLength);
+ Pos += NameLength;
+ }
+ } else {
ModuleName = BinaryName.str();
- }
- // Skip delimiters and parse module offset.
- Pos += strspn(Pos, kDelimiters);
- int OffsetLength = strcspn(Pos, kDelimiters);
- StringRef Offset(Pos, OffsetLength);
- // GNU addr2line assumes the offset is hexadecimal and allows a redundant
- // "0x" or "0X" prefix; do the same for compatibility.
- if (IsAddr2Line)
- Offset.consume_front("0x") || Offset.consume_front("0X");
- return !Offset.getAsInteger(IsAddr2Line ? 16 : 0, ModuleOffset);
-}
-
+ }
+ // Skip delimiters and parse module offset.
+ Pos += strspn(Pos, kDelimiters);
+ int OffsetLength = strcspn(Pos, kDelimiters);
+ StringRef Offset(Pos, OffsetLength);
+ // GNU addr2line assumes the offset is hexadecimal and allows a redundant
+ // "0x" or "0X" prefix; do the same for compatibility.
+ if (IsAddr2Line)
+ Offset.consume_front("0x") || Offset.consume_front("0X");
+ return !Offset.getAsInteger(IsAddr2Line ? 16 : 0, ModuleOffset);
+}
+
static void symbolizeInput(const opt::InputArgList &Args, uint64_t AdjustVMA,
bool IsAddr2Line, DIPrinter::OutputStyle OutputStyle,
StringRef InputString, LLVMSymbolizer &Symbolizer,
DIPrinter &Printer) {
- Command Cmd;
- std::string ModuleName;
- uint64_t Offset = 0;
+ Command Cmd;
+ std::string ModuleName;
+ uint64_t Offset = 0;
if (!parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
StringRef(InputString), Cmd, ModuleName, Offset)) {
- outs() << InputString << "\n";
- return;
- }
-
+ outs() << InputString << "\n";
+ return;
+ }
+
if (Args.hasArg(OPT_addresses)) {
- outs() << "0x";
- outs().write_hex(Offset);
+ outs() << "0x";
+ outs().write_hex(Offset);
StringRef Delimiter = Args.hasArg(OPT_pretty_print) ? ": " : "\n";
- outs() << Delimiter;
- }
+ outs() << Delimiter;
+ }
Offset -= AdjustVMA;
- if (Cmd == Command::Data) {
- auto ResOrErr = Symbolizer.symbolizeData(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
- Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get());
- } else if (Cmd == Command::Frame) {
- auto ResOrErr = Symbolizer.symbolizeFrame(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
- if (!error(ResOrErr)) {
- for (DILocal Local : *ResOrErr)
- Printer << Local;
- if (ResOrErr->empty())
- outs() << "??\n";
- }
+ if (Cmd == Command::Data) {
+ auto ResOrErr = Symbolizer.symbolizeData(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
+ Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get());
+ } else if (Cmd == Command::Frame) {
+ auto ResOrErr = Symbolizer.symbolizeFrame(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
+ if (!error(ResOrErr)) {
+ for (DILocal Local : *ResOrErr)
+ Printer << Local;
+ if (ResOrErr->empty())
+ outs() << "??\n";
+ }
} else if (Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line)) {
- auto ResOrErr = Symbolizer.symbolizeInlinedCode(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
- Printer << (error(ResOrErr) ? DIInliningInfo() : ResOrErr.get());
+ auto ResOrErr = Symbolizer.symbolizeInlinedCode(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
+ Printer << (error(ResOrErr) ? DIInliningInfo() : ResOrErr.get());
} else if (OutputStyle == DIPrinter::OutputStyle::GNU) {
// With PrintFunctions == FunctionNameKind::LinkageName (default)
// and UseSymbolTable == true (also default), Symbolizer.symbolizeCode()
- // may override the name of an inlined function with the name of the topmost
- // caller function in the inlining chain. This contradicts the existing
- // behavior of addr2line. Symbolizer.symbolizeInlinedCode() overrides only
- // the topmost function, which suits our needs better.
- auto ResOrErr = Symbolizer.symbolizeInlinedCode(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
+ // may override the name of an inlined function with the name of the topmost
+ // caller function in the inlining chain. This contradicts the existing
+ // behavior of addr2line. Symbolizer.symbolizeInlinedCode() overrides only
+ // the topmost function, which suits our needs better.
+ auto ResOrErr = Symbolizer.symbolizeInlinedCode(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
if (!ResOrErr || ResOrErr->getNumberOfFrames() == 0) {
error(ResOrErr);
Printer << DILineInfo();
} else {
Printer << ResOrErr->getFrame(0);
}
- } else {
- auto ResOrErr = Symbolizer.symbolizeCode(
- ModuleName, {Offset, object::SectionedAddress::UndefSection});
- Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get());
- }
+ } else {
+ auto ResOrErr = Symbolizer.symbolizeCode(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
+ Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get());
+ }
if (OutputStyle == DIPrinter::OutputStyle::LLVM)
- outs() << "\n";
-}
-
+ outs() << "\n";
+}
+
static void printHelp(StringRef ToolName, const SymbolizerOptTable &Tbl,
raw_ostream &OS) {
const char HelpText[] = " [options] addresses...";
@@ -204,7 +204,7 @@ static void printHelp(StringRef ToolName, const SymbolizerOptTable &Tbl,
// TODO Replace this with OptTable API once it adds extrahelp support.
OS << "\nPass @FILE as argument to read options from FILE.\n";
}
-
+
static opt::InputArgList parseOptions(int Argc, char *Argv[], bool IsAddr2Line,
StringSaver &Saver,
SymbolizerOptTable &Tbl) {
@@ -231,7 +231,7 @@ static opt::InputArgList parseOptions(int Argc, char *Argv[], bool IsAddr2Line,
cl::PrintVersionMessage();
exit(0);
}
-
+
return Args;
}
@@ -246,9 +246,9 @@ static void parseIntArg(const opt::InputArgList &Args, int ID, T &Value) {
}
} else {
Value = 0;
- }
+ }
}
-
+
static FunctionNameKind decideHowToPrintFunctions(const opt::InputArgList &Args,
bool IsAddr2Line) {
if (Args.hasArg(OPT_functions))
@@ -260,18 +260,18 @@ static FunctionNameKind decideHowToPrintFunctions(const opt::InputArgList &Args,
.Default(FunctionNameKind::LinkageName);
return IsAddr2Line ? FunctionNameKind::None : FunctionNameKind::LinkageName;
}
-
+
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
sys::InitializeCOMRAII COM(sys::COMThreadingMode::MultiThreaded);
-
+
bool IsAddr2Line = sys::path::stem(argv[0]).contains("addr2line");
BumpPtrAllocator A;
StringSaver Saver(A);
SymbolizerOptTable Tbl;
opt::InputArgList Args = parseOptions(argc, argv, IsAddr2Line, Saver, Tbl);
- LLVMSymbolizer::Options Opts;
+ LLVMSymbolizer::Options Opts;
uint64_t AdjustVMA;
unsigned SourceContextLines;
parseIntArg(Args, OPT_adjust_vma_EQ, AdjustVMA);
@@ -302,16 +302,16 @@ int main(int argc, char **argv) {
}
#endif
Opts.UseSymbolTable = true;
-
+
for (const opt::Arg *A : Args.filtered(OPT_dsym_hint_EQ)) {
StringRef Hint(A->getValue());
if (sys::path::extension(Hint) == ".dSYM") {
Opts.DsymHints.emplace_back(Hint);
- } else {
+ } else {
errs() << "Warning: invalid dSYM hint: \"" << Hint
<< "\" (must have the '.dSYM' extension).\n";
- }
- }
+ }
+ }
auto OutputStyle =
IsAddr2Line ? DIPrinter::OutputStyle::GNU : DIPrinter::OutputStyle::LLVM;
@@ -321,30 +321,30 @@ int main(int argc, char **argv) {
: DIPrinter::OutputStyle::LLVM;
}
- LLVMSymbolizer Symbolizer(Opts);
+ LLVMSymbolizer Symbolizer(Opts);
DIPrinter Printer(outs(), Opts.PrintFunctions != FunctionNameKind::None,
Args.hasArg(OPT_pretty_print), SourceContextLines,
Args.hasArg(OPT_verbose), OutputStyle);
-
+
std::vector<std::string> InputAddresses = Args.getAllArgValues(OPT_INPUT);
if (InputAddresses.empty()) {
- const int kMaxInputStringLength = 1024;
- char InputString[kMaxInputStringLength];
-
- while (fgets(InputString, sizeof(InputString), stdin)) {
- // Strip newline characters.
- std::string StrippedInputString(InputString);
+ const int kMaxInputStringLength = 1024;
+ char InputString[kMaxInputStringLength];
+
+ while (fgets(InputString, sizeof(InputString), stdin)) {
+ // Strip newline characters.
+ std::string StrippedInputString(InputString);
llvm::erase_if(StrippedInputString,
[](char c) { return c == '\r' || c == '\n'; });
symbolizeInput(Args, AdjustVMA, IsAddr2Line, OutputStyle,
StrippedInputString, Symbolizer, Printer);
- outs().flush();
- }
- } else {
+ outs().flush();
+ }
+ } else {
for (StringRef Address : InputAddresses)
symbolizeInput(Args, AdjustVMA, IsAddr2Line, OutputStyle, Address,
Symbolizer, Printer);
- }
-
- return 0;
-}
+ }
+
+ return 0;
+}
diff --git a/contrib/libs/llvm12/tools/llvm-symbolizer/ya.make b/contrib/libs/llvm12/tools/llvm-symbolizer/ya.make
index 1f13f78269..35bf52aeca 100644
--- a/contrib/libs/llvm12/tools/llvm-symbolizer/ya.make
+++ b/contrib/libs/llvm12/tools/llvm-symbolizer/ya.make
@@ -1,17 +1,17 @@
-# Generated by devtools/yamaker.
-
-PROGRAM()
-
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
-
+
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/BinaryFormat
@@ -31,19 +31,19 @@ PEERDIR(
contrib/libs/llvm12/lib/Remarks
contrib/libs/llvm12/lib/Support
contrib/libs/llvm12/lib/TextAPI/MachO
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/llvm-symbolizer
contrib/libs/llvm12/tools/llvm-symbolizer
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- llvm-symbolizer.cpp
-)
-
-END()
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ llvm-symbolizer.cpp
+)
+
+END()