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