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