1 //===-- llvm-debuginfo-analyzer.cpp - LLVM Debug info analysis utility ---===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This program is a utility that displays the logical view for the debug 10 // information. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "Options.h" 15 #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" 16 #include "llvm/DebugInfo/LogicalView/LVReaderHandler.h" 17 #include "llvm/Support/COM.h" 18 #include "llvm/Support/CommandLine.h" 19 #include "llvm/Support/InitLLVM.h" 20 #include "llvm/Support/TargetSelect.h" 21 #include "llvm/Support/ToolOutputFile.h" 22 #include "llvm/Support/WithColor.h" 23 24 using namespace llvm; 25 using namespace logicalview; 26 using namespace cmdline; 27 28 /// Create formatted StringError object. 29 static StringRef ToolName = "llvm-debuginfo-analyzer"; 30 template <typename... Ts> 31 static void error(std::error_code EC, char const *Fmt, const Ts &...Vals) { 32 if (!EC) 33 return; 34 std::string Buffer; 35 raw_string_ostream Stream(Buffer); 36 Stream << format(Fmt, Vals...); 37 WithColor::error(errs(), ToolName) << Stream.str() << "\n"; 38 exit(1); 39 } 40 41 static void error(Error EC) { 42 if (!EC) 43 return; 44 handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) { 45 errs() << "\n"; 46 WithColor::error(errs(), ToolName) << EI.message() << ".\n"; 47 exit(1); 48 }); 49 } 50 51 /// If the input path is a .dSYM bundle (as created by the dsymutil tool), 52 /// replace it with individual entries for each of the object files inside the 53 /// bundle otherwise return the input path. 54 static std::vector<std::string> expandBundle(const std::string &InputPath) { 55 std::vector<std::string> BundlePaths; 56 SmallString<256> BundlePath(InputPath); 57 // Normalize input path. This is necessary to accept `bundle.dSYM/`. 58 sys::path::remove_dots(BundlePath); 59 // Manually open up the bundle to avoid introducing additional dependencies. 60 if (sys::fs::is_directory(BundlePath) && 61 sys::path::extension(BundlePath) == ".dSYM") { 62 std::error_code EC; 63 sys::path::append(BundlePath, "Contents", "Resources", "DWARF"); 64 for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd; 65 Dir != DirEnd && !EC; Dir.increment(EC)) { 66 const std::string &Path = Dir->path(); 67 sys::fs::file_status Status; 68 EC = sys::fs::status(Path, Status); 69 error(EC, "%s", Path.c_str()); 70 switch (Status.type()) { 71 case sys::fs::file_type::regular_file: 72 case sys::fs::file_type::symlink_file: 73 case sys::fs::file_type::type_unknown: 74 BundlePaths.push_back(Path); 75 break; 76 default: /*ignore*/; 77 } 78 } 79 } 80 if (BundlePaths.empty()) 81 BundlePaths.push_back(InputPath); 82 return BundlePaths; 83 } 84 85 int main(int argc, char **argv) { 86 InitLLVM X(argc, argv); 87 88 // Initialize targets and assembly printers/parsers. 89 llvm::InitializeAllTargetInfos(); 90 llvm::InitializeAllTargetMCs(); 91 InitializeAllDisassemblers(); 92 93 llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); 94 95 cl::extrahelp HelpResponse( 96 "\nPass @FILE as argument to read options from FILE.\n"); 97 98 cl::HideUnrelatedOptions( 99 {&AttributeCategory, &CompareCategory, &InternalCategory, &OutputCategory, 100 &PrintCategory, &ReportCategory, &SelectCategory, &WarningCategory}); 101 cl::ParseCommandLineOptions(argc, argv, 102 "Printing a logical representation of low-level " 103 "debug information.\n"); 104 cl::PrintOptionValues(); 105 106 std::error_code EC; 107 ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_None); 108 error(EC, "Unable to open output file %s", OutputFilename.c_str()); 109 // Don't remove output file if we exit with an error. 110 OutputFile.keep(); 111 112 // Defaults to a.out if no filenames specified. 113 if (InputFilenames.empty()) 114 InputFilenames.push_back("a.out"); 115 116 // Expand any .dSYM bundles to the individual object files contained therein. 117 std::vector<std::string> Objects; 118 for (const std::string &Filename : InputFilenames) { 119 std::vector<std::string> Objs = expandBundle(Filename); 120 Objects.insert(Objects.end(), Objs.begin(), Objs.end()); 121 } 122 123 propagateOptions(); 124 ScopedPrinter W(OutputFile.os()); 125 LVReaderHandler ReaderHandler(Objects, W, ReaderOptions); 126 127 // Print the command line. 128 if (options().getInternalCmdline()) { 129 raw_ostream &Stream = W.getOStream(); 130 Stream << "\nCommand line:\n"; 131 for (int Index = 0; Index < argc; ++Index) 132 Stream << " " << argv[Index] << "\n"; 133 Stream << "\n"; 134 } 135 136 // Create readers and perform requested tasks on them. 137 if (Error Err = ReaderHandler.process()) 138 error(std::move(Err)); 139 140 return EXIT_SUCCESS; 141 } 142