1 //===- lldb-test.cpp ------------------------------------------ *- C++ --*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "FormatUtil.h" 11 #include "SystemInitializerTest.h" 12 13 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" 14 #include "lldb/Breakpoint/BreakpointLocation.h" 15 #include "lldb/Core/Debugger.h" 16 #include "lldb/Core/Module.h" 17 #include "lldb/Core/Section.h" 18 #include "lldb/Initialization/SystemLifetimeManager.h" 19 #include "lldb/Interpreter/CommandInterpreter.h" 20 #include "lldb/Interpreter/CommandReturnObject.h" 21 #include "lldb/Symbol/ClangASTContext.h" 22 #include "lldb/Symbol/ClangASTImporter.h" 23 #include "lldb/Utility/DataExtractor.h" 24 #include "lldb/Utility/StreamString.h" 25 26 #include "llvm/ADT/StringRef.h" 27 #include "llvm/Support/CommandLine.h" 28 #include "llvm/Support/ManagedStatic.h" 29 #include "llvm/Support/Path.h" 30 #include "llvm/Support/PrettyStackTrace.h" 31 #include "llvm/Support/Signals.h" 32 #include <thread> 33 34 using namespace lldb; 35 using namespace lldb_private; 36 using namespace llvm; 37 38 namespace opts { 39 static cl::SubCommand BreakpointSubcommand("breakpoints", 40 "Test breakpoint resolution"); 41 cl::SubCommand ModuleSubcommand("module-sections", 42 "Display LLDB Module Information"); 43 cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file"); 44 45 namespace breakpoint { 46 static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"), 47 cl::Required, cl::sub(BreakpointSubcommand)); 48 static cl::opt<std::string> CommandFile(cl::Positional, 49 cl::desc("<command-file>"), 50 cl::init("-"), 51 cl::sub(BreakpointSubcommand)); 52 static cl::opt<bool> Persistent( 53 "persistent", 54 cl::desc("Don't automatically remove all breakpoints before each command"), 55 cl::sub(BreakpointSubcommand)); 56 57 static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; } 58 static void dumpState(const BreakpointList &List, LinePrinter &P); 59 static std::string substitute(StringRef Cmd); 60 static void evaluateBreakpoints(Debugger &Dbg); 61 } // namespace breakpoint 62 63 namespace module { 64 cl::opt<bool> SectionContents("contents", 65 cl::desc("Dump each section's contents"), 66 cl::sub(ModuleSubcommand)); 67 cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"), 68 cl::OneOrMore, cl::sub(ModuleSubcommand)); 69 } // namespace module 70 71 namespace symbols { 72 cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"), 73 cl::OneOrMore, cl::sub(SymbolsSubcommand)); 74 } 75 } // namespace opts 76 77 static llvm::ManagedStatic<SystemLifetimeManager> DebuggerLifetime; 78 79 void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) { 80 P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize())); 81 if (List.GetSize() > 0) 82 P.formatLine("At least one breakpoint."); 83 for (size_t i = 0, e = List.GetSize(); i < e; ++i) { 84 BreakpointSP BP = List.GetBreakpointAtIndex(i); 85 P.formatLine("Breakpoint ID {0}:", BP->GetID()); 86 AutoIndent Indent(P, 2); 87 P.formatLine("{0} location{1}.", BP->GetNumLocations(), 88 plural(BP->GetNumLocations())); 89 if (BP->GetNumLocations() > 0) 90 P.formatLine("At least one location."); 91 P.formatLine("{0} resolved location{1}.", BP->GetNumResolvedLocations(), 92 plural(BP->GetNumResolvedLocations())); 93 if (BP->GetNumResolvedLocations() > 0) 94 P.formatLine("At least one resolved location."); 95 for (size_t l = 0, le = BP->GetNumLocations(); l < le; ++l) { 96 BreakpointLocationSP Loc = BP->GetLocationAtIndex(l); 97 P.formatLine("Location ID {0}:", Loc->GetID()); 98 AutoIndent Indent(P, 2); 99 P.formatLine("Enabled: {0}", Loc->IsEnabled()); 100 P.formatLine("Resolved: {0}", Loc->IsResolved()); 101 SymbolContext sc; 102 Loc->GetAddress().CalculateSymbolContext(&sc); 103 lldb_private::StreamString S; 104 sc.DumpStopContext(&S, BP->GetTarget().GetProcessSP().get(), 105 Loc->GetAddress(), false, true, false, true, true); 106 P.formatLine("Address: {0}", S.GetString()); 107 } 108 } 109 P.NewLine(); 110 } 111 112 std::string opts::breakpoint::substitute(StringRef Cmd) { 113 std::string Result; 114 raw_string_ostream OS(Result); 115 while (!Cmd.empty()) { 116 switch (Cmd[0]) { 117 case '%': 118 if (Cmd.consume_front("%p") && (Cmd.empty() || !isalnum(Cmd[0]))) { 119 OS << sys::path::parent_path(CommandFile); 120 break; 121 } 122 // fall through 123 default: 124 size_t pos = Cmd.find('%'); 125 OS << Cmd.substr(0, pos); 126 Cmd = Cmd.substr(pos); 127 break; 128 } 129 } 130 return std::move(OS.str()); 131 } 132 133 void opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) { 134 TargetSP Target; 135 Status ST = 136 Dbg.GetTargetList().CreateTarget(Dbg, breakpoint::Target, /*triple*/ "", 137 /*get_dependent_modules*/ false, 138 /*platform_options*/ nullptr, Target); 139 if (ST.Fail()) { 140 errs() << formatv("Failed to create target '{0}: {1}\n", breakpoint::Target, 141 ST); 142 exit(1); 143 } 144 145 auto MB = MemoryBuffer::getFileOrSTDIN(CommandFile); 146 if (!MB) { 147 errs() << formatv("Could not open file '{0}: {1}\n", CommandFile, 148 MB.getError().message()); 149 exit(1); 150 } 151 152 LinePrinter P(4, outs()); 153 StringRef Rest = (*MB)->getBuffer(); 154 while (!Rest.empty()) { 155 StringRef Line; 156 std::tie(Line, Rest) = Rest.split('\n'); 157 Line = Line.ltrim(); 158 if (Line.empty() || Line[0] == '#') 159 continue; 160 161 if (!Persistent) 162 Target->RemoveAllBreakpoints(/*internal_also*/ true); 163 164 std::string Command = substitute(Line); 165 P.formatLine("Command: {0}", Command); 166 CommandReturnObject Result; 167 if (!Dbg.GetCommandInterpreter().HandleCommand( 168 Command.c_str(), /*add_to_history*/ eLazyBoolNo, Result)) { 169 P.formatLine("Failed: {0}", Result.GetErrorData()); 170 continue; 171 } 172 173 dumpState(Target->GetBreakpointList(/*internal*/ false), P); 174 } 175 } 176 177 static void dumpSymbols(Debugger &Dbg) { 178 for (const auto &File : opts::symbols::InputFilenames) { 179 ModuleSpec Spec{FileSpec(File, false)}; 180 Spec.GetSymbolFileSpec().SetFile(File, false); 181 182 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); 183 184 StreamString Stream; 185 ModulePtr->ParseAllDebugSymbols(); 186 ModulePtr->Dump(&Stream); 187 llvm::outs() << Stream.GetData() << "\n"; 188 llvm::outs().flush(); 189 } 190 } 191 192 static void dumpModules(Debugger &Dbg) { 193 LinePrinter Printer(4, llvm::outs()); 194 195 for (const auto &File : opts::module::InputFilenames) { 196 ModuleSpec Spec{FileSpec(File, false)}; 197 198 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); 199 // Fetch symbol vendor before we get the section list to give the symbol 200 // vendor a chance to populate it. 201 ModulePtr->GetSymbolVendor(); 202 SectionList *Sections = ModulePtr->GetSectionList(); 203 if (!Sections) { 204 llvm::errs() << "Could not load sections for module " << File << "\n"; 205 continue; 206 } 207 208 size_t Count = Sections->GetNumSections(0); 209 Printer.formatLine("Showing {0} sections", Count); 210 for (size_t I = 0; I < Count; ++I) { 211 AutoIndent Indent(Printer, 2); 212 auto S = Sections->GetSectionAtIndex(I); 213 assert(S); 214 Printer.formatLine("Index: {0}", I); 215 Printer.formatLine("Name: {0}", S->GetName().GetStringRef()); 216 Printer.formatLine("VM size: {0}", S->GetByteSize()); 217 Printer.formatLine("File size: {0}", S->GetFileSize()); 218 219 if (opts::module::SectionContents) { 220 DataExtractor Data; 221 S->GetSectionData(Data); 222 ArrayRef<uint8_t> Bytes = {Data.GetDataStart(), Data.GetDataEnd()}; 223 Printer.formatBinary("Data: ", Bytes, 0); 224 } 225 Printer.NewLine(); 226 } 227 } 228 } 229 230 int main(int argc, const char *argv[]) { 231 StringRef ToolName = argv[0]; 232 sys::PrintStackTraceOnErrorSignal(ToolName); 233 PrettyStackTraceProgram X(argc, argv); 234 llvm_shutdown_obj Y; 235 236 cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n"); 237 238 DebuggerLifetime->Initialize(llvm::make_unique<SystemInitializerTest>(), 239 nullptr); 240 241 auto Dbg = lldb_private::Debugger::CreateInstance(); 242 243 if (opts::BreakpointSubcommand) 244 opts::breakpoint::evaluateBreakpoints(*Dbg); 245 if (opts::ModuleSubcommand) 246 dumpModules(*Dbg); 247 else if (opts::SymbolsSubcommand) 248 dumpSymbols(*Dbg); 249 250 DebuggerLifetime->Terminate(); 251 return 0; 252 } 253