//===- lldb-test.cpp ------------------------------------------ *- C++ --*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "FormatUtil.h" #include "SystemInitializerTest.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" #include "lldb/Expression/IRMemoryMap.h" #include "lldb/Initialization/SystemLifetimeManager.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/CleanUp.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "llvm/ADT/IntervalMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/WithColor.h" #include #include using namespace lldb; using namespace lldb_private; using namespace llvm; namespace opts { static cl::SubCommand BreakpointSubcommand("breakpoints", "Test breakpoint resolution"); cl::SubCommand ObjectFileSubcommand("object-file", "Display LLDB object file information"); cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file"); cl::SubCommand IRMemoryMapSubcommand("ir-memory-map", "Test IRMemoryMap"); cl::opt Log("log", cl::desc("Path to a log file"), cl::init(""), cl::sub(BreakpointSubcommand), cl::sub(ObjectFileSubcommand), cl::sub(SymbolsSubcommand), cl::sub(IRMemoryMapSubcommand)); /// Create a target using the file pointed to by \p Filename, or abort. TargetSP createTarget(Debugger &Dbg, const std::string &Filename); /// Read \p Filename into a null-terminated buffer, or abort. std::unique_ptr openFile(const std::string &Filename); namespace breakpoint { static cl::opt Target(cl::Positional, cl::desc(""), cl::Required, cl::sub(BreakpointSubcommand)); static cl::opt CommandFile(cl::Positional, cl::desc(""), cl::init("-"), cl::sub(BreakpointSubcommand)); static cl::opt Persistent( "persistent", cl::desc("Don't automatically remove all breakpoints before each command"), cl::sub(BreakpointSubcommand)); static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; } static void dumpState(const BreakpointList &List, LinePrinter &P); static std::string substitute(StringRef Cmd); static int evaluateBreakpoints(Debugger &Dbg); } // namespace breakpoint namespace object { cl::opt SectionContents("contents", cl::desc("Dump each section's contents"), cl::sub(ObjectFileSubcommand)); cl::opt SectionDependentModules("dep-modules", cl::desc("Dump each dependent module"), cl::sub(ObjectFileSubcommand)); cl::list InputFilenames(cl::Positional, cl::desc(""), cl::OneOrMore, cl::sub(ObjectFileSubcommand)); } // namespace object namespace symbols { static cl::opt InputFile(cl::Positional, cl::desc(""), cl::Required, cl::sub(SymbolsSubcommand)); static cl::opt SymbolPath("symbol-file", cl::desc("The file from which to fetch symbol information."), cl::value_desc("file"), cl::sub(SymbolsSubcommand)); enum class FindType { None, Function, Block, Namespace, Type, Variable, }; static cl::opt Find( "find", cl::desc("Choose search type:"), cl::values( clEnumValN(FindType::None, "none", "No search, just dump the module."), clEnumValN(FindType::Function, "function", "Find functions."), clEnumValN(FindType::Block, "block", "Find blocks."), clEnumValN(FindType::Namespace, "namespace", "Find namespaces."), clEnumValN(FindType::Type, "type", "Find types."), clEnumValN(FindType::Variable, "variable", "Find global variables.")), cl::sub(SymbolsSubcommand)); static cl::opt Name("name", cl::desc("Name to find."), cl::sub(SymbolsSubcommand)); static cl::opt Regex("regex", cl::desc("Search using regular expressions (avaliable for variables " "and functions only)."), cl::sub(SymbolsSubcommand)); static cl::opt Context("context", cl::desc("Restrict search to the context of the given variable."), cl::value_desc("variable"), cl::sub(SymbolsSubcommand)); static cl::list FunctionNameFlags( "function-flags", cl::desc("Function search flags:"), cl::values(clEnumValN(eFunctionNameTypeAuto, "auto", "Automatically deduce flags based on name."), clEnumValN(eFunctionNameTypeFull, "full", "Full function name."), clEnumValN(eFunctionNameTypeBase, "base", "Base name."), clEnumValN(eFunctionNameTypeMethod, "method", "Method name."), clEnumValN(eFunctionNameTypeSelector, "selector", "Selector name.")), cl::sub(SymbolsSubcommand)); static FunctionNameType getFunctionNameFlags() { FunctionNameType Result = FunctionNameType(0); for (FunctionNameType Flag : FunctionNameFlags) Result = FunctionNameType(Result | Flag); return Result; } static cl::opt DumpAST("dump-ast", cl::desc("Dump AST restored from symbols."), cl::sub(SymbolsSubcommand)); static cl::opt Verify("verify", cl::desc("Verify symbol information."), cl::sub(SymbolsSubcommand)); static cl::opt File("file", cl::desc("File (compile unit) to search."), cl::sub(SymbolsSubcommand)); static cl::opt Line("line", cl::desc("Line to search."), cl::sub(SymbolsSubcommand)); static Expected getDeclContext(SymbolVendor &Vendor); static Error findFunctions(lldb_private::Module &Module); static Error findBlocks(lldb_private::Module &Module); static Error findNamespaces(lldb_private::Module &Module); static Error findTypes(lldb_private::Module &Module); static Error findVariables(lldb_private::Module &Module); static Error dumpModule(lldb_private::Module &Module); static Error dumpAST(lldb_private::Module &Module); static Error verify(lldb_private::Module &Module); static Expected getAction(); static int dumpSymbols(Debugger &Dbg); } // namespace symbols namespace irmemorymap { static cl::opt Target(cl::Positional, cl::desc(""), cl::Required, cl::sub(IRMemoryMapSubcommand)); static cl::opt CommandFile(cl::Positional, cl::desc(""), cl::init("-"), cl::sub(IRMemoryMapSubcommand)); static cl::opt UseHostOnlyAllocationPolicy( "host-only", cl::desc("Use the host-only allocation policy"), cl::init(false), cl::sub(IRMemoryMapSubcommand)); using AllocationT = std::pair; using AddrIntervalMap = IntervalMap>; struct IRMemoryMapTestState { TargetSP Target; IRMemoryMap Map; AddrIntervalMap::Allocator IntervalMapAllocator; AddrIntervalMap Allocations; StringMap Label2AddrMap; IRMemoryMapTestState(TargetSP Target) : Target(Target), Map(Target), Allocations(IntervalMapAllocator) {} }; bool evalMalloc(StringRef Line, IRMemoryMapTestState &State); bool evalFree(StringRef Line, IRMemoryMapTestState &State); int evaluateMemoryMapCommands(Debugger &Dbg); } // namespace irmemorymap } // namespace opts template static Error make_string_error(const char *Format, Args &&... args) { return llvm::make_error( llvm::formatv(Format, std::forward(args)...).str(), llvm::inconvertibleErrorCode()); } TargetSP opts::createTarget(Debugger &Dbg, const std::string &Filename) { TargetSP Target; Status ST = Dbg.GetTargetList().CreateTarget( Dbg, Filename, /*triple*/ "", eLoadDependentsNo, /*platform_options*/ nullptr, Target); if (ST.Fail()) { errs() << formatv("Failed to create target '{0}: {1}\n", Filename, ST); exit(1); } return Target; } std::unique_ptr opts::openFile(const std::string &Filename) { auto MB = MemoryBuffer::getFileOrSTDIN(Filename); if (!MB) { errs() << formatv("Could not open file '{0}: {1}\n", Filename, MB.getError().message()); exit(1); } return std::move(*MB); } void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) { P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize())); if (List.GetSize() > 0) P.formatLine("At least one breakpoint."); for (size_t i = 0, e = List.GetSize(); i < e; ++i) { BreakpointSP BP = List.GetBreakpointAtIndex(i); P.formatLine("Breakpoint ID {0}:", BP->GetID()); AutoIndent Indent(P, 2); P.formatLine("{0} location{1}.", BP->GetNumLocations(), plural(BP->GetNumLocations())); if (BP->GetNumLocations() > 0) P.formatLine("At least one location."); P.formatLine("{0} resolved location{1}.", BP->GetNumResolvedLocations(), plural(BP->GetNumResolvedLocations())); if (BP->GetNumResolvedLocations() > 0) P.formatLine("At least one resolved location."); for (size_t l = 0, le = BP->GetNumLocations(); l < le; ++l) { BreakpointLocationSP Loc = BP->GetLocationAtIndex(l); P.formatLine("Location ID {0}:", Loc->GetID()); AutoIndent Indent(P, 2); P.formatLine("Enabled: {0}", Loc->IsEnabled()); P.formatLine("Resolved: {0}", Loc->IsResolved()); SymbolContext sc; Loc->GetAddress().CalculateSymbolContext(&sc); lldb_private::StreamString S; sc.DumpStopContext(&S, BP->GetTarget().GetProcessSP().get(), Loc->GetAddress(), false, true, false, true, true); P.formatLine("Address: {0}", S.GetString()); } } P.NewLine(); } std::string opts::breakpoint::substitute(StringRef Cmd) { std::string Result; raw_string_ostream OS(Result); while (!Cmd.empty()) { switch (Cmd[0]) { case '%': if (Cmd.consume_front("%p") && (Cmd.empty() || !isalnum(Cmd[0]))) { OS << sys::path::parent_path(breakpoint::CommandFile); break; } LLVM_FALLTHROUGH; default: size_t pos = Cmd.find('%'); OS << Cmd.substr(0, pos); Cmd = Cmd.substr(pos); break; } } return std::move(OS.str()); } int opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) { TargetSP Target = opts::createTarget(Dbg, breakpoint::Target); std::unique_ptr MB = opts::openFile(breakpoint::CommandFile); LinePrinter P(4, outs()); StringRef Rest = MB->getBuffer(); int HadErrors = 0; while (!Rest.empty()) { StringRef Line; std::tie(Line, Rest) = Rest.split('\n'); Line = Line.ltrim(); if (Line.empty() || Line[0] == '#') continue; if (!Persistent) Target->RemoveAllBreakpoints(/*internal_also*/ true); std::string Command = substitute(Line); P.formatLine("Command: {0}", Command); CommandReturnObject Result; if (!Dbg.GetCommandInterpreter().HandleCommand( Command.c_str(), /*add_to_history*/ eLazyBoolNo, Result)) { P.formatLine("Failed: {0}", Result.GetErrorData()); HadErrors = 1; continue; } dumpState(Target->GetBreakpointList(/*internal*/ false), P); } return HadErrors; } Expected opts::symbols::getDeclContext(SymbolVendor &Vendor) { if (Context.empty()) return CompilerDeclContext(); VariableList List; Vendor.FindGlobalVariables(ConstString(Context), nullptr, UINT32_MAX, List); if (List.Empty()) return make_string_error("Context search didn't find a match."); if (List.GetSize() > 1) return make_string_error("Context search found multiple matches."); return List.GetVariableAtIndex(0)->GetDeclContext(); } Error opts::symbols::findFunctions(lldb_private::Module &Module) { SymbolVendor &Vendor = *Module.GetSymbolVendor(); SymbolContextList List; if (!File.empty()) { assert(Line != 0); FileSpec src_file(File); size_t cu_count = Module.GetNumCompileUnits(); for (size_t i = 0; i < cu_count; i++) { lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i); if (!cu_sp) continue; LineEntry le; cu_sp->FindLineEntry(0, Line, &src_file, false, &le); if (!le.IsValid()) continue; auto addr = le.GetSameLineContiguousAddressRange().GetBaseAddress(); if (!addr.IsValid()) continue; SymbolContext sc; uint32_t resolved = addr.CalculateSymbolContext(&sc, eSymbolContextFunction); if (resolved & eSymbolContextFunction) List.Append(sc); } } else if (Regex) { RegularExpression RE(Name); assert(RE.IsValid()); Vendor.FindFunctions(RE, true, false, List); } else { Expected ContextOr = getDeclContext(Vendor); if (!ContextOr) return ContextOr.takeError(); CompilerDeclContext *ContextPtr = ContextOr->IsValid() ? &*ContextOr : nullptr; Vendor.FindFunctions(ConstString(Name), ContextPtr, getFunctionNameFlags(), true, false, List); } outs() << formatv("Found {0} functions:\n", List.GetSize()); StreamString Stream; List.Dump(&Stream, nullptr); outs() << Stream.GetData() << "\n"; return Error::success(); } Error opts::symbols::findBlocks(lldb_private::Module &Module) { assert(!Regex); assert(!File.empty()); assert(Line != 0); SymbolContextList List; FileSpec src_file(File); size_t cu_count = Module.GetNumCompileUnits(); for (size_t i = 0; i < cu_count; i++) { lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i); if (!cu_sp) continue; LineEntry le; cu_sp->FindLineEntry(0, Line, &src_file, false, &le); if (!le.IsValid()) continue; auto addr = le.GetSameLineContiguousAddressRange().GetBaseAddress(); if (!addr.IsValid()) continue; SymbolContext sc; uint32_t resolved = addr.CalculateSymbolContext(&sc, eSymbolContextBlock); if (resolved & eSymbolContextBlock) List.Append(sc); } outs() << formatv("Found {0} blocks:\n", List.GetSize()); StreamString Stream; List.Dump(&Stream, nullptr); outs() << Stream.GetData() << "\n"; return Error::success(); } Error opts::symbols::findNamespaces(lldb_private::Module &Module) { SymbolVendor &Vendor = *Module.GetSymbolVendor(); Expected ContextOr = getDeclContext(Vendor); if (!ContextOr) return ContextOr.takeError(); CompilerDeclContext *ContextPtr = ContextOr->IsValid() ? &*ContextOr : nullptr; CompilerDeclContext Result = Vendor.FindNamespace(ConstString(Name), ContextPtr); if (Result) outs() << "Found namespace: " << Result.GetScopeQualifiedName().GetStringRef() << "\n"; else outs() << "Namespace not found.\n"; return Error::success(); } Error opts::symbols::findTypes(lldb_private::Module &Module) { SymbolVendor &Vendor = *Module.GetSymbolVendor(); Expected ContextOr = getDeclContext(Vendor); if (!ContextOr) return ContextOr.takeError(); CompilerDeclContext *ContextPtr = ContextOr->IsValid() ? &*ContextOr : nullptr; DenseSet SearchedFiles; TypeMap Map; Vendor.FindTypes(ConstString(Name), ContextPtr, true, UINT32_MAX, SearchedFiles, Map); outs() << formatv("Found {0} types:\n", Map.GetSize()); StreamString Stream; Map.Dump(&Stream, false); outs() << Stream.GetData() << "\n"; return Error::success(); } Error opts::symbols::findVariables(lldb_private::Module &Module) { SymbolVendor &Vendor = *Module.GetSymbolVendor(); VariableList List; if (Regex) { RegularExpression RE(Name); assert(RE.IsValid()); Vendor.FindGlobalVariables(RE, UINT32_MAX, List); } else if (!File.empty()) { CompUnitSP CU; for (size_t Ind = 0; !CU && Ind < Module.GetNumCompileUnits(); ++Ind) { CompUnitSP Candidate = Module.GetCompileUnitAtIndex(Ind); if (!Candidate || Candidate->GetFilename().GetStringRef() != File) continue; if (CU) return make_string_error("Multiple compile units for file `{0}` found.", File); CU = std::move(Candidate); } if (!CU) return make_string_error("Compile unit `{0}` not found.", File); List.AddVariables(CU->GetVariableList(true).get()); } else { Expected ContextOr = getDeclContext(Vendor); if (!ContextOr) return ContextOr.takeError(); CompilerDeclContext *ContextPtr = ContextOr->IsValid() ? &*ContextOr : nullptr; Vendor.FindGlobalVariables(ConstString(Name), ContextPtr, UINT32_MAX, List); } outs() << formatv("Found {0} variables:\n", List.GetSize()); StreamString Stream; List.Dump(&Stream, false); outs() << Stream.GetData() << "\n"; return Error::success(); } Error opts::symbols::dumpModule(lldb_private::Module &Module) { StreamString Stream; Module.ParseAllDebugSymbols(); Module.Dump(&Stream); outs() << Stream.GetData() << "\n"; return Error::success(); } Error opts::symbols::dumpAST(lldb_private::Module &Module) { SymbolVendor &plugin = *Module.GetSymbolVendor(); Module.ParseAllDebugSymbols(); auto symfile = plugin.GetSymbolFile(); if (!symfile) return make_string_error("Module has no symbol file."); auto clang_ast_ctx = llvm::dyn_cast_or_null( symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus)); if (!clang_ast_ctx) return make_string_error("Can't retrieve Clang AST context."); auto ast_ctx = clang_ast_ctx->getASTContext(); if (!ast_ctx) return make_string_error("Can't retrieve AST context."); auto tu = ast_ctx->getTranslationUnitDecl(); if (!tu) return make_string_error("Can't retrieve translation unit declaration."); tu->print(outs()); return Error::success(); } Error opts::symbols::verify(lldb_private::Module &Module) { SymbolVendor &plugin = *Module.GetSymbolVendor(); SymbolFile *symfile = plugin.GetSymbolFile(); if (!symfile) return make_string_error("Module has no symbol file."); uint32_t comp_units_count = symfile->GetNumCompileUnits(); outs() << "Found " << comp_units_count << " compile units.\n"; for (uint32_t i = 0; i < comp_units_count; i++) { lldb::CompUnitSP comp_unit = symfile->ParseCompileUnitAtIndex(i); if (!comp_unit) return make_string_error("Connot parse compile unit {0}.", i); outs() << "Processing '" << comp_unit->GetFilename().AsCString() << "' compile unit.\n"; LineTable *lt = comp_unit->GetLineTable(); if (!lt) return make_string_error("Can't get a line table of a compile unit."); uint32_t count = lt->GetSize(); outs() << "The line table contains " << count << " entries.\n"; if (count == 0) continue; LineEntry le; if (!lt->GetLineEntryAtIndex(0, le)) return make_string_error("Can't get a line entry of a compile unit."); for (uint32_t i = 1; i < count; i++) { lldb::addr_t curr_end = le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize(); if (!lt->GetLineEntryAtIndex(i, le)) return make_string_error("Can't get a line entry of a compile unit"); if (curr_end > le.range.GetBaseAddress().GetFileAddress()) return make_string_error( "Line table of a compile unit is inconsistent."); } } outs() << "The symbol information is verified.\n"; return Error::success(); } Expected opts::symbols::getAction() { if (Verify && DumpAST) return make_string_error( "Cannot both verify symbol information and dump AST."); if (Verify) { if (Find != FindType::None) return make_string_error( "Cannot both search and verify symbol information."); if (Regex || !Context.empty() || !Name.empty() || !File.empty() || Line != 0) return make_string_error( "-regex, -context, -name, -file and -line options are not " "applicable for symbol verification."); return verify; } if (DumpAST) { if (Find != FindType::None) return make_string_error("Cannot both search and dump AST."); if (Regex || !Context.empty() || !Name.empty() || !File.empty() || Line != 0) return make_string_error( "-regex, -context, -name, -file and -line options are not " "applicable for dumping AST."); return dumpAST; } if (Regex && !Context.empty()) return make_string_error( "Cannot search using both regular expressions and context."); if (Regex && !RegularExpression(Name).IsValid()) return make_string_error("`{0}` is not a valid regular expression.", Name); if (Regex + !Context.empty() + !File.empty() >= 2) return make_string_error( "Only one of -regex, -context and -file may be used simultaneously."); if (Regex && Name.empty()) return make_string_error("-regex used without a -name"); switch (Find) { case FindType::None: if (!Context.empty() || !Name.empty() || !File.empty() || Line != 0) return make_string_error( "Specify search type (-find) to use search options."); return dumpModule; case FindType::Function: if (!File.empty() + (Line != 0) == 1) return make_string_error("Both file name and line number must be " "specified when searching a function " "by file position."); if (Regex + (getFunctionNameFlags() != 0) + !File.empty() >= 2) return make_string_error("Only one of regular expression, function-flags " "and file position may be used simultaneously " "when searching a function."); return findFunctions; case FindType::Block: if (File.empty() || Line == 0) return make_string_error("Both file name and line number must be " "specified when searching a block."); if (Regex || getFunctionNameFlags() != 0) return make_string_error("Cannot use regular expression or " "function-flags for searching a block."); return findBlocks; case FindType::Namespace: if (Regex || !File.empty() || Line != 0) return make_string_error("Cannot search for namespaces using regular " "expressions, file names or line numbers."); return findNamespaces; case FindType::Type: if (Regex || !File.empty() || Line != 0) return make_string_error("Cannot search for types using regular " "expressions, file names or line numbers."); return findTypes; case FindType::Variable: if (Line != 0) return make_string_error("Cannot search for variables " "using line numbers."); return findVariables; } llvm_unreachable("Unsupported symbol action."); } int opts::symbols::dumpSymbols(Debugger &Dbg) { auto ActionOr = getAction(); if (!ActionOr) { logAllUnhandledErrors(ActionOr.takeError(), WithColor::error(), ""); return 1; } auto Action = *ActionOr; outs() << "Module: " << InputFile << "\n"; ModuleSpec Spec{FileSpec(InputFile)}; StringRef Symbols = SymbolPath.empty() ? InputFile : SymbolPath; Spec.GetSymbolFileSpec().SetFile(Symbols, FileSpec::Style::native); auto ModulePtr = std::make_shared(Spec); SymbolVendor *Vendor = ModulePtr->GetSymbolVendor(); if (!Vendor) { WithColor::error() << "Module has no symbol vendor.\n"; return 1; } if (Error E = Action(*ModulePtr)) { WithColor::error() << toString(std::move(E)) << "\n"; return 1; } return 0; } static void dumpSectionList(LinePrinter &Printer, const SectionList &List, bool is_subsection) { size_t Count = List.GetNumSections(0); if (Count == 0) { Printer.formatLine("There are no {0}sections", is_subsection ? "sub" : ""); return; } Printer.formatLine("Showing {0} {1}sections", Count, is_subsection ? "sub" : ""); for (size_t I = 0; I < Count; ++I) { auto S = List.GetSectionAtIndex(I); assert(S); AutoIndent Indent(Printer, 2); Printer.formatLine("Index: {0}", I); Printer.formatLine("ID: {0:x}", S->GetID()); Printer.formatLine("Name: {0}", S->GetName().GetStringRef()); Printer.formatLine("Type: {0}", S->GetTypeAsCString()); Printer.formatLine("Permissions: {0}", GetPermissionsAsCString(S->GetPermissions())); Printer.formatLine("Thread specific: {0:y}", S->IsThreadSpecific()); Printer.formatLine("VM address: {0:x}", S->GetFileAddress()); Printer.formatLine("VM size: {0}", S->GetByteSize()); Printer.formatLine("File size: {0}", S->GetFileSize()); if (opts::object::SectionContents) { DataExtractor Data; S->GetSectionData(Data); ArrayRef Bytes = {Data.GetDataStart(), Data.GetDataEnd()}; Printer.formatBinary("Data: ", Bytes, 0); } if (S->GetType() == eSectionTypeContainer) dumpSectionList(Printer, S->GetChildren(), true); Printer.NewLine(); } } static int dumpObjectFiles(Debugger &Dbg) { LinePrinter Printer(4, llvm::outs()); int HadErrors = 0; for (const auto &File : opts::object::InputFilenames) { ModuleSpec Spec{FileSpec(File)}; auto ModulePtr = std::make_shared(Spec); ObjectFile *ObjectPtr = ModulePtr->GetObjectFile(); if (!ObjectPtr) { WithColor::error() << File << " not recognised as an object file\n"; HadErrors = 1; continue; } // Fetch symbol vendor before we get the section list to give the symbol // vendor a chance to populate it. ModulePtr->GetSymbolVendor(); SectionList *Sections = ModulePtr->GetSectionList(); if (!Sections) { llvm::errs() << "Could not load sections for module " << File << "\n"; HadErrors = 1; continue; } Printer.formatLine("Plugin name: {0}", ObjectPtr->GetPluginName()); Printer.formatLine("Architecture: {0}", ModulePtr->GetArchitecture().GetTriple().getTriple()); Printer.formatLine("UUID: {0}", ModulePtr->GetUUID().GetAsString()); Printer.formatLine("Executable: {0}", ObjectPtr->IsExecutable()); Printer.formatLine("Stripped: {0}", ObjectPtr->IsStripped()); Printer.formatLine("Type: {0}", ObjectPtr->GetType()); Printer.formatLine("Strata: {0}", ObjectPtr->GetStrata()); Printer.formatLine("Base VM address: {0:x}", ObjectPtr->GetBaseAddress().GetFileAddress()); dumpSectionList(Printer, *Sections, /*is_subsection*/ false); if (opts::object::SectionDependentModules) { // A non-empty section list ensures a valid object file. auto Obj = ModulePtr->GetObjectFile(); FileSpecList Files; auto Count = Obj->GetDependentModules(Files); Printer.formatLine("Showing {0} dependent module(s)", Count); for (size_t I = 0; I < Files.GetSize(); ++I) { AutoIndent Indent(Printer, 2); Printer.formatLine("Name: {0}", Files.GetFileSpecAtIndex(I).GetCString()); } Printer.NewLine(); } } return HadErrors; } bool opts::irmemorymap::evalMalloc(StringRef Line, IRMemoryMapTestState &State) { // ::=