[llvm] r244087 - [dsymutil] Implement support for handling mach-o universal binaries as main input/output.
Frederic Riss
friss at apple.com
Wed Aug 5 11:27:44 PDT 2015
Author: friss
Date: Wed Aug 5 13:27:44 2015
New Revision: 244087
URL: http://llvm.org/viewvc/llvm-project?rev=244087&view=rev
Log:
[dsymutil] Implement support for handling mach-o universal binaries as main input/output.
The DWARF linker isn't touched by this, the implementation links
individual files and merges them together into a fat binary by
calling out to the 'lipo' utility.
The main change is that the MachODebugMapParser can now return
multiple debug maps for a single binary.
The test just verifies that lipo would be invoked correctly, but
doesn't actually generate a binary. This mimics the way clang
tests its external iplatform tools integration.
Added:
llvm/trunk/test/tools/dsymutil/Inputs/fat-test.dylib (with props)
llvm/trunk/test/tools/dsymutil/fat-binary-output.test
llvm/trunk/tools/dsymutil/MachOUtils.cpp
llvm/trunk/tools/dsymutil/MachOUtils.h
Modified:
llvm/trunk/tools/dsymutil/CMakeLists.txt
llvm/trunk/tools/dsymutil/DebugMap.cpp
llvm/trunk/tools/dsymutil/DebugMap.h
llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp
llvm/trunk/tools/dsymutil/dsymutil.cpp
llvm/trunk/tools/dsymutil/dsymutil.h
Added: llvm/trunk/test/tools/dsymutil/Inputs/fat-test.dylib
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/fat-test.dylib?rev=244087&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/dsymutil/Inputs/fat-test.dylib (added) and llvm/trunk/test/tools/dsymutil/Inputs/fat-test.dylib Wed Aug 5 13:27:44 2015 differ
Propchange: llvm/trunk/test/tools/dsymutil/Inputs/fat-test.dylib
------------------------------------------------------------------------------
svn:executable = *
Added: llvm/trunk/test/tools/dsymutil/fat-binary-output.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/fat-binary-output.test?rev=244087&view=auto
==============================================================================
--- llvm/trunk/test/tools/dsymutil/fat-binary-output.test (added)
+++ llvm/trunk/test/tools/dsymutil/fat-binary-output.test Wed Aug 5 13:27:44 2015
@@ -0,0 +1,32 @@
+RUN: llvm-dsymutil -verbose -no-output %p/Inputs/fat-test.dylib -oso-prepend-path %p | FileCheck %s
+
+This test doesn't produce any filesytstem output, we just look at the verbose
+log output.
+
+For each arch in the binary, check that we emit the right triple with the right
+file and the right symbol inside it (each slice has a different symbol, so that
+means that the logic is looking at the right file slice too).
+
+After the link of each architecture, check that lipo is correctly invoked to
+generate the fat output binary.
+
+CHECK: triple: 'x86_64-apple-darwin'
+CHECK: - filename: [[INPUTS_PATH:.*]]fat-test.o
+CHECK: DW_AT_name{{.*}} "x86_64_var"
+
+CHECK: triple: 'i386-apple-darwin'
+CHECK: - filename: [[INPUTS_PATH]]fat-test.o
+CHECK: DW_AT_name{{.*}} "i386_var"
+
+CHECK: triple: 'x86_64h-apple-darwin'
+CHECK: - filename: [[INPUTS_PATH]]fat-test.o
+CHECK: DW_AT_name{{.*}} "x86_64h_var"
+
+CHECK: Running lipo
+CHECK-NEXT: lipo -create
+CHECK-SAME: [[INPUTS_PATH]]fat-test.dylib.tmp{{......}}.dwarf
+CHECK-SAME: [[INPUTS_PATH]]fat-test.dylib.tmp{{......}}.dwarf
+CHECK-SAME: [[INPUTS_PATH]]fat-test.dylib.tmp{{......}}.dwarf
+CHECK-SAME: -segalign x86_64 20 -segalign i386 20 -segalign x86_64h 20
+CHECK-SAME: -output [[INPUTS_PATH]]fat-test.dylib.dwarf
+
Modified: llvm/trunk/tools/dsymutil/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/CMakeLists.txt?rev=244087&r1=244086&r2=244087&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/CMakeLists.txt (original)
+++ llvm/trunk/tools/dsymutil/CMakeLists.txt Wed Aug 5 13:27:44 2015
@@ -14,5 +14,6 @@ add_llvm_tool(llvm-dsymutil
DebugMap.cpp
DwarfLinker.cpp
MachODebugMapParser.cpp
+ MachOUtils.cpp
)
Modified: llvm/trunk/tools/dsymutil/DebugMap.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DebugMap.cpp?rev=244087&r1=244086&r2=244087&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DebugMap.cpp (original)
+++ llvm/trunk/tools/dsymutil/DebugMap.cpp Wed Aug 5 13:27:44 2015
@@ -97,7 +97,7 @@ struct YAMLContext {
};
}
-ErrorOr<std::unique_ptr<DebugMap>>
+ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
bool Verbose) {
auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
@@ -114,8 +114,9 @@ DebugMap::parseYAMLDebugMap(StringRef In
if (auto EC = yin.error())
return EC;
-
- return std::move(Res);
+ std::vector<std::unique_ptr<DebugMap>> Result;
+ Result.push_back(std::move(Res));
+ return std::move(Result);
}
}
Modified: llvm/trunk/tools/dsymutil/DebugMap.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DebugMap.h?rev=244087&r1=244086&r2=244087&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DebugMap.h (original)
+++ llvm/trunk/tools/dsymutil/DebugMap.h Wed Aug 5 13:27:44 2015
@@ -102,7 +102,7 @@ public:
#endif
/// Read a debug map for \a InputFile.
- static ErrorOr<std::unique_ptr<DebugMap>>
+ static ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose);
};
Modified: llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp?rev=244087&r1=244086&r2=244087&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp (original)
+++ llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp Wed Aug 5 13:27:44 2015
@@ -27,10 +27,12 @@ public:
MainBinaryHolder(Verbose), CurrentObjectHolder(Verbose),
CurrentDebugMapObject(nullptr) {}
- /// \brief Parses and returns the DebugMap of the input binary.
+ /// \brief 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::unique_ptr<DebugMap>> parse();
+ ErrorOr<std::vector<std::unique_ptr<DebugMap>>> parse();
private:
std::string BinaryPath;
@@ -55,6 +57,9 @@ private:
const char *CurrentFunctionName;
uint64_t CurrentFunctionAddress;
+ std::unique_ptr<DebugMap> parseOneBinary(const MachOObjectFile &MainBinary,
+ StringRef BinaryPath);
+
void switchToNewDebugMapObject(StringRef Filename, sys::TimeValue Timestamp);
void resetParserState();
uint64_t getMainBinarySymbolAddress(StringRef Name);
@@ -110,19 +115,9 @@ void MachODebugMapParser::switchToNewDeb
loadCurrentObjectFileSymbols(*ErrOrAchObj);
}
-/// 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::unique_ptr<DebugMap>> MachODebugMapParser::parse() {
- auto MainBinOrError =
- MainBinaryHolder.GetFilesAs<MachOObjectFile>(BinaryPath);
- if (auto Error = MainBinOrError.getError())
- return Error;
-
- if (MainBinOrError->size() != 1)
- return make_error_code(object::object_error::invalid_file_type);
-
- const MachOObjectFile &MainBinary = *MainBinOrError->front();
+std::unique_ptr<DebugMap>
+MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
+ StringRef BinaryPath) {
loadMainBinarySymbols(MainBinary);
Result = make_unique<DebugMap>(BinaryHolder::getTriple(MainBinary));
MainBinaryStrings = MainBinary.getStringTableData();
@@ -138,6 +133,22 @@ ErrorOr<std::unique_ptr<DebugMap>> MachO
return std::move(Result);
}
+/// 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 MainBinOrError =
+ MainBinaryHolder.GetFilesAs<MachOObjectFile>(BinaryPath);
+ if (auto Error = MainBinOrError.getError())
+ return Error;
+
+ std::vector<std::unique_ptr<DebugMap>> Results;
+ for (const auto *Binary : *MainBinOrError)
+ Results.push_back(parseOneBinary(*Binary, BinaryPath));
+
+ return std::move(Results);
+}
+
/// Interpret the STAB entries to fill the DebugMap.
void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
uint8_t Type,
@@ -254,10 +265,9 @@ void MachODebugMapParser::loadMainBinary
namespace llvm {
namespace dsymutil {
-llvm::ErrorOr<std::unique_ptr<DebugMap>> parseDebugMap(StringRef InputFile,
- StringRef PrependPath,
- bool Verbose,
- bool InputIsYAML) {
+llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
+parseDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose,
+ bool InputIsYAML) {
if (!InputIsYAML) {
MachODebugMapParser Parser(InputFile, PrependPath, Verbose);
return Parser.parse();
Added: llvm/trunk/tools/dsymutil/MachOUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/MachOUtils.cpp?rev=244087&view=auto
==============================================================================
--- llvm/trunk/tools/dsymutil/MachOUtils.cpp (added)
+++ llvm/trunk/tools/dsymutil/MachOUtils.cpp Wed Aug 5 13:27:44 2015
@@ -0,0 +1,86 @@
+//===-- MachOUtils.h - Mach-o specific helpers for dsymutil --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachOUtils.h"
+#include "dsymutil.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace dsymutil {
+namespace MachOUtils {
+
+static bool runLipo(SmallVectorImpl<const char *> &Args) {
+ auto Path = sys::findProgramByName("lipo");
+
+ if (!Path) {
+ errs() << "error: lipo: " << Path.getError().message() << "\n";
+ return false;
+ }
+
+ std::string ErrMsg;
+ int result =
+ sys::ExecuteAndWait(*Path, Args.data(), nullptr, nullptr, 0, 0, &ErrMsg);
+ if (result) {
+ errs() << "error: lipo: " << ErrMsg << "\n";
+ return false;
+ }
+
+ return true;
+}
+
+bool generateUniversalBinary(SmallVectorImpl<ArchAndFilename> &ArchFiles,
+ StringRef OutputFileName,
+ const LinkOptions &Options) {
+ // No need to merge one file into a universal fat binary. First, try
+ // to move it (rename) to the final location. If that fails because
+ // of cross-device link issues then copy and delete.
+ if (ArchFiles.size() == 1) {
+ StringRef From(ArchFiles.front().Path);
+ if (sys::fs::rename(From, OutputFileName)) {
+ if (std::error_code EC = sys::fs::copy_file(From, OutputFileName)) {
+ errs() << "error: while copying " << From << " to " << OutputFileName
+ << ": " << EC.message() << "\n";
+ return false;
+ }
+ sys::fs::remove(From);
+ }
+ return true;
+ }
+
+ SmallVector<const char *, 8> Args;
+ Args.push_back("lipo");
+ Args.push_back("-create");
+
+ for (auto &Thin : ArchFiles)
+ Args.push_back(Thin.Path.c_str());
+
+ // Align segments to match dsymutil-classic alignment
+ for (auto &Thin : ArchFiles) {
+ Args.push_back("-segalign");
+ Args.push_back(Thin.Arch.c_str());
+ Args.push_back("20");
+ }
+
+ Args.push_back("-output");
+ Args.push_back(OutputFileName.data());
+ Args.push_back(nullptr);
+
+ if (Options.Verbose) {
+ outs() << "Running lipo\n";
+ for (auto Arg : Args)
+ outs() << ' ' << ((Arg == nullptr) ? "\n" : Arg);
+ }
+
+ return Options.NoOutput ? true : runLipo(Args);
+}
+}
+}
+}
Added: llvm/trunk/tools/dsymutil/MachOUtils.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/MachOUtils.h?rev=244087&view=auto
==============================================================================
--- llvm/trunk/tools/dsymutil/MachOUtils.h (added)
+++ llvm/trunk/tools/dsymutil/MachOUtils.h Wed Aug 5 13:27:44 2015
@@ -0,0 +1,30 @@
+//===-- MachOUtils.h - Mach-o specific helpers for dsymutil --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
+#define LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
+
+#include <string>
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+namespace dsymutil {
+struct LinkOptions;
+namespace MachOUtils {
+
+struct ArchAndFilename {
+ std::string Arch, Path;
+ ArchAndFilename(StringRef Arch, StringRef Path) : Arch(Arch), Path(Path) {}
+};
+
+bool generateUniversalBinary(SmallVectorImpl<ArchAndFilename> &ArchFiles,
+ StringRef OutputFileName, const LinkOptions &);
+}
+}
+}
+#endif // LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
Modified: llvm/trunk/tools/dsymutil/dsymutil.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/dsymutil.cpp?rev=244087&r1=244086&r2=244087&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/dsymutil.cpp (original)
+++ llvm/trunk/tools/dsymutil/dsymutil.cpp Wed Aug 5 13:27:44 2015
@@ -13,7 +13,9 @@
//===----------------------------------------------------------------------===//
#include "DebugMap.h"
+#include "MachOUtils.h"
#include "dsymutil.h"
+#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Options.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -68,7 +70,24 @@ static opt<bool> InputIsYAMLDebugMap(
init(false), cat(DsymCategory));
}
-static std::string getOutputFileName(llvm::StringRef InputFile) {
+static std::string getOutputFileName(llvm::StringRef InputFile,
+ bool TempFile = false) {
+ if (TempFile) {
+ std::string OutputFile = (InputFile + ".tmp%%%%%%.dwarf").str();
+ int FD;
+ llvm::SmallString<128> UniqueFile;
+ if (auto EC = llvm::sys::fs::createUniqueFile(OutputFile, FD, UniqueFile)) {
+ llvm::errs() << "error: failed to create temporary outfile '"
+ << OutputFile << "': " << EC.message() << '\n';
+ return "";
+ }
+ llvm::sys::RemoveFileOnSignal(UniqueFile);
+ // Close the file immediately. We know it is unique. It will be
+ // reopened and written to later.
+ llvm::raw_fd_ostream CloseImmediately(FD, true /* shouldClose */, true);
+ return UniqueFile.str();
+ }
+
if (OutputFileOpt.empty()) {
if (InputFile == "-")
return "a.out.dwarf";
@@ -78,6 +97,8 @@ static std::string getOutputFileName(llv
}
void llvm::dsymutil::exitDsymutil(int ExitStatus) {
+ // Cleanup temporary files.
+ llvm::sys::RunInterruptHandlers();
exit(ExitStatus);
}
@@ -118,24 +139,39 @@ int main(int argc, char **argv) {
}
for (auto &InputFile : InputFiles) {
- auto DebugMapPtrOrErr =
+ auto DebugMapPtrsOrErr =
parseDebugMap(InputFile, OsoPrependPath, Verbose, InputIsYAMLDebugMap);
- if (auto EC = DebugMapPtrOrErr.getError()) {
+ if (auto EC = DebugMapPtrsOrErr.getError()) {
llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
<< "\": " << EC.message() << '\n';
exitDsymutil(1);
}
- if (Verbose || DumpDebugMap)
- (*DebugMapPtrOrErr)->print(llvm::outs());
-
- if (DumpDebugMap)
- continue;
+ // If there is more than one link to execute, we need to generate
+ // temporary files.
+ bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1;
+ llvm::SmallVector<MachOUtils::ArchAndFilename, 4> TempFiles;
+ for (auto &Map : *DebugMapPtrsOrErr) {
+ if (Verbose || DumpDebugMap)
+ Map->print(llvm::outs());
+
+ if (DumpDebugMap)
+ continue;
+
+ std::string OutputFile = getOutputFileName(InputFile, NeedsTempFiles);
+ if (OutputFile.empty() || !linkDwarf(OutputFile, *Map, Options))
+ exitDsymutil(1);
+
+ if (NeedsTempFiles)
+ TempFiles.emplace_back(Map->getTriple().getArchName().str(),
+ OutputFile);
+ }
- std::string OutputFile = getOutputFileName(InputFile);
- if (!linkDwarf(OutputFile, **DebugMapPtrOrErr, Options))
- exitDsymuti(1);
+ if (NeedsTempFiles &&
+ !MachOUtils::generateUniversalBinary(
+ TempFiles, getOutputFileName(InputFile), Options))
+ exitDsymutil(1);
}
exitDsymutil(0);
Modified: llvm/trunk/tools/dsymutil/dsymutil.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/dsymutil.h?rev=244087&r1=244086&r2=244087&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/dsymutil.h (original)
+++ llvm/trunk/tools/dsymutil/dsymutil.h Wed Aug 5 13:27:44 2015
@@ -32,12 +32,12 @@ struct LinkOptions {
LinkOptions() : Verbose(false), NoOutput(false) {}
};
-/// \brief Extract the DebugMap from the given file.
-/// The file has to be a MachO object file.
-llvm::ErrorOr<std::unique_ptr<DebugMap>> parseDebugMap(StringRef InputFile,
- StringRef PrependPath,
- bool Verbose,
- bool InputIsYAML);
+/// \brief 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.
+llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
+parseDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose,
+ bool InputIsYAML);
/// \brief Link the Dwarf debuginfo as directed by the passed DebugMap
/// \p DM into a DwarfFile named \p OutputFilename.
@@ -48,7 +48,6 @@ bool linkDwarf(StringRef OutputFilename,
/// \brief Exit the dsymutil process, cleaning up every temporary
/// files that we created.
LLVM_ATTRIBUTE_NORETURN void exitDsymutil(int ExitStatus);
-
}
}
#endif // LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H
More information about the llvm-commits
mailing list