summaryrefslogtreecommitdiff
path: root/llvm/tools
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-24 15:03:44 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-24 15:03:44 +0000
commit4b4fe385e49bd883fd183b5f21c1ea486c722e61 (patch)
treec3d8fdb355c9c73e57723718c22103aaf7d15aa6 /llvm/tools
parent1f917f69ff07f09b6dbb670971f57f8efe718b84 (diff)
Vendor import of llvm-project main llvmorg-15-init-17485-ga3e38b4a206b.vendor/llvm-project/llvmorg-15-init-17485-ga3e38b4a206b
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/llc/llc.cpp2
-rw-r--r--llvm/tools/llvm-ar/llvm-ar.cpp162
-rw-r--r--llvm/tools/llvm-cov/CodeCoverage.cpp17
-rw-r--r--llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp2
-rw-r--r--llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp277
-rw-r--r--llvm/tools/llvm-dwarfutil/DebugInfoLinker.h31
-rw-r--r--llvm/tools/llvm-dwarfutil/Error.h44
-rw-r--r--llvm/tools/llvm-dwarfutil/Options.h46
-rw-r--r--llvm/tools/llvm-dwarfutil/Options.td65
-rw-r--r--llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp527
-rw-r--r--llvm/tools/llvm-mc/llvm-mc.cpp4
-rw-r--r--llvm/tools/llvm-objdump/llvm-objdump.cpp62
-rw-r--r--llvm/tools/llvm-objdump/llvm-objdump.h2
-rw-r--r--llvm/tools/llvm-profdata/llvm-profdata.cpp7
-rw-r--r--llvm/tools/llvm-size/llvm-size.cpp7
-rw-r--r--llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp15
-rw-r--r--llvm/tools/opt/opt.cpp28
17 files changed, 1219 insertions, 79 deletions
diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index 853a0bd8eb54..f084ee2daa93 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -359,8 +359,6 @@ int main(int argc, char **argv) {
initializeCodeGen(*Registry);
initializeLoopStrengthReducePass(*Registry);
initializeLowerIntrinsicsPass(*Registry);
- initializeEntryExitInstrumenterPass(*Registry);
- initializePostInlineEntryExitInstrumenterPass(*Registry);
initializeUnreachableBlockElimLegacyPassPass(*Registry);
initializeConstantHoistingLegacyPassPass(*Registry);
initializeScalarOpts(*Registry);
diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp
index e964dc8256a5..1d4a8e9cd398 100644
--- a/llvm/tools/llvm-ar/llvm-ar.cpp
+++ b/llvm/tools/llvm-ar/llvm-ar.cpp
@@ -18,10 +18,14 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Object/TapiFile.h"
+#include "llvm/Object/Wasm.h"
#include "llvm/Object/XCOFFObjectFile.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/CommandLine.h"
@@ -55,6 +59,7 @@
#endif
using namespace llvm;
+using namespace llvm::object;
// The name this program was invoked as.
static StringRef ToolName;
@@ -82,7 +87,7 @@ static void printArHelp(StringRef ToolName) {
=gnu - gnu
=darwin - darwin
=bsd - bsd
- =aix - aix (big archive)
+ =bigarchive - big archive (AIX OS)
--plugin=<string> - ignored for compatibility
-h --help - display this help and exit
--output - the directory to extract archive members to
@@ -91,6 +96,7 @@ static void printArHelp(StringRef ToolName) {
=windows - windows
--thin - create a thin archive
--version - print the version and exit
+ -X{32|64|32_64|any} - object mode (only for AIX OS)
@<file> - read options from <file>
OPERATIONS:
@@ -184,6 +190,10 @@ static void failIfError(Error E, Twine Context = "") {
});
}
+static void warn(Twine Message) {
+ WithColor::warning(errs(), ToolName) << Message << "\n";
+}
+
static SmallVector<const char *, 256> PositionalArgs;
static bool MRI;
@@ -209,6 +219,10 @@ enum ArchiveOperation {
CreateSymTab ///< Create a symbol table in an existing archive
};
+enum class BitModeTy { Bit32, Bit64, Bit32_64, Any, Unknown };
+
+static BitModeTy BitMode = BitModeTy::Bit32;
+
// Modifiers to follow operation to vary behavior
static bool AddAfter = false; ///< 'a' modifier
static bool AddBefore = false; ///< 'b' modifier
@@ -632,6 +646,71 @@ static bool shouldCreateArchive(ArchiveOperation Op) {
llvm_unreachable("Missing entry in covered switch.");
}
+static bool is64BitSymbolicFile(SymbolicFile &Obj) {
+ if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj))
+ return Triple(IRObj->getTargetTriple()).isArch64Bit();
+ if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj))
+ return false;
+ if (XCOFFObjectFile *XCOFFObj = dyn_cast<XCOFFObjectFile>(&Obj))
+ return XCOFFObj->is64Bit();
+ if (isa<WasmObjectFile>(Obj))
+ return false;
+ if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj))
+ return Tapi->is64Bit();
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
+ return MachO->is64Bit();
+ if (ELFObjectFileBase *ElfO = dyn_cast<ELFObjectFileBase>(&Obj))
+ return ElfO->getBytesInAddress() == 8;
+
+ fail("unsupported file format");
+}
+
+static bool isValidInBitMode(Binary &Bin) {
+ if (BitMode == BitModeTy::Bit32_64 || BitMode == BitModeTy::Any)
+ return true;
+
+ if (SymbolicFile *SymFile = dyn_cast<SymbolicFile>(&Bin)) {
+ bool Is64Bit = is64BitSymbolicFile(*SymFile);
+ if ((Is64Bit && (BitMode == BitModeTy::Bit32)) ||
+ (!Is64Bit && (BitMode == BitModeTy::Bit64)))
+ return false;
+ }
+ // In AIX "ar", non-object files are always considered to have a valid bit
+ // mode.
+ return true;
+}
+
+Expected<std::unique_ptr<Binary>> getAsBinary(const NewArchiveMember &NM,
+ LLVMContext *Context) {
+ auto BinaryOrErr = createBinary(NM.Buf->getMemBufferRef(), Context);
+ if (BinaryOrErr)
+ return std::move(*BinaryOrErr);
+ return BinaryOrErr.takeError();
+}
+
+Expected<std::unique_ptr<Binary>> getAsBinary(const Archive::Child &C,
+ LLVMContext *Context) {
+ return C.getAsBinary(Context);
+}
+
+template <class A> static bool isValidInBitMode(const A &Member) {
+ if (object::Archive::getDefaultKindForHost() != object::Archive::K_AIXBIG)
+ return true;
+ LLVMContext Context;
+ Expected<std::unique_ptr<Binary>> BinOrErr = getAsBinary(Member, &Context);
+ // In AIX "ar", if there is a non-object file member, it is never ignored due
+ // to the bit mode setting.
+ if (!BinOrErr) {
+ consumeError(BinOrErr.takeError());
+ return true;
+ }
+ return isValidInBitMode(*BinOrErr.get());
+}
+
+static void warnInvalidObjectForFileMode(Twine Name) {
+ warn("'" + Name + "' is not valid with the current object file mode");
+}
+
static void performReadOperation(ArchiveOperation Operation,
object::Archive *OldArchive) {
if (Operation == Extract && OldArchive->isThin())
@@ -646,6 +725,10 @@ static void performReadOperation(ArchiveOperation Operation,
failIfError(NameOrErr.takeError());
StringRef Name = NameOrErr.get();
+ // Check whether to ignore this object due to its bitness.
+ if (!isValidInBitMode(C))
+ continue;
+
if (Filter) {
auto I = find_if(Members, [Name](StringRef Path) {
return comparePaths(Name, Path);
@@ -722,8 +805,7 @@ static void addChildMember(std::vector<NewArchiveMember> &Members,
Members.push_back(std::move(*NMOrErr));
}
-static void addMember(std::vector<NewArchiveMember> &Members,
- StringRef FileName, bool FlattenArchive = false) {
+static NewArchiveMember getArchiveMember(StringRef FileName) {
Expected<NewArchiveMember> NMOrErr =
NewArchiveMember::getFile(FileName, Deterministic);
failIfError(NMOrErr.takeError(), FileName);
@@ -743,9 +825,24 @@ static void addMember(std::vector<NewArchiveMember> &Members,
PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName));
}
}
+ return std::move(*NMOrErr);
+}
+
+static void addMember(std::vector<NewArchiveMember> &Members,
+ NewArchiveMember &NM) {
+ Members.push_back(std::move(NM));
+}
+
+static void addMember(std::vector<NewArchiveMember> &Members,
+ StringRef FileName, bool FlattenArchive = false) {
+ NewArchiveMember NM = getArchiveMember(FileName);
+ if (!isValidInBitMode(NM)) {
+ warnInvalidObjectForFileMode(FileName);
+ return;
+ }
if (FlattenArchive &&
- identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
+ identify_magic(NM.Buf->getBuffer()) == file_magic::archive) {
object::Archive &Lib = readLibrary(FileName);
// When creating thin archives, only flatten if the member is also thin.
if (!Thin || Lib.isThin()) {
@@ -757,7 +854,7 @@ static void addMember(std::vector<NewArchiveMember> &Members,
return;
}
}
- Members.push_back(std::move(*NMOrErr));
+ Members.push_back(std::move(NM));
}
enum InsertAction {
@@ -773,6 +870,9 @@ static InsertAction computeInsertAction(ArchiveOperation Operation,
StringRef Name,
std::vector<StringRef>::iterator &Pos,
StringMap<int> &MemberCount) {
+ if (!isValidInBitMode(Member))
+ return IA_AddOldMember;
+
if (Operation == QuickAppend || Members.empty())
return IA_AddOldMember;
auto MI = find_if(
@@ -834,7 +934,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
Expected<StringRef> NameOrErr = Child.getName();
failIfError(NameOrErr.takeError());
std::string Name = std::string(NameOrErr.get());
- if (comparePaths(Name, RelPos)) {
+ if (comparePaths(Name, RelPos) && isValidInBitMode(Child)) {
assert(AddAfter || AddBefore);
if (AddBefore)
InsertPos = Pos;
@@ -845,12 +945,25 @@ computeNewArchiveMembers(ArchiveOperation Operation,
std::vector<StringRef>::iterator MemberI = Members.end();
InsertAction Action =
computeInsertAction(Operation, Child, Name, MemberI, MemberCount);
+
+ auto HandleNewMember = [](auto Member, auto &Members, auto &Child) {
+ NewArchiveMember NM = getArchiveMember(*Member);
+ if (isValidInBitMode(NM))
+ addMember(Members, NM);
+ else {
+ // If a new member is not a valid object for the bit mode, add
+ // the old member back.
+ warnInvalidObjectForFileMode(*Member);
+ addChildMember(Members, Child, /*FlattenArchive=*/Thin);
+ }
+ };
+
switch (Action) {
case IA_AddOldMember:
addChildMember(Ret, Child, /*FlattenArchive=*/Thin);
break;
case IA_AddNewMember:
- addMember(Ret, *MemberI);
+ HandleNewMember(MemberI, Ret, Child);
break;
case IA_Delete:
break;
@@ -858,7 +971,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
addChildMember(Moved, Child, /*FlattenArchive=*/Thin);
break;
case IA_MoveNewMember:
- addMember(Moved, *MemberI);
+ HandleNewMember(MemberI, Moved, Child);
break;
}
// When processing elements with the count param, we need to preserve the
@@ -1043,8 +1156,7 @@ static int performOperation(ArchiveOperation Operation,
} else {
if (!Create) {
// Produce a warning if we should and we're creating the archive
- WithColor::warning(errs(), ToolName)
- << "creating " << ArchiveName << "\n";
+ warn("creating " + ArchiveName);
}
}
@@ -1155,6 +1267,15 @@ static bool handleGenericOption(StringRef arg) {
return false;
}
+static BitModeTy getBitMode(const char *RawBitMode) {
+ return StringSwitch<BitModeTy>(RawBitMode)
+ .Case("32", BitModeTy::Bit32)
+ .Case("64", BitModeTy::Bit64)
+ .Case("32_64", BitModeTy::Bit32_64)
+ .Case("any", BitModeTy::Any)
+ .Default(BitModeTy::Unknown);
+}
+
static const char *matchFlagWithArg(StringRef Expected,
ArrayRef<const char *>::iterator &ArgIt,
ArrayRef<const char *> Args) {
@@ -1204,6 +1325,14 @@ static int ar_main(int argc, char **argv) {
cl::ExpandResponseFiles(Saver, getRspQuoting(makeArrayRef(argv, argc)), Argv);
+ // Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if
+ // specified.
+ if (object::Archive::getDefaultKindForHost() == object::Archive::K_AIXBIG) {
+ BitMode = getBitMode(getenv("OBJECT_MODE"));
+ if (BitMode == BitModeTy::Unknown)
+ BitMode = BitModeTy::Bit32;
+ }
+
for (ArrayRef<const char *>::iterator ArgIt = Argv.begin();
ArgIt != Argv.end(); ++ArgIt) {
const char *Match = nullptr;
@@ -1258,6 +1387,19 @@ static int ar_main(int argc, char **argv) {
matchFlagWithArg("rsp-quoting", ArgIt, Argv))
continue;
+ if (strncmp(*ArgIt, "-X", 2) == 0) {
+ if (object::Archive::getDefaultKindForHost() ==
+ object::Archive::K_AIXBIG) {
+ Match = *(*ArgIt + 2) != '\0' ? *ArgIt + 2 : *(++ArgIt);
+ BitMode = getBitMode(Match);
+ if (BitMode == BitModeTy::Unknown)
+ fail(Twine("invalid bit mode: ") + Match);
+ continue;
+ } else {
+ fail(Twine(*ArgIt) + " option not supported on non AIX OS");
+ }
+ }
+
Options += *ArgIt + 1;
}
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 6932e9b5bd31..13b6c3002216 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -436,8 +436,7 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches,
ViewOpts.CompilationDirectory);
if (Error E = CoverageOrErr.takeError()) {
- error("Failed to load coverage: " + toString(std::move(E)),
- join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "));
+ error("Failed to load coverage: " + toString(std::move(E)));
return nullptr;
}
auto Coverage = std::move(CoverageOrErr.get());
@@ -1053,7 +1052,7 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
sys::fs::file_status Status;
if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
- error("Could not read profile data!", EC.message());
+ error("Could not read profile data!" + EC.message(), PGOFilename);
return 1;
}
@@ -1170,6 +1169,12 @@ int CodeCoverageTool::doReport(int argc, const char **argv,
return 1;
}
+ sys::fs::file_status Status;
+ if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
+ error("Could not read profile data!" + EC.message(), PGOFilename);
+ return 1;
+ }
+
auto Coverage = load();
if (!Coverage)
return 1;
@@ -1219,6 +1224,12 @@ int CodeCoverageTool::doExport(int argc, const char **argv,
return 1;
}
+ sys::fs::file_status Status;
+ if (std::error_code EC = sys::fs::status(PGOFilename, Status)) {
+ error("Could not read profile data!" + EC.message(), PGOFilename);
+ return 1;
+ }
+
auto Coverage = load();
if (!Coverage) {
error("Could not load coverage information");
diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index f7d3052c8c4d..cc7f353330b1 100644
--- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -544,7 +544,7 @@ static bool collectObjectSources(ObjectFile &Obj, DWARFContext &DICtx,
}
// Dedup and order the sources.
- llvm::sort(Sources.begin(), Sources.end());
+ llvm::sort(Sources);
Sources.erase(std::unique(Sources.begin(), Sources.end()), Sources.end());
for (StringRef Name : Sources)
diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
new file mode 100644
index 000000000000..458a58c12ca7
--- /dev/null
+++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
@@ -0,0 +1,277 @@
+//=== DebugInfoLinker.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 "DebugInfoLinker.h"
+#include "Error.h"
+#include "llvm/DWARFLinker/DWARFLinker.h"
+#include "llvm/DWARFLinker/DWARFStreamer.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/Object/ObjectFile.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace dwarfutil {
+
+// ObjFileAddressMap allows to check whether specified DIE referencing
+// dead addresses. It uses tombstone values to determine dead addresses.
+// The concrete values of tombstone constants were discussed in
+// https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825.
+// So we use following values as indicators of dead addresses:
+//
+// bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and DWARF v4 (or less))
+// or ([LowPC, HighPC] is not inside address ranges of .text sections).
+//
+// maxpc: (LowPC == -1) or (LowPC == -2 and DWARF v4 (or less))
+// That value is assumed to be compatible with
+// http://www.dwarfstd.org/ShowIssue.php?issue=200609.1
+//
+// exec: [LowPC, HighPC] is not inside address ranges of .text sections
+//
+// universal: maxpc and bfd
+class ObjFileAddressMap : public AddressesMap {
+public:
+ ObjFileAddressMap(DWARFContext &Context, const Options &Options,
+ object::ObjectFile &ObjFile)
+ : Opts(Options) {
+ // Remember addresses of existing text sections.
+ for (const object::SectionRef &Sect : ObjFile.sections()) {
+ if (!Sect.isText())
+ continue;
+ const uint64_t Size = Sect.getSize();
+ if (Size == 0)
+ continue;
+ const uint64_t StartAddr = Sect.getAddress();
+ TextAddressRanges.insert({StartAddr, StartAddr + Size});
+ }
+
+ // Check CU address ranges for tombstone value.
+ for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) {
+ Expected<llvm::DWARFAddressRangesVector> ARanges =
+ CU->getUnitDIE().getAddressRanges();
+ if (ARanges) {
+ for (auto &Range : *ARanges) {
+ if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),
+ Options.Tombstone, CU->getAddressByteSize()))
+ DWARFAddressRanges.insert({Range.LowPC, Range.HighPC}, 0);
+ }
+ }
+ }
+ }
+
+ // should be renamed into has valid address ranges
+ bool hasValidRelocs() override { return !DWARFAddressRanges.empty(); }
+
+ bool isLiveSubprogram(const DWARFDie &DIE,
+ CompileUnit::DIEInfo &Info) override {
+ assert((DIE.getTag() == dwarf::DW_TAG_subprogram ||
+ DIE.getTag() == dwarf::DW_TAG_label) &&
+ "Wrong type of input die");
+
+ if (Optional<uint64_t> LowPC =
+ dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) {
+ if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(),
+ Opts.Tombstone,
+ DIE.getDwarfUnit()->getAddressByteSize())) {
+ Info.AddrAdjust = 0;
+ Info.InDebugMap = true;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool isLiveVariable(const DWARFDie &DIE,
+ CompileUnit::DIEInfo &Info) override {
+ assert((DIE.getTag() == dwarf::DW_TAG_variable ||
+ DIE.getTag() == dwarf::DW_TAG_constant) &&
+ "Wrong type of input die");
+
+ if (Expected<DWARFLocationExpressionsVector> Loc =
+ DIE.getLocations(dwarf::DW_AT_location)) {
+ DWARFUnit *U = DIE.getDwarfUnit();
+ for (const auto &Entry : *Loc) {
+ DataExtractor Data(toStringRef(Entry.Expr),
+ U->getContext().isLittleEndian(), 0);
+ DWARFExpression Expression(Data, U->getAddressByteSize(),
+ U->getFormParams().Format);
+ bool HasLiveAddresses =
+ any_of(Expression, [&](const DWARFExpression::Operation &Op) {
+ // TODO: add handling of dwarf::DW_OP_addrx
+ return !Op.isError() &&
+ (Op.getCode() == dwarf::DW_OP_addr &&
+ !isDeadAddress(Op.getRawOperand(0), U->getVersion(),
+ Opts.Tombstone,
+ DIE.getDwarfUnit()->getAddressByteSize()));
+ });
+
+ if (HasLiveAddresses) {
+ Info.AddrAdjust = 0;
+ Info.InDebugMap = true;
+ return true;
+ }
+ }
+ } else {
+ // FIXME: missing DW_AT_location is OK here, but other errors should be
+ // reported to the user.
+ consumeError(Loc.takeError());
+ }
+
+ return false;
+ }
+
+ bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
+ // no need to apply relocations to the linked binary.
+ return false;
+ }
+
+ RangesTy &getValidAddressRanges() override { return DWARFAddressRanges; };
+
+ void clear() override { DWARFAddressRanges.clear(); }
+
+ llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t, uint64_t) override {
+ // should not be called.
+ return object::createError("no relocations in linked binary");
+ }
+
+protected:
+ // returns true if specified address range is inside address ranges
+ // of executable sections.
+ bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
+ Optional<uint64_t> HighPC) {
+ Optional<AddressRange> Range =
+ TextAddressRanges.getRangeThatContains(LowPC);
+
+ if (HighPC)
+ return Range.has_value() && Range->end() >= *HighPC;
+
+ return Range.has_value();
+ }
+
+ uint64_t isBFDDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
+ uint16_t Version) {
+ if (LowPC == 0)
+ return true;
+
+ if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))
+ return true;
+
+ return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
+ }
+
+ uint64_t isMAXPCDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
+ uint16_t Version, uint8_t AddressByteSize) {
+ if (Version <= 4 && HighPC) {
+ if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))
+ return true;
+ } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))
+ return true;
+
+ if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))
+ warning("Address referencing invalid text section is not marked with "
+ "tombstone value");
+
+ return false;
+ }
+
+ bool isDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
+ uint16_t Version, TombstoneKind Tombstone,
+ uint8_t AddressByteSize) {
+ switch (Tombstone) {
+ case TombstoneKind::BFD:
+ return isBFDDeadAddressRange(LowPC, HighPC, Version);
+ case TombstoneKind::MaxPC:
+ return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
+ case TombstoneKind::Universal:
+ return isBFDDeadAddressRange(LowPC, HighPC, Version) ||
+ isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
+ case TombstoneKind::Exec:
+ return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
+ }
+
+ llvm_unreachable("Unknown tombstone value");
+ }
+
+ bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,
+ uint8_t AddressByteSize) {
+ return isDeadAddressRange(LowPC, None, Version, Tombstone, AddressByteSize);
+ }
+
+private:
+ RangesTy DWARFAddressRanges;
+ AddressRanges TextAddressRanges;
+ const Options &Opts;
+};
+
+bool linkDebugInfo(object::ObjectFile &File, const Options &Options,
+ raw_pwrite_stream &OutStream) {
+
+ auto ReportWarn = [&](const Twine &Message, StringRef Context,
+ const DWARFDie *Die) {
+ warning(Message, Context);
+
+ if (!Options.Verbose || !Die)
+ return;
+
+ DIDumpOptions DumpOpts;
+ DumpOpts.ChildRecurseDepth = 0;
+ DumpOpts.Verbose = Options.Verbose;
+
+ WithColor::note() << " in DIE:\n";
+ Die->dump(errs(), /*Indent=*/6, DumpOpts);
+ };
+ auto ReportErr = [&](const Twine &Message, StringRef Context,
+ const DWARFDie *) {
+ WithColor::error(errs(), Context) << Message << '\n';
+ };
+
+ // Create output streamer.
+ DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr,
+ ReportWarn, ReportWarn);
+ if (!OutStreamer.init(File.makeTriple(), ""))
+ return false;
+
+ // Create DWARF linker.
+ DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD);
+
+ DebugInfoLinker.setEstimatedObjfilesAmount(1);
+ DebugInfoLinker.setAccelTableKind(DwarfLinkerAccelTableKind::None);
+ DebugInfoLinker.setErrorHandler(ReportErr);
+ DebugInfoLinker.setWarningHandler(ReportWarn);
+ DebugInfoLinker.setNumThreads(Options.NumThreads);
+ DebugInfoLinker.setNoODR(!Options.DoODRDeduplication);
+ DebugInfoLinker.setVerbosity(Options.Verbose);
+ DebugInfoLinker.setUpdate(!Options.DoGarbageCollection);
+
+ std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
+ std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1);
+ std::vector<std::string> EmptyWarnings;
+
+ std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
+
+ // Add object files to the DWARFLinker.
+ AddresssMapForLinking[0] =
+ std::make_unique<ObjFileAddressMap>(*Context, Options, File);
+
+ ObjectsForLinking[0] = std::make_unique<DWARFFile>(
+ File.getFileName(), &*Context, AddresssMapForLinking[0].get(),
+ EmptyWarnings);
+
+ for (size_t I = 0; I < ObjectsForLinking.size(); I++)
+ DebugInfoLinker.addObjectFile(*ObjectsForLinking[I]);
+
+ // Link debug info.
+ DebugInfoLinker.link();
+ OutStreamer.finish();
+ return true;
+}
+
+} // end of namespace dwarfutil
+} // end of namespace llvm
diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
new file mode 100644
index 000000000000..e95c83cb9609
--- /dev/null
+++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.h
@@ -0,0 +1,31 @@
+//===- DebugInfoLinker.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_DWARFUTIL_DEBUGINFOLINKER_H
+#define LLVM_TOOLS_LLVM_DWARFUTIL_DEBUGINFOLINKER_H
+
+#include "Options.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
+
+namespace llvm {
+namespace dwarfutil {
+
+inline bool isDebugSection(StringRef SecName) {
+ return SecName.startswith(".debug") || SecName.startswith(".zdebug") ||
+ SecName == ".gdb_index";
+}
+
+bool linkDebugInfo(object::ObjectFile &file, const Options &Options,
+ raw_pwrite_stream &OutStream);
+
+} // end of namespace dwarfutil
+} // end of namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_DWARFUTIL_DEBUGINFOLINKER_H
diff --git a/llvm/tools/llvm-dwarfutil/Error.h b/llvm/tools/llvm-dwarfutil/Error.h
new file mode 100644
index 000000000000..9ef288d4f657
--- /dev/null
+++ b/llvm/tools/llvm-dwarfutil/Error.h
@@ -0,0 +1,44 @@
+//===- Error.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_DWARFUTIL_ERROR_H
+#define LLVM_TOOLS_LLVM_DWARFUTIL_ERROR_H
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace dwarfutil {
+
+inline void error(Error Err, StringRef Prefix = "") {
+ handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
+ WithColor::error(errs(), Prefix) << Info.message() << '\n';
+ });
+ std::exit(EXIT_FAILURE);
+}
+
+inline void warning(const Twine &Message, StringRef Prefix = "") {
+ WithColor::warning(errs(), Prefix) << Message << '\n';
+}
+
+inline void verbose(const Twine &Message, bool Verbose) {
+ if (Verbose)
+ outs() << Message << '\n';
+}
+
+} // end of namespace dwarfutil
+} // end of namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_DWARFUTIL_ERROR_H
diff --git a/llvm/tools/llvm-dwarfutil/Options.h b/llvm/tools/llvm-dwarfutil/Options.h
new file mode 100644
index 000000000000..c993200ceb4b
--- /dev/null
+++ b/llvm/tools/llvm-dwarfutil/Options.h
@@ -0,0 +1,46 @@
+//===- Options.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_DWARFUTIL_OPTIONS_H
+#define LLVM_TOOLS_LLVM_DWARFUTIL_OPTIONS_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+namespace dwarfutil {
+
+/// The kind of tombstone value.
+enum class TombstoneKind {
+ BFD, /// 0/[1:1]. Bfd default.
+ MaxPC, /// -1/-2. Assumed to match with
+ /// http://www.dwarfstd.org/ShowIssue.php?issue=200609.1.
+ Universal, /// both: BFD + MaxPC
+ Exec, /// match with address range of executable sections.
+};
+
+struct Options {
+ std::string InputFileName;
+ std::string OutputFileName;
+ bool DoGarbageCollection = false;
+ bool DoODRDeduplication = false;
+ bool BuildSeparateDebugFile = false;
+ TombstoneKind Tombstone = TombstoneKind::Universal;
+ bool Verbose = false;
+ int NumThreads = 0;
+ bool Verify = false;
+
+ std::string getSeparateDebugFileName() const {
+ return OutputFileName + ".debug";
+ }
+};
+
+} // namespace dwarfutil
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_DWARFUTIL_OPTIONS_H
diff --git a/llvm/tools/llvm-dwarfutil/Options.td b/llvm/tools/llvm-dwarfutil/Options.td
new file mode 100644
index 000000000000..4ab1b51d808d
--- /dev/null
+++ b/llvm/tools/llvm-dwarfutil/Options.td
@@ -0,0 +1,65 @@
+include "llvm/Option/OptParser.td"
+
+multiclass BB<string name, string help1, string help2> {
+ def NAME: Flag<["--"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["--"], "no-" # name>, HelpText<help2>;
+}
+
+def help : Flag<["--"], "help">,
+ HelpText<"Prints this help output">;
+
+def h : Flag<["-"], "h">,
+ Alias<help>,
+ HelpText<"Alias for --help">;
+
+defm odr_deduplication : BB<"odr-deduplication",
+ "Do ODR deduplication for debug types(default)",
+ "Don`t do ODR deduplication for debug types">;
+
+def odr : Flag<["--"], "odr">,
+ Alias<odr_deduplication>,
+ HelpText<"Alias for --odr-deduplication">;
+
+def no_odr : Flag<["--"], "no-odr">,
+ Alias<no_odr_deduplication>,
+ HelpText<"Alias for --no-odr-deduplication">;
+
+defm garbage_collection : BB<"garbage-collection",
+ "Do garbage collection for debug info(default)",
+ "Don`t do garbage collection for debug info">;
+
+defm separate_debug_file : BB<"separate-debug-file",
+ "Create two output files: file w/o debug tables and file with debug tables",
+ "Create single output file, containing debug tables(default)">;
+
+def tombstone: Separate<["--", "-"], "tombstone">,
+ MetaVarName<"[bfd,maxpc,exec,universal]">,
+ HelpText<"Tombstone value used as a marker of invalid address(default: universal)\n"
+ " =bfd - Zero for all addresses and [1,1] for DWARF v4 (or less) address ranges and exec\n"
+ " =maxpc - Minus 1 for all addresses and minus 2 for DWARF v4 (or less) address ranges\n"
+ " =exec - Match with address ranges of executable sections\n"
+ " =universal - Both: bfd and maxpc"
+ >;
+def: Joined<["--", "-"], "tombstone=">, Alias<tombstone>;
+
+def threads: Separate<["--", "-"], "num-threads">,
+ MetaVarName<"<threads>">,
+ HelpText<"Number of available threads for multi-threaded execution. "
+ "Defaults to the number of cores on the current machine">;
+
+def: Separate<["-"], "j">,
+ Alias<threads>,
+ HelpText<"Alias for --num-threads">;
+
+def verbose : Flag<["--"], "verbose">,
+ HelpText<"Enable verbose logging">;
+
+def verify : Flag<["--"], "verify">,
+ HelpText<"Run the DWARF verifier on the resulting debug info">;
+
+def version : Flag<["--"], "version">,
+ HelpText<"Print the version and exit">;
+
+def V : Flag<["-"], "V">,
+ Alias<version>,
+ HelpText<"Alias for --version">;
diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
new file mode 100644
index 000000000000..e77c82e0fad9
--- /dev/null
+++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
@@ -0,0 +1,527 @@
+//=== llvm-dwarfutil.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 "DebugInfoLinker.h"
+#include "Error.h"
+#include "Options.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include "llvm/ObjCopy/CommonConfig.h"
+#include "llvm/ObjCopy/ConfigManager.h"
+#include "llvm/ObjCopy/ObjCopy.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CRC.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetSelect.h"
+
+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 "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 DwarfutilOptTable : public opt::OptTable {
+public:
+ DwarfutilOptTable() : OptTable(InfoTable) {}
+};
+} // namespace
+
+namespace llvm {
+namespace dwarfutil {
+
+std::string ToolName;
+
+static mc::RegisterMCTargetOptionsFlags MOF;
+
+static Error validateAndSetOptions(opt::InputArgList &Args, Options &Options) {
+ auto UnknownArgs = Args.filtered(OPT_UNKNOWN);
+ if (!UnknownArgs.empty())
+ return createStringError(
+ std::errc::invalid_argument,
+ formatv("unknown option: {0}", (*UnknownArgs.begin())->getSpelling())
+ .str()
+ .c_str());
+
+ std::vector<std::string> InputFiles = Args.getAllArgValues(OPT_INPUT);
+ if (InputFiles.size() != 2)
+ return createStringError(
+ std::errc::invalid_argument,
+ formatv("exactly two positional arguments expected, {0} provided",
+ InputFiles.size())
+ .str()
+ .c_str());
+
+ Options.InputFileName = InputFiles[0];
+ Options.OutputFileName = InputFiles[1];
+
+ Options.BuildSeparateDebugFile =
+ Args.hasFlag(OPT_separate_debug_file, OPT_no_separate_debug_file, false);
+ Options.DoODRDeduplication =
+ Args.hasFlag(OPT_odr_deduplication, OPT_no_odr_deduplication, true);
+ Options.DoGarbageCollection =
+ Args.hasFlag(OPT_garbage_collection, OPT_no_garbage_collection, true);
+ Options.Verbose = Args.hasArg(OPT_verbose);
+ Options.Verify = Args.hasArg(OPT_verify);
+
+ if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads))
+ Options.NumThreads = atoi(NumThreads->getValue());
+ else
+ Options.NumThreads = 0; // Use all available hardware threads
+
+ if (opt::Arg *Tombstone = Args.getLastArg(OPT_tombstone)) {
+ StringRef S = Tombstone->getValue();
+ if (S == "bfd")
+ Options.Tombstone = TombstoneKind::BFD;
+ else if (S == "maxpc")
+ Options.Tombstone = TombstoneKind::MaxPC;
+ else if (S == "universal")
+ Options.Tombstone = TombstoneKind::Universal;
+ else if (S == "exec")
+ Options.Tombstone = TombstoneKind::Exec;
+ else
+ return createStringError(
+ std::errc::invalid_argument,
+ formatv("unknown tombstone value: '{0}'", S).str().c_str());
+ }
+
+ if (Options.Verbose) {
+ if (Options.NumThreads != 1 && Args.hasArg(OPT_threads))
+ warning("--num-threads set to 1 because verbose mode is specified");
+
+ Options.NumThreads = 1;
+ }
+
+ if (Options.DoODRDeduplication && Args.hasArg(OPT_odr_deduplication) &&
+ !Options.DoGarbageCollection)
+ return createStringError(
+ std::errc::invalid_argument,
+ "cannot use --odr-deduplication without --garbage-collection");
+
+ if (Options.BuildSeparateDebugFile && Options.OutputFileName == "-")
+ return createStringError(
+ std::errc::invalid_argument,
+ "unable to write to stdout when --separate-debug-file specified");
+
+ return Error::success();
+}
+
+static Error setConfigToAddNewDebugSections(objcopy::ConfigManager &Config,
+ ObjectFile &ObjFile) {
+ // Add new debug sections.
+ for (SectionRef Sec : ObjFile.sections()) {
+ Expected<StringRef> SecName = Sec.getName();
+ if (!SecName)
+ return SecName.takeError();
+
+ if (isDebugSection(*SecName)) {
+ Expected<StringRef> SecData = Sec.getContents();
+ if (!SecData)
+ return SecData.takeError();
+
+ Config.Common.AddSection.emplace_back(objcopy::NewSectionInfo(
+ *SecName, MemoryBuffer::getMemBuffer(*SecData, *SecName, false)));
+ }
+ }
+
+ return Error::success();
+}
+
+static Error verifyOutput(const Options &Opts) {
+ if (Opts.OutputFileName == "-") {
+ warning("verification skipped because writing to stdout");
+ return Error::success();
+ }
+
+ std::string FileName = Opts.BuildSeparateDebugFile
+ ? Opts.getSeparateDebugFileName()
+ : Opts.OutputFileName;
+ Expected<OwningBinary<Binary>> BinOrErr = createBinary(FileName);
+ if (!BinOrErr)
+ return createFileError(FileName, BinOrErr.takeError());
+
+ if (BinOrErr->getBinary()->isObject()) {
+ if (ObjectFile *Obj = static_cast<ObjectFile *>(BinOrErr->getBinary())) {
+ verbose("Verifying DWARF...", Opts.Verbose);
+ std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
+ DIDumpOptions DumpOpts;
+ if (!DICtx->verify(Opts.Verbose ? outs() : nulls(),
+ DumpOpts.noImplicitRecursion()))
+ return createFileError(FileName,
+ createError("output verification failed"));
+
+ return Error::success();
+ }
+ }
+
+ // The file "FileName" was created by this utility in the previous steps
+ // (i.e. it is already known that it should pass the isObject check).
+ // If the createBinary() function does not return an error, the isObject
+ // check should also be successful.
+ llvm_unreachable(
+ formatv("tool unexpectedly did not emit a supported object file: '{0}'",
+ FileName)
+ .str()
+ .c_str());
+}
+
+class raw_crc_ostream : public raw_ostream {
+public:
+ explicit raw_crc_ostream(raw_ostream &O) : OS(O) { SetUnbuffered(); }
+
+ void reserveExtraSpace(uint64_t ExtraSize) override {
+ OS.reserveExtraSpace(ExtraSize);
+ }
+
+ uint32_t getCRC32() { return CRC32; }
+
+protected:
+ raw_ostream &OS;
+ uint32_t CRC32 = 0;
+
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override {
+ CRC32 = crc32(
+ CRC32, ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Ptr), Size));
+ OS.write(Ptr, Size);
+ }
+
+ /// Return the current position within the stream, not counting the bytes
+ /// currently in the buffer.
+ uint64_t current_pos() const override { return OS.tell(); }
+};
+
+static Expected<uint32_t> saveSeparateDebugInfo(const Options &Opts,
+ ObjectFile &InputFile) {
+ objcopy::ConfigManager Config;
+ std::string OutputFilename = Opts.getSeparateDebugFileName();
+ Config.Common.InputFilename = Opts.InputFileName;
+ Config.Common.OutputFilename = OutputFilename;
+ Config.Common.OnlyKeepDebug = true;
+ uint32_t WrittenFileCRC32 = 0;
+
+ if (Error Err = writeToOutput(
+ Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
+ raw_crc_ostream CRCBuffer(OutFile);
+ if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
+ CRCBuffer))
+ return Err;
+
+ WrittenFileCRC32 = CRCBuffer.getCRC32();
+ return Error::success();
+ }))
+ return std::move(Err);
+
+ return WrittenFileCRC32;
+}
+
+static Error saveNonDebugInfo(const Options &Opts, ObjectFile &InputFile,
+ uint32_t GnuDebugLinkCRC32) {
+ objcopy::ConfigManager Config;
+ Config.Common.InputFilename = Opts.InputFileName;
+ Config.Common.OutputFilename = Opts.OutputFileName;
+ Config.Common.StripDebug = true;
+ std::string SeparateDebugFileName = Opts.getSeparateDebugFileName();
+ Config.Common.AddGnuDebugLink = sys::path::filename(SeparateDebugFileName);
+ Config.Common.GnuDebugLinkCRC32 = GnuDebugLinkCRC32;
+
+ if (Error Err = writeToOutput(
+ Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
+ if (Error Err =
+ objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile))
+ return Err;
+
+ return Error::success();
+ }))
+ return Err;
+
+ return Error::success();
+}
+
+static Error splitDebugIntoSeparateFile(const Options &Opts,
+ ObjectFile &InputFile) {
+ Expected<uint32_t> SeparateDebugFileCRC32OrErr =
+ saveSeparateDebugInfo(Opts, InputFile);
+ if (!SeparateDebugFileCRC32OrErr)
+ return SeparateDebugFileCRC32OrErr.takeError();
+
+ if (Error Err =
+ saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr))
+ return Err;
+
+ return Error::success();
+}
+
+using DebugInfoBits = SmallString<10000>;
+
+static Error addSectionsFromLinkedData(objcopy::ConfigManager &Config,
+ ObjectFile &InputFile,
+ DebugInfoBits &LinkedDebugInfoBits) {
+ if (dyn_cast<ELFObjectFile<ELF32LE>>(&InputFile)) {
+ Expected<ELFObjectFile<ELF32LE>> MemFile = ELFObjectFile<ELF32LE>::create(
+ MemoryBufferRef(LinkedDebugInfoBits, ""));
+ if (!MemFile)
+ return MemFile.takeError();
+
+ if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
+ return Err;
+ } else if (dyn_cast<ELFObjectFile<ELF64LE>>(&InputFile)) {
+ Expected<ELFObjectFile<ELF64LE>> MemFile = ELFObjectFile<ELF64LE>::create(
+ MemoryBufferRef(LinkedDebugInfoBits, ""));
+ if (!MemFile)
+ return MemFile.takeError();
+
+ if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
+ return Err;
+ } else if (dyn_cast<ELFObjectFile<ELF32BE>>(&InputFile)) {
+ Expected<ELFObjectFile<ELF32BE>> MemFile = ELFObjectFile<ELF32BE>::create(
+ MemoryBufferRef(LinkedDebugInfoBits, ""));
+ if (!MemFile)
+ return MemFile.takeError();
+
+ if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
+ return Err;
+ } else if (dyn_cast<ELFObjectFile<ELF64BE>>(&InputFile)) {
+ Expected<ELFObjectFile<ELF64BE>> MemFile = ELFObjectFile<ELF64BE>::create(
+ MemoryBufferRef(LinkedDebugInfoBits, ""));
+ if (!MemFile)
+ return MemFile.takeError();
+
+ if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
+ return Err;
+ } else
+ return createStringError(std::errc::invalid_argument,
+ "unsupported file format");
+
+ return Error::success();
+}
+
+static Expected<uint32_t>
+saveSeparateLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
+ DebugInfoBits LinkedDebugInfoBits) {
+ objcopy::ConfigManager Config;
+ std::string OutputFilename = Opts.getSeparateDebugFileName();
+ Config.Common.InputFilename = Opts.InputFileName;
+ Config.Common.OutputFilename = OutputFilename;
+ Config.Common.StripDebug = true;
+ Config.Common.OnlyKeepDebug = true;
+ uint32_t WrittenFileCRC32 = 0;
+
+ if (Error Err =
+ addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits))
+ return std::move(Err);
+
+ if (Error Err = writeToOutput(
+ Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
+ raw_crc_ostream CRCBuffer(OutFile);
+
+ if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
+ CRCBuffer))
+ return Err;
+
+ WrittenFileCRC32 = CRCBuffer.getCRC32();
+ return Error::success();
+ }))
+ return std::move(Err);
+
+ return WrittenFileCRC32;
+}
+
+static Error saveSingleLinkedDebugInfo(const Options &Opts,
+ ObjectFile &InputFile,
+ DebugInfoBits LinkedDebugInfoBits) {
+ objcopy::ConfigManager Config;
+
+ Config.Common.InputFilename = Opts.InputFileName;
+ Config.Common.OutputFilename = Opts.OutputFileName;
+ Config.Common.StripDebug = true;
+ if (Error Err =
+ addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits))
+ return Err;
+
+ if (Error Err = writeToOutput(
+ Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
+ return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
+ }))
+ return Err;
+
+ return Error::success();
+}
+
+static Error saveLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
+ DebugInfoBits LinkedDebugInfoBits) {
+ if (Opts.BuildSeparateDebugFile) {
+ Expected<uint32_t> SeparateDebugFileCRC32OrErr =
+ saveSeparateLinkedDebugInfo(Opts, InputFile,
+ std::move(LinkedDebugInfoBits));
+ if (!SeparateDebugFileCRC32OrErr)
+ return SeparateDebugFileCRC32OrErr.takeError();
+
+ if (Error Err =
+ saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr))
+ return Err;
+ } else {
+ if (Error Err = saveSingleLinkedDebugInfo(Opts, InputFile,
+ std::move(LinkedDebugInfoBits)))
+ return Err;
+ }
+
+ return Error::success();
+}
+
+static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) {
+ objcopy::ConfigManager Config;
+
+ Config.Common.InputFilename = Opts.InputFileName;
+ Config.Common.OutputFilename = Opts.OutputFileName;
+
+ if (Error Err = writeToOutput(
+ Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
+ return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
+ }))
+ return Err;
+
+ return Error::success();
+}
+
+static Error applyCLOptions(const struct Options &Opts, ObjectFile &InputFile) {
+ if (Opts.DoGarbageCollection) {
+ verbose("Do garbage collection for debug info ...", Opts.Verbose);
+
+ DebugInfoBits LinkedDebugInfo;
+ raw_svector_ostream OutStream(LinkedDebugInfo);
+
+ if (linkDebugInfo(InputFile, Opts, OutStream)) {
+ if (Error Err =
+ saveLinkedDebugInfo(Opts, InputFile, std::move(LinkedDebugInfo)))
+ return Err;
+
+ return Error::success();
+ }
+
+ return createStringError(std::errc::invalid_argument,
+ "possible broken debug info");
+ } else if (Opts.BuildSeparateDebugFile) {
+ if (Error Err = splitDebugIntoSeparateFile(Opts, InputFile))
+ return Err;
+ } else {
+ if (Error Err = saveCopyOfFile(Opts, InputFile))
+ return Err;
+ }
+
+ return Error::success();
+}
+
+} // end of namespace dwarfutil
+} // end of namespace llvm
+
+int main(int Argc, char const *Argv[]) {
+ using namespace dwarfutil;
+
+ InitLLVM X(Argc, Argv);
+ ToolName = Argv[0];
+
+ // Parse arguments.
+ DwarfutilOptTable T;
+ unsigned MAI;
+ unsigned MAC;
+ ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
+ opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC);
+
+ if (Args.hasArg(OPT_help) || Args.size() == 0) {
+ T.printHelp(
+ outs(), (ToolName + " [options] <input file> <output file>").c_str(),
+ "llvm-dwarfutil is a tool to copy and manipulate debug info", false);
+ return EXIT_SUCCESS;
+ }
+
+ if (Args.hasArg(OPT_version)) {
+ cl::PrintVersionMessage();
+ return EXIT_SUCCESS;
+ }
+
+ Options Opts;
+ if (Error Err = validateAndSetOptions(Args, Opts))
+ error(std::move(Err), dwarfutil::ToolName);
+
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllTargetInfos();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
+ MemoryBuffer::getFileOrSTDIN(Opts.InputFileName);
+ if (BuffOrErr.getError())
+ error(createFileError(Opts.InputFileName, BuffOrErr.getError()));
+
+ Expected<std::unique_ptr<Binary>> BinOrErr =
+ object::createBinary(**BuffOrErr);
+ if (!BinOrErr)
+ error(createFileError(Opts.InputFileName, BinOrErr.takeError()));
+
+ Expected<FilePermissionsApplier> PermsApplierOrErr =
+ FilePermissionsApplier::create(Opts.InputFileName);
+ if (!PermsApplierOrErr)
+ error(createFileError(Opts.InputFileName, PermsApplierOrErr.takeError()));
+
+ if (!(*BinOrErr)->isObject())
+ error(createFileError(Opts.InputFileName,
+ createError("unsupported input file")));
+
+ if (Error Err =
+ applyCLOptions(Opts, *static_cast<ObjectFile *>((*BinOrErr).get())))
+ error(createFileError(Opts.InputFileName, std::move(Err)));
+
+ BinOrErr->reset();
+ BuffOrErr->reset();
+
+ if (Error Err = PermsApplierOrErr->apply(Opts.OutputFileName))
+ error(std::move(Err));
+
+ if (Opts.BuildSeparateDebugFile)
+ if (Error Err = PermsApplierOrErr->apply(Opts.getSeparateDebugFileName()))
+ error(std::move(Err));
+
+ if (Opts.Verify) {
+ if (Error Err = verifyOutput(Opts))
+ error(std::move(Err));
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index 3e737b9fbaa0..aa380d3fe9bc 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -77,9 +77,7 @@ static cl::opt<DebugCompressionType> CompressDebugSections(
cl::desc("Choose DWARF debug sections compression:"),
cl::values(clEnumValN(DebugCompressionType::None, "none", "No compression"),
clEnumValN(DebugCompressionType::Z, "zlib",
- "Use zlib compression"),
- clEnumValN(DebugCompressionType::GNU, "zlib-gnu",
- "Use zlib-gnu compression (deprecated)")),
+ "Use zlib compression")),
cl::cat(MCCategory));
static cl::opt<bool>
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 1245f9e18206..9e4fa7c0d9dd 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -1131,7 +1131,21 @@ static void emitPostInstructionInfo(formatted_raw_ostream &FOS,
FOS.flush();
}
-static void disassembleObject(const Target *TheTarget, const ObjectFile &Obj,
+static void createFakeELFSections(ObjectFile &Obj) {
+ assert(Obj.isELF());
+ if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj))
+ Elf32LEObj->createFakeSections();
+ else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj))
+ Elf64LEObj->createFakeSections();
+ else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj))
+ Elf32BEObj->createFakeSections();
+ else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj))
+ Elf64BEObj->createFakeSections();
+ else
+ llvm_unreachable("Unsupported binary format");
+}
+
+static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
MCContext &Ctx, MCDisassembler *PrimaryDisAsm,
MCDisassembler *SecondaryDisAsm,
const MCInstrAnalysis *MIA, MCInstPrinter *IP,
@@ -1198,6 +1212,9 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile &Obj,
if (Obj.isWasm())
addMissingWasmCodeSymbols(cast<WasmObjectFile>(Obj), AllSymbols);
+ if (Obj.isELF() && Obj.sections().empty())
+ createFakeELFSections(Obj);
+
BumpPtrAllocator A;
StringSaver Saver(A);
addPltEntries(Obj, AllSymbols, Saver);
@@ -1261,6 +1278,25 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile &Obj,
LLVM_DEBUG(LVP.dump());
+ std::unordered_map<uint64_t, BBAddrMap> AddrToBBAddrMap;
+ auto ReadBBAddrMap = [&](Optional<unsigned> SectionIndex = None) {
+ AddrToBBAddrMap.clear();
+ if (const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) {
+ auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex);
+ if (!BBAddrMapsOrErr)
+ reportWarning(toString(BBAddrMapsOrErr.takeError()),
+ Obj.getFileName());
+ for (auto &FunctionBBAddrMap : *BBAddrMapsOrErr)
+ AddrToBBAddrMap.emplace(FunctionBBAddrMap.Addr,
+ std::move(FunctionBBAddrMap));
+ }
+ };
+
+ // For non-relocatable objects, Read all LLVM_BB_ADDR_MAP sections into a
+ // single mapping, since they don't have any conflicts.
+ if (SymbolizeOperands && !Obj.isRelocatableObject())
+ ReadBBAddrMap();
+
for (const SectionRef &Section : ToolSectionFilter(Obj)) {
if (FilterSections.empty() && !DisassembleAll &&
(!Section.isText() || Section.isVirtual()))
@@ -1271,19 +1307,10 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile &Obj,
if (!SectSize)
continue;
- std::unordered_map<uint64_t, BBAddrMap> AddrToBBAddrMap;
- if (SymbolizeOperands) {
- if (auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) {
- // Read the BB-address-map corresponding to this section, if present.
- auto SectionBBAddrMapsOrErr = Elf->readBBAddrMap(Section.getIndex());
- if (!SectionBBAddrMapsOrErr)
- reportWarning(toString(SectionBBAddrMapsOrErr.takeError()),
- Obj.getFileName());
- for (auto &FunctionBBAddrMap : *SectionBBAddrMapsOrErr)
- AddrToBBAddrMap.emplace(FunctionBBAddrMap.Addr,
- std::move(FunctionBBAddrMap));
- }
- }
+ // For relocatable object files, read the LLVM_BB_ADDR_MAP section
+ // corresponding to this section, if present.
+ if (SymbolizeOperands && Obj.isRelocatableObject())
+ ReadBBAddrMap(Section.getIndex());
// Get the list of all the symbols in this section.
SectionSymbolsTy &Symbols = AllSymbols[Section];
@@ -1688,7 +1715,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile &Obj,
reportWarning("failed to disassemble missing symbol " + Sym, FileName);
}
-static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
+static void disassembleObject(ObjectFile *Obj, bool InlineRelocs) {
const Target *TheTarget = getTarget(Obj);
// Package up features to be passed to target/subtarget
@@ -1890,7 +1917,7 @@ static size_t getMaxSectionNameWidth(const ObjectFile &Obj) {
return MaxWidth;
}
-void objdump::printSectionHeaders(const ObjectFile &Obj) {
+void objdump::printSectionHeaders(ObjectFile &Obj) {
size_t NameWidth = getMaxSectionNameWidth(Obj);
size_t AddressWidth = 2 * Obj.getBytesInAddress();
bool HasLMAColumn = shouldDisplayLMA(Obj);
@@ -1903,6 +1930,9 @@ void objdump::printSectionHeaders(const ObjectFile &Obj) {
outs() << "Idx " << left_justify("Name", NameWidth) << " Size "
<< left_justify("VMA", AddressWidth) << " Type\n";
+ if (Obj.isELF() && Obj.sections().empty())
+ createFakeELFSections(Obj);
+
uint64_t Idx;
for (const SectionRef &Section : ToolSectionFilter(Obj, &Idx)) {
StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName());
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h
index dd9f58aa3308..c64c042d513e 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -124,7 +124,7 @@ SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O,
bool isRelocAddressLess(object::RelocationRef A, object::RelocationRef B);
void printRelocations(const object::ObjectFile *O);
void printDynamicRelocations(const object::ObjectFile *O);
-void printSectionHeaders(const object::ObjectFile &O);
+void printSectionHeaders(object::ObjectFile &O);
void printSectionContents(const object::ObjectFile *O);
void printSymbolTable(const object::ObjectFile &O, StringRef ArchiveName,
StringRef ArchitectureName = StringRef(),
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 9c6586483ef0..0c23d7c1435f 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -2471,9 +2471,10 @@ static int showHotFunctionList(const sampleprof::SampleProfileMap &Profiles,
(ProfileTotalSample > 0)
? (Func.getTotalSamples() * 100.0) / ProfileTotalSample
: 0;
- PrintValues.emplace_back(HotFuncInfo(
- Func.getContext().toString(), Func.getTotalSamples(),
- TotalSamplePercent, FuncPair.second.second, Func.getEntrySamples()));
+ PrintValues.emplace_back(
+ HotFuncInfo(Func.getContext().toString(), Func.getTotalSamples(),
+ TotalSamplePercent, FuncPair.second.second,
+ Func.getHeadSamplesEstimate()));
}
dumpHotFunctionList(ColumnTitle, ColumnOffset, PrintValues, HotFuncCount,
Profiles.size(), HotFuncSample, ProfileTotalSample,
diff --git a/llvm/tools/llvm-size/llvm-size.cpp b/llvm/tools/llvm-size/llvm-size.cpp
index ec9a4cde56b6..1c7484ba5496 100644
--- a/llvm/tools/llvm-size/llvm-size.cpp
+++ b/llvm/tools/llvm-size/llvm-size.cpp
@@ -868,8 +868,11 @@ int main(int argc, char **argv) {
StringSaver Saver(A);
SizeOptTable Tbl;
ToolName = argv[0];
- opt::InputArgList Args = Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver,
- [&](StringRef Msg) { error(Msg); });
+ opt::InputArgList Args =
+ Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
+ error(Msg);
+ exit(1);
+ });
if (Args.hasArg(OPT_help)) {
Tbl.printHelp(
outs(),
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index b782c7a1720a..7ec70e42f1c1 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -365,20 +365,15 @@ static SmallVector<uint8_t> parseBuildIDArg(const opt::InputArgList &Args,
return BuildID;
}
-// Symbolize the markup from stdin and write the result to stdout.
+// Symbolize markup from stdin and write the result to stdout.
static void filterMarkup(const opt::InputArgList &Args) {
- MarkupParser Parser;
MarkupFilter Filter(outs(), parseColorArg(Args));
- for (std::string InputString; std::getline(std::cin, InputString);) {
+ std::string InputString;
+ while (std::getline(std::cin, InputString)) {
InputString += '\n';
- Parser.parseLine(InputString);
- Filter.beginLine(InputString);
- while (Optional<MarkupNode> Element = Parser.nextNode())
- Filter.filter(*Element);
+ Filter.filter(InputString);
}
- Parser.flush();
- while (Optional<MarkupNode> Element = Parser.nextNode())
- Filter.filter(*Element);
+ Filter.finish();
}
ExitOnError ExitOnErr;
diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp
index 1160412e37af..a02997f82bb3 100644
--- a/llvm/tools/opt/opt.cpp
+++ b/llvm/tools/opt/opt.cpp
@@ -352,32 +352,6 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
if (TM)
TM->adjustPassManager(Builder);
- switch (PGOKindFlag) {
- case InstrGen:
- Builder.EnablePGOInstrGen = true;
- Builder.PGOInstrGen = ProfileFile;
- break;
- case InstrUse:
- Builder.PGOInstrUse = ProfileFile;
- break;
- case SampleUse:
- Builder.PGOSampleUse = ProfileFile;
- break;
- default:
- break;
- }
-
- switch (CSPGOKindFlag) {
- case CSInstrGen:
- Builder.EnablePGOCSInstrGen = true;
- break;
- case CSInstrUse:
- Builder.EnablePGOCSInstrUse = true;
- break;
- default:
- break;
- }
-
Builder.populateFunctionPassManager(FPM);
Builder.populateModulePassManager(MPM);
}
@@ -545,8 +519,6 @@ int main(int argc, char **argv) {
initializeIndirectBrExpandPassPass(Registry);
initializeInterleavedLoadCombinePass(Registry);
initializeInterleavedAccessPass(Registry);
- initializeEntryExitInstrumenterPass(Registry);
- initializePostInlineEntryExitInstrumenterPass(Registry);
initializeUnreachableBlockElimLegacyPassPass(Registry);
initializeExpandReductionsPass(Registry);
initializeExpandVectorPredicationPass(Registry);