| //===-- llvm-debuginfo-analyzer.cpp - LLVM Debug info analysis utility ---===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This program is a utility that displays the logical view for the debug |
| // information. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "Options.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" |
| #include "llvm/DebugInfo/LogicalView/LVReaderHandler.h" |
| #include "llvm/Support/COM.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/InitLLVM.h" |
| #include "llvm/Support/TargetSelect.h" |
| #include "llvm/Support/ToolOutputFile.h" |
| #include "llvm/Support/WithColor.h" |
| |
| using namespace llvm; |
| using namespace logicalview; |
| using namespace cmdline; |
| |
| /// Create formatted StringError object. |
| static StringRef ToolName = "llvm-debuginfo-analyzer"; |
| template <typename... Ts> |
| static void error(std::error_code EC, char const *Fmt, const Ts &...Vals) { |
| if (!EC) |
| return; |
| std::string Buffer; |
| raw_string_ostream Stream(Buffer); |
| Stream << format(Fmt, Vals...); |
| WithColor::error(errs(), ToolName) << Stream.str() << "\n"; |
| exit(1); |
| } |
| |
| static void error(Error EC) { |
| if (!EC) |
| return; |
| handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) { |
| errs() << "\n"; |
| WithColor::error(errs(), ToolName) << EI.message() << ".\n"; |
| exit(1); |
| }); |
| } |
| |
| /// If the input path is a .dSYM bundle (as created by the dsymutil tool), |
| /// replace it with individual entries for each of the object files inside the |
| /// bundle otherwise return the input path. |
| static std::vector<std::string> expandBundle(const std::string &InputPath) { |
| std::vector<std::string> BundlePaths; |
| SmallString<256> BundlePath(InputPath); |
| // Normalize input path. This is necessary to accept `bundle.dSYM/`. |
| sys::path::remove_dots(BundlePath); |
| // Manually open up the bundle to avoid introducing additional dependencies. |
| if (sys::fs::is_directory(BundlePath) && |
| sys::path::extension(BundlePath) == ".dSYM") { |
| std::error_code EC; |
| sys::path::append(BundlePath, "Contents", "Resources", "DWARF"); |
| for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd; |
| Dir != DirEnd && !EC; Dir.increment(EC)) { |
| const std::string &Path = Dir->path(); |
| sys::fs::file_status Status; |
| EC = sys::fs::status(Path, Status); |
| error(EC, "%s", Path.c_str()); |
| switch (Status.type()) { |
| case sys::fs::file_type::regular_file: |
| case sys::fs::file_type::symlink_file: |
| case sys::fs::file_type::type_unknown: |
| BundlePaths.push_back(Path); |
| break; |
| default: /*ignore*/; |
| } |
| } |
| } |
| if (BundlePaths.empty()) |
| BundlePaths.push_back(InputPath); |
| return BundlePaths; |
| } |
| |
| int main(int argc, char **argv) { |
| InitLLVM X(argc, argv); |
| |
| // Initialize targets and assembly printers/parsers. |
| llvm::InitializeAllTargetInfos(); |
| llvm::InitializeAllTargetMCs(); |
| InitializeAllDisassemblers(); |
| |
| llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); |
| |
| cl::extrahelp HelpResponse( |
| "\nPass @FILE as argument to read options from FILE.\n"); |
| |
| cl::HideUnrelatedOptions( |
| {&AttributeCategory, &CompareCategory, &InternalCategory, &OutputCategory, |
| &PrintCategory, &ReportCategory, &SelectCategory, &WarningCategory}); |
| cl::ParseCommandLineOptions(argc, argv, |
| "Printing a logical representation of low-level " |
| "debug information.\n"); |
| cl::PrintOptionValues(); |
| |
| std::error_code EC; |
| ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_None); |
| error(EC, "Unable to open output file %s", OutputFilename.c_str()); |
| // Don't remove output file if we exit with an error. |
| OutputFile.keep(); |
| |
| // Defaults to a.out if no filenames specified. |
| if (InputFilenames.empty()) |
| InputFilenames.push_back("a.out"); |
| |
| // Expand any .dSYM bundles to the individual object files contained therein. |
| std::vector<std::string> Objects; |
| for (const std::string &Filename : InputFilenames) { |
| std::vector<std::string> Objs = expandBundle(Filename); |
| Objects.insert(Objects.end(), Objs.begin(), Objs.end()); |
| } |
| |
| propagateOptions(); |
| ScopedPrinter W(OutputFile.os()); |
| LVReaderHandler ReaderHandler(Objects, W, ReaderOptions); |
| |
| // Print the command line. |
| if (options().getInternalCmdline()) { |
| raw_ostream &Stream = W.getOStream(); |
| Stream << "\nCommand line:\n"; |
| for (int Index = 0; Index < argc; ++Index) |
| Stream << " " << argv[Index] << "\n"; |
| Stream << "\n"; |
| } |
| |
| // Create readers and perform requested tasks on them. |
| if (Error Err = ReaderHandler.process()) |
| error(std::move(Err)); |
| |
| return EXIT_SUCCESS; |
| } |