1 //===- lldb-test.cpp ------------------------------------------ *- C++ --*-===//
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 #include "FormatUtil.h"
10 #include "SystemInitializerTest.h"
11 
12 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
13 #include "lldb/Breakpoint/BreakpointLocation.h"
14 #include "lldb/Core/Debugger.h"
15 #include "lldb/Core/Module.h"
16 #include "lldb/Core/Section.h"
17 #include "lldb/Expression/IRMemoryMap.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/CompileUnit.h"
23 #include "lldb/Symbol/LineTable.h"
24 #include "lldb/Symbol/SymbolFile.h"
25 #include "lldb/Symbol/TypeList.h"
26 #include "lldb/Symbol/TypeMap.h"
27 #include "lldb/Symbol/VariableList.h"
28 #include "lldb/Target/Language.h"
29 #include "lldb/Target/Process.h"
30 #include "lldb/Target/Target.h"
31 #include "lldb/Utility/DataExtractor.h"
32 #include "lldb/Utility/State.h"
33 #include "lldb/Utility/StreamString.h"
34 
35 #include "llvm/ADT/IntervalMap.h"
36 #include "llvm/ADT/ScopeExit.h"
37 #include "llvm/ADT/StringRef.h"
38 #include "llvm/Support/CommandLine.h"
39 #include "llvm/Support/ManagedStatic.h"
40 #include "llvm/Support/MathExtras.h"
41 #include "llvm/Support/Path.h"
42 #include "llvm/Support/PrettyStackTrace.h"
43 #include "llvm/Support/Signals.h"
44 #include "llvm/Support/WithColor.h"
45 
46 #include <cstdio>
47 #include <thread>
48 
49 using namespace lldb;
50 using namespace lldb_private;
51 using namespace llvm;
52 
53 namespace opts {
54 static cl::SubCommand BreakpointSubcommand("breakpoints",
55                                            "Test breakpoint resolution");
56 cl::SubCommand ObjectFileSubcommand("object-file",
57                                     "Display LLDB object file information");
58 cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file");
59 cl::SubCommand IRMemoryMapSubcommand("ir-memory-map", "Test IRMemoryMap");
60 
61 cl::opt<std::string> Log("log", cl::desc("Path to a log file"), cl::init(""),
62                          cl::sub(BreakpointSubcommand),
63                          cl::sub(ObjectFileSubcommand),
64                          cl::sub(SymbolsSubcommand),
65                          cl::sub(IRMemoryMapSubcommand));
66 
67 /// Create a target using the file pointed to by \p Filename, or abort.
68 TargetSP createTarget(Debugger &Dbg, const std::string &Filename);
69 
70 /// Read \p Filename into a null-terminated buffer, or abort.
71 std::unique_ptr<MemoryBuffer> openFile(const std::string &Filename);
72 
73 namespace breakpoint {
74 static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
75                                    cl::Required, cl::sub(BreakpointSubcommand));
76 static cl::opt<std::string> CommandFile(cl::Positional,
77                                         cl::desc("<command-file>"),
78                                         cl::init("-"),
79                                         cl::sub(BreakpointSubcommand));
80 static cl::opt<bool> Persistent(
81     "persistent",
82     cl::desc("Don't automatically remove all breakpoints before each command"),
83     cl::sub(BreakpointSubcommand));
84 
plural(uintmax_t value)85 static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; }
86 static void dumpState(const BreakpointList &List, LinePrinter &P);
87 static std::string substitute(StringRef Cmd);
88 static int evaluateBreakpoints(Debugger &Dbg);
89 } // namespace breakpoint
90 
91 namespace object {
92 cl::opt<bool> SectionContents("contents",
93                               cl::desc("Dump each section's contents"),
94                               cl::sub(ObjectFileSubcommand));
95 cl::opt<bool> SectionDependentModules("dep-modules",
96                                       cl::desc("Dump each dependent module"),
97                                       cl::sub(ObjectFileSubcommand));
98 cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
99                                      cl::OneOrMore,
100                                      cl::sub(ObjectFileSubcommand));
101 } // namespace object
102 
103 namespace symbols {
104 static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input file>"),
105                                       cl::Required, cl::sub(SymbolsSubcommand));
106 
107 static cl::opt<std::string>
108     SymbolPath("symbol-file",
109                cl::desc("The file from which to fetch symbol information."),
110                cl::value_desc("file"), cl::sub(SymbolsSubcommand));
111 
112 enum class FindType {
113   None,
114   Function,
115   Block,
116   Namespace,
117   Type,
118   Variable,
119 };
120 static cl::opt<FindType> Find(
121     "find", cl::desc("Choose search type:"),
122     cl::values(
123         clEnumValN(FindType::None, "none", "No search, just dump the module."),
124         clEnumValN(FindType::Function, "function", "Find functions."),
125         clEnumValN(FindType::Block, "block", "Find blocks."),
126         clEnumValN(FindType::Namespace, "namespace", "Find namespaces."),
127         clEnumValN(FindType::Type, "type", "Find types."),
128         clEnumValN(FindType::Variable, "variable", "Find global variables.")),
129     cl::sub(SymbolsSubcommand));
130 
131 static cl::opt<std::string> Name("name", cl::desc("Name to find."),
132                                  cl::sub(SymbolsSubcommand));
133 static cl::opt<bool>
134     Regex("regex",
135           cl::desc("Search using regular expressions (avaliable for variables "
136                    "and functions only)."),
137           cl::sub(SymbolsSubcommand));
138 static cl::opt<std::string>
139     Context("context",
140             cl::desc("Restrict search to the context of the given variable."),
141             cl::value_desc("variable"), cl::sub(SymbolsSubcommand));
142 
143 static cl::opt<std::string> CompilerContext(
144     "compiler-context",
145     cl::desc("Specify a compiler context as \"kind:name,...\"."),
146     cl::value_desc("context"), cl::sub(SymbolsSubcommand));
147 
148 static cl::opt<std::string>
149     Language("language", cl::desc("Specify a language type, like C99."),
150              cl::value_desc("language"), cl::sub(SymbolsSubcommand));
151 
152 static cl::list<FunctionNameType> FunctionNameFlags(
153     "function-flags", cl::desc("Function search flags:"),
154     cl::values(clEnumValN(eFunctionNameTypeAuto, "auto",
155                           "Automatically deduce flags based on name."),
156                clEnumValN(eFunctionNameTypeFull, "full", "Full function name."),
157                clEnumValN(eFunctionNameTypeBase, "base", "Base name."),
158                clEnumValN(eFunctionNameTypeMethod, "method", "Method name."),
159                clEnumValN(eFunctionNameTypeSelector, "selector",
160                           "Selector name.")),
161     cl::sub(SymbolsSubcommand));
getFunctionNameFlags()162 static FunctionNameType getFunctionNameFlags() {
163   FunctionNameType Result = FunctionNameType(0);
164   for (FunctionNameType Flag : FunctionNameFlags)
165     Result = FunctionNameType(Result | Flag);
166   return Result;
167 }
168 
169 static cl::opt<bool> DumpAST("dump-ast",
170                              cl::desc("Dump AST restored from symbols."),
171                              cl::sub(SymbolsSubcommand));
172 static cl::opt<bool>
173     DumpClangAST("dump-clang-ast",
174                  cl::desc("Dump clang AST restored from symbols."),
175                  cl::sub(SymbolsSubcommand));
176 
177 static cl::opt<bool> Verify("verify", cl::desc("Verify symbol information."),
178                             cl::sub(SymbolsSubcommand));
179 
180 static cl::opt<std::string> File("file",
181                                  cl::desc("File (compile unit) to search."),
182                                  cl::sub(SymbolsSubcommand));
183 static cl::opt<int> Line("line", cl::desc("Line to search."),
184                          cl::sub(SymbolsSubcommand));
185 
186 static Expected<CompilerDeclContext> getDeclContext(SymbolFile &Symfile);
187 
188 static Error findFunctions(lldb_private::Module &Module);
189 static Error findBlocks(lldb_private::Module &Module);
190 static Error findNamespaces(lldb_private::Module &Module);
191 static Error findTypes(lldb_private::Module &Module);
192 static Error findVariables(lldb_private::Module &Module);
193 static Error dumpModule(lldb_private::Module &Module);
194 static Error dumpAST(lldb_private::Module &Module);
195 static Error dumpClangAST(lldb_private::Module &Module);
196 static Error verify(lldb_private::Module &Module);
197 
198 static Expected<Error (*)(lldb_private::Module &)> getAction();
199 static int dumpSymbols(Debugger &Dbg);
200 } // namespace symbols
201 
202 namespace irmemorymap {
203 static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
204                                    cl::Required,
205                                    cl::sub(IRMemoryMapSubcommand));
206 static cl::opt<std::string> CommandFile(cl::Positional,
207                                         cl::desc("<command-file>"),
208                                         cl::init("-"),
209                                         cl::sub(IRMemoryMapSubcommand));
210 static cl::opt<bool> UseHostOnlyAllocationPolicy(
211     "host-only", cl::desc("Use the host-only allocation policy"),
212     cl::init(false), cl::sub(IRMemoryMapSubcommand));
213 
214 using AllocationT = std::pair<addr_t, addr_t>;
215 using AddrIntervalMap =
216     IntervalMap<addr_t, unsigned, 8, IntervalMapHalfOpenInfo<addr_t>>;
217 
218 struct IRMemoryMapTestState {
219   TargetSP Target;
220   IRMemoryMap Map;
221 
222   AddrIntervalMap::Allocator IntervalMapAllocator;
223   AddrIntervalMap Allocations;
224 
225   StringMap<addr_t> Label2AddrMap;
226 
IRMemoryMapTestStateopts::irmemorymap::IRMemoryMapTestState227   IRMemoryMapTestState(TargetSP Target)
228       : Target(Target), Map(Target), Allocations(IntervalMapAllocator) {}
229 };
230 
231 bool evalMalloc(StringRef Line, IRMemoryMapTestState &State);
232 bool evalFree(StringRef Line, IRMemoryMapTestState &State);
233 int evaluateMemoryMapCommands(Debugger &Dbg);
234 } // namespace irmemorymap
235 
236 } // namespace opts
237 
parseCompilerContext()238 std::vector<CompilerContext> parseCompilerContext() {
239   std::vector<CompilerContext> result;
240   if (opts::symbols::CompilerContext.empty())
241     return result;
242 
243   StringRef str{opts::symbols::CompilerContext};
244   SmallVector<StringRef, 8> entries_str;
245   str.split(entries_str, ',', /*maxSplit*/-1, /*keepEmpty=*/false);
246   for (auto entry_str : entries_str) {
247     StringRef key, value;
248     std::tie(key, value) = entry_str.split(':');
249     auto kind =
250         StringSwitch<CompilerContextKind>(key)
251             .Case("TranslationUnit", CompilerContextKind::TranslationUnit)
252             .Case("Module", CompilerContextKind::Module)
253             .Case("Namespace", CompilerContextKind::Namespace)
254             .Case("Class", CompilerContextKind::Class)
255             .Case("Struct", CompilerContextKind::Struct)
256             .Case("Union", CompilerContextKind::Union)
257             .Case("Function", CompilerContextKind::Function)
258             .Case("Variable", CompilerContextKind::Variable)
259             .Case("Enum", CompilerContextKind::Enum)
260             .Case("Typedef", CompilerContextKind::Typedef)
261             .Case("AnyModule", CompilerContextKind::AnyModule)
262             .Case("AnyType", CompilerContextKind::AnyType)
263             .Default(CompilerContextKind::Invalid);
264     if (value.empty()) {
265       WithColor::error() << "compiler context entry has no \"name\"\n";
266       exit(1);
267     }
268     result.push_back({kind, ConstString{value}});
269   }
270   outs() << "Search context: {\n";
271   for (auto entry: result)
272     entry.Dump();
273   outs() << "}\n";
274 
275   return result;
276 }
277 
278 template <typename... Args>
make_string_error(const char * Format,Args &&...args)279 static Error make_string_error(const char *Format, Args &&... args) {
280   return llvm::make_error<llvm::StringError>(
281       llvm::formatv(Format, std::forward<Args>(args)...).str(),
282       llvm::inconvertibleErrorCode());
283 }
284 
createTarget(Debugger & Dbg,const std::string & Filename)285 TargetSP opts::createTarget(Debugger &Dbg, const std::string &Filename) {
286   TargetSP Target;
287   Status ST = Dbg.GetTargetList().CreateTarget(
288       Dbg, Filename, /*triple*/ "", eLoadDependentsNo,
289       /*platform_options*/ nullptr, Target);
290   if (ST.Fail()) {
291     errs() << formatv("Failed to create target '{0}: {1}\n", Filename, ST);
292     exit(1);
293   }
294   return Target;
295 }
296 
openFile(const std::string & Filename)297 std::unique_ptr<MemoryBuffer> opts::openFile(const std::string &Filename) {
298   auto MB = MemoryBuffer::getFileOrSTDIN(Filename);
299   if (!MB) {
300     errs() << formatv("Could not open file '{0}: {1}\n", Filename,
301                       MB.getError().message());
302     exit(1);
303   }
304   return std::move(*MB);
305 }
306 
dumpState(const BreakpointList & List,LinePrinter & P)307 void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) {
308   P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize()));
309   if (List.GetSize() > 0)
310     P.formatLine("At least one breakpoint.");
311   for (size_t i = 0, e = List.GetSize(); i < e; ++i) {
312     BreakpointSP BP = List.GetBreakpointAtIndex(i);
313     P.formatLine("Breakpoint ID {0}:", BP->GetID());
314     AutoIndent Indent(P, 2);
315     P.formatLine("{0} location{1}.", BP->GetNumLocations(),
316                  plural(BP->GetNumLocations()));
317     if (BP->GetNumLocations() > 0)
318       P.formatLine("At least one location.");
319     P.formatLine("{0} resolved location{1}.", BP->GetNumResolvedLocations(),
320                  plural(BP->GetNumResolvedLocations()));
321     if (BP->GetNumResolvedLocations() > 0)
322       P.formatLine("At least one resolved location.");
323     for (size_t l = 0, le = BP->GetNumLocations(); l < le; ++l) {
324       BreakpointLocationSP Loc = BP->GetLocationAtIndex(l);
325       P.formatLine("Location ID {0}:", Loc->GetID());
326       AutoIndent Indent(P, 2);
327       P.formatLine("Enabled: {0}", Loc->IsEnabled());
328       P.formatLine("Resolved: {0}", Loc->IsResolved());
329       SymbolContext sc;
330       Loc->GetAddress().CalculateSymbolContext(&sc);
331       lldb_private::StreamString S;
332       sc.DumpStopContext(&S, BP->GetTarget().GetProcessSP().get(),
333                          Loc->GetAddress(), false, true, false, true, true);
334       P.formatLine("Address: {0}", S.GetString());
335     }
336   }
337   P.NewLine();
338 }
339 
substitute(StringRef Cmd)340 std::string opts::breakpoint::substitute(StringRef Cmd) {
341   std::string Result;
342   raw_string_ostream OS(Result);
343   while (!Cmd.empty()) {
344     switch (Cmd[0]) {
345     case '%':
346       if (Cmd.consume_front("%p") && (Cmd.empty() || !isalnum(Cmd[0]))) {
347         OS << sys::path::parent_path(breakpoint::CommandFile);
348         break;
349       }
350       LLVM_FALLTHROUGH;
351     default:
352       size_t pos = Cmd.find('%');
353       OS << Cmd.substr(0, pos);
354       Cmd = Cmd.substr(pos);
355       break;
356     }
357   }
358   return std::move(OS.str());
359 }
360 
evaluateBreakpoints(Debugger & Dbg)361 int opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) {
362   TargetSP Target = opts::createTarget(Dbg, breakpoint::Target);
363   std::unique_ptr<MemoryBuffer> MB = opts::openFile(breakpoint::CommandFile);
364 
365   LinePrinter P(4, outs());
366   StringRef Rest = MB->getBuffer();
367   int HadErrors = 0;
368   while (!Rest.empty()) {
369     StringRef Line;
370     std::tie(Line, Rest) = Rest.split('\n');
371     Line = Line.ltrim().rtrim();
372     if (Line.empty() || Line[0] == '#')
373       continue;
374 
375     if (!Persistent)
376       Target->RemoveAllBreakpoints(/*internal_also*/ true);
377 
378     std::string Command = substitute(Line);
379     P.formatLine("Command: {0}", Command);
380     CommandReturnObject Result;
381     if (!Dbg.GetCommandInterpreter().HandleCommand(
382             Command.c_str(), /*add_to_history*/ eLazyBoolNo, Result)) {
383       P.formatLine("Failed: {0}", Result.GetErrorData());
384       HadErrors = 1;
385       continue;
386     }
387 
388     dumpState(Target->GetBreakpointList(/*internal*/ false), P);
389   }
390   return HadErrors;
391 }
392 
393 Expected<CompilerDeclContext>
getDeclContext(SymbolFile & Symfile)394 opts::symbols::getDeclContext(SymbolFile &Symfile) {
395   if (Context.empty())
396     return CompilerDeclContext();
397   VariableList List;
398   Symfile.FindGlobalVariables(ConstString(Context), nullptr, UINT32_MAX, List);
399   if (List.Empty())
400     return make_string_error("Context search didn't find a match.");
401   if (List.GetSize() > 1)
402     return make_string_error("Context search found multiple matches.");
403   return List.GetVariableAtIndex(0)->GetDeclContext();
404 }
405 
findFunctions(lldb_private::Module & Module)406 Error opts::symbols::findFunctions(lldb_private::Module &Module) {
407   SymbolFile &Symfile = *Module.GetSymbolFile();
408   SymbolContextList List;
409   if (!File.empty()) {
410     assert(Line != 0);
411 
412     FileSpec src_file(File);
413     size_t cu_count = Module.GetNumCompileUnits();
414     for (size_t i = 0; i < cu_count; i++) {
415       lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i);
416       if (!cu_sp)
417         continue;
418 
419       LineEntry le;
420       cu_sp->FindLineEntry(0, Line, &src_file, false, &le);
421       if (!le.IsValid())
422         continue;
423       const bool include_inlined_functions = false;
424       auto addr =
425           le.GetSameLineContiguousAddressRange(include_inlined_functions)
426               .GetBaseAddress();
427       if (!addr.IsValid())
428         continue;
429 
430       SymbolContext sc;
431       uint32_t resolved =
432           addr.CalculateSymbolContext(&sc, eSymbolContextFunction);
433       if (resolved & eSymbolContextFunction)
434         List.Append(sc);
435     }
436   } else if (Regex) {
437     RegularExpression RE(Name);
438     assert(RE.IsValid());
439     List.Clear();
440     Symfile.FindFunctions(RE, true, List);
441   } else {
442     Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
443     if (!ContextOr)
444       return ContextOr.takeError();
445     CompilerDeclContext *ContextPtr =
446         ContextOr->IsValid() ? &*ContextOr : nullptr;
447 
448     List.Clear();
449     Symfile.FindFunctions(ConstString(Name), ContextPtr, getFunctionNameFlags(),
450                          true, List);
451   }
452   outs() << formatv("Found {0} functions:\n", List.GetSize());
453   StreamString Stream;
454   List.Dump(&Stream, nullptr);
455   outs() << Stream.GetData() << "\n";
456   return Error::success();
457 }
458 
findBlocks(lldb_private::Module & Module)459 Error opts::symbols::findBlocks(lldb_private::Module &Module) {
460   assert(!Regex);
461   assert(!File.empty());
462   assert(Line != 0);
463 
464   SymbolContextList List;
465 
466   FileSpec src_file(File);
467   size_t cu_count = Module.GetNumCompileUnits();
468   for (size_t i = 0; i < cu_count; i++) {
469     lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i);
470     if (!cu_sp)
471       continue;
472 
473     LineEntry le;
474     cu_sp->FindLineEntry(0, Line, &src_file, false, &le);
475     if (!le.IsValid())
476       continue;
477     const bool include_inlined_functions = false;
478     auto addr = le.GetSameLineContiguousAddressRange(include_inlined_functions)
479                     .GetBaseAddress();
480     if (!addr.IsValid())
481       continue;
482 
483     SymbolContext sc;
484     uint32_t resolved = addr.CalculateSymbolContext(&sc, eSymbolContextBlock);
485     if (resolved & eSymbolContextBlock)
486       List.Append(sc);
487   }
488 
489   outs() << formatv("Found {0} blocks:\n", List.GetSize());
490   StreamString Stream;
491   List.Dump(&Stream, nullptr);
492   outs() << Stream.GetData() << "\n";
493   return Error::success();
494 }
495 
findNamespaces(lldb_private::Module & Module)496 Error opts::symbols::findNamespaces(lldb_private::Module &Module) {
497   SymbolFile &Symfile = *Module.GetSymbolFile();
498   Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
499   if (!ContextOr)
500     return ContextOr.takeError();
501   CompilerDeclContext *ContextPtr =
502       ContextOr->IsValid() ? &*ContextOr : nullptr;
503 
504   CompilerDeclContext Result =
505       Symfile.FindNamespace(ConstString(Name), ContextPtr);
506   if (Result)
507     outs() << "Found namespace: "
508            << Result.GetScopeQualifiedName().GetStringRef() << "\n";
509   else
510     outs() << "Namespace not found.\n";
511   return Error::success();
512 }
513 
findTypes(lldb_private::Module & Module)514 Error opts::symbols::findTypes(lldb_private::Module &Module) {
515   SymbolFile &Symfile = *Module.GetSymbolFile();
516   Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
517   if (!ContextOr)
518     return ContextOr.takeError();
519   CompilerDeclContext *ContextPtr =
520       ContextOr->IsValid() ? &*ContextOr : nullptr;
521 
522   LanguageSet languages;
523   if (!Language.empty())
524     languages.Insert(Language::GetLanguageTypeFromString(Language));
525 
526   DenseSet<SymbolFile *> SearchedFiles;
527   TypeMap Map;
528   if (!Name.empty())
529     Symfile.FindTypes(ConstString(Name), ContextPtr, UINT32_MAX, SearchedFiles,
530                       Map);
531   else
532     Module.FindTypes(parseCompilerContext(), languages, SearchedFiles, Map);
533 
534   outs() << formatv("Found {0} types:\n", Map.GetSize());
535   StreamString Stream;
536   Map.Dump(&Stream, false);
537   outs() << Stream.GetData() << "\n";
538   return Error::success();
539 }
540 
findVariables(lldb_private::Module & Module)541 Error opts::symbols::findVariables(lldb_private::Module &Module) {
542   SymbolFile &Symfile = *Module.GetSymbolFile();
543   VariableList List;
544   if (Regex) {
545     RegularExpression RE(Name);
546     assert(RE.IsValid());
547     Symfile.FindGlobalVariables(RE, UINT32_MAX, List);
548   } else if (!File.empty()) {
549     CompUnitSP CU;
550     for (size_t Ind = 0; !CU && Ind < Module.GetNumCompileUnits(); ++Ind) {
551       CompUnitSP Candidate = Module.GetCompileUnitAtIndex(Ind);
552       if (!Candidate ||
553           Candidate->GetPrimaryFile().GetFilename().GetStringRef() != File)
554         continue;
555       if (CU)
556         return make_string_error("Multiple compile units for file `{0}` found.",
557                                  File);
558       CU = std::move(Candidate);
559     }
560 
561     if (!CU)
562       return make_string_error("Compile unit `{0}` not found.", File);
563 
564     List.AddVariables(CU->GetVariableList(true).get());
565   } else {
566     Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
567     if (!ContextOr)
568       return ContextOr.takeError();
569     CompilerDeclContext *ContextPtr =
570         ContextOr->IsValid() ? &*ContextOr : nullptr;
571 
572     Symfile.FindGlobalVariables(ConstString(Name), ContextPtr, UINT32_MAX, List);
573   }
574   outs() << formatv("Found {0} variables:\n", List.GetSize());
575   StreamString Stream;
576   List.Dump(&Stream, false);
577   outs() << Stream.GetData() << "\n";
578   return Error::success();
579 }
580 
dumpModule(lldb_private::Module & Module)581 Error opts::symbols::dumpModule(lldb_private::Module &Module) {
582   StreamString Stream;
583   Module.ParseAllDebugSymbols();
584   Module.Dump(&Stream);
585   outs() << Stream.GetData() << "\n";
586   return Error::success();
587 }
588 
dumpAST(lldb_private::Module & Module)589 Error opts::symbols::dumpAST(lldb_private::Module &Module) {
590   Module.ParseAllDebugSymbols();
591 
592   SymbolFile *symfile = Module.GetSymbolFile();
593   if (!symfile)
594     return make_string_error("Module has no symbol file.");
595 
596   llvm::Expected<TypeSystem &> type_system_or_err =
597       symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
598   if (!type_system_or_err)
599     return make_string_error("Can't retrieve ClangASTContext");
600 
601   auto *clang_ast_ctx =
602       llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get());
603   if (!clang_ast_ctx)
604     return make_string_error("Retrieved TypeSystem was not a ClangASTContext");
605 
606   clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext();
607 
608   clang::TranslationUnitDecl *tu = ast_ctx.getTranslationUnitDecl();
609   if (!tu)
610     return make_string_error("Can't retrieve translation unit declaration.");
611 
612   tu->print(outs());
613 
614   return Error::success();
615 }
616 
dumpClangAST(lldb_private::Module & Module)617 Error opts::symbols::dumpClangAST(lldb_private::Module &Module) {
618   Module.ParseAllDebugSymbols();
619 
620   SymbolFile *symfile = Module.GetSymbolFile();
621   if (!symfile)
622     return make_string_error("Module has no symbol file.");
623 
624   llvm::Expected<TypeSystem &> type_system_or_err =
625       symfile->GetTypeSystemForLanguage(eLanguageTypeObjC_plus_plus);
626   if (!type_system_or_err)
627     return make_string_error("Can't retrieve ClangASTContext");
628 
629   auto *clang_ast_ctx =
630       llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get());
631   if (!clang_ast_ctx)
632     return make_string_error("Retrieved TypeSystem was not a ClangASTContext");
633 
634   StreamString Stream;
635   clang_ast_ctx->DumpFromSymbolFile(Stream, Name);
636   outs() << Stream.GetData() << "\n";
637 
638   return Error::success();
639 }
640 
verify(lldb_private::Module & Module)641 Error opts::symbols::verify(lldb_private::Module &Module) {
642   SymbolFile *symfile = Module.GetSymbolFile();
643   if (!symfile)
644     return make_string_error("Module has no symbol file.");
645 
646   uint32_t comp_units_count = symfile->GetNumCompileUnits();
647 
648   outs() << "Found " << comp_units_count << " compile units.\n";
649 
650   for (uint32_t i = 0; i < comp_units_count; i++) {
651     lldb::CompUnitSP comp_unit = symfile->GetCompileUnitAtIndex(i);
652     if (!comp_unit)
653       return make_string_error("Connot parse compile unit {0}.", i);
654 
655     outs() << "Processing '"
656            << comp_unit->GetPrimaryFile().GetFilename().AsCString()
657            << "' compile unit.\n";
658 
659     LineTable *lt = comp_unit->GetLineTable();
660     if (!lt)
661       return make_string_error("Can't get a line table of a compile unit.");
662 
663     uint32_t count = lt->GetSize();
664 
665     outs() << "The line table contains " << count << " entries.\n";
666 
667     if (count == 0)
668       continue;
669 
670     LineEntry le;
671     if (!lt->GetLineEntryAtIndex(0, le))
672       return make_string_error("Can't get a line entry of a compile unit.");
673 
674     for (uint32_t i = 1; i < count; i++) {
675       lldb::addr_t curr_end =
676           le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize();
677 
678       if (!lt->GetLineEntryAtIndex(i, le))
679         return make_string_error("Can't get a line entry of a compile unit");
680 
681       if (curr_end > le.range.GetBaseAddress().GetFileAddress())
682         return make_string_error(
683             "Line table of a compile unit is inconsistent.");
684     }
685   }
686 
687   outs() << "The symbol information is verified.\n";
688 
689   return Error::success();
690 }
691 
getAction()692 Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
693   if (Verify && DumpAST)
694     return make_string_error(
695         "Cannot both verify symbol information and dump AST.");
696 
697   if (Verify) {
698     if (Find != FindType::None)
699       return make_string_error(
700           "Cannot both search and verify symbol information.");
701     if (Regex || !Context.empty() || !Name.empty() || !File.empty() ||
702         Line != 0)
703       return make_string_error(
704           "-regex, -context, -name, -file and -line options are not "
705           "applicable for symbol verification.");
706     return verify;
707   }
708 
709   if (DumpAST) {
710     if (Find != FindType::None)
711       return make_string_error("Cannot both search and dump AST.");
712     if (Regex || !Context.empty() || !Name.empty() || !File.empty() ||
713         Line != 0)
714       return make_string_error(
715           "-regex, -context, -name, -file and -line options are not "
716           "applicable for dumping AST.");
717     return dumpAST;
718   }
719 
720   if (DumpClangAST) {
721     if (Find != FindType::None)
722       return make_string_error("Cannot both search and dump clang AST.");
723     if (Regex || !Context.empty() || !File.empty() || Line != 0)
724       return make_string_error(
725           "-regex, -context, -name, -file and -line options are not "
726           "applicable for dumping clang AST.");
727     return dumpClangAST;
728   }
729 
730   if (Regex && !Context.empty())
731     return make_string_error(
732         "Cannot search using both regular expressions and context.");
733 
734   if (Regex && !RegularExpression(Name).IsValid())
735     return make_string_error("`{0}` is not a valid regular expression.", Name);
736 
737   if (Regex + !Context.empty() + !File.empty() >= 2)
738     return make_string_error(
739         "Only one of -regex, -context and -file may be used simultaneously.");
740   if (Regex && Name.empty())
741     return make_string_error("-regex used without a -name");
742 
743   switch (Find) {
744   case FindType::None:
745     if (!Context.empty() || !Name.empty() || !File.empty() || Line != 0)
746       return make_string_error(
747           "Specify search type (-find) to use search options.");
748     return dumpModule;
749 
750   case FindType::Function:
751     if (!File.empty() + (Line != 0) == 1)
752       return make_string_error("Both file name and line number must be "
753                                "specified when searching a function "
754                                "by file position.");
755     if (Regex + (getFunctionNameFlags() != 0) + !File.empty() >= 2)
756       return make_string_error("Only one of regular expression, function-flags "
757                                "and file position may be used simultaneously "
758                                "when searching a function.");
759     return findFunctions;
760 
761   case FindType::Block:
762     if (File.empty() || Line == 0)
763       return make_string_error("Both file name and line number must be "
764                                "specified when searching a block.");
765     if (Regex || getFunctionNameFlags() != 0)
766       return make_string_error("Cannot use regular expression or "
767                                "function-flags for searching a block.");
768     return findBlocks;
769 
770   case FindType::Namespace:
771     if (Regex || !File.empty() || Line != 0)
772       return make_string_error("Cannot search for namespaces using regular "
773                                "expressions, file names or line numbers.");
774     return findNamespaces;
775 
776   case FindType::Type:
777     if (Regex || !File.empty() || Line != 0)
778       return make_string_error("Cannot search for types using regular "
779                                "expressions, file names or line numbers.");
780     if (!Name.empty() && !CompilerContext.empty())
781       return make_string_error("Name is ignored if compiler context present.");
782 
783     return findTypes;
784 
785   case FindType::Variable:
786     if (Line != 0)
787       return make_string_error("Cannot search for variables "
788                                "using line numbers.");
789     return findVariables;
790   }
791 
792   llvm_unreachable("Unsupported symbol action.");
793 }
794 
dumpSymbols(Debugger & Dbg)795 int opts::symbols::dumpSymbols(Debugger &Dbg) {
796   auto ActionOr = getAction();
797   if (!ActionOr) {
798     logAllUnhandledErrors(ActionOr.takeError(), WithColor::error(), "");
799     return 1;
800   }
801   auto Action = *ActionOr;
802 
803   outs() << "Module: " << InputFile << "\n";
804   ModuleSpec Spec{FileSpec(InputFile)};
805   StringRef Symbols = SymbolPath.empty() ? InputFile : SymbolPath;
806   Spec.GetSymbolFileSpec().SetFile(Symbols, FileSpec::Style::native);
807 
808   auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
809   SymbolFile *Symfile = ModulePtr->GetSymbolFile();
810   if (!Symfile) {
811     WithColor::error() << "Module has no symbol vendor.\n";
812     return 1;
813   }
814 
815   if (Error E = Action(*ModulePtr)) {
816     WithColor::error() << toString(std::move(E)) << "\n";
817     return 1;
818   }
819 
820   return 0;
821 }
822 
dumpSectionList(LinePrinter & Printer,const SectionList & List,bool is_subsection)823 static void dumpSectionList(LinePrinter &Printer, const SectionList &List, bool is_subsection) {
824   size_t Count = List.GetNumSections(0);
825   if (Count == 0) {
826     Printer.formatLine("There are no {0}sections", is_subsection ? "sub" : "");
827     return;
828   }
829   Printer.formatLine("Showing {0} {1}sections", Count,
830                      is_subsection ? "sub" : "");
831   for (size_t I = 0; I < Count; ++I) {
832     auto S = List.GetSectionAtIndex(I);
833     assert(S);
834     AutoIndent Indent(Printer, 2);
835     Printer.formatLine("Index: {0}", I);
836     Printer.formatLine("ID: {0:x}", S->GetID());
837     Printer.formatLine("Name: {0}", S->GetName().GetStringRef());
838     Printer.formatLine("Type: {0}", S->GetTypeAsCString());
839     Printer.formatLine("Permissions: {0}", GetPermissionsAsCString(S->GetPermissions()));
840     Printer.formatLine("Thread specific: {0:y}", S->IsThreadSpecific());
841     Printer.formatLine("VM address: {0:x}", S->GetFileAddress());
842     Printer.formatLine("VM size: {0}", S->GetByteSize());
843     Printer.formatLine("File size: {0}", S->GetFileSize());
844 
845     if (opts::object::SectionContents) {
846       lldb_private::DataExtractor Data;
847       S->GetSectionData(Data);
848       ArrayRef<uint8_t> Bytes = {Data.GetDataStart(), Data.GetDataEnd()};
849       Printer.formatBinary("Data: ", Bytes, 0);
850     }
851 
852     if (S->GetType() == eSectionTypeContainer)
853       dumpSectionList(Printer, S->GetChildren(), true);
854     Printer.NewLine();
855   }
856 }
857 
dumpObjectFiles(Debugger & Dbg)858 static int dumpObjectFiles(Debugger &Dbg) {
859   LinePrinter Printer(4, llvm::outs());
860 
861   int HadErrors = 0;
862   for (const auto &File : opts::object::InputFilenames) {
863     ModuleSpec Spec{FileSpec(File)};
864 
865     auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
866 
867     ObjectFile *ObjectPtr = ModulePtr->GetObjectFile();
868     if (!ObjectPtr) {
869       WithColor::error() << File << " not recognised as an object file\n";
870       HadErrors = 1;
871       continue;
872     }
873 
874     // Fetch symbol vendor before we get the section list to give the symbol
875     // vendor a chance to populate it.
876     ModulePtr->GetSymbolFile();
877     SectionList *Sections = ModulePtr->GetSectionList();
878     if (!Sections) {
879       llvm::errs() << "Could not load sections for module " << File << "\n";
880       HadErrors = 1;
881       continue;
882     }
883 
884     Printer.formatLine("Plugin name: {0}", ObjectPtr->GetPluginName());
885     Printer.formatLine("Architecture: {0}",
886                        ModulePtr->GetArchitecture().GetTriple().getTriple());
887     Printer.formatLine("UUID: {0}", ModulePtr->GetUUID().GetAsString());
888     Printer.formatLine("Executable: {0}", ObjectPtr->IsExecutable());
889     Printer.formatLine("Stripped: {0}", ObjectPtr->IsStripped());
890     Printer.formatLine("Type: {0}", ObjectPtr->GetType());
891     Printer.formatLine("Strata: {0}", ObjectPtr->GetStrata());
892     Printer.formatLine("Base VM address: {0:x}",
893                        ObjectPtr->GetBaseAddress().GetFileAddress());
894 
895     dumpSectionList(Printer, *Sections, /*is_subsection*/ false);
896 
897     if (opts::object::SectionDependentModules) {
898       // A non-empty section list ensures a valid object file.
899       auto Obj = ModulePtr->GetObjectFile();
900       FileSpecList Files;
901       auto Count = Obj->GetDependentModules(Files);
902       Printer.formatLine("Showing {0} dependent module(s)", Count);
903       for (size_t I = 0; I < Files.GetSize(); ++I) {
904         AutoIndent Indent(Printer, 2);
905         Printer.formatLine("Name: {0}",
906                            Files.GetFileSpecAtIndex(I).GetCString());
907       }
908       Printer.NewLine();
909     }
910   }
911   return HadErrors;
912 }
913 
evalMalloc(StringRef Line,IRMemoryMapTestState & State)914 bool opts::irmemorymap::evalMalloc(StringRef Line,
915                                    IRMemoryMapTestState &State) {
916   // ::= <label> = malloc <size> <alignment>
917   StringRef Label;
918   std::tie(Label, Line) = Line.split('=');
919   if (Line.empty())
920     return false;
921   Label = Label.trim();
922   Line = Line.trim();
923   size_t Size;
924   uint8_t Alignment;
925   int Matches = sscanf(Line.data(), "malloc %zu %hhu", &Size, &Alignment);
926   if (Matches != 2)
927     return false;
928 
929   outs() << formatv("Command: {0} = malloc(size={1}, alignment={2})\n", Label,
930                     Size, Alignment);
931   if (!isPowerOf2_32(Alignment)) {
932     outs() << "Malloc error: alignment is not a power of 2\n";
933     exit(1);
934   }
935 
936   IRMemoryMap::AllocationPolicy AP =
937       UseHostOnlyAllocationPolicy ? IRMemoryMap::eAllocationPolicyHostOnly
938                                   : IRMemoryMap::eAllocationPolicyProcessOnly;
939 
940   // Issue the malloc in the target process with "-rw" permissions.
941   const uint32_t Permissions = 0x3;
942   const bool ZeroMemory = false;
943   Status ST;
944   addr_t Addr =
945       State.Map.Malloc(Size, Alignment, Permissions, AP, ZeroMemory, ST);
946   if (ST.Fail()) {
947     outs() << formatv("Malloc error: {0}\n", ST);
948     return true;
949   }
950 
951   // Print the result of the allocation before checking its validity.
952   outs() << formatv("Malloc: address = {0:x}\n", Addr);
953 
954   // Check that the allocation is aligned.
955   if (!Addr || Addr % Alignment != 0) {
956     outs() << "Malloc error: zero or unaligned allocation detected\n";
957     exit(1);
958   }
959 
960   // In case of Size == 0, we still expect the returned address to be unique and
961   // non-overlapping.
962   addr_t EndOfRegion = Addr + std::max<size_t>(Size, 1);
963   if (State.Allocations.overlaps(Addr, EndOfRegion)) {
964     auto I = State.Allocations.find(Addr);
965     outs() << "Malloc error: overlapping allocation detected"
966            << formatv(", previous allocation at [{0:x}, {1:x})\n", I.start(),
967                       I.stop());
968     exit(1);
969   }
970 
971   // Insert the new allocation into the interval map. Use unique allocation
972   // IDs to inhibit interval coalescing.
973   static unsigned AllocationID = 0;
974   State.Allocations.insert(Addr, EndOfRegion, AllocationID++);
975 
976   // Store the label -> address mapping.
977   State.Label2AddrMap[Label] = Addr;
978 
979   return true;
980 }
981 
evalFree(StringRef Line,IRMemoryMapTestState & State)982 bool opts::irmemorymap::evalFree(StringRef Line, IRMemoryMapTestState &State) {
983   // ::= free <label>
984   if (!Line.consume_front("free"))
985     return false;
986   StringRef Label = Line.trim();
987 
988   outs() << formatv("Command: free({0})\n", Label);
989   auto LabelIt = State.Label2AddrMap.find(Label);
990   if (LabelIt == State.Label2AddrMap.end()) {
991     outs() << "Free error: Invalid allocation label\n";
992     exit(1);
993   }
994 
995   Status ST;
996   addr_t Addr = LabelIt->getValue();
997   State.Map.Free(Addr, ST);
998   if (ST.Fail()) {
999     outs() << formatv("Free error: {0}\n", ST);
1000     exit(1);
1001   }
1002 
1003   // Erase the allocation from the live interval map.
1004   auto Interval = State.Allocations.find(Addr);
1005   if (Interval != State.Allocations.end()) {
1006     outs() << formatv("Free: [{0:x}, {1:x})\n", Interval.start(),
1007                       Interval.stop());
1008     Interval.erase();
1009   }
1010 
1011   return true;
1012 }
1013 
evaluateMemoryMapCommands(Debugger & Dbg)1014 int opts::irmemorymap::evaluateMemoryMapCommands(Debugger &Dbg) {
1015   // Set up a Target.
1016   TargetSP Target = opts::createTarget(Dbg, irmemorymap::Target);
1017 
1018   // Set up a Process. In order to allocate memory within a target, this
1019   // process must be alive and must support JIT'ing.
1020   CommandReturnObject Result;
1021   Dbg.SetAsyncExecution(false);
1022   CommandInterpreter &CI = Dbg.GetCommandInterpreter();
1023   auto IssueCmd = [&](const char *Cmd) -> bool {
1024     return CI.HandleCommand(Cmd, eLazyBoolNo, Result);
1025   };
1026   if (!IssueCmd("b main") || !IssueCmd("run")) {
1027     outs() << formatv("Failed: {0}\n", Result.GetErrorData());
1028     exit(1);
1029   }
1030 
1031   ProcessSP Process = Target->GetProcessSP();
1032   if (!Process || !Process->IsAlive() || !Process->CanJIT()) {
1033     outs() << "Cannot use process to test IRMemoryMap\n";
1034     exit(1);
1035   }
1036 
1037   // Set up an IRMemoryMap and associated testing state.
1038   IRMemoryMapTestState State(Target);
1039 
1040   // Parse and apply commands from the command file.
1041   std::unique_ptr<MemoryBuffer> MB = opts::openFile(irmemorymap::CommandFile);
1042   StringRef Rest = MB->getBuffer();
1043   while (!Rest.empty()) {
1044     StringRef Line;
1045     std::tie(Line, Rest) = Rest.split('\n');
1046     Line = Line.ltrim().rtrim();
1047 
1048     if (Line.empty() || Line[0] == '#')
1049       continue;
1050 
1051     if (evalMalloc(Line, State))
1052       continue;
1053 
1054     if (evalFree(Line, State))
1055       continue;
1056 
1057     errs() << "Could not parse line: " << Line << "\n";
1058     exit(1);
1059   }
1060   return 0;
1061 }
1062 
main(int argc,const char * argv[])1063 int main(int argc, const char *argv[]) {
1064   StringRef ToolName = argv[0];
1065   sys::PrintStackTraceOnErrorSignal(ToolName);
1066   PrettyStackTraceProgram X(argc, argv);
1067   llvm_shutdown_obj Y;
1068 
1069   cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
1070 
1071   SystemLifetimeManager DebuggerLifetime;
1072   if (auto e = DebuggerLifetime.Initialize(
1073           std::make_unique<SystemInitializerTest>(), nullptr)) {
1074     WithColor::error() << "initialization failed: " << toString(std::move(e))
1075                        << '\n';
1076     return 1;
1077   }
1078 
1079   auto TerminateDebugger =
1080       llvm::make_scope_exit([&] { DebuggerLifetime.Terminate(); });
1081 
1082   auto Dbg = lldb_private::Debugger::CreateInstance();
1083   ModuleList::GetGlobalModuleListProperties().SetEnableExternalLookup(false);
1084   CommandReturnObject Result;
1085   Dbg->GetCommandInterpreter().HandleCommand(
1086       "settings set plugin.process.gdb-remote.packet-timeout 60",
1087       /*add_to_history*/ eLazyBoolNo, Result);
1088 
1089   if (!opts::Log.empty())
1090     Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, errs());
1091 
1092   if (opts::BreakpointSubcommand)
1093     return opts::breakpoint::evaluateBreakpoints(*Dbg);
1094   if (opts::ObjectFileSubcommand)
1095     return dumpObjectFiles(*Dbg);
1096   if (opts::SymbolsSubcommand)
1097     return opts::symbols::dumpSymbols(*Dbg);
1098   if (opts::IRMemoryMapSubcommand)
1099     return opts::irmemorymap::evaluateMemoryMapCommands(*Dbg);
1100 
1101   WithColor::error() << "No command specified.\n";
1102   return 1;
1103 }
1104