1061da546Spatrick //===- lldb-test.cpp ------------------------------------------ *- C++ --*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "FormatUtil.h"
10061da546Spatrick #include "SystemInitializerTest.h"
11061da546Spatrick
12061da546Spatrick #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
13dda28197Spatrick #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
14061da546Spatrick #include "lldb/Breakpoint/BreakpointLocation.h"
15061da546Spatrick #include "lldb/Core/Debugger.h"
16061da546Spatrick #include "lldb/Core/Module.h"
17061da546Spatrick #include "lldb/Core/Section.h"
18061da546Spatrick #include "lldb/Expression/IRMemoryMap.h"
19061da546Spatrick #include "lldb/Initialization/SystemLifetimeManager.h"
20061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
21061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
22061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
23061da546Spatrick #include "lldb/Symbol/LineTable.h"
24061da546Spatrick #include "lldb/Symbol/SymbolFile.h"
25*f6aab3d8Srobert #include "lldb/Symbol/Symtab.h"
26061da546Spatrick #include "lldb/Symbol/TypeList.h"
27061da546Spatrick #include "lldb/Symbol/TypeMap.h"
28061da546Spatrick #include "lldb/Symbol/VariableList.h"
29061da546Spatrick #include "lldb/Target/Language.h"
30061da546Spatrick #include "lldb/Target/Process.h"
31061da546Spatrick #include "lldb/Target/Target.h"
32061da546Spatrick #include "lldb/Utility/DataExtractor.h"
33be691f3bSpatrick #include "lldb/Utility/LLDBAssert.h"
34061da546Spatrick #include "lldb/Utility/State.h"
35061da546Spatrick #include "lldb/Utility/StreamString.h"
36061da546Spatrick
37061da546Spatrick #include "llvm/ADT/IntervalMap.h"
38061da546Spatrick #include "llvm/ADT/ScopeExit.h"
39061da546Spatrick #include "llvm/ADT/StringRef.h"
40061da546Spatrick #include "llvm/Support/CommandLine.h"
41061da546Spatrick #include "llvm/Support/ManagedStatic.h"
42061da546Spatrick #include "llvm/Support/MathExtras.h"
43061da546Spatrick #include "llvm/Support/Path.h"
44061da546Spatrick #include "llvm/Support/PrettyStackTrace.h"
45061da546Spatrick #include "llvm/Support/Signals.h"
46061da546Spatrick #include "llvm/Support/WithColor.h"
47061da546Spatrick
48061da546Spatrick #include <cstdio>
49*f6aab3d8Srobert #include <optional>
50061da546Spatrick #include <thread>
51061da546Spatrick
52061da546Spatrick using namespace lldb;
53061da546Spatrick using namespace lldb_private;
54061da546Spatrick using namespace llvm;
55061da546Spatrick
56061da546Spatrick namespace opts {
57061da546Spatrick static cl::SubCommand BreakpointSubcommand("breakpoints",
58061da546Spatrick "Test breakpoint resolution");
59061da546Spatrick cl::SubCommand ObjectFileSubcommand("object-file",
60061da546Spatrick "Display LLDB object file information");
61061da546Spatrick cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file");
62*f6aab3d8Srobert cl::SubCommand SymTabSubcommand("symtab",
63*f6aab3d8Srobert "Test symbol table functionality");
64061da546Spatrick cl::SubCommand IRMemoryMapSubcommand("ir-memory-map", "Test IRMemoryMap");
65be691f3bSpatrick cl::SubCommand AssertSubcommand("assert", "Test assert handling");
66061da546Spatrick
67061da546Spatrick cl::opt<std::string> Log("log", cl::desc("Path to a log file"), cl::init(""),
68061da546Spatrick cl::sub(BreakpointSubcommand),
69061da546Spatrick cl::sub(ObjectFileSubcommand),
70061da546Spatrick cl::sub(SymbolsSubcommand),
71*f6aab3d8Srobert cl::sub(SymTabSubcommand),
72061da546Spatrick cl::sub(IRMemoryMapSubcommand));
73061da546Spatrick
74061da546Spatrick /// Create a target using the file pointed to by \p Filename, or abort.
75061da546Spatrick TargetSP createTarget(Debugger &Dbg, const std::string &Filename);
76061da546Spatrick
77061da546Spatrick /// Read \p Filename into a null-terminated buffer, or abort.
78061da546Spatrick std::unique_ptr<MemoryBuffer> openFile(const std::string &Filename);
79061da546Spatrick
80061da546Spatrick namespace breakpoint {
81061da546Spatrick static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
82061da546Spatrick cl::Required, cl::sub(BreakpointSubcommand));
83061da546Spatrick static cl::opt<std::string> CommandFile(cl::Positional,
84061da546Spatrick cl::desc("<command-file>"),
85061da546Spatrick cl::init("-"),
86061da546Spatrick cl::sub(BreakpointSubcommand));
87061da546Spatrick static cl::opt<bool> Persistent(
88061da546Spatrick "persistent",
89061da546Spatrick cl::desc("Don't automatically remove all breakpoints before each command"),
90061da546Spatrick cl::sub(BreakpointSubcommand));
91061da546Spatrick
plural(uintmax_t value)92061da546Spatrick static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; }
93061da546Spatrick static void dumpState(const BreakpointList &List, LinePrinter &P);
94061da546Spatrick static std::string substitute(StringRef Cmd);
95061da546Spatrick static int evaluateBreakpoints(Debugger &Dbg);
96061da546Spatrick } // namespace breakpoint
97061da546Spatrick
98061da546Spatrick namespace object {
99061da546Spatrick cl::opt<bool> SectionContents("contents",
100061da546Spatrick cl::desc("Dump each section's contents"),
101061da546Spatrick cl::sub(ObjectFileSubcommand));
102061da546Spatrick cl::opt<bool> SectionDependentModules("dep-modules",
103061da546Spatrick cl::desc("Dump each dependent module"),
104061da546Spatrick cl::sub(ObjectFileSubcommand));
105061da546Spatrick cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
106061da546Spatrick cl::OneOrMore,
107061da546Spatrick cl::sub(ObjectFileSubcommand));
108061da546Spatrick } // namespace object
109061da546Spatrick
110*f6aab3d8Srobert namespace symtab {
111*f6aab3d8Srobert
112*f6aab3d8Srobert /// The same enum as Mangled::NamePreference but with a default
113*f6aab3d8Srobert /// 'None' case. This is needed to disambiguate wheter "ManglingPreference" was
114*f6aab3d8Srobert /// explicitly set or not.
115*f6aab3d8Srobert enum class ManglingPreference {
116*f6aab3d8Srobert None,
117*f6aab3d8Srobert Mangled,
118*f6aab3d8Srobert Demangled,
119*f6aab3d8Srobert MangledWithoutArguments,
120*f6aab3d8Srobert };
121*f6aab3d8Srobert
122*f6aab3d8Srobert static cl::opt<std::string> FindSymbolsByRegex(
123*f6aab3d8Srobert "find-symbols-by-regex",
124*f6aab3d8Srobert cl::desc(
125*f6aab3d8Srobert "Dump symbols found in the symbol table matching the specified regex."),
126*f6aab3d8Srobert cl::sub(SymTabSubcommand));
127*f6aab3d8Srobert
128*f6aab3d8Srobert static cl::opt<ManglingPreference> ManglingPreference(
129*f6aab3d8Srobert "mangling-preference",
130*f6aab3d8Srobert cl::desc("Preference on mangling scheme the regex should match against and "
131*f6aab3d8Srobert "dumped."),
132*f6aab3d8Srobert cl::values(
133*f6aab3d8Srobert clEnumValN(ManglingPreference::Mangled, "mangled", "Prefer mangled"),
134*f6aab3d8Srobert clEnumValN(ManglingPreference::Demangled, "demangled",
135*f6aab3d8Srobert "Prefer demangled"),
136*f6aab3d8Srobert clEnumValN(ManglingPreference::MangledWithoutArguments,
137*f6aab3d8Srobert "demangled-without-args", "Prefer mangled without args")),
138*f6aab3d8Srobert cl::sub(SymTabSubcommand));
139*f6aab3d8Srobert
140*f6aab3d8Srobert static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input file>"),
141*f6aab3d8Srobert cl::Required, cl::sub(SymTabSubcommand));
142*f6aab3d8Srobert
143*f6aab3d8Srobert /// Validate that the options passed make sense.
144*f6aab3d8Srobert static std::optional<llvm::Error> validate();
145*f6aab3d8Srobert
146*f6aab3d8Srobert /// Transforms the selected mangling preference into a Mangled::NamePreference
147*f6aab3d8Srobert static Mangled::NamePreference getNamePreference();
148*f6aab3d8Srobert
149*f6aab3d8Srobert static int handleSymtabCommand(Debugger &Dbg);
150*f6aab3d8Srobert } // namespace symtab
151*f6aab3d8Srobert
152061da546Spatrick namespace symbols {
153061da546Spatrick static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input file>"),
154061da546Spatrick cl::Required, cl::sub(SymbolsSubcommand));
155061da546Spatrick
156061da546Spatrick static cl::opt<std::string>
157061da546Spatrick SymbolPath("symbol-file",
158061da546Spatrick cl::desc("The file from which to fetch symbol information."),
159061da546Spatrick cl::value_desc("file"), cl::sub(SymbolsSubcommand));
160061da546Spatrick
161061da546Spatrick enum class FindType {
162061da546Spatrick None,
163061da546Spatrick Function,
164061da546Spatrick Block,
165061da546Spatrick Namespace,
166061da546Spatrick Type,
167061da546Spatrick Variable,
168061da546Spatrick };
169061da546Spatrick static cl::opt<FindType> Find(
170061da546Spatrick "find", cl::desc("Choose search type:"),
171061da546Spatrick cl::values(
172061da546Spatrick clEnumValN(FindType::None, "none", "No search, just dump the module."),
173061da546Spatrick clEnumValN(FindType::Function, "function", "Find functions."),
174061da546Spatrick clEnumValN(FindType::Block, "block", "Find blocks."),
175061da546Spatrick clEnumValN(FindType::Namespace, "namespace", "Find namespaces."),
176061da546Spatrick clEnumValN(FindType::Type, "type", "Find types."),
177061da546Spatrick clEnumValN(FindType::Variable, "variable", "Find global variables.")),
178061da546Spatrick cl::sub(SymbolsSubcommand));
179061da546Spatrick
180061da546Spatrick static cl::opt<std::string> Name("name", cl::desc("Name to find."),
181061da546Spatrick cl::sub(SymbolsSubcommand));
182061da546Spatrick static cl::opt<bool>
183061da546Spatrick Regex("regex",
184dda28197Spatrick cl::desc("Search using regular expressions (available for variables "
185061da546Spatrick "and functions only)."),
186061da546Spatrick cl::sub(SymbolsSubcommand));
187061da546Spatrick static cl::opt<std::string>
188061da546Spatrick Context("context",
189061da546Spatrick cl::desc("Restrict search to the context of the given variable."),
190061da546Spatrick cl::value_desc("variable"), cl::sub(SymbolsSubcommand));
191061da546Spatrick
192061da546Spatrick static cl::opt<std::string> CompilerContext(
193061da546Spatrick "compiler-context",
194061da546Spatrick cl::desc("Specify a compiler context as \"kind:name,...\"."),
195061da546Spatrick cl::value_desc("context"), cl::sub(SymbolsSubcommand));
196061da546Spatrick
197061da546Spatrick static cl::opt<std::string>
198061da546Spatrick Language("language", cl::desc("Specify a language type, like C99."),
199061da546Spatrick cl::value_desc("language"), cl::sub(SymbolsSubcommand));
200061da546Spatrick
201061da546Spatrick static cl::list<FunctionNameType> FunctionNameFlags(
202061da546Spatrick "function-flags", cl::desc("Function search flags:"),
203061da546Spatrick cl::values(clEnumValN(eFunctionNameTypeAuto, "auto",
204061da546Spatrick "Automatically deduce flags based on name."),
205061da546Spatrick clEnumValN(eFunctionNameTypeFull, "full", "Full function name."),
206061da546Spatrick clEnumValN(eFunctionNameTypeBase, "base", "Base name."),
207061da546Spatrick clEnumValN(eFunctionNameTypeMethod, "method", "Method name."),
208061da546Spatrick clEnumValN(eFunctionNameTypeSelector, "selector",
209061da546Spatrick "Selector name.")),
210061da546Spatrick cl::sub(SymbolsSubcommand));
getFunctionNameFlags()211061da546Spatrick static FunctionNameType getFunctionNameFlags() {
212061da546Spatrick FunctionNameType Result = FunctionNameType(0);
213061da546Spatrick for (FunctionNameType Flag : FunctionNameFlags)
214061da546Spatrick Result = FunctionNameType(Result | Flag);
215061da546Spatrick return Result;
216061da546Spatrick }
217061da546Spatrick
218061da546Spatrick static cl::opt<bool> DumpAST("dump-ast",
219061da546Spatrick cl::desc("Dump AST restored from symbols."),
220061da546Spatrick cl::sub(SymbolsSubcommand));
221dda28197Spatrick static cl::opt<bool> DumpClangAST(
222dda28197Spatrick "dump-clang-ast",
223dda28197Spatrick cl::desc("Dump clang AST restored from symbols. When used on its own this "
224dda28197Spatrick "will dump the entire AST of all loaded symbols. When combined "
225dda28197Spatrick "with -find, it changes the presentation of the search results "
226dda28197Spatrick "from pretty-printing the types to an AST dump."),
227061da546Spatrick cl::sub(SymbolsSubcommand));
228061da546Spatrick
229061da546Spatrick static cl::opt<bool> Verify("verify", cl::desc("Verify symbol information."),
230061da546Spatrick cl::sub(SymbolsSubcommand));
231061da546Spatrick
232061da546Spatrick static cl::opt<std::string> File("file",
233061da546Spatrick cl::desc("File (compile unit) to search."),
234061da546Spatrick cl::sub(SymbolsSubcommand));
235061da546Spatrick static cl::opt<int> Line("line", cl::desc("Line to search."),
236061da546Spatrick cl::sub(SymbolsSubcommand));
237061da546Spatrick
238061da546Spatrick static Expected<CompilerDeclContext> getDeclContext(SymbolFile &Symfile);
239061da546Spatrick
240061da546Spatrick static Error findFunctions(lldb_private::Module &Module);
241061da546Spatrick static Error findBlocks(lldb_private::Module &Module);
242061da546Spatrick static Error findNamespaces(lldb_private::Module &Module);
243061da546Spatrick static Error findTypes(lldb_private::Module &Module);
244061da546Spatrick static Error findVariables(lldb_private::Module &Module);
245061da546Spatrick static Error dumpModule(lldb_private::Module &Module);
246061da546Spatrick static Error dumpAST(lldb_private::Module &Module);
247dda28197Spatrick static Error dumpEntireClangAST(lldb_private::Module &Module);
248061da546Spatrick static Error verify(lldb_private::Module &Module);
249061da546Spatrick
250061da546Spatrick static Expected<Error (*)(lldb_private::Module &)> getAction();
251061da546Spatrick static int dumpSymbols(Debugger &Dbg);
252061da546Spatrick } // namespace symbols
253061da546Spatrick
254061da546Spatrick namespace irmemorymap {
255061da546Spatrick static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
256061da546Spatrick cl::Required,
257061da546Spatrick cl::sub(IRMemoryMapSubcommand));
258061da546Spatrick static cl::opt<std::string> CommandFile(cl::Positional,
259061da546Spatrick cl::desc("<command-file>"),
260061da546Spatrick cl::init("-"),
261061da546Spatrick cl::sub(IRMemoryMapSubcommand));
262061da546Spatrick static cl::opt<bool> UseHostOnlyAllocationPolicy(
263061da546Spatrick "host-only", cl::desc("Use the host-only allocation policy"),
264061da546Spatrick cl::init(false), cl::sub(IRMemoryMapSubcommand));
265061da546Spatrick
266061da546Spatrick using AllocationT = std::pair<addr_t, addr_t>;
267061da546Spatrick using AddrIntervalMap =
268061da546Spatrick IntervalMap<addr_t, unsigned, 8, IntervalMapHalfOpenInfo<addr_t>>;
269061da546Spatrick
270061da546Spatrick struct IRMemoryMapTestState {
271061da546Spatrick TargetSP Target;
272061da546Spatrick IRMemoryMap Map;
273061da546Spatrick
274061da546Spatrick AddrIntervalMap::Allocator IntervalMapAllocator;
275061da546Spatrick AddrIntervalMap Allocations;
276061da546Spatrick
277061da546Spatrick StringMap<addr_t> Label2AddrMap;
278061da546Spatrick
IRMemoryMapTestStateopts::irmemorymap::IRMemoryMapTestState279061da546Spatrick IRMemoryMapTestState(TargetSP Target)
280061da546Spatrick : Target(Target), Map(Target), Allocations(IntervalMapAllocator) {}
281061da546Spatrick };
282061da546Spatrick
283061da546Spatrick bool evalMalloc(StringRef Line, IRMemoryMapTestState &State);
284061da546Spatrick bool evalFree(StringRef Line, IRMemoryMapTestState &State);
285061da546Spatrick int evaluateMemoryMapCommands(Debugger &Dbg);
286061da546Spatrick } // namespace irmemorymap
287061da546Spatrick
288be691f3bSpatrick namespace assert {
289be691f3bSpatrick int lldb_assert(Debugger &Dbg);
290be691f3bSpatrick } // namespace assert
291061da546Spatrick } // namespace opts
292061da546Spatrick
parseCompilerContext()293061da546Spatrick std::vector<CompilerContext> parseCompilerContext() {
294061da546Spatrick std::vector<CompilerContext> result;
295061da546Spatrick if (opts::symbols::CompilerContext.empty())
296061da546Spatrick return result;
297061da546Spatrick
298061da546Spatrick StringRef str{opts::symbols::CompilerContext};
299061da546Spatrick SmallVector<StringRef, 8> entries_str;
300061da546Spatrick str.split(entries_str, ',', /*maxSplit*/-1, /*keepEmpty=*/false);
301061da546Spatrick for (auto entry_str : entries_str) {
302061da546Spatrick StringRef key, value;
303061da546Spatrick std::tie(key, value) = entry_str.split(':');
304061da546Spatrick auto kind =
305061da546Spatrick StringSwitch<CompilerContextKind>(key)
306061da546Spatrick .Case("TranslationUnit", CompilerContextKind::TranslationUnit)
307061da546Spatrick .Case("Module", CompilerContextKind::Module)
308061da546Spatrick .Case("Namespace", CompilerContextKind::Namespace)
309061da546Spatrick .Case("Class", CompilerContextKind::Class)
310061da546Spatrick .Case("Struct", CompilerContextKind::Struct)
311061da546Spatrick .Case("Union", CompilerContextKind::Union)
312061da546Spatrick .Case("Function", CompilerContextKind::Function)
313061da546Spatrick .Case("Variable", CompilerContextKind::Variable)
314061da546Spatrick .Case("Enum", CompilerContextKind::Enum)
315061da546Spatrick .Case("Typedef", CompilerContextKind::Typedef)
316061da546Spatrick .Case("AnyModule", CompilerContextKind::AnyModule)
317061da546Spatrick .Case("AnyType", CompilerContextKind::AnyType)
318061da546Spatrick .Default(CompilerContextKind::Invalid);
319061da546Spatrick if (value.empty()) {
320061da546Spatrick WithColor::error() << "compiler context entry has no \"name\"\n";
321061da546Spatrick exit(1);
322061da546Spatrick }
323061da546Spatrick result.push_back({kind, ConstString{value}});
324061da546Spatrick }
325061da546Spatrick outs() << "Search context: {\n";
326061da546Spatrick for (auto entry: result)
327061da546Spatrick entry.Dump();
328061da546Spatrick outs() << "}\n";
329061da546Spatrick
330061da546Spatrick return result;
331061da546Spatrick }
332061da546Spatrick
333061da546Spatrick template <typename... Args>
make_string_error(const char * Format,Args &&...args)334061da546Spatrick static Error make_string_error(const char *Format, Args &&... args) {
335061da546Spatrick return llvm::make_error<llvm::StringError>(
336061da546Spatrick llvm::formatv(Format, std::forward<Args>(args)...).str(),
337061da546Spatrick llvm::inconvertibleErrorCode());
338061da546Spatrick }
339061da546Spatrick
createTarget(Debugger & Dbg,const std::string & Filename)340061da546Spatrick TargetSP opts::createTarget(Debugger &Dbg, const std::string &Filename) {
341061da546Spatrick TargetSP Target;
342061da546Spatrick Status ST = Dbg.GetTargetList().CreateTarget(
343061da546Spatrick Dbg, Filename, /*triple*/ "", eLoadDependentsNo,
344061da546Spatrick /*platform_options*/ nullptr, Target);
345061da546Spatrick if (ST.Fail()) {
346061da546Spatrick errs() << formatv("Failed to create target '{0}: {1}\n", Filename, ST);
347061da546Spatrick exit(1);
348061da546Spatrick }
349061da546Spatrick return Target;
350061da546Spatrick }
351061da546Spatrick
openFile(const std::string & Filename)352061da546Spatrick std::unique_ptr<MemoryBuffer> opts::openFile(const std::string &Filename) {
353061da546Spatrick auto MB = MemoryBuffer::getFileOrSTDIN(Filename);
354061da546Spatrick if (!MB) {
355061da546Spatrick errs() << formatv("Could not open file '{0}: {1}\n", Filename,
356061da546Spatrick MB.getError().message());
357061da546Spatrick exit(1);
358061da546Spatrick }
359061da546Spatrick return std::move(*MB);
360061da546Spatrick }
361061da546Spatrick
dumpState(const BreakpointList & List,LinePrinter & P)362061da546Spatrick void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) {
363061da546Spatrick P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize()));
364061da546Spatrick if (List.GetSize() > 0)
365061da546Spatrick P.formatLine("At least one breakpoint.");
366061da546Spatrick for (size_t i = 0, e = List.GetSize(); i < e; ++i) {
367061da546Spatrick BreakpointSP BP = List.GetBreakpointAtIndex(i);
368061da546Spatrick P.formatLine("Breakpoint ID {0}:", BP->GetID());
369061da546Spatrick AutoIndent Indent(P, 2);
370061da546Spatrick P.formatLine("{0} location{1}.", BP->GetNumLocations(),
371061da546Spatrick plural(BP->GetNumLocations()));
372061da546Spatrick if (BP->GetNumLocations() > 0)
373061da546Spatrick P.formatLine("At least one location.");
374061da546Spatrick P.formatLine("{0} resolved location{1}.", BP->GetNumResolvedLocations(),
375061da546Spatrick plural(BP->GetNumResolvedLocations()));
376061da546Spatrick if (BP->GetNumResolvedLocations() > 0)
377061da546Spatrick P.formatLine("At least one resolved location.");
378061da546Spatrick for (size_t l = 0, le = BP->GetNumLocations(); l < le; ++l) {
379061da546Spatrick BreakpointLocationSP Loc = BP->GetLocationAtIndex(l);
380061da546Spatrick P.formatLine("Location ID {0}:", Loc->GetID());
381061da546Spatrick AutoIndent Indent(P, 2);
382061da546Spatrick P.formatLine("Enabled: {0}", Loc->IsEnabled());
383061da546Spatrick P.formatLine("Resolved: {0}", Loc->IsResolved());
384061da546Spatrick SymbolContext sc;
385061da546Spatrick Loc->GetAddress().CalculateSymbolContext(&sc);
386061da546Spatrick lldb_private::StreamString S;
387061da546Spatrick sc.DumpStopContext(&S, BP->GetTarget().GetProcessSP().get(),
388061da546Spatrick Loc->GetAddress(), false, true, false, true, true);
389061da546Spatrick P.formatLine("Address: {0}", S.GetString());
390061da546Spatrick }
391061da546Spatrick }
392061da546Spatrick P.NewLine();
393061da546Spatrick }
394061da546Spatrick
substitute(StringRef Cmd)395061da546Spatrick std::string opts::breakpoint::substitute(StringRef Cmd) {
396061da546Spatrick std::string Result;
397061da546Spatrick raw_string_ostream OS(Result);
398061da546Spatrick while (!Cmd.empty()) {
399061da546Spatrick switch (Cmd[0]) {
400061da546Spatrick case '%':
401061da546Spatrick if (Cmd.consume_front("%p") && (Cmd.empty() || !isalnum(Cmd[0]))) {
402061da546Spatrick OS << sys::path::parent_path(breakpoint::CommandFile);
403061da546Spatrick break;
404061da546Spatrick }
405*f6aab3d8Srobert [[fallthrough]];
406061da546Spatrick default:
407061da546Spatrick size_t pos = Cmd.find('%');
408061da546Spatrick OS << Cmd.substr(0, pos);
409061da546Spatrick Cmd = Cmd.substr(pos);
410061da546Spatrick break;
411061da546Spatrick }
412061da546Spatrick }
413061da546Spatrick return std::move(OS.str());
414061da546Spatrick }
415061da546Spatrick
evaluateBreakpoints(Debugger & Dbg)416061da546Spatrick int opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) {
417061da546Spatrick TargetSP Target = opts::createTarget(Dbg, breakpoint::Target);
418061da546Spatrick std::unique_ptr<MemoryBuffer> MB = opts::openFile(breakpoint::CommandFile);
419061da546Spatrick
420061da546Spatrick LinePrinter P(4, outs());
421061da546Spatrick StringRef Rest = MB->getBuffer();
422061da546Spatrick int HadErrors = 0;
423061da546Spatrick while (!Rest.empty()) {
424061da546Spatrick StringRef Line;
425061da546Spatrick std::tie(Line, Rest) = Rest.split('\n');
426061da546Spatrick Line = Line.ltrim().rtrim();
427061da546Spatrick if (Line.empty() || Line[0] == '#')
428061da546Spatrick continue;
429061da546Spatrick
430061da546Spatrick if (!Persistent)
431061da546Spatrick Target->RemoveAllBreakpoints(/*internal_also*/ true);
432061da546Spatrick
433061da546Spatrick std::string Command = substitute(Line);
434061da546Spatrick P.formatLine("Command: {0}", Command);
435dda28197Spatrick CommandReturnObject Result(/*colors*/ false);
436061da546Spatrick if (!Dbg.GetCommandInterpreter().HandleCommand(
437061da546Spatrick Command.c_str(), /*add_to_history*/ eLazyBoolNo, Result)) {
438061da546Spatrick P.formatLine("Failed: {0}", Result.GetErrorData());
439061da546Spatrick HadErrors = 1;
440061da546Spatrick continue;
441061da546Spatrick }
442061da546Spatrick
443061da546Spatrick dumpState(Target->GetBreakpointList(/*internal*/ false), P);
444061da546Spatrick }
445061da546Spatrick return HadErrors;
446061da546Spatrick }
447061da546Spatrick
448061da546Spatrick Expected<CompilerDeclContext>
getDeclContext(SymbolFile & Symfile)449061da546Spatrick opts::symbols::getDeclContext(SymbolFile &Symfile) {
450061da546Spatrick if (Context.empty())
451061da546Spatrick return CompilerDeclContext();
452061da546Spatrick VariableList List;
453dda28197Spatrick Symfile.FindGlobalVariables(ConstString(Context), CompilerDeclContext(),
454dda28197Spatrick UINT32_MAX, List);
455061da546Spatrick if (List.Empty())
456061da546Spatrick return make_string_error("Context search didn't find a match.");
457061da546Spatrick if (List.GetSize() > 1)
458061da546Spatrick return make_string_error("Context search found multiple matches.");
459061da546Spatrick return List.GetVariableAtIndex(0)->GetDeclContext();
460061da546Spatrick }
461061da546Spatrick
GetDescriptionLevel()462dda28197Spatrick static lldb::DescriptionLevel GetDescriptionLevel() {
463dda28197Spatrick return opts::symbols::DumpClangAST ? eDescriptionLevelVerbose : eDescriptionLevelFull;
464dda28197Spatrick }
465dda28197Spatrick
findFunctions(lldb_private::Module & Module)466061da546Spatrick Error opts::symbols::findFunctions(lldb_private::Module &Module) {
467061da546Spatrick SymbolFile &Symfile = *Module.GetSymbolFile();
468061da546Spatrick SymbolContextList List;
469061da546Spatrick if (!File.empty()) {
470061da546Spatrick assert(Line != 0);
471061da546Spatrick
472061da546Spatrick FileSpec src_file(File);
473061da546Spatrick size_t cu_count = Module.GetNumCompileUnits();
474061da546Spatrick for (size_t i = 0; i < cu_count; i++) {
475061da546Spatrick lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i);
476061da546Spatrick if (!cu_sp)
477061da546Spatrick continue;
478061da546Spatrick
479061da546Spatrick LineEntry le;
480061da546Spatrick cu_sp->FindLineEntry(0, Line, &src_file, false, &le);
481061da546Spatrick if (!le.IsValid())
482061da546Spatrick continue;
483061da546Spatrick const bool include_inlined_functions = false;
484061da546Spatrick auto addr =
485061da546Spatrick le.GetSameLineContiguousAddressRange(include_inlined_functions)
486061da546Spatrick .GetBaseAddress();
487061da546Spatrick if (!addr.IsValid())
488061da546Spatrick continue;
489061da546Spatrick
490061da546Spatrick SymbolContext sc;
491061da546Spatrick uint32_t resolved =
492061da546Spatrick addr.CalculateSymbolContext(&sc, eSymbolContextFunction);
493061da546Spatrick if (resolved & eSymbolContextFunction)
494061da546Spatrick List.Append(sc);
495061da546Spatrick }
496061da546Spatrick } else if (Regex) {
497061da546Spatrick RegularExpression RE(Name);
498061da546Spatrick assert(RE.IsValid());
499061da546Spatrick List.Clear();
500061da546Spatrick Symfile.FindFunctions(RE, true, List);
501061da546Spatrick } else {
502061da546Spatrick Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
503061da546Spatrick if (!ContextOr)
504061da546Spatrick return ContextOr.takeError();
505dda28197Spatrick const CompilerDeclContext &ContextPtr =
506dda28197Spatrick ContextOr->IsValid() ? *ContextOr : CompilerDeclContext();
507061da546Spatrick
508061da546Spatrick List.Clear();
509*f6aab3d8Srobert Module::LookupInfo lookup_info(ConstString(Name), getFunctionNameFlags(),
510*f6aab3d8Srobert eLanguageTypeUnknown);
511*f6aab3d8Srobert Symfile.FindFunctions(lookup_info, ContextPtr, true, List);
512061da546Spatrick }
513061da546Spatrick outs() << formatv("Found {0} functions:\n", List.GetSize());
514061da546Spatrick StreamString Stream;
515061da546Spatrick List.Dump(&Stream, nullptr);
516061da546Spatrick outs() << Stream.GetData() << "\n";
517061da546Spatrick return Error::success();
518061da546Spatrick }
519061da546Spatrick
findBlocks(lldb_private::Module & Module)520061da546Spatrick Error opts::symbols::findBlocks(lldb_private::Module &Module) {
521061da546Spatrick assert(!Regex);
522061da546Spatrick assert(!File.empty());
523061da546Spatrick assert(Line != 0);
524061da546Spatrick
525061da546Spatrick SymbolContextList List;
526061da546Spatrick
527061da546Spatrick FileSpec src_file(File);
528061da546Spatrick size_t cu_count = Module.GetNumCompileUnits();
529061da546Spatrick for (size_t i = 0; i < cu_count; i++) {
530061da546Spatrick lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i);
531061da546Spatrick if (!cu_sp)
532061da546Spatrick continue;
533061da546Spatrick
534061da546Spatrick LineEntry le;
535061da546Spatrick cu_sp->FindLineEntry(0, Line, &src_file, false, &le);
536061da546Spatrick if (!le.IsValid())
537061da546Spatrick continue;
538061da546Spatrick const bool include_inlined_functions = false;
539061da546Spatrick auto addr = le.GetSameLineContiguousAddressRange(include_inlined_functions)
540061da546Spatrick .GetBaseAddress();
541061da546Spatrick if (!addr.IsValid())
542061da546Spatrick continue;
543061da546Spatrick
544061da546Spatrick SymbolContext sc;
545061da546Spatrick uint32_t resolved = addr.CalculateSymbolContext(&sc, eSymbolContextBlock);
546061da546Spatrick if (resolved & eSymbolContextBlock)
547061da546Spatrick List.Append(sc);
548061da546Spatrick }
549061da546Spatrick
550061da546Spatrick outs() << formatv("Found {0} blocks:\n", List.GetSize());
551061da546Spatrick StreamString Stream;
552061da546Spatrick List.Dump(&Stream, nullptr);
553061da546Spatrick outs() << Stream.GetData() << "\n";
554061da546Spatrick return Error::success();
555061da546Spatrick }
556061da546Spatrick
findNamespaces(lldb_private::Module & Module)557061da546Spatrick Error opts::symbols::findNamespaces(lldb_private::Module &Module) {
558061da546Spatrick SymbolFile &Symfile = *Module.GetSymbolFile();
559061da546Spatrick Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
560061da546Spatrick if (!ContextOr)
561061da546Spatrick return ContextOr.takeError();
562dda28197Spatrick const CompilerDeclContext &ContextPtr =
563dda28197Spatrick ContextOr->IsValid() ? *ContextOr : CompilerDeclContext();
564061da546Spatrick
565061da546Spatrick CompilerDeclContext Result =
566061da546Spatrick Symfile.FindNamespace(ConstString(Name), ContextPtr);
567061da546Spatrick if (Result)
568061da546Spatrick outs() << "Found namespace: "
569061da546Spatrick << Result.GetScopeQualifiedName().GetStringRef() << "\n";
570061da546Spatrick else
571061da546Spatrick outs() << "Namespace not found.\n";
572061da546Spatrick return Error::success();
573061da546Spatrick }
574061da546Spatrick
findTypes(lldb_private::Module & Module)575061da546Spatrick Error opts::symbols::findTypes(lldb_private::Module &Module) {
576061da546Spatrick SymbolFile &Symfile = *Module.GetSymbolFile();
577061da546Spatrick Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
578061da546Spatrick if (!ContextOr)
579061da546Spatrick return ContextOr.takeError();
580dda28197Spatrick const CompilerDeclContext &ContextPtr =
581dda28197Spatrick ContextOr->IsValid() ? *ContextOr : CompilerDeclContext();
582061da546Spatrick
583061da546Spatrick LanguageSet languages;
584061da546Spatrick if (!Language.empty())
585061da546Spatrick languages.Insert(Language::GetLanguageTypeFromString(Language));
586061da546Spatrick
587061da546Spatrick DenseSet<SymbolFile *> SearchedFiles;
588061da546Spatrick TypeMap Map;
589061da546Spatrick if (!Name.empty())
590061da546Spatrick Symfile.FindTypes(ConstString(Name), ContextPtr, UINT32_MAX, SearchedFiles,
591061da546Spatrick Map);
592061da546Spatrick else
593061da546Spatrick Module.FindTypes(parseCompilerContext(), languages, SearchedFiles, Map);
594061da546Spatrick
595061da546Spatrick outs() << formatv("Found {0} types:\n", Map.GetSize());
596061da546Spatrick StreamString Stream;
597dda28197Spatrick // Resolve types to force-materialize typedef types.
598dda28197Spatrick Map.ForEach([&](TypeSP &type) {
599dda28197Spatrick type->GetFullCompilerType();
600dda28197Spatrick return false;
601dda28197Spatrick });
602dda28197Spatrick Map.Dump(&Stream, false, GetDescriptionLevel());
603061da546Spatrick outs() << Stream.GetData() << "\n";
604061da546Spatrick return Error::success();
605061da546Spatrick }
606061da546Spatrick
findVariables(lldb_private::Module & Module)607061da546Spatrick Error opts::symbols::findVariables(lldb_private::Module &Module) {
608061da546Spatrick SymbolFile &Symfile = *Module.GetSymbolFile();
609061da546Spatrick VariableList List;
610061da546Spatrick if (Regex) {
611061da546Spatrick RegularExpression RE(Name);
612061da546Spatrick assert(RE.IsValid());
613061da546Spatrick Symfile.FindGlobalVariables(RE, UINT32_MAX, List);
614061da546Spatrick } else if (!File.empty()) {
615061da546Spatrick CompUnitSP CU;
616061da546Spatrick for (size_t Ind = 0; !CU && Ind < Module.GetNumCompileUnits(); ++Ind) {
617061da546Spatrick CompUnitSP Candidate = Module.GetCompileUnitAtIndex(Ind);
618061da546Spatrick if (!Candidate ||
619061da546Spatrick Candidate->GetPrimaryFile().GetFilename().GetStringRef() != File)
620061da546Spatrick continue;
621061da546Spatrick if (CU)
622061da546Spatrick return make_string_error("Multiple compile units for file `{0}` found.",
623061da546Spatrick File);
624061da546Spatrick CU = std::move(Candidate);
625061da546Spatrick }
626061da546Spatrick
627061da546Spatrick if (!CU)
628061da546Spatrick return make_string_error("Compile unit `{0}` not found.", File);
629061da546Spatrick
630061da546Spatrick List.AddVariables(CU->GetVariableList(true).get());
631061da546Spatrick } else {
632061da546Spatrick Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
633061da546Spatrick if (!ContextOr)
634061da546Spatrick return ContextOr.takeError();
635dda28197Spatrick const CompilerDeclContext &ContextPtr =
636dda28197Spatrick ContextOr->IsValid() ? *ContextOr : CompilerDeclContext();
637061da546Spatrick
638061da546Spatrick Symfile.FindGlobalVariables(ConstString(Name), ContextPtr, UINT32_MAX, List);
639061da546Spatrick }
640061da546Spatrick outs() << formatv("Found {0} variables:\n", List.GetSize());
641061da546Spatrick StreamString Stream;
642061da546Spatrick List.Dump(&Stream, false);
643061da546Spatrick outs() << Stream.GetData() << "\n";
644061da546Spatrick return Error::success();
645061da546Spatrick }
646061da546Spatrick
dumpModule(lldb_private::Module & Module)647061da546Spatrick Error opts::symbols::dumpModule(lldb_private::Module &Module) {
648061da546Spatrick StreamString Stream;
649061da546Spatrick Module.ParseAllDebugSymbols();
650061da546Spatrick Module.Dump(&Stream);
651061da546Spatrick outs() << Stream.GetData() << "\n";
652061da546Spatrick return Error::success();
653061da546Spatrick }
654061da546Spatrick
dumpAST(lldb_private::Module & Module)655061da546Spatrick Error opts::symbols::dumpAST(lldb_private::Module &Module) {
656061da546Spatrick Module.ParseAllDebugSymbols();
657061da546Spatrick
658061da546Spatrick SymbolFile *symfile = Module.GetSymbolFile();
659061da546Spatrick if (!symfile)
660061da546Spatrick return make_string_error("Module has no symbol file.");
661061da546Spatrick
662*f6aab3d8Srobert auto type_system_or_err =
663061da546Spatrick symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
664061da546Spatrick if (!type_system_or_err)
665dda28197Spatrick return make_string_error("Can't retrieve TypeSystemClang");
666061da546Spatrick
667*f6aab3d8Srobert auto ts = *type_system_or_err;
668*f6aab3d8Srobert auto *clang_ast_ctx = llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
669061da546Spatrick if (!clang_ast_ctx)
670dda28197Spatrick return make_string_error("Retrieved TypeSystem was not a TypeSystemClang");
671061da546Spatrick
672061da546Spatrick clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext();
673061da546Spatrick
674061da546Spatrick clang::TranslationUnitDecl *tu = ast_ctx.getTranslationUnitDecl();
675061da546Spatrick if (!tu)
676061da546Spatrick return make_string_error("Can't retrieve translation unit declaration.");
677061da546Spatrick
678061da546Spatrick tu->print(outs());
679061da546Spatrick
680061da546Spatrick return Error::success();
681061da546Spatrick }
682061da546Spatrick
dumpEntireClangAST(lldb_private::Module & Module)683dda28197Spatrick Error opts::symbols::dumpEntireClangAST(lldb_private::Module &Module) {
684061da546Spatrick Module.ParseAllDebugSymbols();
685061da546Spatrick
686061da546Spatrick SymbolFile *symfile = Module.GetSymbolFile();
687061da546Spatrick if (!symfile)
688061da546Spatrick return make_string_error("Module has no symbol file.");
689061da546Spatrick
690*f6aab3d8Srobert auto type_system_or_err =
691061da546Spatrick symfile->GetTypeSystemForLanguage(eLanguageTypeObjC_plus_plus);
692061da546Spatrick if (!type_system_or_err)
693dda28197Spatrick return make_string_error("Can't retrieve TypeSystemClang");
694*f6aab3d8Srobert auto ts = *type_system_or_err;
695*f6aab3d8Srobert auto *clang_ast_ctx = llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
696061da546Spatrick if (!clang_ast_ctx)
697dda28197Spatrick return make_string_error("Retrieved TypeSystem was not a TypeSystemClang");
698061da546Spatrick
699061da546Spatrick StreamString Stream;
700061da546Spatrick clang_ast_ctx->DumpFromSymbolFile(Stream, Name);
701061da546Spatrick outs() << Stream.GetData() << "\n";
702061da546Spatrick
703061da546Spatrick return Error::success();
704061da546Spatrick }
705061da546Spatrick
verify(lldb_private::Module & Module)706061da546Spatrick Error opts::symbols::verify(lldb_private::Module &Module) {
707061da546Spatrick SymbolFile *symfile = Module.GetSymbolFile();
708061da546Spatrick if (!symfile)
709061da546Spatrick return make_string_error("Module has no symbol file.");
710061da546Spatrick
711061da546Spatrick uint32_t comp_units_count = symfile->GetNumCompileUnits();
712061da546Spatrick
713061da546Spatrick outs() << "Found " << comp_units_count << " compile units.\n";
714061da546Spatrick
715061da546Spatrick for (uint32_t i = 0; i < comp_units_count; i++) {
716061da546Spatrick lldb::CompUnitSP comp_unit = symfile->GetCompileUnitAtIndex(i);
717061da546Spatrick if (!comp_unit)
718dda28197Spatrick return make_string_error("Cannot parse compile unit {0}.", i);
719061da546Spatrick
720061da546Spatrick outs() << "Processing '"
721061da546Spatrick << comp_unit->GetPrimaryFile().GetFilename().AsCString()
722061da546Spatrick << "' compile unit.\n";
723061da546Spatrick
724061da546Spatrick LineTable *lt = comp_unit->GetLineTable();
725061da546Spatrick if (!lt)
726061da546Spatrick return make_string_error("Can't get a line table of a compile unit.");
727061da546Spatrick
728061da546Spatrick uint32_t count = lt->GetSize();
729061da546Spatrick
730061da546Spatrick outs() << "The line table contains " << count << " entries.\n";
731061da546Spatrick
732061da546Spatrick if (count == 0)
733061da546Spatrick continue;
734061da546Spatrick
735061da546Spatrick LineEntry le;
736061da546Spatrick if (!lt->GetLineEntryAtIndex(0, le))
737061da546Spatrick return make_string_error("Can't get a line entry of a compile unit.");
738061da546Spatrick
739061da546Spatrick for (uint32_t i = 1; i < count; i++) {
740061da546Spatrick lldb::addr_t curr_end =
741061da546Spatrick le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize();
742061da546Spatrick
743061da546Spatrick if (!lt->GetLineEntryAtIndex(i, le))
744061da546Spatrick return make_string_error("Can't get a line entry of a compile unit");
745061da546Spatrick
746061da546Spatrick if (curr_end > le.range.GetBaseAddress().GetFileAddress())
747061da546Spatrick return make_string_error(
748061da546Spatrick "Line table of a compile unit is inconsistent.");
749061da546Spatrick }
750061da546Spatrick }
751061da546Spatrick
752061da546Spatrick outs() << "The symbol information is verified.\n";
753061da546Spatrick
754061da546Spatrick return Error::success();
755061da546Spatrick }
756061da546Spatrick
getAction()757061da546Spatrick Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
758061da546Spatrick if (Verify && DumpAST)
759061da546Spatrick return make_string_error(
760061da546Spatrick "Cannot both verify symbol information and dump AST.");
761061da546Spatrick
762061da546Spatrick if (Verify) {
763061da546Spatrick if (Find != FindType::None)
764061da546Spatrick return make_string_error(
765061da546Spatrick "Cannot both search and verify symbol information.");
766061da546Spatrick if (Regex || !Context.empty() || !Name.empty() || !File.empty() ||
767061da546Spatrick Line != 0)
768061da546Spatrick return make_string_error(
769061da546Spatrick "-regex, -context, -name, -file and -line options are not "
770061da546Spatrick "applicable for symbol verification.");
771061da546Spatrick return verify;
772061da546Spatrick }
773061da546Spatrick
774061da546Spatrick if (DumpAST) {
775061da546Spatrick if (Find != FindType::None)
776061da546Spatrick return make_string_error("Cannot both search and dump AST.");
777061da546Spatrick if (Regex || !Context.empty() || !Name.empty() || !File.empty() ||
778061da546Spatrick Line != 0)
779061da546Spatrick return make_string_error(
780061da546Spatrick "-regex, -context, -name, -file and -line options are not "
781061da546Spatrick "applicable for dumping AST.");
782061da546Spatrick return dumpAST;
783061da546Spatrick }
784061da546Spatrick
785061da546Spatrick if (DumpClangAST) {
786dda28197Spatrick if (Find == FindType::None) {
787061da546Spatrick if (Regex || !Context.empty() || !File.empty() || Line != 0)
788061da546Spatrick return make_string_error(
789061da546Spatrick "-regex, -context, -name, -file and -line options are not "
790dda28197Spatrick "applicable for dumping the entire clang AST. Either combine with "
791dda28197Spatrick "-find, or use -dump-clang-ast as a standalone option.");
792dda28197Spatrick return dumpEntireClangAST;
793dda28197Spatrick }
794dda28197Spatrick if (Find != FindType::Type)
795dda28197Spatrick return make_string_error("This combination of -dump-clang-ast and -find "
796dda28197Spatrick "<kind> is not yet implemented.");
797061da546Spatrick }
798061da546Spatrick
799061da546Spatrick if (Regex && !Context.empty())
800061da546Spatrick return make_string_error(
801061da546Spatrick "Cannot search using both regular expressions and context.");
802061da546Spatrick
803061da546Spatrick if (Regex && !RegularExpression(Name).IsValid())
804061da546Spatrick return make_string_error("`{0}` is not a valid regular expression.", Name);
805061da546Spatrick
806061da546Spatrick if (Regex + !Context.empty() + !File.empty() >= 2)
807061da546Spatrick return make_string_error(
808061da546Spatrick "Only one of -regex, -context and -file may be used simultaneously.");
809061da546Spatrick if (Regex && Name.empty())
810061da546Spatrick return make_string_error("-regex used without a -name");
811061da546Spatrick
812061da546Spatrick switch (Find) {
813061da546Spatrick case FindType::None:
814061da546Spatrick if (!Context.empty() || !Name.empty() || !File.empty() || Line != 0)
815061da546Spatrick return make_string_error(
816061da546Spatrick "Specify search type (-find) to use search options.");
817061da546Spatrick return dumpModule;
818061da546Spatrick
819061da546Spatrick case FindType::Function:
820061da546Spatrick if (!File.empty() + (Line != 0) == 1)
821061da546Spatrick return make_string_error("Both file name and line number must be "
822061da546Spatrick "specified when searching a function "
823061da546Spatrick "by file position.");
824061da546Spatrick if (Regex + (getFunctionNameFlags() != 0) + !File.empty() >= 2)
825061da546Spatrick return make_string_error("Only one of regular expression, function-flags "
826061da546Spatrick "and file position may be used simultaneously "
827061da546Spatrick "when searching a function.");
828061da546Spatrick return findFunctions;
829061da546Spatrick
830061da546Spatrick case FindType::Block:
831061da546Spatrick if (File.empty() || Line == 0)
832061da546Spatrick return make_string_error("Both file name and line number must be "
833061da546Spatrick "specified when searching a block.");
834061da546Spatrick if (Regex || getFunctionNameFlags() != 0)
835061da546Spatrick return make_string_error("Cannot use regular expression or "
836061da546Spatrick "function-flags for searching a block.");
837061da546Spatrick return findBlocks;
838061da546Spatrick
839061da546Spatrick case FindType::Namespace:
840061da546Spatrick if (Regex || !File.empty() || Line != 0)
841061da546Spatrick return make_string_error("Cannot search for namespaces using regular "
842061da546Spatrick "expressions, file names or line numbers.");
843061da546Spatrick return findNamespaces;
844061da546Spatrick
845061da546Spatrick case FindType::Type:
846061da546Spatrick if (Regex || !File.empty() || Line != 0)
847061da546Spatrick return make_string_error("Cannot search for types using regular "
848061da546Spatrick "expressions, file names or line numbers.");
849061da546Spatrick if (!Name.empty() && !CompilerContext.empty())
850061da546Spatrick return make_string_error("Name is ignored if compiler context present.");
851061da546Spatrick
852061da546Spatrick return findTypes;
853061da546Spatrick
854061da546Spatrick case FindType::Variable:
855061da546Spatrick if (Line != 0)
856061da546Spatrick return make_string_error("Cannot search for variables "
857061da546Spatrick "using line numbers.");
858061da546Spatrick return findVariables;
859061da546Spatrick }
860061da546Spatrick
861061da546Spatrick llvm_unreachable("Unsupported symbol action.");
862061da546Spatrick }
863061da546Spatrick
validate()864*f6aab3d8Srobert std::optional<llvm::Error> opts::symtab::validate() {
865*f6aab3d8Srobert if (ManglingPreference != ManglingPreference::None &&
866*f6aab3d8Srobert FindSymbolsByRegex.empty())
867*f6aab3d8Srobert return make_string_error("Mangling preference set but no regex specified.");
868*f6aab3d8Srobert
869*f6aab3d8Srobert return {};
870*f6aab3d8Srobert }
871*f6aab3d8Srobert
getNamePreference()872*f6aab3d8Srobert static Mangled::NamePreference opts::symtab::getNamePreference() {
873*f6aab3d8Srobert switch (ManglingPreference) {
874*f6aab3d8Srobert case ManglingPreference::None:
875*f6aab3d8Srobert case ManglingPreference::Mangled:
876*f6aab3d8Srobert return Mangled::ePreferMangled;
877*f6aab3d8Srobert case ManglingPreference::Demangled:
878*f6aab3d8Srobert return Mangled::ePreferDemangled;
879*f6aab3d8Srobert case ManglingPreference::MangledWithoutArguments:
880*f6aab3d8Srobert return Mangled::ePreferDemangledWithoutArguments;
881*f6aab3d8Srobert }
882*f6aab3d8Srobert llvm_unreachable("Fully covered switch above!");
883*f6aab3d8Srobert }
884*f6aab3d8Srobert
handleSymtabCommand(Debugger & Dbg)885*f6aab3d8Srobert int opts::symtab::handleSymtabCommand(Debugger &Dbg) {
886*f6aab3d8Srobert if (auto error = validate()) {
887*f6aab3d8Srobert logAllUnhandledErrors(std::move(*error), WithColor::error(), "");
888*f6aab3d8Srobert return 1;
889*f6aab3d8Srobert }
890*f6aab3d8Srobert
891*f6aab3d8Srobert if (!FindSymbolsByRegex.empty()) {
892*f6aab3d8Srobert ModuleSpec Spec{FileSpec(InputFile)};
893*f6aab3d8Srobert
894*f6aab3d8Srobert auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
895*f6aab3d8Srobert auto *Symtab = ModulePtr->GetSymtab();
896*f6aab3d8Srobert auto NamePreference = getNamePreference();
897*f6aab3d8Srobert std::vector<uint32_t> Indexes;
898*f6aab3d8Srobert
899*f6aab3d8Srobert Symtab->FindAllSymbolsMatchingRexExAndType(
900*f6aab3d8Srobert RegularExpression(FindSymbolsByRegex), lldb::eSymbolTypeAny,
901*f6aab3d8Srobert Symtab::eDebugAny, Symtab::eVisibilityAny, Indexes, NamePreference);
902*f6aab3d8Srobert for (auto i : Indexes) {
903*f6aab3d8Srobert auto *symbol = Symtab->SymbolAtIndex(i);
904*f6aab3d8Srobert if (symbol) {
905*f6aab3d8Srobert StreamString stream;
906*f6aab3d8Srobert symbol->Dump(&stream, nullptr, i, NamePreference);
907*f6aab3d8Srobert outs() << stream.GetString();
908*f6aab3d8Srobert }
909*f6aab3d8Srobert }
910*f6aab3d8Srobert }
911*f6aab3d8Srobert
912*f6aab3d8Srobert return 0;
913*f6aab3d8Srobert }
914*f6aab3d8Srobert
dumpSymbols(Debugger & Dbg)915061da546Spatrick int opts::symbols::dumpSymbols(Debugger &Dbg) {
916061da546Spatrick auto ActionOr = getAction();
917061da546Spatrick if (!ActionOr) {
918061da546Spatrick logAllUnhandledErrors(ActionOr.takeError(), WithColor::error(), "");
919061da546Spatrick return 1;
920061da546Spatrick }
921061da546Spatrick auto Action = *ActionOr;
922061da546Spatrick
923061da546Spatrick outs() << "Module: " << InputFile << "\n";
924061da546Spatrick ModuleSpec Spec{FileSpec(InputFile)};
925061da546Spatrick StringRef Symbols = SymbolPath.empty() ? InputFile : SymbolPath;
926061da546Spatrick Spec.GetSymbolFileSpec().SetFile(Symbols, FileSpec::Style::native);
927061da546Spatrick
928061da546Spatrick auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
929061da546Spatrick SymbolFile *Symfile = ModulePtr->GetSymbolFile();
930061da546Spatrick if (!Symfile) {
931061da546Spatrick WithColor::error() << "Module has no symbol vendor.\n";
932061da546Spatrick return 1;
933061da546Spatrick }
934061da546Spatrick
935061da546Spatrick if (Error E = Action(*ModulePtr)) {
936061da546Spatrick WithColor::error() << toString(std::move(E)) << "\n";
937061da546Spatrick return 1;
938061da546Spatrick }
939061da546Spatrick
940061da546Spatrick return 0;
941061da546Spatrick }
942061da546Spatrick
dumpSectionList(LinePrinter & Printer,const SectionList & List,bool is_subsection)943061da546Spatrick static void dumpSectionList(LinePrinter &Printer, const SectionList &List, bool is_subsection) {
944061da546Spatrick size_t Count = List.GetNumSections(0);
945061da546Spatrick if (Count == 0) {
946061da546Spatrick Printer.formatLine("There are no {0}sections", is_subsection ? "sub" : "");
947061da546Spatrick return;
948061da546Spatrick }
949061da546Spatrick Printer.formatLine("Showing {0} {1}sections", Count,
950061da546Spatrick is_subsection ? "sub" : "");
951061da546Spatrick for (size_t I = 0; I < Count; ++I) {
952061da546Spatrick auto S = List.GetSectionAtIndex(I);
953061da546Spatrick assert(S);
954061da546Spatrick AutoIndent Indent(Printer, 2);
955061da546Spatrick Printer.formatLine("Index: {0}", I);
956061da546Spatrick Printer.formatLine("ID: {0:x}", S->GetID());
957061da546Spatrick Printer.formatLine("Name: {0}", S->GetName().GetStringRef());
958061da546Spatrick Printer.formatLine("Type: {0}", S->GetTypeAsCString());
959061da546Spatrick Printer.formatLine("Permissions: {0}", GetPermissionsAsCString(S->GetPermissions()));
960061da546Spatrick Printer.formatLine("Thread specific: {0:y}", S->IsThreadSpecific());
961061da546Spatrick Printer.formatLine("VM address: {0:x}", S->GetFileAddress());
962061da546Spatrick Printer.formatLine("VM size: {0}", S->GetByteSize());
963061da546Spatrick Printer.formatLine("File size: {0}", S->GetFileSize());
964061da546Spatrick
965061da546Spatrick if (opts::object::SectionContents) {
966061da546Spatrick lldb_private::DataExtractor Data;
967061da546Spatrick S->GetSectionData(Data);
968dda28197Spatrick ArrayRef<uint8_t> Bytes(Data.GetDataStart(), Data.GetDataEnd());
969061da546Spatrick Printer.formatBinary("Data: ", Bytes, 0);
970061da546Spatrick }
971061da546Spatrick
972061da546Spatrick if (S->GetType() == eSectionTypeContainer)
973061da546Spatrick dumpSectionList(Printer, S->GetChildren(), true);
974061da546Spatrick Printer.NewLine();
975061da546Spatrick }
976061da546Spatrick }
977061da546Spatrick
dumpObjectFiles(Debugger & Dbg)978061da546Spatrick static int dumpObjectFiles(Debugger &Dbg) {
979061da546Spatrick LinePrinter Printer(4, llvm::outs());
980061da546Spatrick
981061da546Spatrick int HadErrors = 0;
982061da546Spatrick for (const auto &File : opts::object::InputFilenames) {
983061da546Spatrick ModuleSpec Spec{FileSpec(File)};
984061da546Spatrick
985061da546Spatrick auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
986061da546Spatrick
987061da546Spatrick ObjectFile *ObjectPtr = ModulePtr->GetObjectFile();
988061da546Spatrick if (!ObjectPtr) {
989061da546Spatrick WithColor::error() << File << " not recognised as an object file\n";
990061da546Spatrick HadErrors = 1;
991061da546Spatrick continue;
992061da546Spatrick }
993061da546Spatrick
994061da546Spatrick // Fetch symbol vendor before we get the section list to give the symbol
995061da546Spatrick // vendor a chance to populate it.
996061da546Spatrick ModulePtr->GetSymbolFile();
997061da546Spatrick SectionList *Sections = ModulePtr->GetSectionList();
998061da546Spatrick if (!Sections) {
999061da546Spatrick llvm::errs() << "Could not load sections for module " << File << "\n";
1000061da546Spatrick HadErrors = 1;
1001061da546Spatrick continue;
1002061da546Spatrick }
1003061da546Spatrick
1004061da546Spatrick Printer.formatLine("Plugin name: {0}", ObjectPtr->GetPluginName());
1005061da546Spatrick Printer.formatLine("Architecture: {0}",
1006061da546Spatrick ModulePtr->GetArchitecture().GetTriple().getTriple());
1007061da546Spatrick Printer.formatLine("UUID: {0}", ModulePtr->GetUUID().GetAsString());
1008061da546Spatrick Printer.formatLine("Executable: {0}", ObjectPtr->IsExecutable());
1009061da546Spatrick Printer.formatLine("Stripped: {0}", ObjectPtr->IsStripped());
1010061da546Spatrick Printer.formatLine("Type: {0}", ObjectPtr->GetType());
1011061da546Spatrick Printer.formatLine("Strata: {0}", ObjectPtr->GetStrata());
1012061da546Spatrick Printer.formatLine("Base VM address: {0:x}",
1013061da546Spatrick ObjectPtr->GetBaseAddress().GetFileAddress());
1014061da546Spatrick
1015061da546Spatrick dumpSectionList(Printer, *Sections, /*is_subsection*/ false);
1016061da546Spatrick
1017061da546Spatrick if (opts::object::SectionDependentModules) {
1018061da546Spatrick // A non-empty section list ensures a valid object file.
1019061da546Spatrick auto Obj = ModulePtr->GetObjectFile();
1020061da546Spatrick FileSpecList Files;
1021061da546Spatrick auto Count = Obj->GetDependentModules(Files);
1022061da546Spatrick Printer.formatLine("Showing {0} dependent module(s)", Count);
1023061da546Spatrick for (size_t I = 0; I < Files.GetSize(); ++I) {
1024061da546Spatrick AutoIndent Indent(Printer, 2);
1025061da546Spatrick Printer.formatLine("Name: {0}",
1026*f6aab3d8Srobert Files.GetFileSpecAtIndex(I).GetPath());
1027061da546Spatrick }
1028061da546Spatrick Printer.NewLine();
1029061da546Spatrick }
1030061da546Spatrick }
1031061da546Spatrick return HadErrors;
1032061da546Spatrick }
1033061da546Spatrick
evalMalloc(StringRef Line,IRMemoryMapTestState & State)1034061da546Spatrick bool opts::irmemorymap::evalMalloc(StringRef Line,
1035061da546Spatrick IRMemoryMapTestState &State) {
1036061da546Spatrick // ::= <label> = malloc <size> <alignment>
1037061da546Spatrick StringRef Label;
1038061da546Spatrick std::tie(Label, Line) = Line.split('=');
1039061da546Spatrick if (Line.empty())
1040061da546Spatrick return false;
1041061da546Spatrick Label = Label.trim();
1042061da546Spatrick Line = Line.trim();
1043061da546Spatrick size_t Size;
1044061da546Spatrick uint8_t Alignment;
1045061da546Spatrick int Matches = sscanf(Line.data(), "malloc %zu %hhu", &Size, &Alignment);
1046061da546Spatrick if (Matches != 2)
1047061da546Spatrick return false;
1048061da546Spatrick
1049061da546Spatrick outs() << formatv("Command: {0} = malloc(size={1}, alignment={2})\n", Label,
1050061da546Spatrick Size, Alignment);
1051061da546Spatrick if (!isPowerOf2_32(Alignment)) {
1052061da546Spatrick outs() << "Malloc error: alignment is not a power of 2\n";
1053061da546Spatrick exit(1);
1054061da546Spatrick }
1055061da546Spatrick
1056061da546Spatrick IRMemoryMap::AllocationPolicy AP =
1057061da546Spatrick UseHostOnlyAllocationPolicy ? IRMemoryMap::eAllocationPolicyHostOnly
1058061da546Spatrick : IRMemoryMap::eAllocationPolicyProcessOnly;
1059061da546Spatrick
1060061da546Spatrick // Issue the malloc in the target process with "-rw" permissions.
1061061da546Spatrick const uint32_t Permissions = 0x3;
1062061da546Spatrick const bool ZeroMemory = false;
1063061da546Spatrick Status ST;
1064061da546Spatrick addr_t Addr =
1065061da546Spatrick State.Map.Malloc(Size, Alignment, Permissions, AP, ZeroMemory, ST);
1066061da546Spatrick if (ST.Fail()) {
1067061da546Spatrick outs() << formatv("Malloc error: {0}\n", ST);
1068061da546Spatrick return true;
1069061da546Spatrick }
1070061da546Spatrick
1071061da546Spatrick // Print the result of the allocation before checking its validity.
1072061da546Spatrick outs() << formatv("Malloc: address = {0:x}\n", Addr);
1073061da546Spatrick
1074061da546Spatrick // Check that the allocation is aligned.
1075061da546Spatrick if (!Addr || Addr % Alignment != 0) {
1076061da546Spatrick outs() << "Malloc error: zero or unaligned allocation detected\n";
1077061da546Spatrick exit(1);
1078061da546Spatrick }
1079061da546Spatrick
1080061da546Spatrick // In case of Size == 0, we still expect the returned address to be unique and
1081061da546Spatrick // non-overlapping.
1082061da546Spatrick addr_t EndOfRegion = Addr + std::max<size_t>(Size, 1);
1083061da546Spatrick if (State.Allocations.overlaps(Addr, EndOfRegion)) {
1084061da546Spatrick auto I = State.Allocations.find(Addr);
1085061da546Spatrick outs() << "Malloc error: overlapping allocation detected"
1086061da546Spatrick << formatv(", previous allocation at [{0:x}, {1:x})\n", I.start(),
1087061da546Spatrick I.stop());
1088061da546Spatrick exit(1);
1089061da546Spatrick }
1090061da546Spatrick
1091061da546Spatrick // Insert the new allocation into the interval map. Use unique allocation
1092061da546Spatrick // IDs to inhibit interval coalescing.
1093061da546Spatrick static unsigned AllocationID = 0;
1094061da546Spatrick State.Allocations.insert(Addr, EndOfRegion, AllocationID++);
1095061da546Spatrick
1096061da546Spatrick // Store the label -> address mapping.
1097061da546Spatrick State.Label2AddrMap[Label] = Addr;
1098061da546Spatrick
1099061da546Spatrick return true;
1100061da546Spatrick }
1101061da546Spatrick
evalFree(StringRef Line,IRMemoryMapTestState & State)1102061da546Spatrick bool opts::irmemorymap::evalFree(StringRef Line, IRMemoryMapTestState &State) {
1103061da546Spatrick // ::= free <label>
1104061da546Spatrick if (!Line.consume_front("free"))
1105061da546Spatrick return false;
1106061da546Spatrick StringRef Label = Line.trim();
1107061da546Spatrick
1108061da546Spatrick outs() << formatv("Command: free({0})\n", Label);
1109061da546Spatrick auto LabelIt = State.Label2AddrMap.find(Label);
1110061da546Spatrick if (LabelIt == State.Label2AddrMap.end()) {
1111061da546Spatrick outs() << "Free error: Invalid allocation label\n";
1112061da546Spatrick exit(1);
1113061da546Spatrick }
1114061da546Spatrick
1115061da546Spatrick Status ST;
1116061da546Spatrick addr_t Addr = LabelIt->getValue();
1117061da546Spatrick State.Map.Free(Addr, ST);
1118061da546Spatrick if (ST.Fail()) {
1119061da546Spatrick outs() << formatv("Free error: {0}\n", ST);
1120061da546Spatrick exit(1);
1121061da546Spatrick }
1122061da546Spatrick
1123061da546Spatrick // Erase the allocation from the live interval map.
1124061da546Spatrick auto Interval = State.Allocations.find(Addr);
1125061da546Spatrick if (Interval != State.Allocations.end()) {
1126061da546Spatrick outs() << formatv("Free: [{0:x}, {1:x})\n", Interval.start(),
1127061da546Spatrick Interval.stop());
1128061da546Spatrick Interval.erase();
1129061da546Spatrick }
1130061da546Spatrick
1131061da546Spatrick return true;
1132061da546Spatrick }
1133061da546Spatrick
evaluateMemoryMapCommands(Debugger & Dbg)1134061da546Spatrick int opts::irmemorymap::evaluateMemoryMapCommands(Debugger &Dbg) {
1135061da546Spatrick // Set up a Target.
1136061da546Spatrick TargetSP Target = opts::createTarget(Dbg, irmemorymap::Target);
1137061da546Spatrick
1138061da546Spatrick // Set up a Process. In order to allocate memory within a target, this
1139061da546Spatrick // process must be alive and must support JIT'ing.
1140dda28197Spatrick CommandReturnObject Result(/*colors*/ false);
1141061da546Spatrick Dbg.SetAsyncExecution(false);
1142061da546Spatrick CommandInterpreter &CI = Dbg.GetCommandInterpreter();
1143061da546Spatrick auto IssueCmd = [&](const char *Cmd) -> bool {
1144061da546Spatrick return CI.HandleCommand(Cmd, eLazyBoolNo, Result);
1145061da546Spatrick };
1146061da546Spatrick if (!IssueCmd("b main") || !IssueCmd("run")) {
1147061da546Spatrick outs() << formatv("Failed: {0}\n", Result.GetErrorData());
1148061da546Spatrick exit(1);
1149061da546Spatrick }
1150061da546Spatrick
1151061da546Spatrick ProcessSP Process = Target->GetProcessSP();
1152061da546Spatrick if (!Process || !Process->IsAlive() || !Process->CanJIT()) {
1153061da546Spatrick outs() << "Cannot use process to test IRMemoryMap\n";
1154061da546Spatrick exit(1);
1155061da546Spatrick }
1156061da546Spatrick
1157061da546Spatrick // Set up an IRMemoryMap and associated testing state.
1158061da546Spatrick IRMemoryMapTestState State(Target);
1159061da546Spatrick
1160061da546Spatrick // Parse and apply commands from the command file.
1161061da546Spatrick std::unique_ptr<MemoryBuffer> MB = opts::openFile(irmemorymap::CommandFile);
1162061da546Spatrick StringRef Rest = MB->getBuffer();
1163061da546Spatrick while (!Rest.empty()) {
1164061da546Spatrick StringRef Line;
1165061da546Spatrick std::tie(Line, Rest) = Rest.split('\n');
1166061da546Spatrick Line = Line.ltrim().rtrim();
1167061da546Spatrick
1168061da546Spatrick if (Line.empty() || Line[0] == '#')
1169061da546Spatrick continue;
1170061da546Spatrick
1171061da546Spatrick if (evalMalloc(Line, State))
1172061da546Spatrick continue;
1173061da546Spatrick
1174061da546Spatrick if (evalFree(Line, State))
1175061da546Spatrick continue;
1176061da546Spatrick
1177061da546Spatrick errs() << "Could not parse line: " << Line << "\n";
1178061da546Spatrick exit(1);
1179061da546Spatrick }
1180061da546Spatrick return 0;
1181061da546Spatrick }
1182061da546Spatrick
lldb_assert(Debugger & Dbg)1183be691f3bSpatrick int opts::assert::lldb_assert(Debugger &Dbg) {
1184be691f3bSpatrick lldbassert(false && "lldb-test assert");
1185be691f3bSpatrick return 1;
1186be691f3bSpatrick }
1187be691f3bSpatrick
main(int argc,const char * argv[])1188061da546Spatrick int main(int argc, const char *argv[]) {
1189061da546Spatrick StringRef ToolName = argv[0];
1190061da546Spatrick sys::PrintStackTraceOnErrorSignal(ToolName);
1191061da546Spatrick PrettyStackTraceProgram X(argc, argv);
1192061da546Spatrick llvm_shutdown_obj Y;
1193061da546Spatrick
1194061da546Spatrick cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
1195061da546Spatrick
1196061da546Spatrick SystemLifetimeManager DebuggerLifetime;
1197061da546Spatrick if (auto e = DebuggerLifetime.Initialize(
1198061da546Spatrick std::make_unique<SystemInitializerTest>(), nullptr)) {
1199061da546Spatrick WithColor::error() << "initialization failed: " << toString(std::move(e))
1200061da546Spatrick << '\n';
1201061da546Spatrick return 1;
1202061da546Spatrick }
1203061da546Spatrick
1204061da546Spatrick auto TerminateDebugger =
1205061da546Spatrick llvm::make_scope_exit([&] { DebuggerLifetime.Terminate(); });
1206061da546Spatrick
1207061da546Spatrick auto Dbg = lldb_private::Debugger::CreateInstance();
1208061da546Spatrick ModuleList::GetGlobalModuleListProperties().SetEnableExternalLookup(false);
1209dda28197Spatrick CommandReturnObject Result(/*colors*/ false);
1210061da546Spatrick Dbg->GetCommandInterpreter().HandleCommand(
1211061da546Spatrick "settings set plugin.process.gdb-remote.packet-timeout 60",
1212061da546Spatrick /*add_to_history*/ eLazyBoolNo, Result);
1213be691f3bSpatrick Dbg->GetCommandInterpreter().HandleCommand(
1214be691f3bSpatrick "settings set target.inherit-tcc true",
1215be691f3bSpatrick /*add_to_history*/ eLazyBoolNo, Result);
1216be691f3bSpatrick Dbg->GetCommandInterpreter().HandleCommand(
1217be691f3bSpatrick "settings set target.detach-on-error false",
1218be691f3bSpatrick /*add_to_history*/ eLazyBoolNo, Result);
1219061da546Spatrick
1220061da546Spatrick if (!opts::Log.empty())
1221*f6aab3d8Srobert Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, 0, eLogHandlerStream, errs());
1222061da546Spatrick
1223061da546Spatrick if (opts::BreakpointSubcommand)
1224061da546Spatrick return opts::breakpoint::evaluateBreakpoints(*Dbg);
1225061da546Spatrick if (opts::ObjectFileSubcommand)
1226061da546Spatrick return dumpObjectFiles(*Dbg);
1227061da546Spatrick if (opts::SymbolsSubcommand)
1228061da546Spatrick return opts::symbols::dumpSymbols(*Dbg);
1229*f6aab3d8Srobert if (opts::SymTabSubcommand)
1230*f6aab3d8Srobert return opts::symtab::handleSymtabCommand(*Dbg);
1231061da546Spatrick if (opts::IRMemoryMapSubcommand)
1232061da546Spatrick return opts::irmemorymap::evaluateMemoryMapCommands(*Dbg);
1233be691f3bSpatrick if (opts::AssertSubcommand)
1234be691f3bSpatrick return opts::assert::lldb_assert(*Dbg);
1235061da546Spatrick
1236061da546Spatrick WithColor::error() << "No command specified.\n";
1237061da546Spatrick return 1;
1238061da546Spatrick }
1239