llvm.org GIT mirror llvm / 7a42578
[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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244087 91177308-0d34-0410-b5e6-96231b3b80d8 Frederic Riss 5 years ago
10 changed file(s) with 235 addition(s) and 40 deletion(s). Raw diff Collapse all Expand all
0 RUN: llvm-dsymutil -verbose -no-output %p/Inputs/fat-test.dylib -oso-prepend-path %p | FileCheck %s
1
2 This test doesn't produce any filesytstem output, we just look at the verbose
3 log output.
4
5 For each arch in the binary, check that we emit the right triple with the right
6 file and the right symbol inside it (each slice has a different symbol, so that
7 means that the logic is looking at the right file slice too).
8
9 After the link of each architecture, check that lipo is correctly invoked to
10 generate the fat output binary.
11
12 CHECK: triple: 'x86_64-apple-darwin'
13 CHECK: - filename: [[INPUTS_PATH:.*]]fat-test.o
14 CHECK: DW_AT_name{{.*}} "x86_64_var"
15
16 CHECK: triple: 'i386-apple-darwin'
17 CHECK: - filename: [[INPUTS_PATH]]fat-test.o
18 CHECK: DW_AT_name{{.*}} "i386_var"
19
20 CHECK: triple: 'x86_64h-apple-darwin'
21 CHECK: - filename: [[INPUTS_PATH]]fat-test.o
22 CHECK: DW_AT_name{{.*}} "x86_64h_var"
23
24 CHECK: Running lipo
25 CHECK-NEXT: lipo -create
26 CHECK-SAME: [[INPUTS_PATH]]fat-test.dylib.tmp{{......}}.dwarf
27 CHECK-SAME: [[INPUTS_PATH]]fat-test.dylib.tmp{{......}}.dwarf
28 CHECK-SAME: [[INPUTS_PATH]]fat-test.dylib.tmp{{......}}.dwarf
29 CHECK-SAME: -segalign x86_64 20 -segalign i386 20 -segalign x86_64h 20
30 CHECK-SAME: -output [[INPUTS_PATH]]fat-test.dylib.dwarf
31
1313 DebugMap.cpp
1414 DwarfLinker.cpp
1515 MachODebugMapParser.cpp
16 MachOUtils.cpp
1617 )
1718
9696 };
9797 }
9898
99 ErrorOrunique_ptr>>
99 ErrorOrvector>>
100100 DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
101101 bool Verbose) {
102102 auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
113113
114114 if (auto EC = yin.error())
115115 return EC;
116
117 return std::move(Res);
116 std::vector> Result;
117 Result.push_back(std::move(Res));
118 return std::move(Result);
118119 }
119120 }
120121
101101 #endif
102102
103103 /// Read a debug map for \a InputFile.
104 static ErrorOrunique_ptr>>
104 static ErrorOrvector>>
105105 parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose);
106106 };
107107
2626 MainBinaryHolder(Verbose), CurrentObjectHolder(Verbose),
2727 CurrentDebugMapObject(nullptr) {}
2828
29 /// \brief Parses and returns the DebugMap of the input binary.
29 /// \brief Parses and returns the DebugMaps of the input binary.
30 /// The binary contains multiple maps in case it is a universal
31 /// binary.
3032 /// \returns an error in case the provided BinaryPath doesn't exist
3133 /// or isn't of a supported type.
32 ErrorOrunique_ptr>> parse();
34 ErrorOrvector>> parse();
3335
3436 private:
3537 std::string BinaryPath;
5355 /// Holds function info while function scope processing.
5456 const char *CurrentFunctionName;
5557 uint64_t CurrentFunctionAddress;
58
59 std::unique_ptr parseOneBinary(const MachOObjectFile &MainBinary,
60 StringRef BinaryPath);
5661
5762 void switchToNewDebugMapObject(StringRef Filename, sys::TimeValue Timestamp);
5863 void resetParserState();
109114 loadCurrentObjectFileSymbols(*ErrOrAchObj);
110115 }
111116
112 /// This main parsing routine tries to open the main binary and if
113 /// successful iterates over the STAB entries. The real parsing is
114 /// done in handleStabSymbolTableEntry.
115 ErrorOr> MachODebugMapParser::parse() {
116 auto MainBinOrError =
117 MainBinaryHolder.GetFilesAs(BinaryPath);
118 if (auto Error = MainBinOrError.getError())
119 return Error;
120
121 if (MainBinOrError->size() != 1)
122 return make_error_code(object::object_error::invalid_file_type);
123
124 const MachOObjectFile &MainBinary = *MainBinOrError->front();
117 std::unique_ptr
118 MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
119 StringRef BinaryPath) {
125120 loadMainBinarySymbols(MainBinary);
126121 Result = make_unique(BinaryHolder::getTriple(MainBinary));
127122 MainBinaryStrings = MainBinary.getStringTableData();
135130
136131 resetParserState();
137132 return std::move(Result);
133 }
134
135 /// This main parsing routine tries to open the main binary and if
136 /// successful iterates over the STAB entries. The real parsing is
137 /// done in handleStabSymbolTableEntry.
138 ErrorOr>> MachODebugMapParser::parse() {
139 auto MainBinOrError =
140 MainBinaryHolder.GetFilesAs(BinaryPath);
141 if (auto Error = MainBinOrError.getError())
142 return Error;
143
144 std::vector> Results;
145 for (const auto *Binary : *MainBinOrError)
146 Results.push_back(parseOneBinary(*Binary, BinaryPath));
147
148 return std::move(Results);
138149 }
139150
140151 /// Interpret the STAB entries to fill the DebugMap.
253264
254265 namespace llvm {
255266 namespace dsymutil {
256 llvm::ErrorOr> parseDebugMap(StringRef InputFile,
257 StringRef PrependPath,
258 bool Verbose,
259 bool InputIsYAML) {
267 llvm::ErrorOr>>
268 parseDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose,
269 bool InputIsYAML) {
260270 if (!InputIsYAML) {
261271 MachODebugMapParser Parser(InputFile, PrependPath, Verbose);
262272 return Parser.parse();
0 //===-- MachOUtils.h - Mach-o specific helpers for dsymutil --------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "MachOUtils.h"
10 #include "dsymutil.h"
11 #include "llvm/Support/FileUtilities.h"
12 #include "llvm/Support/Program.h"
13 #include "llvm/Support/raw_ostream.h"
14
15 namespace llvm {
16 namespace dsymutil {
17 namespace MachOUtils {
18
19 static bool runLipo(SmallVectorImpl &Args) {
20 auto Path = sys::findProgramByName("lipo");
21
22 if (!Path) {
23 errs() << "error: lipo: " << Path.getError().message() << "\n";
24 return false;
25 }
26
27 std::string ErrMsg;
28 int result =
29 sys::ExecuteAndWait(*Path, Args.data(), nullptr, nullptr, 0, 0, &ErrMsg);
30 if (result) {
31 errs() << "error: lipo: " << ErrMsg << "\n";
32 return false;
33 }
34
35 return true;
36 }
37
38 bool generateUniversalBinary(SmallVectorImpl &ArchFiles,
39 StringRef OutputFileName,
40 const LinkOptions &Options) {
41 // No need to merge one file into a universal fat binary. First, try
42 // to move it (rename) to the final location. If that fails because
43 // of cross-device link issues then copy and delete.
44 if (ArchFiles.size() == 1) {
45 StringRef From(ArchFiles.front().Path);
46 if (sys::fs::rename(From, OutputFileName)) {
47 if (std::error_code EC = sys::fs::copy_file(From, OutputFileName)) {
48 errs() << "error: while copying " << From << " to " << OutputFileName
49 << ": " << EC.message() << "\n";
50 return false;
51 }
52 sys::fs::remove(From);
53 }
54 return true;
55 }
56
57 SmallVector Args;
58 Args.push_back("lipo");
59 Args.push_back("-create");
60
61 for (auto &Thin : ArchFiles)
62 Args.push_back(Thin.Path.c_str());
63
64 // Align segments to match dsymutil-classic alignment
65 for (auto &Thin : ArchFiles) {
66 Args.push_back("-segalign");
67 Args.push_back(Thin.Arch.c_str());
68 Args.push_back("20");
69 }
70
71 Args.push_back("-output");
72 Args.push_back(OutputFileName.data());
73 Args.push_back(nullptr);
74
75 if (Options.Verbose) {
76 outs() << "Running lipo\n";
77 for (auto Arg : Args)
78 outs() << ' ' << ((Arg == nullptr) ? "\n" : Arg);
79 }
80
81 return Options.NoOutput ? true : runLipo(Args);
82 }
83 }
84 }
85 }
0 //===-- MachOUtils.h - Mach-o specific helpers for dsymutil --------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 #ifndef LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
9 #define LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
10
11 #include
12 #include "llvm/ADT/StringRef.h"
13
14 namespace llvm {
15 namespace dsymutil {
16 struct LinkOptions;
17 namespace MachOUtils {
18
19 struct ArchAndFilename {
20 std::string Arch, Path;
21 ArchAndFilename(StringRef Arch, StringRef Path) : Arch(Arch), Path(Path) {}
22 };
23
24 bool generateUniversalBinary(SmallVectorImpl &ArchFiles,
25 StringRef OutputFileName, const LinkOptions &);
26 }
27 }
28 }
29 #endif // LLVM_TOOLS_DSYMUTIL_MACHOUTILS_H
1212 //===----------------------------------------------------------------------===//
1313
1414 #include "DebugMap.h"
15 #include "MachOUtils.h"
1516 #include "dsymutil.h"
17 #include "llvm/Support/FileUtilities.h"
1618 #include "llvm/Support/ManagedStatic.h"
1719 #include "llvm/Support/Options.h"
1820 #include "llvm/Support/PrettyStackTrace.h"
6769 init(false), cat(DsymCategory));
6870 }
6971
70 static std::string getOutputFileName(llvm::StringRef InputFile) {
72 static std::string getOutputFileName(llvm::StringRef InputFile,
73 bool TempFile = false) {
74 if (TempFile) {
75 std::string OutputFile = (InputFile + ".tmp%%%%%%.dwarf").str();
76 int FD;
77 llvm::SmallString<128> UniqueFile;
78 if (auto EC = llvm::sys::fs::createUniqueFile(OutputFile, FD, UniqueFile)) {
79 llvm::errs() << "error: failed to create temporary outfile '"
80 << OutputFile << "': " << EC.message() << '\n';
81 return "";
82 }
83 llvm::sys::RemoveFileOnSignal(UniqueFile);
84 // Close the file immediately. We know it is unique. It will be
85 // reopened and written to later.
86 llvm::raw_fd_ostream CloseImmediately(FD, true /* shouldClose */, true);
87 return UniqueFile.str();
88 }
89
7190 if (OutputFileOpt.empty()) {
7291 if (InputFile == "-")
7392 return "a.out.dwarf";
7796 }
7897
7998 void llvm::dsymutil::exitDsymutil(int ExitStatus) {
99 // Cleanup temporary files.
100 llvm::sys::RunInterruptHandlers();
80101 exit(ExitStatus);
81102 }
82103
117138 }
118139
119140 for (auto &InputFile : InputFiles) {
120 auto DebugMapPtrOrErr =
141 auto DebugMapPtrsOrErr =
121142 parseDebugMap(InputFile, OsoPrependPath, Verbose, InputIsYAMLDebugMap);
122143
123 if (auto EC = DebugMapPtrOrErr.getError()) {
144 if (auto EC = DebugMapPtrsOrErr.getError()) {
124145 llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
125146 << "\": " << EC.message() << '\n';
126147 exitDsymutil(1);
127148 }
128149
129 if (Verbose || DumpDebugMap)
130 (*DebugMapPtrOrErr)->print(llvm::outs());
150 // If there is more than one link to execute, we need to generate
151 // temporary files.
152 bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1;
153 llvm::SmallVector TempFiles;
154 for (auto &Map : *DebugMapPtrsOrErr) {
155 if (Verbose || DumpDebugMap)
156 Map->print(llvm::outs());
131157
132 if (DumpDebugMap)
133 continue;
158 if (DumpDebugMap)
159 continue;
134160
135 std::string OutputFile = getOutputFileName(InputFile);
136 if (!linkDwarf(OutputFile, **DebugMapPtrOrErr, Options))
137 exitDsymuti(1);
161 std::string OutputFile = getOutputFileName(InputFile, NeedsTempFiles);
162 if (OutputFile.empty() || !linkDwarf(OutputFile, *Map, Options))
163 exitDsymutil(1);
164
165 if (NeedsTempFiles)
166 TempFiles.emplace_back(Map->getTriple().getArchName().str(),
167 OutputFile);
168 }
169
170 if (NeedsTempFiles &&
171 !MachOUtils::generateUniversalBinary(
172 TempFiles, getOutputFileName(InputFile), Options))
173 exitDsymutil(1);
138174 }
139175
140176 exitDsymutil(0);
3131 LinkOptions() : Verbose(false), NoOutput(false) {}
3232 };
3333
34 /// \brief Extract the DebugMap from the given file.
35 /// The file has to be a MachO object file.
36 llvm::ErrorOr> parseDebugMap(StringRef InputFile,
37 StringRef PrependPath,
38 bool Verbose,
39 bool InputIsYAML);
34 /// \brief Extract the DebugMaps from the given file.
35 /// The file has to be a MachO object file. Multiple debug maps can be
36 /// returned when the file is universal (aka fat) binary.
37 llvm::ErrorOr>>
38 parseDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose,
39 bool InputIsYAML);
4040
4141 /// \brief Link the Dwarf debuginfo as directed by the passed DebugMap
4242 /// \p DM into a DwarfFile named \p OutputFilename.
4747 /// \brief Exit the dsymutil process, cleaning up every temporary
4848 /// files that we created.
4949 LLVM_ATTRIBUTE_NORETURN void exitDsymutil(int ExitStatus);
50
5150 }
5251 }
5352 #endif // LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H