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