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