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

source code of lldb/tools/lldb-test/lldb-test.cpp