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