X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fdsymutil%2Fdsymutil.cpp;h=e9ee57f3dee674e6dad863b2ed055a17f0f0e5f7;hb=0dbce2b4db35efb12f5a2fe79e616ee2a7c37d36;hp=2b4fcfe07008cd42666d44b1f052dbd531ea45b4;hpb=1b279144ecc41e788f7173892dfcc89f7ee6772a;p=oota-llvm.git diff --git a/tools/dsymutil/dsymutil.cpp b/tools/dsymutil/dsymutil.cpp index 2b4fcfe0700..e9ee57f3dee 100644 --- a/tools/dsymutil/dsymutil.cpp +++ b/tools/dsymutil/dsymutil.cpp @@ -13,12 +13,18 @@ //===----------------------------------------------------------------------===// #include "DebugMap.h" +#include "MachOUtils.h" #include "dsymutil.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Options.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TargetSelect.h" +#include #include using namespace llvm::dsymutil; @@ -26,46 +32,311 @@ using namespace llvm::dsymutil; namespace { using namespace llvm::cl; -static opt InputFile(Positional, desc(""), - init("a.out")); +OptionCategory DsymCategory("Specific Options"); +static opt Help("h", desc("Alias for -help"), Hidden); +static opt Version("v", desc("Alias for -version"), Hidden); -static opt OsoPrependPath("oso-prepend-path", - desc("Specify a directory to prepend " - "to the paths of object files."), - value_desc("path")); +static list InputFiles(Positional, OneOrMore, + desc(""), cat(DsymCategory)); -static opt Verbose("v", desc("Verbosity level"), init(false)); +static opt + OutputFileOpt("o", + desc("Specify the output file. default: .dwarf"), + value_desc("filename"), cat(DsymCategory)); + +static opt OsoPrependPath( + "oso-prepend-path", + desc("Specify a directory to prepend to the paths of object files."), + value_desc("path"), cat(DsymCategory)); + +static opt DumpStab( + "symtab", + desc("Dumps the symbol table found in executable or object file(s) and\n" + "exits."), + init(false), cat(DsymCategory)); +static alias DumpStabA("s", desc("Alias for --symtab"), aliasopt(DumpStab)); + +static opt FlatOut("flat", + desc("Produce a flat dSYM file (not a bundle)."), + init(false), cat(DsymCategory)); +static alias FlatOutA("f", desc("Alias for --flat"), aliasopt(FlatOut)); + +static opt Verbose("verbose", desc("Verbosity level"), init(false), + cat(DsymCategory)); + +static opt + NoOutput("no-output", + desc("Do the link in memory, but do not emit the result file."), + init(false), cat(DsymCategory)); + +static list ArchFlags( + "arch", + desc("Link DWARF debug information only for specified CPU architecture\n" + "types. This option can be specified multiple times, once for each\n" + "desired architecture. All cpu architectures will be linked by\n" + "default."), + ZeroOrMore, cat(DsymCategory)); static opt - ParseOnly("parse-only", - desc("Only parse the debug map, do not actaully link " - "the DWARF."), - init(false)); + NoODR("no-odr", + desc("Do not use ODR (One Definition Rule) for type uniquing."), + init(false), cat(DsymCategory)); + +static opt DumpDebugMap( + "dump-debug-map", + desc("Parse and dump the debug map to standard output. Not DWARF link " + "will take place."), + init(false), cat(DsymCategory)); + +static opt InputIsYAMLDebugMap( + "y", desc("Treat the input file is a YAML debug map rather than a binary."), + init(false), cat(DsymCategory)); +} + +static bool createPlistFile(llvm::StringRef BundleRoot) { + if (NoOutput) + return true; + + // Create plist file to write to. + llvm::SmallString<128> InfoPlist(BundleRoot); + llvm::sys::path::append(InfoPlist, "Contents/Info.plist"); + std::error_code EC; + llvm::raw_fd_ostream PL(InfoPlist, EC, llvm::sys::fs::F_Text); + if (EC) { + llvm::errs() << "error: cannot create plist file " << InfoPlist << ": " + << EC.message() << '\n'; + return false; + } + + // FIXME: Use CoreFoundation to get executable bundle info. Use + // dummy values for now. + std::string bundleVersionStr = "1", bundleShortVersionStr = "1.0", + bundleIDStr; + + llvm::StringRef BundleID = *llvm::sys::path::rbegin(BundleRoot); + if (llvm::sys::path::extension(BundleRoot) == ".dSYM") + bundleIDStr = llvm::sys::path::stem(BundleID); + else + bundleIDStr = BundleID; + + // Print out information to the plist file. + PL << "\n" + << "\n" + << "\n" + << "\t\n" + << "\t\tCFBundleDevelopmentRegion\n" + << "\t\tEnglish\n" + << "\t\tCFBundleIdentifier\n" + << "\t\tcom.apple.xcode.dsym." << bundleIDStr << "\n" + << "\t\tCFBundleInfoDictionaryVersion\n" + << "\t\t6.0\n" + << "\t\tCFBundlePackageType\n" + << "\t\tdSYM\n" + << "\t\tCFBundleSignature\n" + << "\t\t\?\?\?\?\n" + << "\t\tCFBundleShortVersionString\n" + << "\t\t" << bundleShortVersionStr << "\n" + << "\t\tCFBundleVersion\n" + << "\t\t" << bundleVersionStr << "\n" + << "\t\n" + << "\n"; + + PL.close(); + return true; +} + +static bool createBundleDir(llvm::StringRef BundleBase) { + if (NoOutput) + return true; + + llvm::SmallString<128> Bundle(BundleBase); + llvm::sys::path::append(Bundle, "Contents", "Resources", "DWARF"); + if (std::error_code EC = create_directories(Bundle.str(), true, + llvm::sys::fs::perms::all_all)) { + llvm::errs() << "error: cannot create directory " << Bundle << ": " + << EC.message() << "\n"; + return false; + } + return true; +} + +static std::error_code getUniqueFile(const llvm::Twine &Model, int &ResultFD, + llvm::SmallVectorImpl &ResultPath) { + // If in NoOutput mode, use the createUniqueFile variant that + // doesn't open the file but still generates a somewhat unique + // name. In the real usage scenario, we'll want to ensure that the + // file is trully unique, and creating it is the only way to achieve + // that. + if (NoOutput) + return llvm::sys::fs::createUniqueFile(Model, ResultPath); + return llvm::sys::fs::createUniqueFile(Model, ResultFD, ResultPath); +} + +static std::string getOutputFileName(llvm::StringRef InputFile, + bool TempFile = false) { + if (TempFile) { + llvm::StringRef Basename = + OutputFileOpt.empty() ? InputFile : llvm::StringRef(OutputFileOpt); + llvm::Twine OutputFile = Basename + ".tmp%%%%%%.dwarf"; + int FD; + llvm::SmallString<128> UniqueFile; + if (auto EC = getUniqueFile(OutputFile, FD, UniqueFile)) { + llvm::errs() << "error: failed to create temporary outfile '" + << OutputFile << "': " << EC.message() << '\n'; + return ""; + } + llvm::sys::RemoveFileOnSignal(UniqueFile); + if (!NoOutput) { + // 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 (FlatOut) { + // If a flat dSYM has been requested, things are pretty simple. + if (OutputFileOpt.empty()) { + if (InputFile == "-") + return "a.out.dwarf"; + return (InputFile + ".dwarf").str(); + } + + return OutputFileOpt; + } + + // We need to create/update a dSYM bundle. + // A bundle hierarchy looks like this: + // .dSYM/ + // Contents/ + // Info.plist + // Resources/ + // DWARF/ + // + std::string DwarfFile = + InputFile == "-" ? llvm::StringRef("a.out") : InputFile; + llvm::SmallString<128> BundleDir(OutputFileOpt); + if (BundleDir.empty()) + BundleDir = DwarfFile + ".dSYM"; + if (!createBundleDir(BundleDir) || !createPlistFile(BundleDir)) + return ""; + + llvm::sys::path::append(BundleDir, "Contents", "Resources", "DWARF", + llvm::sys::path::filename(DwarfFile)); + return BundleDir.str(); +} + +void llvm::dsymutil::exitDsymutil(int ExitStatus) { + // Cleanup temporary files. + llvm::sys::RunInterruptHandlers(); + exit(ExitStatus); } int main(int argc, char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram StackPrinter(argc, argv); llvm::llvm_shutdown_obj Shutdown; + LinkOptions Options; + void *MainAddr = (void *)(intptr_t)&exitDsymutil; + std::string SDKPath = llvm::sys::fs::getMainExecutable(argv[0], MainAddr); + SDKPath = llvm::sys::path::parent_path(SDKPath); + + HideUnrelatedOptions(DsymCategory); + llvm::cl::ParseCommandLineOptions( + argc, argv, + "manipulate archived DWARF debug symbol files.\n\n" + "dsymutil links the DWARF debug information found in the object files\n" + "for the executable by using debug symbols information\n" + "contained in its symbol table.\n"); + + if (Help) + PrintHelpMessage(); + + if (Version) { + llvm::cl::PrintVersionMessage(); + return 0; + } + + Options.Verbose = Verbose; + Options.NoOutput = NoOutput; + Options.NoODR = NoODR; + Options.PrependPath = OsoPrependPath; - llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n"); - auto DebugMapPtrOrErr = parseDebugMap(InputFile, OsoPrependPath, Verbose); + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); - if (auto EC = DebugMapPtrOrErr.getError()) { - llvm::errs() << "error: cannot parse the debug map for \"" << InputFile - << "\": " << EC.message() << '\n'; + if (!FlatOut && OutputFileOpt == "-") { + llvm::errs() << "error: cannot emit to standard output without --flat\n"; return 1; } - if (Verbose) - (*DebugMapPtrOrErr)->print(llvm::outs()); + if (InputFiles.size() > 1 && FlatOut && !OutputFileOpt.empty()) { + llvm::errs() << "error: cannot use -o with multiple inputs in flat mode\n"; + return 1; + } - if (ParseOnly) - return 0; + for (const auto &Arch : ArchFlags) + if (Arch != "*" && Arch != "all" && + !llvm::object::MachOObjectFile::isValidArch(Arch)) { + llvm::errs() << "error: Unsupported cpu architecture: '" << Arch << "'\n"; + exitDsymutil(1); + } + + for (auto &InputFile : InputFiles) { + // Dump the symbol table for each input file and requested arch + if (DumpStab) { + if (!dumpStab(InputFile, ArchFlags, OsoPrependPath)) + exitDsymutil(1); + continue; + } + + auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath, + Verbose, InputIsYAMLDebugMap); + + if (auto EC = DebugMapPtrsOrErr.getError()) { + llvm::errs() << "error: cannot parse the debug map for \"" << InputFile + << "\": " << EC.message() << '\n'; + exitDsymutil(1); + } + + if (DebugMapPtrsOrErr->empty()) { + llvm::errs() << "error: no architecture to link\n"; + exitDsymutil(1); + } - std::string OutputBasename(InputFile); - if (OutputBasename == "-") - OutputBasename = "a.out"; + // If there is more than one link to execute, we need to generate + // temporary files. + bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1; + llvm::SmallVector TempFiles; + for (auto &Map : *DebugMapPtrsOrErr) { + if (Verbose || DumpDebugMap) + Map->print(llvm::outs()); + + if (DumpDebugMap) + continue; + + if (Map->begin() == Map->end()) + llvm::errs() << "warning: no debug symbols in executable (-arch " + << MachOUtils::getArchName(Map->getTriple().getArchName()) + << ")\n"; + + 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); + } + + if (NeedsTempFiles && + !MachOUtils::generateUniversalBinary( + TempFiles, getOutputFileName(InputFile), Options, SDKPath)) + exitDsymutil(1); + } - return !linkDwarf(OutputBasename + ".dwarf", **DebugMapPtrOrErr, Verbose); + exitDsymutil(0); }