blob: 0bd532fa2945a982f22d963bd6292d62e9d82437 [file] [log] [blame]
Zachary Turner888a4282017-12-01 00:52:51 +00001//===- lldb-test.cpp ------------------------------------------ *- C++ --*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Zachary Turner888a4282017-12-01 00:52:51 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "FormatUtil.h"
10#include "SystemInitializerTest.h"
11
Zachary Turnera6d54642017-12-02 00:15:29 +000012#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
Alex Langford8be30212020-01-29 11:59:28 -080013#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
Pavel Labath7c945822018-02-26 18:50:16 +000014#include "lldb/Breakpoint/BreakpointLocation.h"
Zachary Turner888a4282017-12-01 00:52:51 +000015#include "lldb/Core/Debugger.h"
16#include "lldb/Core/Module.h"
17#include "lldb/Core/Section.h"
Vedant Kumarc1cd8262018-05-30 19:39:10 +000018#include "lldb/Expression/IRMemoryMap.h"
Zachary Turner888a4282017-12-01 00:52:51 +000019#include "lldb/Initialization/SystemLifetimeManager.h"
Pavel Labath7c945822018-02-26 18:50:16 +000020#include "lldb/Interpreter/CommandInterpreter.h"
21#include "lldb/Interpreter/CommandReturnObject.h"
Aaron Smith010edd32018-06-08 02:45:25 +000022#include "lldb/Symbol/CompileUnit.h"
23#include "lldb/Symbol/LineTable.h"
Pavel Labath465eae32019-08-06 09:12:42 +000024#include "lldb/Symbol/SymbolFile.h"
Pavel Labath90b0a532018-05-03 10:57:16 +000025#include "lldb/Symbol/TypeList.h"
Pavel Labath465eae32019-08-06 09:12:42 +000026#include "lldb/Symbol/TypeMap.h"
Pavel Labath90b0a532018-05-03 10:57:16 +000027#include "lldb/Symbol/VariableList.h"
Adrian Prantlaa97a892019-08-22 21:45:58 +000028#include "lldb/Target/Language.h"
Vedant Kumarc1cd8262018-05-30 19:39:10 +000029#include "lldb/Target/Process.h"
30#include "lldb/Target/Target.h"
Zachary Turner888a4282017-12-01 00:52:51 +000031#include "lldb/Utility/DataExtractor.h"
Pavel Labath62a82542018-12-15 13:45:38 +000032#include "lldb/Utility/State.h"
Zachary Turnera6d54642017-12-02 00:15:29 +000033#include "lldb/Utility/StreamString.h"
Zachary Turner888a4282017-12-01 00:52:51 +000034
Vedant Kumarc1cd8262018-05-30 19:39:10 +000035#include "llvm/ADT/IntervalMap.h"
Jonas Devliegheree0ea8d82019-09-10 00:20:50 +000036#include "llvm/ADT/ScopeExit.h"
Zachary Turner888a4282017-12-01 00:52:51 +000037#include "llvm/ADT/StringRef.h"
38#include "llvm/Support/CommandLine.h"
39#include "llvm/Support/ManagedStatic.h"
Pavel Labath9ea80d22018-06-28 10:03:42 +000040#include "llvm/Support/MathExtras.h"
Pavel Labath7c945822018-02-26 18:50:16 +000041#include "llvm/Support/Path.h"
Zachary Turner888a4282017-12-01 00:52:51 +000042#include "llvm/Support/PrettyStackTrace.h"
43#include "llvm/Support/Signals.h"
Pavel Labath90b0a532018-05-03 10:57:16 +000044#include "llvm/Support/WithColor.h"
Shafik Yaghmour5f469822019-10-11 16:36:20 +000045
Vedant Kumarc1cd8262018-05-30 19:39:10 +000046#include <cstdio>
Zachary Turner888a4282017-12-01 00:52:51 +000047#include <thread>
48
49using namespace lldb;
50using namespace lldb_private;
51using namespace llvm;
52
53namespace opts {
Pavel Labath7c945822018-02-26 18:50:16 +000054static cl::SubCommand BreakpointSubcommand("breakpoints",
55 "Test breakpoint resolution");
Pavel Labath62a7f802018-06-29 12:15:54 +000056cl::SubCommand ObjectFileSubcommand("object-file",
57 "Display LLDB object file information");
Zachary Turnera6d54642017-12-02 00:15:29 +000058cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file");
Vedant Kumarc1cd8262018-05-30 19:39:10 +000059cl::SubCommand IRMemoryMapSubcommand("ir-memory-map", "Test IRMemoryMap");
Vedant Kumar7e4c84a2018-05-31 22:09:00 +000060
Vedant Kumarc1cd8262018-05-30 19:39:10 +000061cl::opt<std::string> Log("log", cl::desc("Path to a log file"), cl::init(""),
Vedant Kumar7e4c84a2018-05-31 22:09:00 +000062 cl::sub(BreakpointSubcommand),
Pavel Labath62a7f802018-06-29 12:15:54 +000063 cl::sub(ObjectFileSubcommand),
64 cl::sub(SymbolsSubcommand),
Vedant Kumarc1cd8262018-05-30 19:39:10 +000065 cl::sub(IRMemoryMapSubcommand));
66
67/// Create a target using the file pointed to by \p Filename, or abort.
68TargetSP createTarget(Debugger &Dbg, const std::string &Filename);
69
70/// Read \p Filename into a null-terminated buffer, or abort.
71std::unique_ptr<MemoryBuffer> openFile(const std::string &Filename);
Zachary Turner888a4282017-12-01 00:52:51 +000072
Pavel Labath7c945822018-02-26 18:50:16 +000073namespace breakpoint {
74static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
75 cl::Required, cl::sub(BreakpointSubcommand));
76static cl::opt<std::string> CommandFile(cl::Positional,
77 cl::desc("<command-file>"),
78 cl::init("-"),
79 cl::sub(BreakpointSubcommand));
80static cl::opt<bool> Persistent(
81 "persistent",
82 cl::desc("Don't automatically remove all breakpoints before each command"),
83 cl::sub(BreakpointSubcommand));
84
85static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; }
86static void dumpState(const BreakpointList &List, LinePrinter &P);
87static std::string substitute(StringRef Cmd);
Pavel Labath90b0a532018-05-03 10:57:16 +000088static int evaluateBreakpoints(Debugger &Dbg);
Pavel Labath7c945822018-02-26 18:50:16 +000089} // namespace breakpoint
90
Pavel Labath62a7f802018-06-29 12:15:54 +000091namespace object {
Zachary Turner888a4282017-12-01 00:52:51 +000092cl::opt<bool> SectionContents("contents",
93 cl::desc("Dump each section's contents"),
Pavel Labath62a7f802018-06-29 12:15:54 +000094 cl::sub(ObjectFileSubcommand));
Aaron Smith037ed1b2018-12-06 21:36:39 +000095cl::opt<bool> SectionDependentModules("dep-modules",
96 cl::desc("Dump each dependent module"),
97 cl::sub(ObjectFileSubcommand));
Zachary Turner888a4282017-12-01 00:52:51 +000098cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
Pavel Labath62a7f802018-06-29 12:15:54 +000099 cl::OneOrMore,
100 cl::sub(ObjectFileSubcommand));
101} // namespace object
Zachary Turnera6d54642017-12-02 00:15:29 +0000102
103namespace symbols {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000104static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input file>"),
105 cl::Required, cl::sub(SymbolsSubcommand));
106
107static cl::opt<std::string>
108 SymbolPath("symbol-file",
109 cl::desc("The file from which to fetch symbol information."),
110 cl::value_desc("file"), cl::sub(SymbolsSubcommand));
111
Pavel Labath90b0a532018-05-03 10:57:16 +0000112enum class FindType {
113 None,
114 Function,
Aleksandr Urakov398f81b2018-08-29 07:26:11 +0000115 Block,
Pavel Labath90b0a532018-05-03 10:57:16 +0000116 Namespace,
117 Type,
118 Variable,
119};
120static cl::opt<FindType> Find(
121 "find", cl::desc("Choose search type:"),
122 cl::values(
Pavel Labath9ea80d22018-06-28 10:03:42 +0000123 clEnumValN(FindType::None, "none", "No search, just dump the module."),
Pavel Labath90b0a532018-05-03 10:57:16 +0000124 clEnumValN(FindType::Function, "function", "Find functions."),
Aleksandr Urakov398f81b2018-08-29 07:26:11 +0000125 clEnumValN(FindType::Block, "block", "Find blocks."),
Pavel Labath90b0a532018-05-03 10:57:16 +0000126 clEnumValN(FindType::Namespace, "namespace", "Find namespaces."),
127 clEnumValN(FindType::Type, "type", "Find types."),
128 clEnumValN(FindType::Variable, "variable", "Find global variables.")),
129 cl::sub(SymbolsSubcommand));
130
131static cl::opt<std::string> Name("name", cl::desc("Name to find."),
132 cl::sub(SymbolsSubcommand));
133static cl::opt<bool>
134 Regex("regex",
135 cl::desc("Search using regular expressions (avaliable for variables "
136 "and functions only)."),
137 cl::sub(SymbolsSubcommand));
138static cl::opt<std::string>
139 Context("context",
140 cl::desc("Restrict search to the context of the given variable."),
141 cl::value_desc("variable"), cl::sub(SymbolsSubcommand));
142
Adrian Prantl260aa0f2019-08-20 16:44:25 +0000143static cl::opt<std::string> CompilerContext(
144 "compiler-context",
145 cl::desc("Specify a compiler context as \"kind:name,...\"."),
146 cl::value_desc("context"), cl::sub(SymbolsSubcommand));
147
Adrian Prantlaa97a892019-08-22 21:45:58 +0000148static cl::opt<std::string>
149 Language("language", cl::desc("Specify a language type, like C99."),
150 cl::value_desc("language"), cl::sub(SymbolsSubcommand));
151
Pavel Labath90b0a532018-05-03 10:57:16 +0000152static cl::list<FunctionNameType> FunctionNameFlags(
153 "function-flags", cl::desc("Function search flags:"),
154 cl::values(clEnumValN(eFunctionNameTypeAuto, "auto",
155 "Automatically deduce flags based on name."),
156 clEnumValN(eFunctionNameTypeFull, "full", "Full function name."),
157 clEnumValN(eFunctionNameTypeBase, "base", "Base name."),
158 clEnumValN(eFunctionNameTypeMethod, "method", "Method name."),
159 clEnumValN(eFunctionNameTypeSelector, "selector",
160 "Selector name.")),
161 cl::sub(SymbolsSubcommand));
162static FunctionNameType getFunctionNameFlags() {
163 FunctionNameType Result = FunctionNameType(0);
164 for (FunctionNameType Flag : FunctionNameFlags)
165 Result = FunctionNameType(Result | Flag);
166 return Result;
167}
168
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000169static cl::opt<bool> DumpAST("dump-ast",
170 cl::desc("Dump AST restored from symbols."),
171 cl::sub(SymbolsSubcommand));
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000172static cl::opt<bool>
173 DumpClangAST("dump-clang-ast",
174 cl::desc("Dump clang AST restored from symbols."),
175 cl::sub(SymbolsSubcommand));
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000176
Aaron Smith010edd32018-06-08 02:45:25 +0000177static cl::opt<bool> Verify("verify", cl::desc("Verify symbol information."),
178 cl::sub(SymbolsSubcommand));
179
Pavel Labathe6954cb2018-06-12 12:57:36 +0000180static cl::opt<std::string> File("file",
181 cl::desc("File (compile unit) to search."),
182 cl::sub(SymbolsSubcommand));
Pavel Labath9ea80d22018-06-28 10:03:42 +0000183static cl::opt<int> Line("line", cl::desc("Line to search."),
184 cl::sub(SymbolsSubcommand));
Pavel Labathe6954cb2018-06-12 12:57:36 +0000185
Pavel Labath465eae32019-08-06 09:12:42 +0000186static Expected<CompilerDeclContext> getDeclContext(SymbolFile &Symfile);
Pavel Labath90b0a532018-05-03 10:57:16 +0000187
188static Error findFunctions(lldb_private::Module &Module);
Aleksandr Urakov398f81b2018-08-29 07:26:11 +0000189static Error findBlocks(lldb_private::Module &Module);
Pavel Labath90b0a532018-05-03 10:57:16 +0000190static Error findNamespaces(lldb_private::Module &Module);
191static Error findTypes(lldb_private::Module &Module);
192static Error findVariables(lldb_private::Module &Module);
193static Error dumpModule(lldb_private::Module &Module);
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000194static Error dumpAST(lldb_private::Module &Module);
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000195static Error dumpClangAST(lldb_private::Module &Module);
Aaron Smith010edd32018-06-08 02:45:25 +0000196static Error verify(lldb_private::Module &Module);
Pavel Labath90b0a532018-05-03 10:57:16 +0000197
Pavel Labath38d9ff72018-06-12 13:26:43 +0000198static Expected<Error (*)(lldb_private::Module &)> getAction();
Pavel Labath90b0a532018-05-03 10:57:16 +0000199static int dumpSymbols(Debugger &Dbg);
Pavel Labath9ea80d22018-06-28 10:03:42 +0000200} // namespace symbols
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000201
202namespace irmemorymap {
203static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"),
204 cl::Required,
205 cl::sub(IRMemoryMapSubcommand));
206static cl::opt<std::string> CommandFile(cl::Positional,
207 cl::desc("<command-file>"),
208 cl::init("-"),
209 cl::sub(IRMemoryMapSubcommand));
Vedant Kumarf616b9d2018-05-31 22:09:00 +0000210static cl::opt<bool> UseHostOnlyAllocationPolicy(
211 "host-only", cl::desc("Use the host-only allocation policy"),
212 cl::init(false), cl::sub(IRMemoryMapSubcommand));
213
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000214using AllocationT = std::pair<addr_t, addr_t>;
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000215using AddrIntervalMap =
Pavel Labath9ea80d22018-06-28 10:03:42 +0000216 IntervalMap<addr_t, unsigned, 8, IntervalMapHalfOpenInfo<addr_t>>;
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000217
218struct IRMemoryMapTestState {
219 TargetSP Target;
220 IRMemoryMap Map;
221
222 AddrIntervalMap::Allocator IntervalMapAllocator;
223 AddrIntervalMap Allocations;
224
225 StringMap<addr_t> Label2AddrMap;
226
227 IRMemoryMapTestState(TargetSP Target)
228 : Target(Target), Map(Target), Allocations(IntervalMapAllocator) {}
229};
230
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000231bool evalMalloc(StringRef Line, IRMemoryMapTestState &State);
232bool evalFree(StringRef Line, IRMemoryMapTestState &State);
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000233int evaluateMemoryMapCommands(Debugger &Dbg);
234} // namespace irmemorymap
235
Zachary Turner888a4282017-12-01 00:52:51 +0000236} // namespace opts
237
Adrian Prantl260aa0f2019-08-20 16:44:25 +0000238std::vector<CompilerContext> parseCompilerContext() {
239 std::vector<CompilerContext> result;
240 if (opts::symbols::CompilerContext.empty())
241 return result;
242
243 StringRef str{opts::symbols::CompilerContext};
244 SmallVector<StringRef, 8> entries_str;
245 str.split(entries_str, ',', /*maxSplit*/-1, /*keepEmpty=*/false);
246 for (auto entry_str : entries_str) {
247 StringRef key, value;
248 std::tie(key, value) = entry_str.split(':');
249 auto kind =
250 StringSwitch<CompilerContextKind>(key)
251 .Case("TranslationUnit", CompilerContextKind::TranslationUnit)
252 .Case("Module", CompilerContextKind::Module)
253 .Case("Namespace", CompilerContextKind::Namespace)
254 .Case("Class", CompilerContextKind::Class)
Adrian Prantl330ae19a2019-08-21 18:06:56 +0000255 .Case("Struct", CompilerContextKind::Struct)
Adrian Prantl260aa0f2019-08-20 16:44:25 +0000256 .Case("Union", CompilerContextKind::Union)
257 .Case("Function", CompilerContextKind::Function)
258 .Case("Variable", CompilerContextKind::Variable)
Adrian Prantl330ae19a2019-08-21 18:06:56 +0000259 .Case("Enum", CompilerContextKind::Enum)
Adrian Prantl260aa0f2019-08-20 16:44:25 +0000260 .Case("Typedef", CompilerContextKind::Typedef)
Adrian Prantl330ae19a2019-08-21 18:06:56 +0000261 .Case("AnyModule", CompilerContextKind::AnyModule)
262 .Case("AnyType", CompilerContextKind::AnyType)
Adrian Prantl260aa0f2019-08-20 16:44:25 +0000263 .Default(CompilerContextKind::Invalid);
264 if (value.empty()) {
265 WithColor::error() << "compiler context entry has no \"name\"\n";
266 exit(1);
267 }
268 result.push_back({kind, ConstString{value}});
269 }
270 outs() << "Search context: {\n";
271 for (auto entry: result)
272 entry.Dump();
273 outs() << "}\n";
274
275 return result;
276}
277
Pavel Labathe6954cb2018-06-12 12:57:36 +0000278template <typename... Args>
279static Error make_string_error(const char *Format, Args &&... args) {
280 return llvm::make_error<llvm::StringError>(
281 llvm::formatv(Format, std::forward<Args>(args)...).str(),
282 llvm::inconvertibleErrorCode());
283}
284
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000285TargetSP opts::createTarget(Debugger &Dbg, const std::string &Filename) {
286 TargetSP Target;
Jonas Devliegheref9a07e92018-09-20 09:09:05 +0000287 Status ST = Dbg.GetTargetList().CreateTarget(
288 Dbg, Filename, /*triple*/ "", eLoadDependentsNo,
289 /*platform_options*/ nullptr, Target);
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000290 if (ST.Fail()) {
291 errs() << formatv("Failed to create target '{0}: {1}\n", Filename, ST);
292 exit(1);
293 }
294 return Target;
295}
296
297std::unique_ptr<MemoryBuffer> opts::openFile(const std::string &Filename) {
298 auto MB = MemoryBuffer::getFileOrSTDIN(Filename);
299 if (!MB) {
300 errs() << formatv("Could not open file '{0}: {1}\n", Filename,
301 MB.getError().message());
302 exit(1);
303 }
304 return std::move(*MB);
305}
306
Pavel Labath7c945822018-02-26 18:50:16 +0000307void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) {
308 P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize()));
309 if (List.GetSize() > 0)
310 P.formatLine("At least one breakpoint.");
311 for (size_t i = 0, e = List.GetSize(); i < e; ++i) {
312 BreakpointSP BP = List.GetBreakpointAtIndex(i);
313 P.formatLine("Breakpoint ID {0}:", BP->GetID());
314 AutoIndent Indent(P, 2);
315 P.formatLine("{0} location{1}.", BP->GetNumLocations(),
316 plural(BP->GetNumLocations()));
317 if (BP->GetNumLocations() > 0)
318 P.formatLine("At least one location.");
319 P.formatLine("{0} resolved location{1}.", BP->GetNumResolvedLocations(),
320 plural(BP->GetNumResolvedLocations()));
321 if (BP->GetNumResolvedLocations() > 0)
322 P.formatLine("At least one resolved location.");
323 for (size_t l = 0, le = BP->GetNumLocations(); l < le; ++l) {
324 BreakpointLocationSP Loc = BP->GetLocationAtIndex(l);
325 P.formatLine("Location ID {0}:", Loc->GetID());
326 AutoIndent Indent(P, 2);
327 P.formatLine("Enabled: {0}", Loc->IsEnabled());
328 P.formatLine("Resolved: {0}", Loc->IsResolved());
Jim Ingham08581262018-03-12 21:17:04 +0000329 SymbolContext sc;
330 Loc->GetAddress().CalculateSymbolContext(&sc);
331 lldb_private::StreamString S;
332 sc.DumpStopContext(&S, BP->GetTarget().GetProcessSP().get(),
333 Loc->GetAddress(), false, true, false, true, true);
334 P.formatLine("Address: {0}", S.GetString());
Pavel Labath7c945822018-02-26 18:50:16 +0000335 }
336 }
337 P.NewLine();
338}
339
340std::string opts::breakpoint::substitute(StringRef Cmd) {
341 std::string Result;
342 raw_string_ostream OS(Result);
343 while (!Cmd.empty()) {
344 switch (Cmd[0]) {
345 case '%':
346 if (Cmd.consume_front("%p") && (Cmd.empty() || !isalnum(Cmd[0]))) {
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000347 OS << sys::path::parent_path(breakpoint::CommandFile);
Pavel Labath7c945822018-02-26 18:50:16 +0000348 break;
349 }
Reid Kleckner4dc0b1a2018-11-01 19:54:45 +0000350 LLVM_FALLTHROUGH;
Pavel Labath7c945822018-02-26 18:50:16 +0000351 default:
352 size_t pos = Cmd.find('%');
353 OS << Cmd.substr(0, pos);
354 Cmd = Cmd.substr(pos);
355 break;
356 }
357 }
358 return std::move(OS.str());
359}
360
Pavel Labath90b0a532018-05-03 10:57:16 +0000361int opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) {
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000362 TargetSP Target = opts::createTarget(Dbg, breakpoint::Target);
363 std::unique_ptr<MemoryBuffer> MB = opts::openFile(breakpoint::CommandFile);
Pavel Labath7c945822018-02-26 18:50:16 +0000364
365 LinePrinter P(4, outs());
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000366 StringRef Rest = MB->getBuffer();
Pavel Labath90b0a532018-05-03 10:57:16 +0000367 int HadErrors = 0;
Pavel Labath7c945822018-02-26 18:50:16 +0000368 while (!Rest.empty()) {
369 StringRef Line;
370 std::tie(Line, Rest) = Rest.split('\n');
Adrian McCarthy4447d152019-06-07 21:13:30 +0000371 Line = Line.ltrim().rtrim();
Pavel Labath7c945822018-02-26 18:50:16 +0000372 if (Line.empty() || Line[0] == '#')
373 continue;
374
375 if (!Persistent)
376 Target->RemoveAllBreakpoints(/*internal_also*/ true);
377
378 std::string Command = substitute(Line);
379 P.formatLine("Command: {0}", Command);
380 CommandReturnObject Result;
381 if (!Dbg.GetCommandInterpreter().HandleCommand(
382 Command.c_str(), /*add_to_history*/ eLazyBoolNo, Result)) {
383 P.formatLine("Failed: {0}", Result.GetErrorData());
Pavel Labath90b0a532018-05-03 10:57:16 +0000384 HadErrors = 1;
Pavel Labath7c945822018-02-26 18:50:16 +0000385 continue;
386 }
387
388 dumpState(Target->GetBreakpointList(/*internal*/ false), P);
389 }
Pavel Labath90b0a532018-05-03 10:57:16 +0000390 return HadErrors;
Pavel Labath7c945822018-02-26 18:50:16 +0000391}
392
Pavel Labath90b0a532018-05-03 10:57:16 +0000393Expected<CompilerDeclContext>
Pavel Labath465eae32019-08-06 09:12:42 +0000394opts::symbols::getDeclContext(SymbolFile &Symfile) {
Pavel Labath90b0a532018-05-03 10:57:16 +0000395 if (Context.empty())
396 return CompilerDeclContext();
397 VariableList List;
Pavel Labath465eae32019-08-06 09:12:42 +0000398 Symfile.FindGlobalVariables(ConstString(Context), nullptr, UINT32_MAX, List);
Pavel Labathe6954cb2018-06-12 12:57:36 +0000399 if (List.Empty())
400 return make_string_error("Context search didn't find a match.");
401 if (List.GetSize() > 1)
402 return make_string_error("Context search found multiple matches.");
Pavel Labath90b0a532018-05-03 10:57:16 +0000403 return List.GetVariableAtIndex(0)->GetDeclContext();
404}
405
406Error opts::symbols::findFunctions(lldb_private::Module &Module) {
Pavel Labath465eae32019-08-06 09:12:42 +0000407 SymbolFile &Symfile = *Module.GetSymbolFile();
Pavel Labath90b0a532018-05-03 10:57:16 +0000408 SymbolContextList List;
Pavel Labath9ea80d22018-06-28 10:03:42 +0000409 if (!File.empty()) {
410 assert(Line != 0);
411
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000412 FileSpec src_file(File);
Pavel Labath9ea80d22018-06-28 10:03:42 +0000413 size_t cu_count = Module.GetNumCompileUnits();
414 for (size_t i = 0; i < cu_count; i++) {
415 lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i);
416 if (!cu_sp)
417 continue;
418
419 LineEntry le;
420 cu_sp->FindLineEntry(0, Line, &src_file, false, &le);
421 if (!le.IsValid())
422 continue;
Greg Clayton8a777922019-05-06 20:01:21 +0000423 const bool include_inlined_functions = false;
424 auto addr =
425 le.GetSameLineContiguousAddressRange(include_inlined_functions)
426 .GetBaseAddress();
Pavel Labath9ea80d22018-06-28 10:03:42 +0000427 if (!addr.IsValid())
428 continue;
429
430 SymbolContext sc;
431 uint32_t resolved =
432 addr.CalculateSymbolContext(&sc, eSymbolContextFunction);
433 if (resolved & eSymbolContextFunction)
434 List.Append(sc);
435 }
436 } else if (Regex) {
Pavel Labath90b0a532018-05-03 10:57:16 +0000437 RegularExpression RE(Name);
438 assert(RE.IsValid());
Adrian Prantl1ad655e2019-10-17 19:56:40 +0000439 List.Clear();
440 Symfile.FindFunctions(RE, true, List);
Pavel Labath90b0a532018-05-03 10:57:16 +0000441 } else {
Pavel Labath465eae32019-08-06 09:12:42 +0000442 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
Pavel Labath90b0a532018-05-03 10:57:16 +0000443 if (!ContextOr)
444 return ContextOr.takeError();
445 CompilerDeclContext *ContextPtr =
446 ContextOr->IsValid() ? &*ContextOr : nullptr;
447
Adrian Prantl1ad655e2019-10-17 19:56:40 +0000448 List.Clear();
Pavel Labath465eae32019-08-06 09:12:42 +0000449 Symfile.FindFunctions(ConstString(Name), ContextPtr, getFunctionNameFlags(),
Adrian Prantl1ad655e2019-10-17 19:56:40 +0000450 true, List);
Pavel Labath90b0a532018-05-03 10:57:16 +0000451 }
452 outs() << formatv("Found {0} functions:\n", List.GetSize());
453 StreamString Stream;
454 List.Dump(&Stream, nullptr);
455 outs() << Stream.GetData() << "\n";
456 return Error::success();
457}
458
Aleksandr Urakov398f81b2018-08-29 07:26:11 +0000459Error opts::symbols::findBlocks(lldb_private::Module &Module) {
460 assert(!Regex);
461 assert(!File.empty());
462 assert(Line != 0);
463
464 SymbolContextList List;
465
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000466 FileSpec src_file(File);
Aleksandr Urakov398f81b2018-08-29 07:26:11 +0000467 size_t cu_count = Module.GetNumCompileUnits();
468 for (size_t i = 0; i < cu_count; i++) {
469 lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i);
470 if (!cu_sp)
471 continue;
472
473 LineEntry le;
474 cu_sp->FindLineEntry(0, Line, &src_file, false, &le);
475 if (!le.IsValid())
476 continue;
Greg Clayton8a777922019-05-06 20:01:21 +0000477 const bool include_inlined_functions = false;
478 auto addr = le.GetSameLineContiguousAddressRange(include_inlined_functions)
479 .GetBaseAddress();
Aleksandr Urakov398f81b2018-08-29 07:26:11 +0000480 if (!addr.IsValid())
481 continue;
482
483 SymbolContext sc;
484 uint32_t resolved = addr.CalculateSymbolContext(&sc, eSymbolContextBlock);
485 if (resolved & eSymbolContextBlock)
486 List.Append(sc);
487 }
488
489 outs() << formatv("Found {0} blocks:\n", List.GetSize());
490 StreamString Stream;
491 List.Dump(&Stream, nullptr);
492 outs() << Stream.GetData() << "\n";
493 return Error::success();
494}
495
Pavel Labath90b0a532018-05-03 10:57:16 +0000496Error opts::symbols::findNamespaces(lldb_private::Module &Module) {
Pavel Labath465eae32019-08-06 09:12:42 +0000497 SymbolFile &Symfile = *Module.GetSymbolFile();
498 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
Pavel Labath90b0a532018-05-03 10:57:16 +0000499 if (!ContextOr)
500 return ContextOr.takeError();
501 CompilerDeclContext *ContextPtr =
502 ContextOr->IsValid() ? &*ContextOr : nullptr;
503
Pavel Labath90b0a532018-05-03 10:57:16 +0000504 CompilerDeclContext Result =
Pavel Labath465eae32019-08-06 09:12:42 +0000505 Symfile.FindNamespace(ConstString(Name), ContextPtr);
Pavel Labath90b0a532018-05-03 10:57:16 +0000506 if (Result)
507 outs() << "Found namespace: "
508 << Result.GetScopeQualifiedName().GetStringRef() << "\n";
509 else
510 outs() << "Namespace not found.\n";
511 return Error::success();
512}
513
514Error opts::symbols::findTypes(lldb_private::Module &Module) {
Pavel Labath465eae32019-08-06 09:12:42 +0000515 SymbolFile &Symfile = *Module.GetSymbolFile();
516 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
Pavel Labath90b0a532018-05-03 10:57:16 +0000517 if (!ContextOr)
518 return ContextOr.takeError();
519 CompilerDeclContext *ContextPtr =
520 ContextOr->IsValid() ? &*ContextOr : nullptr;
521
Adrian Prantlaa97a892019-08-22 21:45:58 +0000522 LanguageSet languages;
523 if (!Language.empty())
524 languages.Insert(Language::GetLanguageTypeFromString(Language));
525
Pavel Labath90b0a532018-05-03 10:57:16 +0000526 DenseSet<SymbolFile *> SearchedFiles;
527 TypeMap Map;
Adrian Prantl260aa0f2019-08-20 16:44:25 +0000528 if (!Name.empty())
Adrian Prantld4d428e2019-09-30 16:42:28 +0000529 Symfile.FindTypes(ConstString(Name), ContextPtr, UINT32_MAX, SearchedFiles,
530 Map);
Adrian Prantl260aa0f2019-08-20 16:44:25 +0000531 else
Adrian Prantl3b73dcd2019-11-12 09:25:59 -0800532 Module.FindTypes(parseCompilerContext(), languages, SearchedFiles, Map);
Pavel Labath90b0a532018-05-03 10:57:16 +0000533
534 outs() << formatv("Found {0} types:\n", Map.GetSize());
535 StreamString Stream;
536 Map.Dump(&Stream, false);
537 outs() << Stream.GetData() << "\n";
538 return Error::success();
539}
540
541Error opts::symbols::findVariables(lldb_private::Module &Module) {
Pavel Labath465eae32019-08-06 09:12:42 +0000542 SymbolFile &Symfile = *Module.GetSymbolFile();
Pavel Labath90b0a532018-05-03 10:57:16 +0000543 VariableList List;
544 if (Regex) {
545 RegularExpression RE(Name);
546 assert(RE.IsValid());
Pavel Labath465eae32019-08-06 09:12:42 +0000547 Symfile.FindGlobalVariables(RE, UINT32_MAX, List);
Pavel Labathe6954cb2018-06-12 12:57:36 +0000548 } else if (!File.empty()) {
549 CompUnitSP CU;
550 for (size_t Ind = 0; !CU && Ind < Module.GetNumCompileUnits(); ++Ind) {
551 CompUnitSP Candidate = Module.GetCompileUnitAtIndex(Ind);
Pavel Labath38870af2019-11-28 16:22:44 +0100552 if (!Candidate ||
553 Candidate->GetPrimaryFile().GetFilename().GetStringRef() != File)
Pavel Labathe6954cb2018-06-12 12:57:36 +0000554 continue;
555 if (CU)
556 return make_string_error("Multiple compile units for file `{0}` found.",
557 File);
558 CU = std::move(Candidate);
559 }
560
561 if (!CU)
562 return make_string_error("Compile unit `{0}` not found.", File);
563
564 List.AddVariables(CU->GetVariableList(true).get());
Pavel Labath90b0a532018-05-03 10:57:16 +0000565 } else {
Pavel Labath465eae32019-08-06 09:12:42 +0000566 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
Pavel Labath90b0a532018-05-03 10:57:16 +0000567 if (!ContextOr)
568 return ContextOr.takeError();
569 CompilerDeclContext *ContextPtr =
570 ContextOr->IsValid() ? &*ContextOr : nullptr;
571
Pavel Labath465eae32019-08-06 09:12:42 +0000572 Symfile.FindGlobalVariables(ConstString(Name), ContextPtr, UINT32_MAX, List);
Pavel Labath90b0a532018-05-03 10:57:16 +0000573 }
574 outs() << formatv("Found {0} variables:\n", List.GetSize());
575 StreamString Stream;
576 List.Dump(&Stream, false);
577 outs() << Stream.GetData() << "\n";
578 return Error::success();
579}
580
581Error opts::symbols::dumpModule(lldb_private::Module &Module) {
582 StreamString Stream;
583 Module.ParseAllDebugSymbols();
584 Module.Dump(&Stream);
585 outs() << Stream.GetData() << "\n";
586 return Error::success();
587}
588
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000589Error opts::symbols::dumpAST(lldb_private::Module &Module) {
Pavel Labath465eae32019-08-06 09:12:42 +0000590 Module.ParseAllDebugSymbols();
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000591
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000592 SymbolFile *symfile = Module.GetSymbolFile();
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000593 if (!symfile)
594 return make_string_error("Module has no symbol file.");
595
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000596 llvm::Expected<TypeSystem &> type_system_or_err =
Alex Langford0e252e32019-07-30 22:12:34 +0000597 symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
598 if (!type_system_or_err)
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +0100599 return make_string_error("Can't retrieve TypeSystemClang");
Alex Langford0e252e32019-07-30 22:12:34 +0000600
601 auto *clang_ast_ctx =
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +0100602 llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get());
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000603 if (!clang_ast_ctx)
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +0100604 return make_string_error("Retrieved TypeSystem was not a TypeSystemClang");
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000605
Raphael Isemannf9f49d32019-12-21 22:40:52 +0100606 clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext();
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000607
Raphael Isemannf9f49d32019-12-21 22:40:52 +0100608 clang::TranslationUnitDecl *tu = ast_ctx.getTranslationUnitDecl();
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000609 if (!tu)
610 return make_string_error("Can't retrieve translation unit declaration.");
611
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000612 tu->print(outs());
613
614 return Error::success();
615}
616
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000617Error opts::symbols::dumpClangAST(lldb_private::Module &Module) {
618 Module.ParseAllDebugSymbols();
619
620 SymbolFile *symfile = Module.GetSymbolFile();
621 if (!symfile)
622 return make_string_error("Module has no symbol file.");
623
624 llvm::Expected<TypeSystem &> type_system_or_err =
Adrian Prantlc0eeea52019-11-21 17:21:49 -0800625 symfile->GetTypeSystemForLanguage(eLanguageTypeObjC_plus_plus);
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000626 if (!type_system_or_err)
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +0100627 return make_string_error("Can't retrieve TypeSystemClang");
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000628
629 auto *clang_ast_ctx =
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +0100630 llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get());
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000631 if (!clang_ast_ctx)
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +0100632 return make_string_error("Retrieved TypeSystem was not a TypeSystemClang");
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000633
634 StreamString Stream;
635 clang_ast_ctx->DumpFromSymbolFile(Stream, Name);
636 outs() << Stream.GetData() << "\n";
637
638 return Error::success();
639}
640
Aaron Smith010edd32018-06-08 02:45:25 +0000641Error opts::symbols::verify(lldb_private::Module &Module) {
Pavel Labath465eae32019-08-06 09:12:42 +0000642 SymbolFile *symfile = Module.GetSymbolFile();
Aaron Smith010edd32018-06-08 02:45:25 +0000643 if (!symfile)
Pavel Labathe6954cb2018-06-12 12:57:36 +0000644 return make_string_error("Module has no symbol file.");
Aaron Smith010edd32018-06-08 02:45:25 +0000645
646 uint32_t comp_units_count = symfile->GetNumCompileUnits();
647
648 outs() << "Found " << comp_units_count << " compile units.\n";
649
650 for (uint32_t i = 0; i < comp_units_count; i++) {
Pavel Labathe0119902019-07-23 09:24:02 +0000651 lldb::CompUnitSP comp_unit = symfile->GetCompileUnitAtIndex(i);
Aaron Smith010edd32018-06-08 02:45:25 +0000652 if (!comp_unit)
Pavel Labathe6954cb2018-06-12 12:57:36 +0000653 return make_string_error("Connot parse compile unit {0}.", i);
Aaron Smith010edd32018-06-08 02:45:25 +0000654
Pavel Labath38870af2019-11-28 16:22:44 +0100655 outs() << "Processing '"
656 << comp_unit->GetPrimaryFile().GetFilename().AsCString()
Pavel Labath9ea80d22018-06-28 10:03:42 +0000657 << "' compile unit.\n";
Aaron Smith010edd32018-06-08 02:45:25 +0000658
659 LineTable *lt = comp_unit->GetLineTable();
660 if (!lt)
Pavel Labathe6954cb2018-06-12 12:57:36 +0000661 return make_string_error("Can't get a line table of a compile unit.");
Aaron Smith010edd32018-06-08 02:45:25 +0000662
663 uint32_t count = lt->GetSize();
664
665 outs() << "The line table contains " << count << " entries.\n";
666
667 if (count == 0)
668 continue;
669
670 LineEntry le;
671 if (!lt->GetLineEntryAtIndex(0, le))
Pavel Labathe6954cb2018-06-12 12:57:36 +0000672 return make_string_error("Can't get a line entry of a compile unit.");
Aaron Smith010edd32018-06-08 02:45:25 +0000673
674 for (uint32_t i = 1; i < count; i++) {
675 lldb::addr_t curr_end =
Pavel Labath9ea80d22018-06-28 10:03:42 +0000676 le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize();
Aaron Smith010edd32018-06-08 02:45:25 +0000677
678 if (!lt->GetLineEntryAtIndex(i, le))
Pavel Labathe6954cb2018-06-12 12:57:36 +0000679 return make_string_error("Can't get a line entry of a compile unit");
Aaron Smith010edd32018-06-08 02:45:25 +0000680
681 if (curr_end > le.range.GetBaseAddress().GetFileAddress())
Pavel Labathe6954cb2018-06-12 12:57:36 +0000682 return make_string_error(
683 "Line table of a compile unit is inconsistent.");
Aaron Smith010edd32018-06-08 02:45:25 +0000684 }
685 }
686
687 outs() << "The symbol information is verified.\n";
688
689 return Error::success();
690}
691
Pavel Labath38d9ff72018-06-12 13:26:43 +0000692Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() {
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000693 if (Verify && DumpAST)
694 return make_string_error(
695 "Cannot both verify symbol information and dump AST.");
696
Pavel Labathe6954cb2018-06-12 12:57:36 +0000697 if (Verify) {
698 if (Find != FindType::None)
699 return make_string_error(
700 "Cannot both search and verify symbol information.");
Pavel Labath9ea80d22018-06-28 10:03:42 +0000701 if (Regex || !Context.empty() || !Name.empty() || !File.empty() ||
702 Line != 0)
703 return make_string_error(
704 "-regex, -context, -name, -file and -line options are not "
705 "applicable for symbol verification.");
Pavel Labathe6954cb2018-06-12 12:57:36 +0000706 return verify;
Pavel Labath90b0a532018-05-03 10:57:16 +0000707 }
708
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000709 if (DumpAST) {
710 if (Find != FindType::None)
Aaron Smith037ed1b2018-12-06 21:36:39 +0000711 return make_string_error("Cannot both search and dump AST.");
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000712 if (Regex || !Context.empty() || !Name.empty() || !File.empty() ||
713 Line != 0)
714 return make_string_error(
715 "-regex, -context, -name, -file and -line options are not "
716 "applicable for dumping AST.");
717 return dumpAST;
718 }
719
Shafik Yaghmour5f469822019-10-11 16:36:20 +0000720 if (DumpClangAST) {
721 if (Find != FindType::None)
722 return make_string_error("Cannot both search and dump clang AST.");
723 if (Regex || !Context.empty() || !File.empty() || Line != 0)
724 return make_string_error(
725 "-regex, -context, -name, -file and -line options are not "
726 "applicable for dumping clang AST.");
727 return dumpClangAST;
728 }
729
Pavel Labathe6954cb2018-06-12 12:57:36 +0000730 if (Regex && !Context.empty())
731 return make_string_error(
732 "Cannot search using both regular expressions and context.");
733
734 if (Regex && !RegularExpression(Name).IsValid())
735 return make_string_error("`{0}` is not a valid regular expression.", Name);
736
737 if (Regex + !Context.empty() + !File.empty() >= 2)
738 return make_string_error(
739 "Only one of -regex, -context and -file may be used simultaneously.");
740 if (Regex && Name.empty())
741 return make_string_error("-regex used without a -name");
742
743 switch (Find) {
744 case FindType::None:
Pavel Labath9ea80d22018-06-28 10:03:42 +0000745 if (!Context.empty() || !Name.empty() || !File.empty() || Line != 0)
Pavel Labathe6954cb2018-06-12 12:57:36 +0000746 return make_string_error(
747 "Specify search type (-find) to use search options.");
748 return dumpModule;
749
750 case FindType::Function:
Pavel Labath9ea80d22018-06-28 10:03:42 +0000751 if (!File.empty() + (Line != 0) == 1)
752 return make_string_error("Both file name and line number must be "
753 "specified when searching a function "
754 "by file position.");
755 if (Regex + (getFunctionNameFlags() != 0) + !File.empty() >= 2)
756 return make_string_error("Only one of regular expression, function-flags "
757 "and file position may be used simultaneously "
758 "when searching a function.");
Pavel Labathe6954cb2018-06-12 12:57:36 +0000759 return findFunctions;
760
Aleksandr Urakov398f81b2018-08-29 07:26:11 +0000761 case FindType::Block:
762 if (File.empty() || Line == 0)
763 return make_string_error("Both file name and line number must be "
764 "specified when searching a block.");
765 if (Regex || getFunctionNameFlags() != 0)
766 return make_string_error("Cannot use regular expression or "
767 "function-flags for searching a block.");
768 return findBlocks;
769
Pavel Labathe6954cb2018-06-12 12:57:36 +0000770 case FindType::Namespace:
Pavel Labath9ea80d22018-06-28 10:03:42 +0000771 if (Regex || !File.empty() || Line != 0)
Pavel Labathe6954cb2018-06-12 12:57:36 +0000772 return make_string_error("Cannot search for namespaces using regular "
Pavel Labath9ea80d22018-06-28 10:03:42 +0000773 "expressions, file names or line numbers.");
Pavel Labathe6954cb2018-06-12 12:57:36 +0000774 return findNamespaces;
775
776 case FindType::Type:
Pavel Labath9ea80d22018-06-28 10:03:42 +0000777 if (Regex || !File.empty() || Line != 0)
Pavel Labathe6954cb2018-06-12 12:57:36 +0000778 return make_string_error("Cannot search for types using regular "
Pavel Labath9ea80d22018-06-28 10:03:42 +0000779 "expressions, file names or line numbers.");
Adrian Prantl260aa0f2019-08-20 16:44:25 +0000780 if (!Name.empty() && !CompilerContext.empty())
781 return make_string_error("Name is ignored if compiler context present.");
782
Pavel Labathe6954cb2018-06-12 12:57:36 +0000783 return findTypes;
784
785 case FindType::Variable:
Pavel Labath9ea80d22018-06-28 10:03:42 +0000786 if (Line != 0)
787 return make_string_error("Cannot search for variables "
788 "using line numbers.");
Pavel Labathe6954cb2018-06-12 12:57:36 +0000789 return findVariables;
790 }
Aleksandr Urakov709426b2018-09-10 08:08:43 +0000791
792 llvm_unreachable("Unsupported symbol action.");
Pavel Labathe6954cb2018-06-12 12:57:36 +0000793}
794
795int opts::symbols::dumpSymbols(Debugger &Dbg) {
796 auto ActionOr = getAction();
797 if (!ActionOr) {
798 logAllUnhandledErrors(ActionOr.takeError(), WithColor::error(), "");
799 return 1;
800 }
801 auto Action = *ActionOr;
Pavel Labath90b0a532018-05-03 10:57:16 +0000802
Pavel Labath1cf23e12019-01-11 11:17:51 +0000803 outs() << "Module: " << InputFile << "\n";
804 ModuleSpec Spec{FileSpec(InputFile)};
805 StringRef Symbols = SymbolPath.empty() ? InputFile : SymbolPath;
806 Spec.GetSymbolFileSpec().SetFile(Symbols, FileSpec::Style::native);
Zachary Turnera6d54642017-12-02 00:15:29 +0000807
Pavel Labath1cf23e12019-01-11 11:17:51 +0000808 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
Pavel Labath465eae32019-08-06 09:12:42 +0000809 SymbolFile *Symfile = ModulePtr->GetSymbolFile();
810 if (!Symfile) {
Pavel Labath1cf23e12019-01-11 11:17:51 +0000811 WithColor::error() << "Module has no symbol vendor.\n";
812 return 1;
Zachary Turnera6d54642017-12-02 00:15:29 +0000813 }
Pavel Labath1cf23e12019-01-11 11:17:51 +0000814
815 if (Error E = Action(*ModulePtr)) {
816 WithColor::error() << toString(std::move(E)) << "\n";
817 return 1;
818 }
819
820 return 0;
Zachary Turnera6d54642017-12-02 00:15:29 +0000821}
822
Pavel Labath280d2e82018-12-12 12:35:25 +0000823static void dumpSectionList(LinePrinter &Printer, const SectionList &List, bool is_subsection) {
824 size_t Count = List.GetNumSections(0);
825 if (Count == 0) {
826 Printer.formatLine("There are no {0}sections", is_subsection ? "sub" : "");
827 return;
828 }
829 Printer.formatLine("Showing {0} {1}sections", Count,
830 is_subsection ? "sub" : "");
831 for (size_t I = 0; I < Count; ++I) {
832 auto S = List.GetSectionAtIndex(I);
833 assert(S);
834 AutoIndent Indent(Printer, 2);
835 Printer.formatLine("Index: {0}", I);
Pavel Labath0d38e4f2018-12-18 15:56:45 +0000836 Printer.formatLine("ID: {0:x}", S->GetID());
Pavel Labath280d2e82018-12-12 12:35:25 +0000837 Printer.formatLine("Name: {0}", S->GetName().GetStringRef());
838 Printer.formatLine("Type: {0}", S->GetTypeAsCString());
Pavel Labath62a82542018-12-15 13:45:38 +0000839 Printer.formatLine("Permissions: {0}", GetPermissionsAsCString(S->GetPermissions()));
Pavel Labathef8683a2018-12-12 15:46:18 +0000840 Printer.formatLine("Thread specific: {0:y}", S->IsThreadSpecific());
Pavel Labath62a82542018-12-15 13:45:38 +0000841 Printer.formatLine("VM address: {0:x}", S->GetFileAddress());
Pavel Labath280d2e82018-12-12 12:35:25 +0000842 Printer.formatLine("VM size: {0}", S->GetByteSize());
843 Printer.formatLine("File size: {0}", S->GetFileSize());
844
845 if (opts::object::SectionContents) {
Jonas Devliegheref4af9a92019-07-11 20:26:53 +0000846 lldb_private::DataExtractor Data;
Pavel Labath280d2e82018-12-12 12:35:25 +0000847 S->GetSectionData(Data);
848 ArrayRef<uint8_t> Bytes = {Data.GetDataStart(), Data.GetDataEnd()};
849 Printer.formatBinary("Data: ", Bytes, 0);
850 }
851
852 if (S->GetType() == eSectionTypeContainer)
853 dumpSectionList(Printer, S->GetChildren(), true);
854 Printer.NewLine();
855 }
856}
857
Pavel Labath62a7f802018-06-29 12:15:54 +0000858static int dumpObjectFiles(Debugger &Dbg) {
Zachary Turner888a4282017-12-01 00:52:51 +0000859 LinePrinter Printer(4, llvm::outs());
860
Pavel Labath90b0a532018-05-03 10:57:16 +0000861 int HadErrors = 0;
Pavel Labath62a7f802018-06-29 12:15:54 +0000862 for (const auto &File : opts::object::InputFilenames) {
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000863 ModuleSpec Spec{FileSpec(File)};
Zachary Turner888a4282017-12-01 00:52:51 +0000864
Zachary Turnera6d54642017-12-02 00:15:29 +0000865 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec);
Pavel Labath1f6b2472018-12-10 17:16:38 +0000866
867 ObjectFile *ObjectPtr = ModulePtr->GetObjectFile();
868 if (!ObjectPtr) {
869 WithColor::error() << File << " not recognised as an object file\n";
870 HadErrors = 1;
871 continue;
872 }
873
Pavel Labath96979ce2018-03-06 15:56:20 +0000874 // Fetch symbol vendor before we get the section list to give the symbol
875 // vendor a chance to populate it.
Pavel Labath465eae32019-08-06 09:12:42 +0000876 ModulePtr->GetSymbolFile();
Zachary Turner888a4282017-12-01 00:52:51 +0000877 SectionList *Sections = ModulePtr->GetSectionList();
878 if (!Sections) {
879 llvm::errs() << "Could not load sections for module " << File << "\n";
Pavel Labath90b0a532018-05-03 10:57:16 +0000880 HadErrors = 1;
Zachary Turner888a4282017-12-01 00:52:51 +0000881 continue;
882 }
883
Pavel Labath1f6b2472018-12-10 17:16:38 +0000884 Printer.formatLine("Plugin name: {0}", ObjectPtr->GetPluginName());
Pavel Labath62a7f802018-06-29 12:15:54 +0000885 Printer.formatLine("Architecture: {0}",
886 ModulePtr->GetArchitecture().GetTriple().getTriple());
887 Printer.formatLine("UUID: {0}", ModulePtr->GetUUID().GetAsString());
Pavel Labath1f6b2472018-12-10 17:16:38 +0000888 Printer.formatLine("Executable: {0}", ObjectPtr->IsExecutable());
889 Printer.formatLine("Stripped: {0}", ObjectPtr->IsStripped());
890 Printer.formatLine("Type: {0}", ObjectPtr->GetType());
891 Printer.formatLine("Strata: {0}", ObjectPtr->GetStrata());
Pavel Labath976af432019-01-10 09:32:31 +0000892 Printer.formatLine("Base VM address: {0:x}",
893 ObjectPtr->GetBaseAddress().GetFileAddress());
Pavel Labath62a7f802018-06-29 12:15:54 +0000894
Pavel Labath280d2e82018-12-12 12:35:25 +0000895 dumpSectionList(Printer, *Sections, /*is_subsection*/ false);
Aaron Smith037ed1b2018-12-06 21:36:39 +0000896
897 if (opts::object::SectionDependentModules) {
898 // A non-empty section list ensures a valid object file.
899 auto Obj = ModulePtr->GetObjectFile();
900 FileSpecList Files;
901 auto Count = Obj->GetDependentModules(Files);
902 Printer.formatLine("Showing {0} dependent module(s)", Count);
903 for (size_t I = 0; I < Files.GetSize(); ++I) {
904 AutoIndent Indent(Printer, 2);
905 Printer.formatLine("Name: {0}",
906 Files.GetFileSpecAtIndex(I).GetCString());
907 }
908 Printer.NewLine();
909 }
Zachary Turner888a4282017-12-01 00:52:51 +0000910 }
Pavel Labath90b0a532018-05-03 10:57:16 +0000911 return HadErrors;
Zachary Turner888a4282017-12-01 00:52:51 +0000912}
913
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000914bool opts::irmemorymap::evalMalloc(StringRef Line,
915 IRMemoryMapTestState &State) {
916 // ::= <label> = malloc <size> <alignment>
917 StringRef Label;
918 std::tie(Label, Line) = Line.split('=');
919 if (Line.empty())
920 return false;
921 Label = Label.trim();
922 Line = Line.trim();
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000923 size_t Size;
924 uint8_t Alignment;
925 int Matches = sscanf(Line.data(), "malloc %zu %hhu", &Size, &Alignment);
926 if (Matches != 2)
927 return false;
928
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000929 outs() << formatv("Command: {0} = malloc(size={1}, alignment={2})\n", Label,
930 Size, Alignment);
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000931 if (!isPowerOf2_32(Alignment)) {
932 outs() << "Malloc error: alignment is not a power of 2\n";
933 exit(1);
934 }
935
Vedant Kumarf616b9d2018-05-31 22:09:00 +0000936 IRMemoryMap::AllocationPolicy AP =
937 UseHostOnlyAllocationPolicy ? IRMemoryMap::eAllocationPolicyHostOnly
938 : IRMemoryMap::eAllocationPolicyProcessOnly;
939
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000940 // Issue the malloc in the target process with "-rw" permissions.
941 const uint32_t Permissions = 0x3;
942 const bool ZeroMemory = false;
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000943 Status ST;
944 addr_t Addr =
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000945 State.Map.Malloc(Size, Alignment, Permissions, AP, ZeroMemory, ST);
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000946 if (ST.Fail()) {
947 outs() << formatv("Malloc error: {0}\n", ST);
948 return true;
949 }
950
951 // Print the result of the allocation before checking its validity.
952 outs() << formatv("Malloc: address = {0:x}\n", Addr);
953
954 // Check that the allocation is aligned.
955 if (!Addr || Addr % Alignment != 0) {
956 outs() << "Malloc error: zero or unaligned allocation detected\n";
957 exit(1);
958 }
959
Pavel Labatha352ed22018-12-27 09:32:04 +0000960 // In case of Size == 0, we still expect the returned address to be unique and
961 // non-overlapping.
962 addr_t EndOfRegion = Addr + std::max<size_t>(Size, 1);
963 if (State.Allocations.overlaps(Addr, EndOfRegion)) {
964 auto I = State.Allocations.find(Addr);
965 outs() << "Malloc error: overlapping allocation detected"
966 << formatv(", previous allocation at [{0:x}, {1:x})\n", I.start(),
967 I.stop());
968 exit(1);
Vedant Kumarc1cd8262018-05-30 19:39:10 +0000969 }
970
Aaron Smith037ed1b2018-12-06 21:36:39 +0000971 // Insert the new allocation into the interval map. Use unique allocation
972 // IDs to inhibit interval coalescing.
Vedant Kumarcc5a6162018-05-31 22:09:01 +0000973 static unsigned AllocationID = 0;
Pavel Labatha352ed22018-12-27 09:32:04 +0000974 State.Allocations.insert(Addr, EndOfRegion, AllocationID++);
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000975
976 // Store the label -> address mapping.
977 State.Label2AddrMap[Label] = Addr;
Vedant Kumarcc5a6162018-05-31 22:09:01 +0000978
979 return true;
980}
981
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000982bool opts::irmemorymap::evalFree(StringRef Line, IRMemoryMapTestState &State) {
983 // ::= free <label>
984 if (!Line.consume_front("free"))
Vedant Kumarcc5a6162018-05-31 22:09:01 +0000985 return false;
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000986 StringRef Label = Line.trim();
Vedant Kumarcc5a6162018-05-31 22:09:01 +0000987
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000988 outs() << formatv("Command: free({0})\n", Label);
989 auto LabelIt = State.Label2AddrMap.find(Label);
990 if (LabelIt == State.Label2AddrMap.end()) {
991 outs() << "Free error: Invalid allocation label\n";
Vedant Kumarcc5a6162018-05-31 22:09:01 +0000992 exit(1);
993 }
994
995 Status ST;
Vedant Kumarc418b5c2018-06-04 17:11:15 +0000996 addr_t Addr = LabelIt->getValue();
997 State.Map.Free(Addr, ST);
Vedant Kumarcc5a6162018-05-31 22:09:01 +0000998 if (ST.Fail()) {
999 outs() << formatv("Free error: {0}\n", ST);
1000 exit(1);
1001 }
1002
1003 // Erase the allocation from the live interval map.
Vedant Kumarc418b5c2018-06-04 17:11:15 +00001004 auto Interval = State.Allocations.find(Addr);
1005 if (Interval != State.Allocations.end()) {
1006 outs() << formatv("Free: [{0:x}, {1:x})\n", Interval.start(),
1007 Interval.stop());
1008 Interval.erase();
1009 }
Vedant Kumarc1cd8262018-05-30 19:39:10 +00001010
1011 return true;
1012}
1013
1014int opts::irmemorymap::evaluateMemoryMapCommands(Debugger &Dbg) {
1015 // Set up a Target.
1016 TargetSP Target = opts::createTarget(Dbg, irmemorymap::Target);
1017
1018 // Set up a Process. In order to allocate memory within a target, this
1019 // process must be alive and must support JIT'ing.
1020 CommandReturnObject Result;
1021 Dbg.SetAsyncExecution(false);
1022 CommandInterpreter &CI = Dbg.GetCommandInterpreter();
1023 auto IssueCmd = [&](const char *Cmd) -> bool {
1024 return CI.HandleCommand(Cmd, eLazyBoolNo, Result);
1025 };
1026 if (!IssueCmd("b main") || !IssueCmd("run")) {
1027 outs() << formatv("Failed: {0}\n", Result.GetErrorData());
1028 exit(1);
1029 }
1030
1031 ProcessSP Process = Target->GetProcessSP();
1032 if (!Process || !Process->IsAlive() || !Process->CanJIT()) {
1033 outs() << "Cannot use process to test IRMemoryMap\n";
1034 exit(1);
1035 }
1036
1037 // Set up an IRMemoryMap and associated testing state.
Vedant Kumarc418b5c2018-06-04 17:11:15 +00001038 IRMemoryMapTestState State(Target);
Vedant Kumarc1cd8262018-05-30 19:39:10 +00001039
1040 // Parse and apply commands from the command file.
1041 std::unique_ptr<MemoryBuffer> MB = opts::openFile(irmemorymap::CommandFile);
1042 StringRef Rest = MB->getBuffer();
1043 while (!Rest.empty()) {
1044 StringRef Line;
1045 std::tie(Line, Rest) = Rest.split('\n');
Adrian McCarthy4447d152019-06-07 21:13:30 +00001046 Line = Line.ltrim().rtrim();
Vedant Kumarc1cd8262018-05-30 19:39:10 +00001047
1048 if (Line.empty() || Line[0] == '#')
1049 continue;
1050
Vedant Kumarc418b5c2018-06-04 17:11:15 +00001051 if (evalMalloc(Line, State))
Vedant Kumarc1cd8262018-05-30 19:39:10 +00001052 continue;
1053
Vedant Kumarc418b5c2018-06-04 17:11:15 +00001054 if (evalFree(Line, State))
Vedant Kumarcc5a6162018-05-31 22:09:01 +00001055 continue;
1056
Vedant Kumarc1cd8262018-05-30 19:39:10 +00001057 errs() << "Could not parse line: " << Line << "\n";
1058 exit(1);
1059 }
1060 return 0;
1061}
1062
Zachary Turner888a4282017-12-01 00:52:51 +00001063int main(int argc, const char *argv[]) {
1064 StringRef ToolName = argv[0];
1065 sys::PrintStackTraceOnErrorSignal(ToolName);
1066 PrettyStackTraceProgram X(argc, argv);
1067 llvm_shutdown_obj Y;
1068
1069 cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
1070
Pavel Labath90b0a532018-05-03 10:57:16 +00001071 SystemLifetimeManager DebuggerLifetime;
Jonas Devlieghere15eacd72018-12-03 17:28:29 +00001072 if (auto e = DebuggerLifetime.Initialize(
Jonas Devliegherea8f3ae72019-08-14 22:19:23 +00001073 std::make_unique<SystemInitializerTest>(), nullptr)) {
Jonas Devlieghere15eacd72018-12-03 17:28:29 +00001074 WithColor::error() << "initialization failed: " << toString(std::move(e))
1075 << '\n';
1076 return 1;
1077 }
1078
Jonas Devliegheree0ea8d82019-09-10 00:20:50 +00001079 auto TerminateDebugger =
1080 llvm::make_scope_exit([&] { DebuggerLifetime.Terminate(); });
Zachary Turner888a4282017-12-01 00:52:51 +00001081
1082 auto Dbg = lldb_private::Debugger::CreateInstance();
Jan Kratochvil8c82c412019-06-17 14:46:17 +00001083 ModuleList::GetGlobalModuleListProperties().SetEnableExternalLookup(false);
Jan Kratochvil2b389512019-07-29 16:10:16 +00001084 CommandReturnObject Result;
1085 Dbg->GetCommandInterpreter().HandleCommand(
1086 "settings set plugin.process.gdb-remote.packet-timeout 60",
1087 /*add_to_history*/ eLazyBoolNo, Result);
Zachary Turner888a4282017-12-01 00:52:51 +00001088
Vedant Kumarc1cd8262018-05-30 19:39:10 +00001089 if (!opts::Log.empty())
1090 Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, errs());
1091
Pavel Labath7c945822018-02-26 18:50:16 +00001092 if (opts::BreakpointSubcommand)
Pavel Labath90b0a532018-05-03 10:57:16 +00001093 return opts::breakpoint::evaluateBreakpoints(*Dbg);
Pavel Labath62a7f802018-06-29 12:15:54 +00001094 if (opts::ObjectFileSubcommand)
1095 return dumpObjectFiles(*Dbg);
Pavel Labath90b0a532018-05-03 10:57:16 +00001096 if (opts::SymbolsSubcommand)
1097 return opts::symbols::dumpSymbols(*Dbg);
Vedant Kumarc1cd8262018-05-30 19:39:10 +00001098 if (opts::IRMemoryMapSubcommand)
1099 return opts::irmemorymap::evaluateMemoryMapCommands(*Dbg);
Zachary Turner888a4282017-12-01 00:52:51 +00001100
Pavel Labath90b0a532018-05-03 10:57:16 +00001101 WithColor::error() << "No command specified.\n";
1102 return 1;
Zachary Turner888a4282017-12-01 00:52:51 +00001103}