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