summaryrefslogtreecommitdiffstats
path: root/llvm/tools/dsymutil/dsymutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/dsymutil/dsymutil.cpp')
-rw-r--r--llvm/tools/dsymutil/dsymutil.cpp129
1 files changed, 115 insertions, 14 deletions
diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp
index 4a01b1d9db4..dae872fe165 100644
--- a/llvm/tools/dsymutil/dsymutil.cpp
+++ b/llvm/tools/dsymutil/dsymutil.cpp
@@ -80,10 +80,21 @@ static opt<bool> Minimize(
desc("When used when creating a dSYM file, this option will suppress\n"
"the emission of the .debug_inlines, .debug_pubnames, and\n"
".debug_pubtypes sections since dsymutil currently has better\n"
- "equivalents: .apple_names and .apple_types."),
+ "equivalents: .apple_names and .apple_types. When used in\n"
+ "conjunction with --update option, this option will cause redundant\n"
+ "accelerator tables to be removed."),
init(false), cat(DsymCategory));
static alias MinimizeA("z", desc("Alias for --minimize"), aliasopt(Minimize));
+static opt<bool> Update(
+ "update",
+ desc("Updates existing dSYM files to contain the latest accelerator\n"
+ "tables and other DWARF optimizations. This option will currently\n"
+ "add the new .apple_names and .apple_types hashed accelerator\n"
+ "tables."),
+ init(false), cat(DsymCategory));
+static alias UpdateA("u", desc("Alias for --update"), aliasopt(Update));
+
static opt<unsigned> NumThreads(
"num-threads",
desc("Specifies the maximum number (n) of simultaneous threads to use\n"
@@ -230,8 +241,12 @@ static bool verify(llvm::StringRef OutputFile, llvm::StringRef Arch) {
}
static std::string getOutputFileName(llvm::StringRef InputFile) {
+ // When updating, do in place replacement.
+ if (OutputFileOpt.empty() && Update)
+ return InputFile;
+
+ // If a flat dSYM has been requested, things are pretty simple.
if (FlatOut) {
- // If a flat dSYM has been requested, things are pretty simple.
if (OutputFileOpt.empty()) {
if (InputFile == "-")
return "a.out.dwarf";
@@ -269,6 +284,76 @@ static Expected<sys::fs::TempFile> createTempFile() {
return sys::fs::TempFile::create(TmpModel);
}
+/// Parses the command line options into the LinkOptions struct and performs
+/// some sanity checking. Returns an error in case the latter fails.
+static Expected<LinkOptions> getOptions() {
+ LinkOptions Options;
+
+ Options.Verbose = Verbose;
+ Options.NoOutput = NoOutput;
+ Options.NoODR = NoODR;
+ Options.Minimize = Minimize;
+ Options.Update = Update;
+ Options.NoTimestamp = NoTimestamp;
+ Options.PrependPath = OsoPrependPath;
+
+ if (Options.Update && std::find(InputFiles.begin(), InputFiles.end(), "-") !=
+ InputFiles.end()) {
+ // 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>(
+ "error: standard input cannot be used as input for a dSYM update.",
+ inconvertibleErrorCode());
+ }
+
+ return Options;
+}
+
+/// 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(bool DsymAsInput) {
+ 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 (!llvm::sys::fs::is_directory(Input)) {
+ Inputs.push_back(Input);
+ continue;
+ }
+
+ // Make sure that we're dealing with a dSYM bundle.
+ std::string dSYMDir = Input + "/Contents/Resources/DWARF";
+ if (!llvm::sys::fs::is_directory(dSYMDir))
+ 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;
+ llvm::sys::fs::directory_iterator DirIt(dSYMDir, EC);
+ llvm::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;
+}
+
namespace {
struct TempFileVector {
std::vector<sys::fs::TempFile> Files;
@@ -285,7 +370,6 @@ int main(int argc, char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
llvm::llvm_shutdown_obj Shutdown;
- LinkOptions Options;
void *P = (void *)(intptr_t)getOutputFileName;
std::string SDKPath = llvm::sys::fs::getMainExecutable(argv[0], P);
SDKPath = llvm::sys::path::parent_path(SDKPath);
@@ -308,24 +392,29 @@ int main(int argc, char **argv) {
return 0;
}
- Options.Verbose = Verbose;
- Options.NoOutput = NoOutput;
- Options.NoODR = NoODR;
- Options.Minimize = Minimize;
- Options.NoTimestamp = NoTimestamp;
- Options.PrependPath = OsoPrependPath;
+ auto OptionsOrErr = getOptions();
+ if (!OptionsOrErr) {
+ errs() << "error: " << toString(OptionsOrErr.takeError());
+ return 1;
+ }
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
+ auto InputsOrErr = getInputs(OptionsOrErr->Update);
+ if (!InputsOrErr) {
+ errs() << "error: " << toString(InputsOrErr.takeError()) << '\n';
+ return 1;
+ }
+
if (!FlatOut && OutputFileOpt == "-") {
llvm::errs() << "error: cannot emit to standard output without --flat\n";
return 1;
}
- if (InputFiles.size() > 1 && FlatOut && !OutputFileOpt.empty()) {
+ if (InputsOrErr->size() > 1 && FlatOut && !OutputFileOpt.empty()) {
llvm::errs() << "error: cannot use -o with multiple inputs in flat mode\n";
return 1;
}
@@ -337,7 +426,7 @@ int main(int argc, char **argv) {
return 1;
}
- for (auto &InputFile : InputFiles) {
+ for (auto &InputFile : *InputsOrErr) {
// Dump the symbol table for each input file and requested arch
if (DumpStab) {
if (!dumpStab(InputFile, ArchFlags, OsoPrependPath))
@@ -354,6 +443,15 @@ int main(int argc, char **argv) {
return 1;
}
+ if (OptionsOrErr->Update) {
+ // The debug map should be empty. Add one object file corresponding to
+ // the input file.
+ for (auto &Map : *DebugMapPtrsOrErr)
+ Map->addDebugMapObject(InputFile,
+ llvm::sys::TimePoint<std::chrono::seconds>());
+ }
+
+ // Ensure that the debug map is not empty (anymore).
if (DebugMapPtrsOrErr->empty()) {
llvm::errs() << "error: no architecture to link\n";
return 1;
@@ -369,7 +467,10 @@ int main(int argc, char **argv) {
// If there is more than one link to execute, we need to generate
// temporary files.
- bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1;
+ bool NeedsTempFiles =
+ !DumpDebugMap && (OutputFileOpt != "-") &&
+ (DebugMapPtrsOrErr->size() != 1 || OptionsOrErr->Update);
+
llvm::SmallVector<MachOUtils::ArchAndFilename, 4> TempFiles;
TempFileVector TempFileStore;
std::atomic_char AllOK(1);
@@ -412,7 +513,7 @@ int main(int argc, char **argv) {
auto LinkLambda = [&,
OutputFile](std::shared_ptr<raw_fd_ostream> Stream) {
- AllOK.fetch_and(linkDwarf(*Stream, *Map, Options));
+ AllOK.fetch_and(linkDwarf(*Stream, *Map, *OptionsOrErr));
Stream->flush();
if (Verify && !NoOutput)
AllOK.fetch_and(verify(OutputFile, Map->getTriple().getArchName()));
@@ -434,7 +535,7 @@ int main(int argc, char **argv) {
if (NeedsTempFiles &&
!MachOUtils::generateUniversalBinary(
- TempFiles, getOutputFileName(InputFile), Options, SDKPath))
+ TempFiles, getOutputFileName(InputFile), *OptionsOrErr, SDKPath))
return 1;
}
OpenPOWER on IntegriCloud