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 "lldb/Breakpoint/BreakpointLocation.h" 14 #include "lldb/Core/Debugger.h" 15 #include "lldb/Core/Module.h" 16 #include "lldb/Core/Section.h" 17 #include "lldb/Expression/IRMemoryMap.h" 18 #include "lldb/Initialization/SystemLifetimeManager.h" 19 #include "lldb/Interpreter/CommandInterpreter.h" 20 #include "lldb/Interpreter/CommandReturnObject.h" 21 #include "lldb/Symbol/ClangASTContext.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 (avaliable 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), nullptr, UINT32_MAX, List); 399 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."); 403 return List.GetVariableAtIndex(0)->GetDeclContext(); 404 } 405 406 Error opts::symbols::findFunctions(lldb_private::Module &Module) { 407 SymbolFile &Symfile = *Module.GetSymbolFile(); 408 SymbolContextList List; 409 if (!File.empty()) { 410 assert(Line != 0); 411 412 FileSpec src_file(File); 413 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; 423 const bool include_inlined_functions = false; 424 auto addr = 425 le.GetSameLineContiguousAddressRange(include_inlined_functions) 426 .GetBaseAddress(); 427 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) { 437 RegularExpression RE(Name); 438 assert(RE.IsValid()); 439 List.Clear(); 440 Symfile.FindFunctions(RE, true, List); 441 } else { 442 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile); 443 if (!ContextOr) 444 return ContextOr.takeError(); 445 CompilerDeclContext *ContextPtr = 446 ContextOr->IsValid() ? &*ContextOr : nullptr; 447 448 List.Clear(); 449 Symfile.FindFunctions(ConstString(Name), ContextPtr, getFunctionNameFlags(), 450 true, List); 451 } 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 459 Error opts::symbols::findBlocks(lldb_private::Module &Module) { 460 assert(!Regex); 461 assert(!File.empty()); 462 assert(Line != 0); 463 464 SymbolContextList List; 465 466 FileSpec src_file(File); 467 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; 477 const bool include_inlined_functions = false; 478 auto addr = le.GetSameLineContiguousAddressRange(include_inlined_functions) 479 .GetBaseAddress(); 480 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 496 Error opts::symbols::findNamespaces(lldb_private::Module &Module) { 497 SymbolFile &Symfile = *Module.GetSymbolFile(); 498 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile); 499 if (!ContextOr) 500 return ContextOr.takeError(); 501 CompilerDeclContext *ContextPtr = 502 ContextOr->IsValid() ? &*ContextOr : nullptr; 503 504 CompilerDeclContext Result = 505 Symfile.FindNamespace(ConstString(Name), ContextPtr); 506 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 514 Error opts::symbols::findTypes(lldb_private::Module &Module) { 515 SymbolFile &Symfile = *Module.GetSymbolFile(); 516 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile); 517 if (!ContextOr) 518 return ContextOr.takeError(); 519 CompilerDeclContext *ContextPtr = 520 ContextOr->IsValid() ? &*ContextOr : nullptr; 521 522 LanguageSet languages; 523 if (!Language.empty()) 524 languages.Insert(Language::GetLanguageTypeFromString(Language)); 525 526 DenseSet<SymbolFile *> SearchedFiles; 527 TypeMap Map; 528 if (!Name.empty()) 529 Symfile.FindTypes(ConstString(Name), ContextPtr, UINT32_MAX, SearchedFiles, 530 Map); 531 else 532 Module.FindTypes(parseCompilerContext(), languages, SearchedFiles, Map); 533 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 541 Error opts::symbols::findVariables(lldb_private::Module &Module) { 542 SymbolFile &Symfile = *Module.GetSymbolFile(); 543 VariableList List; 544 if (Regex) { 545 RegularExpression RE(Name); 546 assert(RE.IsValid()); 547 Symfile.FindGlobalVariables(RE, UINT32_MAX, List); 548 } else if (!File.empty()) { 549 CompUnitSP CU; 550 for (size_t Ind = 0; !CU && Ind < Module.GetNumCompileUnits(); ++Ind) { 551 CompUnitSP Candidate = Module.GetCompileUnitAtIndex(Ind); 552 if (!Candidate || 553 Candidate->GetPrimaryFile().GetFilename().GetStringRef() != File) 554 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()); 565 } else { 566 Expected<CompilerDeclContext> ContextOr = getDeclContext(Symfile); 567 if (!ContextOr) 568 return ContextOr.takeError(); 569 CompilerDeclContext *ContextPtr = 570 ContextOr->IsValid() ? &*ContextOr : nullptr; 571 572 Symfile.FindGlobalVariables(ConstString(Name), ContextPtr, UINT32_MAX, List); 573 } 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 581 Error 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 589 Error opts::symbols::dumpAST(lldb_private::Module &Module) { 590 Module.ParseAllDebugSymbols(); 591 592 SymbolFile *symfile = Module.GetSymbolFile(); 593 if (!symfile) 594 return make_string_error("Module has no symbol file."); 595 596 llvm::Expected<TypeSystem &> type_system_or_err = 597 symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus); 598 if (!type_system_or_err) 599 return make_string_error("Can't retrieve ClangASTContext"); 600 601 auto *clang_ast_ctx = 602 llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); 603 if (!clang_ast_ctx) 604 return make_string_error("Retrieved TypeSystem was not a ClangASTContext"); 605 606 clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext(); 607 608 clang::TranslationUnitDecl *tu = ast_ctx.getTranslationUnitDecl(); 609 if (!tu) 610 return make_string_error("Can't retrieve translation unit declaration."); 611 612 tu->print(outs()); 613 614 return Error::success(); 615 } 616 617 Error 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 = 625 symfile->GetTypeSystemForLanguage(eLanguageTypeObjC_plus_plus); 626 if (!type_system_or_err) 627 return make_string_error("Can't retrieve ClangASTContext"); 628 629 auto *clang_ast_ctx = 630 llvm::dyn_cast_or_null<ClangASTContext>(&type_system_or_err.get()); 631 if (!clang_ast_ctx) 632 return make_string_error("Retrieved TypeSystem was not a ClangASTContext"); 633 634 StreamString Stream; 635 clang_ast_ctx->DumpFromSymbolFile(Stream, Name); 636 outs() << Stream.GetData() << "\n"; 637 638 return Error::success(); 639 } 640 641 Error opts::symbols::verify(lldb_private::Module &Module) { 642 SymbolFile *symfile = Module.GetSymbolFile(); 643 if (!symfile) 644 return make_string_error("Module has no symbol file."); 645 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++) { 651 lldb::CompUnitSP comp_unit = symfile->GetCompileUnitAtIndex(i); 652 if (!comp_unit) 653 return make_string_error("Connot parse compile unit {0}.", i); 654 655 outs() << "Processing '" 656 << comp_unit->GetPrimaryFile().GetFilename().AsCString() 657 << "' compile unit.\n"; 658 659 LineTable *lt = comp_unit->GetLineTable(); 660 if (!lt) 661 return make_string_error("Can't get a line table of a compile unit."); 662 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)) 672 return make_string_error("Can't get a line entry of a compile unit."); 673 674 for (uint32_t i = 1; i < count; i++) { 675 lldb::addr_t curr_end = 676 le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize(); 677 678 if (!lt->GetLineEntryAtIndex(i, le)) 679 return make_string_error("Can't get a line entry of a compile unit"); 680 681 if (curr_end > le.range.GetBaseAddress().GetFileAddress()) 682 return make_string_error( 683 "Line table of a compile unit is inconsistent."); 684 } 685 } 686 687 outs() << "The symbol information is verified.\n"; 688 689 return Error::success(); 690 } 691 692 Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() { 693 if (Verify && DumpAST) 694 return make_string_error( 695 "Cannot both verify symbol information and dump AST."); 696 697 if (Verify) { 698 if (Find != FindType::None) 699 return make_string_error( 700 "Cannot both search and verify symbol information."); 701 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."); 706 return verify; 707 } 708 709 if (DumpAST) { 710 if (Find != FindType::None) 711 return make_string_error("Cannot both search and dump AST."); 712 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 720 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 730 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: 745 if (!Context.empty() || !Name.empty() || !File.empty() || Line != 0) 746 return make_string_error( 747 "Specify search type (-find) to use search options."); 748 return dumpModule; 749 750 case FindType::Function: 751 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."); 759 return findFunctions; 760 761 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 770 case FindType::Namespace: 771 if (Regex || !File.empty() || Line != 0) 772 return make_string_error("Cannot search for namespaces using regular " 773 "expressions, file names or line numbers."); 774 return findNamespaces; 775 776 case FindType::Type: 777 if (Regex || !File.empty() || Line != 0) 778 return make_string_error("Cannot search for types using regular " 779 "expressions, file names or line numbers."); 780 if (!Name.empty() && !CompilerContext.empty()) 781 return make_string_error("Name is ignored if compiler context present."); 782 783 return findTypes; 784 785 case FindType::Variable: 786 if (Line != 0) 787 return make_string_error("Cannot search for variables " 788 "using line numbers."); 789 return findVariables; 790 } 791 792 llvm_unreachable("Unsupported symbol action."); 793 } 794 795 int 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; 802 803 outs() << "Module: " << InputFile << "\n"; 804 ModuleSpec Spec{FileSpec(InputFile)}; 805 StringRef Symbols = SymbolPath.empty() ? InputFile : SymbolPath; 806 Spec.GetSymbolFileSpec().SetFile(Symbols, FileSpec::Style::native); 807 808 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); 809 SymbolFile *Symfile = ModulePtr->GetSymbolFile(); 810 if (!Symfile) { 811 WithColor::error() << "Module has no symbol vendor.\n"; 812 return 1; 813 } 814 815 if (Error E = Action(*ModulePtr)) { 816 WithColor::error() << toString(std::move(E)) << "\n"; 817 return 1; 818 } 819 820 return 0; 821 } 822 823 static 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); 836 Printer.formatLine("ID: {0:x}", S->GetID()); 837 Printer.formatLine("Name: {0}", S->GetName().GetStringRef()); 838 Printer.formatLine("Type: {0}", S->GetTypeAsCString()); 839 Printer.formatLine("Permissions: {0}", GetPermissionsAsCString(S->GetPermissions())); 840 Printer.formatLine("Thread specific: {0:y}", S->IsThreadSpecific()); 841 Printer.formatLine("VM address: {0:x}", S->GetFileAddress()); 842 Printer.formatLine("VM size: {0}", S->GetByteSize()); 843 Printer.formatLine("File size: {0}", S->GetFileSize()); 844 845 if (opts::object::SectionContents) { 846 lldb_private::DataExtractor Data; 847 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 858 static int dumpObjectFiles(Debugger &Dbg) { 859 LinePrinter Printer(4, llvm::outs()); 860 861 int HadErrors = 0; 862 for (const auto &File : opts::object::InputFilenames) { 863 ModuleSpec Spec{FileSpec(File)}; 864 865 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); 866 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 874 // Fetch symbol vendor before we get the section list to give the symbol 875 // vendor a chance to populate it. 876 ModulePtr->GetSymbolFile(); 877 SectionList *Sections = ModulePtr->GetSectionList(); 878 if (!Sections) { 879 llvm::errs() << "Could not load sections for module " << File << "\n"; 880 HadErrors = 1; 881 continue; 882 } 883 884 Printer.formatLine("Plugin name: {0}", ObjectPtr->GetPluginName()); 885 Printer.formatLine("Architecture: {0}", 886 ModulePtr->GetArchitecture().GetTriple().getTriple()); 887 Printer.formatLine("UUID: {0}", ModulePtr->GetUUID().GetAsString()); 888 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()); 892 Printer.formatLine("Base VM address: {0:x}", 893 ObjectPtr->GetBaseAddress().GetFileAddress()); 894 895 dumpSectionList(Printer, *Sections, /*is_subsection*/ false); 896 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 } 910 } 911 return HadErrors; 912 } 913 914 bool 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(); 923 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 929 outs() << formatv("Command: {0} = malloc(size={1}, alignment={2})\n", Label, 930 Size, Alignment); 931 if (!isPowerOf2_32(Alignment)) { 932 outs() << "Malloc error: alignment is not a power of 2\n"; 933 exit(1); 934 } 935 936 IRMemoryMap::AllocationPolicy AP = 937 UseHostOnlyAllocationPolicy ? IRMemoryMap::eAllocationPolicyHostOnly 938 : IRMemoryMap::eAllocationPolicyProcessOnly; 939 940 // Issue the malloc in the target process with "-rw" permissions. 941 const uint32_t Permissions = 0x3; 942 const bool ZeroMemory = false; 943 Status ST; 944 addr_t Addr = 945 State.Map.Malloc(Size, Alignment, Permissions, AP, ZeroMemory, ST); 946 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 960 // 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); 969 } 970 971 // Insert the new allocation into the interval map. Use unique allocation 972 // IDs to inhibit interval coalescing. 973 static unsigned AllocationID = 0; 974 State.Allocations.insert(Addr, EndOfRegion, AllocationID++); 975 976 // Store the label -> address mapping. 977 State.Label2AddrMap[Label] = Addr; 978 979 return true; 980 } 981 982 bool opts::irmemorymap::evalFree(StringRef Line, IRMemoryMapTestState &State) { 983 // ::= free <label> 984 if (!Line.consume_front("free")) 985 return false; 986 StringRef Label = Line.trim(); 987 988 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"; 992 exit(1); 993 } 994 995 Status ST; 996 addr_t Addr = LabelIt->getValue(); 997 State.Map.Free(Addr, ST); 998 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. 1004 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 } 1010 1011 return true; 1012 } 1013 1014 int 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. 1038 IRMemoryMapTestState State(Target); 1039 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'); 1046 Line = Line.ltrim().rtrim(); 1047 1048 if (Line.empty() || Line[0] == '#') 1049 continue; 1050 1051 if (evalMalloc(Line, State)) 1052 continue; 1053 1054 if (evalFree(Line, State)) 1055 continue; 1056 1057 errs() << "Could not parse line: " << Line << "\n"; 1058 exit(1); 1059 } 1060 return 0; 1061 } 1062 1063 int 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 1071 SystemLifetimeManager DebuggerLifetime; 1072 if (auto e = DebuggerLifetime.Initialize( 1073 std::make_unique<SystemInitializerTest>(), nullptr)) { 1074 WithColor::error() << "initialization failed: " << toString(std::move(e)) 1075 << '\n'; 1076 return 1; 1077 } 1078 1079 auto TerminateDebugger = 1080 llvm::make_scope_exit([&] { DebuggerLifetime.Terminate(); }); 1081 1082 auto Dbg = lldb_private::Debugger::CreateInstance(); 1083 ModuleList::GetGlobalModuleListProperties().SetEnableExternalLookup(false); 1084 CommandReturnObject Result; 1085 Dbg->GetCommandInterpreter().HandleCommand( 1086 "settings set plugin.process.gdb-remote.packet-timeout 60", 1087 /*add_to_history*/ eLazyBoolNo, Result); 1088 1089 if (!opts::Log.empty()) 1090 Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, errs()); 1091 1092 if (opts::BreakpointSubcommand) 1093 return opts::breakpoint::evaluateBreakpoints(*Dbg); 1094 if (opts::ObjectFileSubcommand) 1095 return dumpObjectFiles(*Dbg); 1096 if (opts::SymbolsSubcommand) 1097 return opts::symbols::dumpSymbols(*Dbg); 1098 if (opts::IRMemoryMapSubcommand) 1099 return opts::irmemorymap::evaluateMemoryMapCommands(*Dbg); 1100 1101 WithColor::error() << "No command specified.\n"; 1102 return 1; 1103 } 1104