1 //===- lldb-test.cpp ------------------------------------------ *- C++ --*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "FormatUtil.h" 10 #include "SystemInitializerTest.h" 11 12 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" 13 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 14 #include "lldb/Breakpoint/BreakpointLocation.h" 15 #include "lldb/Core/Debugger.h" 16 #include "lldb/Core/Module.h" 17 #include "lldb/Core/Section.h" 18 #include "lldb/Expression/IRMemoryMap.h" 19 #include "lldb/Initialization/SystemLifetimeManager.h" 20 #include "lldb/Interpreter/CommandInterpreter.h" 21 #include "lldb/Interpreter/CommandReturnObject.h" 22 #include "lldb/Symbol/CompileUnit.h" 23 #include "lldb/Symbol/LineTable.h" 24 #include "lldb/Symbol/SymbolFile.h" 25 #include "lldb/Symbol/TypeList.h" 26 #include "lldb/Symbol/TypeMap.h" 27 #include "lldb/Symbol/VariableList.h" 28 #include "lldb/Target/Language.h" 29 #include "lldb/Target/Process.h" 30 #include "lldb/Target/Target.h" 31 #include "lldb/Utility/DataExtractor.h" 32 #include "lldb/Utility/State.h" 33 #include "lldb/Utility/StreamString.h" 34 35 #include "llvm/ADT/IntervalMap.h" 36 #include "llvm/ADT/ScopeExit.h" 37 #include "llvm/ADT/StringRef.h" 38 #include "llvm/Support/CommandLine.h" 39 #include "llvm/Support/ManagedStatic.h" 40 #include "llvm/Support/MathExtras.h" 41 #include "llvm/Support/Path.h" 42 #include "llvm/Support/PrettyStackTrace.h" 43 #include "llvm/Support/Signals.h" 44 #include "llvm/Support/WithColor.h" 45 46 #include <cstdio> 47 #include <thread> 48 49 using namespace lldb; 50 using namespace lldb_private; 51 using namespace llvm; 52 53 namespace opts { 54 static cl::SubCommand BreakpointSubcommand("breakpoints", 55 "Test breakpoint resolution"); 56 cl::SubCommand ObjectFileSubcommand("object-file", 57 "Display LLDB object file information"); 58 cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file"); 59 cl::SubCommand IRMemoryMapSubcommand("ir-memory-map", "Test IRMemoryMap"); 60 61 cl::opt<std::string> Log("log", cl::desc("Path to a log file"), cl::init(""), 62 cl::sub(BreakpointSubcommand), 63 cl::sub(ObjectFileSubcommand), 64 cl::sub(SymbolsSubcommand), 65 cl::sub(IRMemoryMapSubcommand)); 66 67 /// Create a target using the file pointed to by \p Filename, or abort. 68 TargetSP createTarget(Debugger &Dbg, const std::string &Filename); 69 70 /// Read \p Filename into a null-terminated buffer, or abort. 71 std::unique_ptr<MemoryBuffer> openFile(const std::string &Filename); 72 73 namespace breakpoint { 74 static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"), 75 cl::Required, cl::sub(BreakpointSubcommand)); 76 static cl::opt<std::string> CommandFile(cl::Positional, 77 cl::desc("<command-file>"), 78 cl::init("-"), 79 cl::sub(BreakpointSubcommand)); 80 static cl::opt<bool> Persistent( 81 "persistent", 82 cl::desc("Don't automatically remove all breakpoints before each command"), 83 cl::sub(BreakpointSubcommand)); 84 85 static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; } 86 static void dumpState(const BreakpointList &List, LinePrinter &P); 87 static std::string substitute(StringRef Cmd); 88 static int evaluateBreakpoints(Debugger &Dbg); 89 } // namespace breakpoint 90 91 namespace object { 92 cl::opt<bool> SectionContents("contents", 93 cl::desc("Dump each section's contents"), 94 cl::sub(ObjectFileSubcommand)); 95 cl::opt<bool> SectionDependentModules("dep-modules", 96 cl::desc("Dump each dependent module"), 97 cl::sub(ObjectFileSubcommand)); 98 cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"), 99 cl::OneOrMore, 100 cl::sub(ObjectFileSubcommand)); 101 } // namespace object 102 103 namespace symbols { 104 static cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input file>"), 105 cl::Required, cl::sub(SymbolsSubcommand)); 106 107 static 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 112 enum class FindType { 113 None, 114 Function, 115 Block, 116 Namespace, 117 Type, 118 Variable, 119 }; 120 static cl::opt<FindType> Find( 121 "find", cl::desc("Choose search type:"), 122 cl::values( 123 clEnumValN(FindType::None, "none", "No search, just dump the module."), 124 clEnumValN(FindType::Function, "function", "Find functions."), 125 clEnumValN(FindType::Block, "block", "Find blocks."), 126 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 131 static cl::opt<std::string> Name("name", cl::desc("Name to find."), 132 cl::sub(SymbolsSubcommand)); 133 static cl::opt<bool> 134 Regex("regex", 135 cl::desc("Search using regular expressions (available for variables " 136 "and functions only)."), 137 cl::sub(SymbolsSubcommand)); 138 static 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 143 static 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 148 static cl::opt<std::string> 149 Language("language", cl::desc("Specify a language type, like C99."), 150 cl::value_desc("language"), cl::sub(SymbolsSubcommand)); 151 152 static 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)); 162 static FunctionNameType getFunctionNameFlags() { 163 FunctionNameType Result = FunctionNameType(0); 164 for (FunctionNameType Flag : FunctionNameFlags) 165 Result = FunctionNameType(Result | Flag); 166 return Result; 167 } 168 169 static cl::opt<bool> DumpAST("dump-ast", 170 cl::desc("Dump AST restored from symbols."), 171 cl::sub(SymbolsSubcommand)); 172 static cl::opt<bool> 173 DumpClangAST("dump-clang-ast", 174 cl::desc("Dump clang AST restored from symbols."), 175 cl::sub(SymbolsSubcommand)); 176 177 static cl::opt<bool> Verify("verify", cl::desc("Verify symbol information."), 178 cl::sub(SymbolsSubcommand)); 179 180 static cl::opt<std::string> File("file", 181 cl::desc("File (compile unit) to search."), 182 cl::sub(SymbolsSubcommand)); 183 static cl::opt<int> Line("line", cl::desc("Line to search."), 184 cl::sub(SymbolsSubcommand)); 185 186 static Expected<CompilerDeclContext> getDeclContext(SymbolFile &Symfile); 187 188 static Error findFunctions(lldb_private::Module &Module); 189 static Error findBlocks(lldb_private::Module &Module); 190 static Error findNamespaces(lldb_private::Module &Module); 191 static Error findTypes(lldb_private::Module &Module); 192 static Error findVariables(lldb_private::Module &Module); 193 static Error dumpModule(lldb_private::Module &Module); 194 static Error dumpAST(lldb_private::Module &Module); 195 static Error dumpClangAST(lldb_private::Module &Module); 196 static Error verify(lldb_private::Module &Module); 197 198 static Expected<Error (*)(lldb_private::Module &)> getAction(); 199 static int dumpSymbols(Debugger &Dbg); 200 } // namespace symbols 201 202 namespace irmemorymap { 203 static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"), 204 cl::Required, 205 cl::sub(IRMemoryMapSubcommand)); 206 static cl::opt<std::string> CommandFile(cl::Positional, 207 cl::desc("<command-file>"), 208 cl::init("-"), 209 cl::sub(IRMemoryMapSubcommand)); 210 static cl::opt<bool> UseHostOnlyAllocationPolicy( 211 "host-only", cl::desc("Use the host-only allocation policy"), 212 cl::init(false), cl::sub(IRMemoryMapSubcommand)); 213 214 using AllocationT = std::pair<addr_t, addr_t>; 215 using AddrIntervalMap = 216 IntervalMap<addr_t, unsigned, 8, IntervalMapHalfOpenInfo<addr_t>>; 217 218 struct 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 231 bool evalMalloc(StringRef Line, IRMemoryMapTestState &State); 232 bool evalFree(StringRef Line, IRMemoryMapTestState &State); 233 int evaluateMemoryMapCommands(Debugger &Dbg); 234 } // namespace irmemorymap 235 236 } // namespace opts 237 238 std::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) 255 .Case("Struct", CompilerContextKind::Struct) 256 .Case("Union", CompilerContextKind::Union) 257 .Case("Function", CompilerContextKind::Function) 258 .Case("Variable", CompilerContextKind::Variable) 259 .Case("Enum", CompilerContextKind::Enum) 260 .Case("Typedef", CompilerContextKind::Typedef) 261 .Case("AnyModule", CompilerContextKind::AnyModule) 262 .Case("AnyType", CompilerContextKind::AnyType) 263 .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 278 template <typename... Args> 279 static 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 285 TargetSP opts::createTarget(Debugger &Dbg, const std::string &Filename) { 286 TargetSP Target; 287 Status ST = Dbg.GetTargetList().CreateTarget( 288 Dbg, Filename, /*triple*/ "", eLoadDependentsNo, 289 /*platform_options*/ nullptr, Target); 290 if (ST.Fail()) { 291 errs() << formatv("Failed to create target '{0}: {1}\n", Filename, ST); 292 exit(1); 293 } 294 return Target; 295 } 296 297 std::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 307 void 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()); 329 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()); 335 } 336 } 337 P.NewLine(); 338 } 339 340 std::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]))) { 347 OS << sys::path::parent_path(breakpoint::CommandFile); 348 break; 349 } 350 LLVM_FALLTHROUGH; 351 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 361 int opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) { 362 TargetSP Target = opts::createTarget(Dbg, breakpoint::Target); 363 std::unique_ptr<MemoryBuffer> MB = opts::openFile(breakpoint::CommandFile); 364 365 LinePrinter P(4, outs()); 366 StringRef Rest = MB->getBuffer(); 367 int HadErrors = 0; 368 while (!Rest.empty()) { 369 StringRef Line; 370 std::tie(Line, Rest) = Rest.split('\n'); 371 Line = Line.ltrim().rtrim(); 372 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()); 384 HadErrors = 1; 385 continue; 386 } 387 388 dumpState(Target->GetBreakpointList(/*internal*/ false), P); 389 } 390 return HadErrors; 391 } 392 393 Expected<CompilerDeclContext> 394 opts::symbols::getDeclContext(SymbolFile &Symfile) { 395 if (Context.empty()) 396 return CompilerDeclContext(); 397 VariableList List; 398 Symfile.FindGlobalVariables(ConstString(Context), CompilerDeclContext(), 399 UINT32_MAX, List); 400 if (List.Empty()) 401 return make_string_error("Context search didn't find a match."); 402 if (List.GetSize() > 1) 403 return make_string_error("Context search found multiple matches."); 404 return List.GetVariableAtIndex(0)->GetDeclContext(); 405 } 406 407 Error opts::symbols::findFunctions(lldb_private::Module &Module) { 408 SymbolFile &Symfile = *Module.GetSymbolFile(); 409 SymbolContextList List; 410 if (!File.empty()) { 411 assert(Line != 0); 412 413 FileSpec src_file(File); 414 size_t cu_count = Module.GetNumCompileUnits(); 415 for (size_t i = 0; i < cu_count; i++) { 416 lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i); 417 if (!cu_sp) 418 continue; 419 420 LineEntry le; 421 cu_sp->FindLineEntry(0, Line, &src_file, false, &le); 422 if (!le.IsValid()) 423 continue; 424 const bool include_inlined_functions = false; 425 auto addr = 426 le.GetSameLineContiguousAddressRange(include_inlined_functions) 427 .GetBaseAddress(); 428 if (!addr.IsValid()) 429 continue; 430 431 SymbolContext sc; 432 uint32_t resolved = 433 addr.CalculateSymbolContext(&sc, eSymbolContextFunction); 434 if (resolved & eSymbolContextFunction) 435 List.Append(sc); 436 } 437 } else if (Regex) { 438 RegularExpression RE(Name); 439 assert(RE.IsValid()); 440 List.Clear(); 441 Symfile.FindFunctions(RE, true, List); 442 } else { 443 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile); 444 if (!ContextOr) 445 return ContextOr.takeError(); 446 const CompilerDeclContext &ContextPtr = 447 ContextOr->IsValid() ? *ContextOr : CompilerDeclContext(); 448 449 List.Clear(); 450 Symfile.FindFunctions(ConstString(Name), ContextPtr, getFunctionNameFlags(), 451 true, List); 452 } 453 outs() << formatv("Found {0} functions:\n", List.GetSize()); 454 StreamString Stream; 455 List.Dump(&Stream, nullptr); 456 outs() << Stream.GetData() << "\n"; 457 return Error::success(); 458 } 459 460 Error opts::symbols::findBlocks(lldb_private::Module &Module) { 461 assert(!Regex); 462 assert(!File.empty()); 463 assert(Line != 0); 464 465 SymbolContextList List; 466 467 FileSpec src_file(File); 468 size_t cu_count = Module.GetNumCompileUnits(); 469 for (size_t i = 0; i < cu_count; i++) { 470 lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i); 471 if (!cu_sp) 472 continue; 473 474 LineEntry le; 475 cu_sp->FindLineEntry(0, Line, &src_file, false, &le); 476 if (!le.IsValid()) 477 continue; 478 const bool include_inlined_functions = false; 479 auto addr = le.GetSameLineContiguousAddressRange(include_inlined_functions) 480 .GetBaseAddress(); 481 if (!addr.IsValid()) 482 continue; 483 484 SymbolContext sc; 485 uint32_t resolved = addr.CalculateSymbolContext(&sc, eSymbolContextBlock); 486 if (resolved & eSymbolContextBlock) 487 List.Append(sc); 488 } 489 490 outs() << formatv("Found {0} blocks:\n", List.GetSize()); 491 StreamString Stream; 492 List.Dump(&Stream, nullptr); 493 outs() << Stream.GetData() << "\n"; 494 return Error::success(); 495 } 496 497 Error opts::symbols::findNamespaces(lldb_private::Module &Module) { 498 SymbolFile &Symfile = *Module.GetSymbolFile(); 499 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile); 500 if (!ContextOr) 501 return ContextOr.takeError(); 502 const CompilerDeclContext &ContextPtr = 503 ContextOr->IsValid() ? *ContextOr : CompilerDeclContext(); 504 505 CompilerDeclContext Result = 506 Symfile.FindNamespace(ConstString(Name), ContextPtr); 507 if (Result) 508 outs() << "Found namespace: " 509 << Result.GetScopeQualifiedName().GetStringRef() << "\n"; 510 else 511 outs() << "Namespace not found.\n"; 512 return Error::success(); 513 } 514 515 Error opts::symbols::findTypes(lldb_private::Module &Module) { 516 SymbolFile &Symfile = *Module.GetSymbolFile(); 517 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile); 518 if (!ContextOr) 519 return ContextOr.takeError(); 520 const CompilerDeclContext &ContextPtr = 521 ContextOr->IsValid() ? *ContextOr : CompilerDeclContext(); 522 523 LanguageSet languages; 524 if (!Language.empty()) 525 languages.Insert(Language::GetLanguageTypeFromString(Language)); 526 527 DenseSet<SymbolFile *> SearchedFiles; 528 TypeMap Map; 529 if (!Name.empty()) 530 Symfile.FindTypes(ConstString(Name), ContextPtr, UINT32_MAX, SearchedFiles, 531 Map); 532 else 533 Module.FindTypes(parseCompilerContext(), languages, SearchedFiles, Map); 534 535 outs() << formatv("Found {0} types:\n", Map.GetSize()); 536 StreamString Stream; 537 Map.Dump(&Stream, false); 538 outs() << Stream.GetData() << "\n"; 539 return Error::success(); 540 } 541 542 Error opts::symbols::findVariables(lldb_private::Module &Module) { 543 SymbolFile &Symfile = *Module.GetSymbolFile(); 544 VariableList List; 545 if (Regex) { 546 RegularExpression RE(Name); 547 assert(RE.IsValid()); 548 Symfile.FindGlobalVariables(RE, UINT32_MAX, List); 549 } else if (!File.empty()) { 550 CompUnitSP CU; 551 for (size_t Ind = 0; !CU && Ind < Module.GetNumCompileUnits(); ++Ind) { 552 CompUnitSP Candidate = Module.GetCompileUnitAtIndex(Ind); 553 if (!Candidate || 554 Candidate->GetPrimaryFile().GetFilename().GetStringRef() != File) 555 continue; 556 if (CU) 557 return make_string_error("Multiple compile units for file `{0}` found.", 558 File); 559 CU = std::move(Candidate); 560 } 561 562 if (!CU) 563 return make_string_error("Compile unit `{0}` not found.", File); 564 565 List.AddVariables(CU->GetVariableList(true).get()); 566 } else { 567 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile); 568 if (!ContextOr) 569 return ContextOr.takeError(); 570 const CompilerDeclContext &ContextPtr = 571 ContextOr->IsValid() ? *ContextOr : CompilerDeclContext(); 572 573 Symfile.FindGlobalVariables(ConstString(Name), ContextPtr, UINT32_MAX, List); 574 } 575 outs() << formatv("Found {0} variables:\n", List.GetSize()); 576 StreamString Stream; 577 List.Dump(&Stream, false); 578 outs() << Stream.GetData() << "\n"; 579 return Error::success(); 580 } 581 582 Error opts::symbols::dumpModule(lldb_private::Module &Module) { 583 StreamString Stream; 584 Module.ParseAllDebugSymbols(); 585 Module.Dump(&Stream); 586 outs() << Stream.GetData() << "\n"; 587 return Error::success(); 588 } 589 590 Error opts::symbols::dumpAST(lldb_private::Module &Module) { 591 Module.ParseAllDebugSymbols(); 592 593 SymbolFile *symfile = Module.GetSymbolFile(); 594 if (!symfile) 595 return make_string_error("Module has no symbol file."); 596 597 llvm::Expected<TypeSystem &> type_system_or_err = 598 symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus); 599 if (!type_system_or_err) 600 return make_string_error("Can't retrieve TypeSystemClang"); 601 602 auto *clang_ast_ctx = 603 llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); 604 if (!clang_ast_ctx) 605 return make_string_error("Retrieved TypeSystem was not a TypeSystemClang"); 606 607 clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext(); 608 609 clang::TranslationUnitDecl *tu = ast_ctx.getTranslationUnitDecl(); 610 if (!tu) 611 return make_string_error("Can't retrieve translation unit declaration."); 612 613 tu->print(outs()); 614 615 return Error::success(); 616 } 617 618 Error opts::symbols::dumpClangAST(lldb_private::Module &Module) { 619 Module.ParseAllDebugSymbols(); 620 621 SymbolFile *symfile = Module.GetSymbolFile(); 622 if (!symfile) 623 return make_string_error("Module has no symbol file."); 624 625 llvm::Expected<TypeSystem &> type_system_or_err = 626 symfile->GetTypeSystemForLanguage(eLanguageTypeObjC_plus_plus); 627 if (!type_system_or_err) 628 return make_string_error("Can't retrieve TypeSystemClang"); 629 630 auto *clang_ast_ctx = 631 llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get()); 632 if (!clang_ast_ctx) 633 return make_string_error("Retrieved TypeSystem was not a TypeSystemClang"); 634 635 StreamString Stream; 636 clang_ast_ctx->DumpFromSymbolFile(Stream, Name); 637 outs() << Stream.GetData() << "\n"; 638 639 return Error::success(); 640 } 641 642 Error opts::symbols::verify(lldb_private::Module &Module) { 643 SymbolFile *symfile = Module.GetSymbolFile(); 644 if (!symfile) 645 return make_string_error("Module has no symbol file."); 646 647 uint32_t comp_units_count = symfile->GetNumCompileUnits(); 648 649 outs() << "Found " << comp_units_count << " compile units.\n"; 650 651 for (uint32_t i = 0; i < comp_units_count; i++) { 652 lldb::CompUnitSP comp_unit = symfile->GetCompileUnitAtIndex(i); 653 if (!comp_unit) 654 return make_string_error("Cannot parse compile unit {0}.", i); 655 656 outs() << "Processing '" 657 << comp_unit->GetPrimaryFile().GetFilename().AsCString() 658 << "' compile unit.\n"; 659 660 LineTable *lt = comp_unit->GetLineTable(); 661 if (!lt) 662 return make_string_error("Can't get a line table of a compile unit."); 663 664 uint32_t count = lt->GetSize(); 665 666 outs() << "The line table contains " << count << " entries.\n"; 667 668 if (count == 0) 669 continue; 670 671 LineEntry le; 672 if (!lt->GetLineEntryAtIndex(0, le)) 673 return make_string_error("Can't get a line entry of a compile unit."); 674 675 for (uint32_t i = 1; i < count; i++) { 676 lldb::addr_t curr_end = 677 le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize(); 678 679 if (!lt->GetLineEntryAtIndex(i, le)) 680 return make_string_error("Can't get a line entry of a compile unit"); 681 682 if (curr_end > le.range.GetBaseAddress().GetFileAddress()) 683 return make_string_error( 684 "Line table of a compile unit is inconsistent."); 685 } 686 } 687 688 outs() << "The symbol information is verified.\n"; 689 690 return Error::success(); 691 } 692 693 Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() { 694 if (Verify && DumpAST) 695 return make_string_error( 696 "Cannot both verify symbol information and dump AST."); 697 698 if (Verify) { 699 if (Find != FindType::None) 700 return make_string_error( 701 "Cannot both search and verify symbol information."); 702 if (Regex || !Context.empty() || !Name.empty() || !File.empty() || 703 Line != 0) 704 return make_string_error( 705 "-regex, -context, -name, -file and -line options are not " 706 "applicable for symbol verification."); 707 return verify; 708 } 709 710 if (DumpAST) { 711 if (Find != FindType::None) 712 return make_string_error("Cannot both search and dump AST."); 713 if (Regex || !Context.empty() || !Name.empty() || !File.empty() || 714 Line != 0) 715 return make_string_error( 716 "-regex, -context, -name, -file and -line options are not " 717 "applicable for dumping AST."); 718 return dumpAST; 719 } 720 721 if (DumpClangAST) { 722 if (Find != FindType::None) 723 return make_string_error("Cannot both search and dump clang AST."); 724 if (Regex || !Context.empty() || !File.empty() || Line != 0) 725 return make_string_error( 726 "-regex, -context, -name, -file and -line options are not " 727 "applicable for dumping clang AST."); 728 return dumpClangAST; 729 } 730 731 if (Regex && !Context.empty()) 732 return make_string_error( 733 "Cannot search using both regular expressions and context."); 734 735 if (Regex && !RegularExpression(Name).IsValid()) 736 return make_string_error("`{0}` is not a valid regular expression.", Name); 737 738 if (Regex + !Context.empty() + !File.empty() >= 2) 739 return make_string_error( 740 "Only one of -regex, -context and -file may be used simultaneously."); 741 if (Regex && Name.empty()) 742 return make_string_error("-regex used without a -name"); 743 744 switch (Find) { 745 case FindType::None: 746 if (!Context.empty() || !Name.empty() || !File.empty() || Line != 0) 747 return make_string_error( 748 "Specify search type (-find) to use search options."); 749 return dumpModule; 750 751 case FindType::Function: 752 if (!File.empty() + (Line != 0) == 1) 753 return make_string_error("Both file name and line number must be " 754 "specified when searching a function " 755 "by file position."); 756 if (Regex + (getFunctionNameFlags() != 0) + !File.empty() >= 2) 757 return make_string_error("Only one of regular expression, function-flags " 758 "and file position may be used simultaneously " 759 "when searching a function."); 760 return findFunctions; 761 762 case FindType::Block: 763 if (File.empty() || Line == 0) 764 return make_string_error("Both file name and line number must be " 765 "specified when searching a block."); 766 if (Regex || getFunctionNameFlags() != 0) 767 return make_string_error("Cannot use regular expression or " 768 "function-flags for searching a block."); 769 return findBlocks; 770 771 case FindType::Namespace: 772 if (Regex || !File.empty() || Line != 0) 773 return make_string_error("Cannot search for namespaces using regular " 774 "expressions, file names or line numbers."); 775 return findNamespaces; 776 777 case FindType::Type: 778 if (Regex || !File.empty() || Line != 0) 779 return make_string_error("Cannot search for types using regular " 780 "expressions, file names or line numbers."); 781 if (!Name.empty() && !CompilerContext.empty()) 782 return make_string_error("Name is ignored if compiler context present."); 783 784 return findTypes; 785 786 case FindType::Variable: 787 if (Line != 0) 788 return make_string_error("Cannot search for variables " 789 "using line numbers."); 790 return findVariables; 791 } 792 793 llvm_unreachable("Unsupported symbol action."); 794 } 795 796 int opts::symbols::dumpSymbols(Debugger &Dbg) { 797 auto ActionOr = getAction(); 798 if (!ActionOr) { 799 logAllUnhandledErrors(ActionOr.takeError(), WithColor::error(), ""); 800 return 1; 801 } 802 auto Action = *ActionOr; 803 804 outs() << "Module: " << InputFile << "\n"; 805 ModuleSpec Spec{FileSpec(InputFile)}; 806 StringRef Symbols = SymbolPath.empty() ? InputFile : SymbolPath; 807 Spec.GetSymbolFileSpec().SetFile(Symbols, FileSpec::Style::native); 808 809 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); 810 SymbolFile *Symfile = ModulePtr->GetSymbolFile(); 811 if (!Symfile) { 812 WithColor::error() << "Module has no symbol vendor.\n"; 813 return 1; 814 } 815 816 if (Error E = Action(*ModulePtr)) { 817 WithColor::error() << toString(std::move(E)) << "\n"; 818 return 1; 819 } 820 821 return 0; 822 } 823 824 static void dumpSectionList(LinePrinter &Printer, const SectionList &List, bool is_subsection) { 825 size_t Count = List.GetNumSections(0); 826 if (Count == 0) { 827 Printer.formatLine("There are no {0}sections", is_subsection ? "sub" : ""); 828 return; 829 } 830 Printer.formatLine("Showing {0} {1}sections", Count, 831 is_subsection ? "sub" : ""); 832 for (size_t I = 0; I < Count; ++I) { 833 auto S = List.GetSectionAtIndex(I); 834 assert(S); 835 AutoIndent Indent(Printer, 2); 836 Printer.formatLine("Index: {0}", I); 837 Printer.formatLine("ID: {0:x}", S->GetID()); 838 Printer.formatLine("Name: {0}", S->GetName().GetStringRef()); 839 Printer.formatLine("Type: {0}", S->GetTypeAsCString()); 840 Printer.formatLine("Permissions: {0}", GetPermissionsAsCString(S->GetPermissions())); 841 Printer.formatLine("Thread specific: {0:y}", S->IsThreadSpecific()); 842 Printer.formatLine("VM address: {0:x}", S->GetFileAddress()); 843 Printer.formatLine("VM size: {0}", S->GetByteSize()); 844 Printer.formatLine("File size: {0}", S->GetFileSize()); 845 846 if (opts::object::SectionContents) { 847 lldb_private::DataExtractor Data; 848 S->GetSectionData(Data); 849 ArrayRef<uint8_t> Bytes(Data.GetDataStart(), Data.GetDataEnd()); 850 Printer.formatBinary("Data: ", Bytes, 0); 851 } 852 853 if (S->GetType() == eSectionTypeContainer) 854 dumpSectionList(Printer, S->GetChildren(), true); 855 Printer.NewLine(); 856 } 857 } 858 859 static int dumpObjectFiles(Debugger &Dbg) { 860 LinePrinter Printer(4, llvm::outs()); 861 862 int HadErrors = 0; 863 for (const auto &File : opts::object::InputFilenames) { 864 ModuleSpec Spec{FileSpec(File)}; 865 866 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); 867 868 ObjectFile *ObjectPtr = ModulePtr->GetObjectFile(); 869 if (!ObjectPtr) { 870 WithColor::error() << File << " not recognised as an object file\n"; 871 HadErrors = 1; 872 continue; 873 } 874 875 // Fetch symbol vendor before we get the section list to give the symbol 876 // vendor a chance to populate it. 877 ModulePtr->GetSymbolFile(); 878 SectionList *Sections = ModulePtr->GetSectionList(); 879 if (!Sections) { 880 llvm::errs() << "Could not load sections for module " << File << "\n"; 881 HadErrors = 1; 882 continue; 883 } 884 885 Printer.formatLine("Plugin name: {0}", ObjectPtr->GetPluginName()); 886 Printer.formatLine("Architecture: {0}", 887 ModulePtr->GetArchitecture().GetTriple().getTriple()); 888 Printer.formatLine("UUID: {0}", ModulePtr->GetUUID().GetAsString()); 889 Printer.formatLine("Executable: {0}", ObjectPtr->IsExecutable()); 890 Printer.formatLine("Stripped: {0}", ObjectPtr->IsStripped()); 891 Printer.formatLine("Type: {0}", ObjectPtr->GetType()); 892 Printer.formatLine("Strata: {0}", ObjectPtr->GetStrata()); 893 Printer.formatLine("Base VM address: {0:x}", 894 ObjectPtr->GetBaseAddress().GetFileAddress()); 895 896 dumpSectionList(Printer, *Sections, /*is_subsection*/ false); 897 898 if (opts::object::SectionDependentModules) { 899 // A non-empty section list ensures a valid object file. 900 auto Obj = ModulePtr->GetObjectFile(); 901 FileSpecList Files; 902 auto Count = Obj->GetDependentModules(Files); 903 Printer.formatLine("Showing {0} dependent module(s)", Count); 904 for (size_t I = 0; I < Files.GetSize(); ++I) { 905 AutoIndent Indent(Printer, 2); 906 Printer.formatLine("Name: {0}", 907 Files.GetFileSpecAtIndex(I).GetCString()); 908 } 909 Printer.NewLine(); 910 } 911 } 912 return HadErrors; 913 } 914 915 bool opts::irmemorymap::evalMalloc(StringRef Line, 916 IRMemoryMapTestState &State) { 917 // ::= <label> = malloc <size> <alignment> 918 StringRef Label; 919 std::tie(Label, Line) = Line.split('='); 920 if (Line.empty()) 921 return false; 922 Label = Label.trim(); 923 Line = Line.trim(); 924 size_t Size; 925 uint8_t Alignment; 926 int Matches = sscanf(Line.data(), "malloc %zu %hhu", &Size, &Alignment); 927 if (Matches != 2) 928 return false; 929 930 outs() << formatv("Command: {0} = malloc(size={1}, alignment={2})\n", Label, 931 Size, Alignment); 932 if (!isPowerOf2_32(Alignment)) { 933 outs() << "Malloc error: alignment is not a power of 2\n"; 934 exit(1); 935 } 936 937 IRMemoryMap::AllocationPolicy AP = 938 UseHostOnlyAllocationPolicy ? IRMemoryMap::eAllocationPolicyHostOnly 939 : IRMemoryMap::eAllocationPolicyProcessOnly; 940 941 // Issue the malloc in the target process with "-rw" permissions. 942 const uint32_t Permissions = 0x3; 943 const bool ZeroMemory = false; 944 Status ST; 945 addr_t Addr = 946 State.Map.Malloc(Size, Alignment, Permissions, AP, ZeroMemory, ST); 947 if (ST.Fail()) { 948 outs() << formatv("Malloc error: {0}\n", ST); 949 return true; 950 } 951 952 // Print the result of the allocation before checking its validity. 953 outs() << formatv("Malloc: address = {0:x}\n", Addr); 954 955 // Check that the allocation is aligned. 956 if (!Addr || Addr % Alignment != 0) { 957 outs() << "Malloc error: zero or unaligned allocation detected\n"; 958 exit(1); 959 } 960 961 // In case of Size == 0, we still expect the returned address to be unique and 962 // non-overlapping. 963 addr_t EndOfRegion = Addr + std::max<size_t>(Size, 1); 964 if (State.Allocations.overlaps(Addr, EndOfRegion)) { 965 auto I = State.Allocations.find(Addr); 966 outs() << "Malloc error: overlapping allocation detected" 967 << formatv(", previous allocation at [{0:x}, {1:x})\n", I.start(), 968 I.stop()); 969 exit(1); 970 } 971 972 // Insert the new allocation into the interval map. Use unique allocation 973 // IDs to inhibit interval coalescing. 974 static unsigned AllocationID = 0; 975 State.Allocations.insert(Addr, EndOfRegion, AllocationID++); 976 977 // Store the label -> address mapping. 978 State.Label2AddrMap[Label] = Addr; 979 980 return true; 981 } 982 983 bool opts::irmemorymap::evalFree(StringRef Line, IRMemoryMapTestState &State) { 984 // ::= free <label> 985 if (!Line.consume_front("free")) 986 return false; 987 StringRef Label = Line.trim(); 988 989 outs() << formatv("Command: free({0})\n", Label); 990 auto LabelIt = State.Label2AddrMap.find(Label); 991 if (LabelIt == State.Label2AddrMap.end()) { 992 outs() << "Free error: Invalid allocation label\n"; 993 exit(1); 994 } 995 996 Status ST; 997 addr_t Addr = LabelIt->getValue(); 998 State.Map.Free(Addr, ST); 999 if (ST.Fail()) { 1000 outs() << formatv("Free error: {0}\n", ST); 1001 exit(1); 1002 } 1003 1004 // Erase the allocation from the live interval map. 1005 auto Interval = State.Allocations.find(Addr); 1006 if (Interval != State.Allocations.end()) { 1007 outs() << formatv("Free: [{0:x}, {1:x})\n", Interval.start(), 1008 Interval.stop()); 1009 Interval.erase(); 1010 } 1011 1012 return true; 1013 } 1014 1015 int opts::irmemorymap::evaluateMemoryMapCommands(Debugger &Dbg) { 1016 // Set up a Target. 1017 TargetSP Target = opts::createTarget(Dbg, irmemorymap::Target); 1018 1019 // Set up a Process. In order to allocate memory within a target, this 1020 // process must be alive and must support JIT'ing. 1021 CommandReturnObject Result; 1022 Dbg.SetAsyncExecution(false); 1023 CommandInterpreter &CI = Dbg.GetCommandInterpreter(); 1024 auto IssueCmd = [&](const char *Cmd) -> bool { 1025 return CI.HandleCommand(Cmd, eLazyBoolNo, Result); 1026 }; 1027 if (!IssueCmd("b main") || !IssueCmd("run")) { 1028 outs() << formatv("Failed: {0}\n", Result.GetErrorData()); 1029 exit(1); 1030 } 1031 1032 ProcessSP Process = Target->GetProcessSP(); 1033 if (!Process || !Process->IsAlive() || !Process->CanJIT()) { 1034 outs() << "Cannot use process to test IRMemoryMap\n"; 1035 exit(1); 1036 } 1037 1038 // Set up an IRMemoryMap and associated testing state. 1039 IRMemoryMapTestState State(Target); 1040 1041 // Parse and apply commands from the command file. 1042 std::unique_ptr<MemoryBuffer> MB = opts::openFile(irmemorymap::CommandFile); 1043 StringRef Rest = MB->getBuffer(); 1044 while (!Rest.empty()) { 1045 StringRef Line; 1046 std::tie(Line, Rest) = Rest.split('\n'); 1047 Line = Line.ltrim().rtrim(); 1048 1049 if (Line.empty() || Line[0] == '#') 1050 continue; 1051 1052 if (evalMalloc(Line, State)) 1053 continue; 1054 1055 if (evalFree(Line, State)) 1056 continue; 1057 1058 errs() << "Could not parse line: " << Line << "\n"; 1059 exit(1); 1060 } 1061 return 0; 1062 } 1063 1064 int main(int argc, const char *argv[]) { 1065 StringRef ToolName = argv[0]; 1066 sys::PrintStackTraceOnErrorSignal(ToolName); 1067 PrettyStackTraceProgram X(argc, argv); 1068 llvm_shutdown_obj Y; 1069 1070 cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n"); 1071 1072 SystemLifetimeManager DebuggerLifetime; 1073 if (auto e = DebuggerLifetime.Initialize( 1074 std::make_unique<SystemInitializerTest>(), nullptr)) { 1075 WithColor::error() << "initialization failed: " << toString(std::move(e)) 1076 << '\n'; 1077 return 1; 1078 } 1079 1080 auto TerminateDebugger = 1081 llvm::make_scope_exit([&] { DebuggerLifetime.Terminate(); }); 1082 1083 auto Dbg = lldb_private::Debugger::CreateInstance(); 1084 ModuleList::GetGlobalModuleListProperties().SetEnableExternalLookup(false); 1085 CommandReturnObject Result; 1086 Dbg->GetCommandInterpreter().HandleCommand( 1087 "settings set plugin.process.gdb-remote.packet-timeout 60", 1088 /*add_to_history*/ eLazyBoolNo, Result); 1089 1090 if (!opts::Log.empty()) 1091 Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, errs()); 1092 1093 if (opts::BreakpointSubcommand) 1094 return opts::breakpoint::evaluateBreakpoints(*Dbg); 1095 if (opts::ObjectFileSubcommand) 1096 return dumpObjectFiles(*Dbg); 1097 if (opts::SymbolsSubcommand) 1098 return opts::symbols::dumpSymbols(*Dbg); 1099 if (opts::IRMemoryMapSubcommand) 1100 return opts::irmemorymap::evaluateMemoryMapCommands(*Dbg); 1101 1102 WithColor::error() << "No command specified.\n"; 1103 return 1; 1104 } 1105