1 //===- lldb-test.cpp ------------------------------------------ *- C++ --*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "FormatUtil.h" 11 #include "SystemInitializerTest.h" 12 13 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.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/ClangASTContext.h" 23 #include "lldb/Symbol/ClangASTImporter.h" 24 #include "lldb/Symbol/CompileUnit.h" 25 #include "lldb/Symbol/LineTable.h" 26 #include "lldb/Symbol/SymbolVendor.h" 27 #include "lldb/Symbol/TypeList.h" 28 #include "lldb/Symbol/VariableList.h" 29 #include "lldb/Target/Process.h" 30 #include "lldb/Target/Target.h" 31 #include "lldb/Utility/CleanUp.h" 32 #include "lldb/Utility/DataExtractor.h" 33 #include "lldb/Utility/StreamString.h" 34 35 #include "llvm/ADT/IntervalMap.h" 36 #include "llvm/ADT/StringRef.h" 37 #include "llvm/Support/CommandLine.h" 38 #include "llvm/Support/ManagedStatic.h" 39 #include "llvm/Support/MathExtras.h" 40 #include "llvm/Support/Path.h" 41 #include "llvm/Support/PrettyStackTrace.h" 42 #include "llvm/Support/Signals.h" 43 #include "llvm/Support/WithColor.h" 44 #include <cstdio> 45 #include <thread> 46 47 using namespace lldb; 48 using namespace lldb_private; 49 using namespace llvm; 50 51 namespace opts { 52 static cl::SubCommand BreakpointSubcommand("breakpoints", 53 "Test breakpoint resolution"); 54 cl::SubCommand ObjectFileSubcommand("object-file", 55 "Display LLDB object file information"); 56 cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file"); 57 cl::SubCommand IRMemoryMapSubcommand("ir-memory-map", "Test IRMemoryMap"); 58 59 cl::opt<std::string> Log("log", cl::desc("Path to a log file"), cl::init(""), 60 cl::sub(BreakpointSubcommand), 61 cl::sub(ObjectFileSubcommand), 62 cl::sub(SymbolsSubcommand), 63 cl::sub(IRMemoryMapSubcommand)); 64 65 /// Create a target using the file pointed to by \p Filename, or abort. 66 TargetSP createTarget(Debugger &Dbg, const std::string &Filename); 67 68 /// Read \p Filename into a null-terminated buffer, or abort. 69 std::unique_ptr<MemoryBuffer> openFile(const std::string &Filename); 70 71 namespace breakpoint { 72 static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"), 73 cl::Required, cl::sub(BreakpointSubcommand)); 74 static cl::opt<std::string> CommandFile(cl::Positional, 75 cl::desc("<command-file>"), 76 cl::init("-"), 77 cl::sub(BreakpointSubcommand)); 78 static cl::opt<bool> Persistent( 79 "persistent", 80 cl::desc("Don't automatically remove all breakpoints before each command"), 81 cl::sub(BreakpointSubcommand)); 82 83 static llvm::StringRef plural(uintmax_t value) { return value == 1 ? "" : "s"; } 84 static void dumpState(const BreakpointList &List, LinePrinter &P); 85 static std::string substitute(StringRef Cmd); 86 static int evaluateBreakpoints(Debugger &Dbg); 87 } // namespace breakpoint 88 89 namespace object { 90 cl::opt<bool> SectionContents("contents", 91 cl::desc("Dump each section's contents"), 92 cl::sub(ObjectFileSubcommand)); 93 cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"), 94 cl::OneOrMore, 95 cl::sub(ObjectFileSubcommand)); 96 } // namespace object 97 98 namespace symbols { 99 static cl::list<std::string> InputFilenames(cl::Positional, 100 cl::desc("<input files>"), 101 cl::OneOrMore, 102 cl::sub(SymbolsSubcommand)); 103 enum class FindType { 104 None, 105 Function, 106 Block, 107 Namespace, 108 Type, 109 Variable, 110 }; 111 static cl::opt<FindType> Find( 112 "find", cl::desc("Choose search type:"), 113 cl::values( 114 clEnumValN(FindType::None, "none", "No search, just dump the module."), 115 clEnumValN(FindType::Function, "function", "Find functions."), 116 clEnumValN(FindType::Block, "block", "Find blocks."), 117 clEnumValN(FindType::Namespace, "namespace", "Find namespaces."), 118 clEnumValN(FindType::Type, "type", "Find types."), 119 clEnumValN(FindType::Variable, "variable", "Find global variables.")), 120 cl::sub(SymbolsSubcommand)); 121 122 static cl::opt<std::string> Name("name", cl::desc("Name to find."), 123 cl::sub(SymbolsSubcommand)); 124 static cl::opt<bool> 125 Regex("regex", 126 cl::desc("Search using regular expressions (avaliable for variables " 127 "and functions only)."), 128 cl::sub(SymbolsSubcommand)); 129 static cl::opt<std::string> 130 Context("context", 131 cl::desc("Restrict search to the context of the given variable."), 132 cl::value_desc("variable"), cl::sub(SymbolsSubcommand)); 133 134 static cl::list<FunctionNameType> FunctionNameFlags( 135 "function-flags", cl::desc("Function search flags:"), 136 cl::values(clEnumValN(eFunctionNameTypeAuto, "auto", 137 "Automatically deduce flags based on name."), 138 clEnumValN(eFunctionNameTypeFull, "full", "Full function name."), 139 clEnumValN(eFunctionNameTypeBase, "base", "Base name."), 140 clEnumValN(eFunctionNameTypeMethod, "method", "Method name."), 141 clEnumValN(eFunctionNameTypeSelector, "selector", 142 "Selector name.")), 143 cl::sub(SymbolsSubcommand)); 144 static FunctionNameType getFunctionNameFlags() { 145 FunctionNameType Result = FunctionNameType(0); 146 for (FunctionNameType Flag : FunctionNameFlags) 147 Result = FunctionNameType(Result | Flag); 148 return Result; 149 } 150 151 static cl::opt<bool> DumpAST("dump-ast", 152 cl::desc("Dump AST restored from symbols."), 153 cl::sub(SymbolsSubcommand)); 154 155 static cl::opt<bool> Verify("verify", cl::desc("Verify symbol information."), 156 cl::sub(SymbolsSubcommand)); 157 158 static cl::opt<std::string> File("file", 159 cl::desc("File (compile unit) to search."), 160 cl::sub(SymbolsSubcommand)); 161 static cl::opt<int> Line("line", cl::desc("Line to search."), 162 cl::sub(SymbolsSubcommand)); 163 164 static Expected<CompilerDeclContext> getDeclContext(SymbolVendor &Vendor); 165 166 static Error findFunctions(lldb_private::Module &Module); 167 static Error findBlocks(lldb_private::Module &Module); 168 static Error findNamespaces(lldb_private::Module &Module); 169 static Error findTypes(lldb_private::Module &Module); 170 static Error findVariables(lldb_private::Module &Module); 171 static Error dumpModule(lldb_private::Module &Module); 172 static Error dumpAST(lldb_private::Module &Module); 173 static Error verify(lldb_private::Module &Module); 174 175 static Expected<Error (*)(lldb_private::Module &)> getAction(); 176 static int dumpSymbols(Debugger &Dbg); 177 } // namespace symbols 178 179 namespace irmemorymap { 180 static cl::opt<std::string> Target(cl::Positional, cl::desc("<target>"), 181 cl::Required, 182 cl::sub(IRMemoryMapSubcommand)); 183 static cl::opt<std::string> CommandFile(cl::Positional, 184 cl::desc("<command-file>"), 185 cl::init("-"), 186 cl::sub(IRMemoryMapSubcommand)); 187 static cl::opt<bool> UseHostOnlyAllocationPolicy( 188 "host-only", cl::desc("Use the host-only allocation policy"), 189 cl::init(false), cl::sub(IRMemoryMapSubcommand)); 190 191 using AllocationT = std::pair<addr_t, addr_t>; 192 using AddrIntervalMap = 193 IntervalMap<addr_t, unsigned, 8, IntervalMapHalfOpenInfo<addr_t>>; 194 195 struct IRMemoryMapTestState { 196 TargetSP Target; 197 IRMemoryMap Map; 198 199 AddrIntervalMap::Allocator IntervalMapAllocator; 200 AddrIntervalMap Allocations; 201 202 StringMap<addr_t> Label2AddrMap; 203 204 IRMemoryMapTestState(TargetSP Target) 205 : Target(Target), Map(Target), Allocations(IntervalMapAllocator) {} 206 }; 207 208 bool areAllocationsOverlapping(const AllocationT &L, const AllocationT &R); 209 bool evalMalloc(StringRef Line, IRMemoryMapTestState &State); 210 bool evalFree(StringRef Line, IRMemoryMapTestState &State); 211 int evaluateMemoryMapCommands(Debugger &Dbg); 212 } // namespace irmemorymap 213 214 } // namespace opts 215 216 template <typename... Args> 217 static Error make_string_error(const char *Format, Args &&... args) { 218 return llvm::make_error<llvm::StringError>( 219 llvm::formatv(Format, std::forward<Args>(args)...).str(), 220 llvm::inconvertibleErrorCode()); 221 } 222 223 TargetSP opts::createTarget(Debugger &Dbg, const std::string &Filename) { 224 TargetSP Target; 225 Status ST = Dbg.GetTargetList().CreateTarget( 226 Dbg, Filename, /*triple*/ "", eLoadDependentsNo, 227 /*platform_options*/ nullptr, Target); 228 if (ST.Fail()) { 229 errs() << formatv("Failed to create target '{0}: {1}\n", Filename, ST); 230 exit(1); 231 } 232 return Target; 233 } 234 235 std::unique_ptr<MemoryBuffer> opts::openFile(const std::string &Filename) { 236 auto MB = MemoryBuffer::getFileOrSTDIN(Filename); 237 if (!MB) { 238 errs() << formatv("Could not open file '{0}: {1}\n", Filename, 239 MB.getError().message()); 240 exit(1); 241 } 242 return std::move(*MB); 243 } 244 245 void opts::breakpoint::dumpState(const BreakpointList &List, LinePrinter &P) { 246 P.formatLine("{0} breakpoint{1}", List.GetSize(), plural(List.GetSize())); 247 if (List.GetSize() > 0) 248 P.formatLine("At least one breakpoint."); 249 for (size_t i = 0, e = List.GetSize(); i < e; ++i) { 250 BreakpointSP BP = List.GetBreakpointAtIndex(i); 251 P.formatLine("Breakpoint ID {0}:", BP->GetID()); 252 AutoIndent Indent(P, 2); 253 P.formatLine("{0} location{1}.", BP->GetNumLocations(), 254 plural(BP->GetNumLocations())); 255 if (BP->GetNumLocations() > 0) 256 P.formatLine("At least one location."); 257 P.formatLine("{0} resolved location{1}.", BP->GetNumResolvedLocations(), 258 plural(BP->GetNumResolvedLocations())); 259 if (BP->GetNumResolvedLocations() > 0) 260 P.formatLine("At least one resolved location."); 261 for (size_t l = 0, le = BP->GetNumLocations(); l < le; ++l) { 262 BreakpointLocationSP Loc = BP->GetLocationAtIndex(l); 263 P.formatLine("Location ID {0}:", Loc->GetID()); 264 AutoIndent Indent(P, 2); 265 P.formatLine("Enabled: {0}", Loc->IsEnabled()); 266 P.formatLine("Resolved: {0}", Loc->IsResolved()); 267 SymbolContext sc; 268 Loc->GetAddress().CalculateSymbolContext(&sc); 269 lldb_private::StreamString S; 270 sc.DumpStopContext(&S, BP->GetTarget().GetProcessSP().get(), 271 Loc->GetAddress(), false, true, false, true, true); 272 P.formatLine("Address: {0}", S.GetString()); 273 } 274 } 275 P.NewLine(); 276 } 277 278 std::string opts::breakpoint::substitute(StringRef Cmd) { 279 std::string Result; 280 raw_string_ostream OS(Result); 281 while (!Cmd.empty()) { 282 switch (Cmd[0]) { 283 case '%': 284 if (Cmd.consume_front("%p") && (Cmd.empty() || !isalnum(Cmd[0]))) { 285 OS << sys::path::parent_path(breakpoint::CommandFile); 286 break; 287 } 288 // fall through 289 default: 290 size_t pos = Cmd.find('%'); 291 OS << Cmd.substr(0, pos); 292 Cmd = Cmd.substr(pos); 293 break; 294 } 295 } 296 return std::move(OS.str()); 297 } 298 299 int opts::breakpoint::evaluateBreakpoints(Debugger &Dbg) { 300 TargetSP Target = opts::createTarget(Dbg, breakpoint::Target); 301 std::unique_ptr<MemoryBuffer> MB = opts::openFile(breakpoint::CommandFile); 302 303 LinePrinter P(4, outs()); 304 StringRef Rest = MB->getBuffer(); 305 int HadErrors = 0; 306 while (!Rest.empty()) { 307 StringRef Line; 308 std::tie(Line, Rest) = Rest.split('\n'); 309 Line = Line.ltrim(); 310 if (Line.empty() || Line[0] == '#') 311 continue; 312 313 if (!Persistent) 314 Target->RemoveAllBreakpoints(/*internal_also*/ true); 315 316 std::string Command = substitute(Line); 317 P.formatLine("Command: {0}", Command); 318 CommandReturnObject Result; 319 if (!Dbg.GetCommandInterpreter().HandleCommand( 320 Command.c_str(), /*add_to_history*/ eLazyBoolNo, Result)) { 321 P.formatLine("Failed: {0}", Result.GetErrorData()); 322 HadErrors = 1; 323 continue; 324 } 325 326 dumpState(Target->GetBreakpointList(/*internal*/ false), P); 327 } 328 return HadErrors; 329 } 330 331 Expected<CompilerDeclContext> 332 opts::symbols::getDeclContext(SymbolVendor &Vendor) { 333 if (Context.empty()) 334 return CompilerDeclContext(); 335 VariableList List; 336 Vendor.FindGlobalVariables(ConstString(Context), nullptr, UINT32_MAX, List); 337 if (List.Empty()) 338 return make_string_error("Context search didn't find a match."); 339 if (List.GetSize() > 1) 340 return make_string_error("Context search found multiple matches."); 341 return List.GetVariableAtIndex(0)->GetDeclContext(); 342 } 343 344 Error opts::symbols::findFunctions(lldb_private::Module &Module) { 345 SymbolVendor &Vendor = *Module.GetSymbolVendor(); 346 SymbolContextList List; 347 if (!File.empty()) { 348 assert(Line != 0); 349 350 FileSpec src_file(File, false); 351 size_t cu_count = Module.GetNumCompileUnits(); 352 for (size_t i = 0; i < cu_count; i++) { 353 lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i); 354 if (!cu_sp) 355 continue; 356 357 LineEntry le; 358 cu_sp->FindLineEntry(0, Line, &src_file, false, &le); 359 if (!le.IsValid()) 360 continue; 361 362 auto addr = le.GetSameLineContiguousAddressRange().GetBaseAddress(); 363 if (!addr.IsValid()) 364 continue; 365 366 SymbolContext sc; 367 uint32_t resolved = 368 addr.CalculateSymbolContext(&sc, eSymbolContextFunction); 369 if (resolved & eSymbolContextFunction) 370 List.Append(sc); 371 } 372 } else if (Regex) { 373 RegularExpression RE(Name); 374 assert(RE.IsValid()); 375 Vendor.FindFunctions(RE, true, false, List); 376 } else { 377 Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor); 378 if (!ContextOr) 379 return ContextOr.takeError(); 380 CompilerDeclContext *ContextPtr = 381 ContextOr->IsValid() ? &*ContextOr : nullptr; 382 383 Vendor.FindFunctions(ConstString(Name), ContextPtr, getFunctionNameFlags(), 384 true, false, List); 385 } 386 outs() << formatv("Found {0} functions:\n", List.GetSize()); 387 StreamString Stream; 388 List.Dump(&Stream, nullptr); 389 outs() << Stream.GetData() << "\n"; 390 return Error::success(); 391 } 392 393 Error opts::symbols::findBlocks(lldb_private::Module &Module) { 394 assert(!Regex); 395 assert(!File.empty()); 396 assert(Line != 0); 397 398 SymbolContextList List; 399 400 FileSpec src_file(File, false); 401 size_t cu_count = Module.GetNumCompileUnits(); 402 for (size_t i = 0; i < cu_count; i++) { 403 lldb::CompUnitSP cu_sp = Module.GetCompileUnitAtIndex(i); 404 if (!cu_sp) 405 continue; 406 407 LineEntry le; 408 cu_sp->FindLineEntry(0, Line, &src_file, false, &le); 409 if (!le.IsValid()) 410 continue; 411 412 auto addr = le.GetSameLineContiguousAddressRange().GetBaseAddress(); 413 if (!addr.IsValid()) 414 continue; 415 416 SymbolContext sc; 417 uint32_t resolved = addr.CalculateSymbolContext(&sc, eSymbolContextBlock); 418 if (resolved & eSymbolContextBlock) 419 List.Append(sc); 420 } 421 422 outs() << formatv("Found {0} blocks:\n", List.GetSize()); 423 StreamString Stream; 424 List.Dump(&Stream, nullptr); 425 outs() << Stream.GetData() << "\n"; 426 return Error::success(); 427 } 428 429 Error opts::symbols::findNamespaces(lldb_private::Module &Module) { 430 SymbolVendor &Vendor = *Module.GetSymbolVendor(); 431 Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor); 432 if (!ContextOr) 433 return ContextOr.takeError(); 434 CompilerDeclContext *ContextPtr = 435 ContextOr->IsValid() ? &*ContextOr : nullptr; 436 437 SymbolContext SC; 438 CompilerDeclContext Result = 439 Vendor.FindNamespace(SC, ConstString(Name), ContextPtr); 440 if (Result) 441 outs() << "Found namespace: " 442 << Result.GetScopeQualifiedName().GetStringRef() << "\n"; 443 else 444 outs() << "Namespace not found.\n"; 445 return Error::success(); 446 } 447 448 Error opts::symbols::findTypes(lldb_private::Module &Module) { 449 SymbolVendor &Vendor = *Module.GetSymbolVendor(); 450 Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor); 451 if (!ContextOr) 452 return ContextOr.takeError(); 453 CompilerDeclContext *ContextPtr = 454 ContextOr->IsValid() ? &*ContextOr : nullptr; 455 456 SymbolContext SC; 457 DenseSet<SymbolFile *> SearchedFiles; 458 TypeMap Map; 459 Vendor.FindTypes(SC, ConstString(Name), ContextPtr, true, UINT32_MAX, 460 SearchedFiles, Map); 461 462 outs() << formatv("Found {0} types:\n", Map.GetSize()); 463 StreamString Stream; 464 Map.Dump(&Stream, false); 465 outs() << Stream.GetData() << "\n"; 466 return Error::success(); 467 } 468 469 Error opts::symbols::findVariables(lldb_private::Module &Module) { 470 SymbolVendor &Vendor = *Module.GetSymbolVendor(); 471 VariableList List; 472 if (Regex) { 473 RegularExpression RE(Name); 474 assert(RE.IsValid()); 475 Vendor.FindGlobalVariables(RE, UINT32_MAX, List); 476 } else if (!File.empty()) { 477 CompUnitSP CU; 478 for (size_t Ind = 0; !CU && Ind < Module.GetNumCompileUnits(); ++Ind) { 479 CompUnitSP Candidate = Module.GetCompileUnitAtIndex(Ind); 480 if (!Candidate || Candidate->GetFilename().GetStringRef() != File) 481 continue; 482 if (CU) 483 return make_string_error("Multiple compile units for file `{0}` found.", 484 File); 485 CU = std::move(Candidate); 486 } 487 488 if (!CU) 489 return make_string_error("Compile unit `{0}` not found.", File); 490 491 List.AddVariables(CU->GetVariableList(true).get()); 492 } else { 493 Expected<CompilerDeclContext> ContextOr = getDeclContext(Vendor); 494 if (!ContextOr) 495 return ContextOr.takeError(); 496 CompilerDeclContext *ContextPtr = 497 ContextOr->IsValid() ? &*ContextOr : nullptr; 498 499 Vendor.FindGlobalVariables(ConstString(Name), ContextPtr, UINT32_MAX, List); 500 } 501 outs() << formatv("Found {0} variables:\n", List.GetSize()); 502 StreamString Stream; 503 List.Dump(&Stream, false); 504 outs() << Stream.GetData() << "\n"; 505 return Error::success(); 506 } 507 508 Error opts::symbols::dumpModule(lldb_private::Module &Module) { 509 StreamString Stream; 510 Module.ParseAllDebugSymbols(); 511 Module.Dump(&Stream); 512 outs() << Stream.GetData() << "\n"; 513 return Error::success(); 514 } 515 516 Error opts::symbols::dumpAST(lldb_private::Module &Module) { 517 SymbolVendor &plugin = *Module.GetSymbolVendor(); 518 519 auto symfile = plugin.GetSymbolFile(); 520 if (!symfile) 521 return make_string_error("Module has no symbol file."); 522 523 auto clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>( 524 symfile->GetTypeSystemForLanguage(eLanguageTypeC_plus_plus)); 525 if (!clang_ast_ctx) 526 return make_string_error("Can't retrieve Clang AST context."); 527 528 auto ast_ctx = clang_ast_ctx->getASTContext(); 529 if (!ast_ctx) 530 return make_string_error("Can't retrieve AST context."); 531 532 auto tu = ast_ctx->getTranslationUnitDecl(); 533 if (!tu) 534 return make_string_error("Can't retrieve translation unit declaration."); 535 536 symfile->ParseDeclsForContext(CompilerDeclContext( 537 clang_ast_ctx, static_cast<clang::DeclContext *>(tu))); 538 539 tu->print(outs()); 540 541 return Error::success(); 542 } 543 544 Error opts::symbols::verify(lldb_private::Module &Module) { 545 SymbolVendor &plugin = *Module.GetSymbolVendor(); 546 547 SymbolFile *symfile = plugin.GetSymbolFile(); 548 if (!symfile) 549 return make_string_error("Module has no symbol file."); 550 551 uint32_t comp_units_count = symfile->GetNumCompileUnits(); 552 553 outs() << "Found " << comp_units_count << " compile units.\n"; 554 555 for (uint32_t i = 0; i < comp_units_count; i++) { 556 lldb::CompUnitSP comp_unit = symfile->ParseCompileUnitAtIndex(i); 557 if (!comp_unit) 558 return make_string_error("Connot parse compile unit {0}.", i); 559 560 outs() << "Processing '" << comp_unit->GetFilename().AsCString() 561 << "' compile unit.\n"; 562 563 LineTable *lt = comp_unit->GetLineTable(); 564 if (!lt) 565 return make_string_error("Can't get a line table of a compile unit."); 566 567 uint32_t count = lt->GetSize(); 568 569 outs() << "The line table contains " << count << " entries.\n"; 570 571 if (count == 0) 572 continue; 573 574 LineEntry le; 575 if (!lt->GetLineEntryAtIndex(0, le)) 576 return make_string_error("Can't get a line entry of a compile unit."); 577 578 for (uint32_t i = 1; i < count; i++) { 579 lldb::addr_t curr_end = 580 le.range.GetBaseAddress().GetFileAddress() + le.range.GetByteSize(); 581 582 if (!lt->GetLineEntryAtIndex(i, le)) 583 return make_string_error("Can't get a line entry of a compile unit"); 584 585 if (curr_end > le.range.GetBaseAddress().GetFileAddress()) 586 return make_string_error( 587 "Line table of a compile unit is inconsistent."); 588 } 589 } 590 591 outs() << "The symbol information is verified.\n"; 592 593 return Error::success(); 594 } 595 596 Expected<Error (*)(lldb_private::Module &)> opts::symbols::getAction() { 597 if (Verify && DumpAST) 598 return make_string_error( 599 "Cannot both verify symbol information and dump AST."); 600 601 if (Verify) { 602 if (Find != FindType::None) 603 return make_string_error( 604 "Cannot both search and verify symbol information."); 605 if (Regex || !Context.empty() || !Name.empty() || !File.empty() || 606 Line != 0) 607 return make_string_error( 608 "-regex, -context, -name, -file and -line options are not " 609 "applicable for symbol verification."); 610 return verify; 611 } 612 613 if (DumpAST) { 614 if (Find != FindType::None) 615 return make_string_error( 616 "Cannot both search and dump AST."); 617 if (Regex || !Context.empty() || !Name.empty() || !File.empty() || 618 Line != 0) 619 return make_string_error( 620 "-regex, -context, -name, -file and -line options are not " 621 "applicable for dumping AST."); 622 return dumpAST; 623 } 624 625 if (Regex && !Context.empty()) 626 return make_string_error( 627 "Cannot search using both regular expressions and context."); 628 629 if (Regex && !RegularExpression(Name).IsValid()) 630 return make_string_error("`{0}` is not a valid regular expression.", Name); 631 632 if (Regex + !Context.empty() + !File.empty() >= 2) 633 return make_string_error( 634 "Only one of -regex, -context and -file may be used simultaneously."); 635 if (Regex && Name.empty()) 636 return make_string_error("-regex used without a -name"); 637 638 switch (Find) { 639 case FindType::None: 640 if (!Context.empty() || !Name.empty() || !File.empty() || Line != 0) 641 return make_string_error( 642 "Specify search type (-find) to use search options."); 643 return dumpModule; 644 645 case FindType::Function: 646 if (!File.empty() + (Line != 0) == 1) 647 return make_string_error("Both file name and line number must be " 648 "specified when searching a function " 649 "by file position."); 650 if (Regex + (getFunctionNameFlags() != 0) + !File.empty() >= 2) 651 return make_string_error("Only one of regular expression, function-flags " 652 "and file position may be used simultaneously " 653 "when searching a function."); 654 return findFunctions; 655 656 case FindType::Block: 657 if (File.empty() || Line == 0) 658 return make_string_error("Both file name and line number must be " 659 "specified when searching a block."); 660 if (Regex || getFunctionNameFlags() != 0) 661 return make_string_error("Cannot use regular expression or " 662 "function-flags for searching a block."); 663 return findBlocks; 664 665 case FindType::Namespace: 666 if (Regex || !File.empty() || Line != 0) 667 return make_string_error("Cannot search for namespaces using regular " 668 "expressions, file names or line numbers."); 669 return findNamespaces; 670 671 case FindType::Type: 672 if (Regex || !File.empty() || Line != 0) 673 return make_string_error("Cannot search for types using regular " 674 "expressions, file names or line numbers."); 675 return findTypes; 676 677 case FindType::Variable: 678 if (Line != 0) 679 return make_string_error("Cannot search for variables " 680 "using line numbers."); 681 return findVariables; 682 } 683 684 llvm_unreachable("Unsupported symbol action."); 685 } 686 687 int opts::symbols::dumpSymbols(Debugger &Dbg) { 688 auto ActionOr = getAction(); 689 if (!ActionOr) { 690 logAllUnhandledErrors(ActionOr.takeError(), WithColor::error(), ""); 691 return 1; 692 } 693 auto Action = *ActionOr; 694 695 int HadErrors = 0; 696 for (const auto &File : InputFilenames) { 697 outs() << "Module: " << File << "\n"; 698 ModuleSpec Spec{FileSpec(File, false)}; 699 Spec.GetSymbolFileSpec().SetFile(File, false, FileSpec::Style::native); 700 701 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); 702 SymbolVendor *Vendor = ModulePtr->GetSymbolVendor(); 703 if (!Vendor) { 704 WithColor::error() << "Module has no symbol vendor.\n"; 705 HadErrors = 1; 706 continue; 707 } 708 709 if (Error E = Action(*ModulePtr)) { 710 WithColor::error() << toString(std::move(E)) << "\n"; 711 HadErrors = 1; 712 } 713 714 outs().flush(); 715 } 716 return HadErrors; 717 } 718 719 static int dumpObjectFiles(Debugger &Dbg) { 720 LinePrinter Printer(4, llvm::outs()); 721 722 int HadErrors = 0; 723 for (const auto &File : opts::object::InputFilenames) { 724 ModuleSpec Spec{FileSpec(File, false)}; 725 726 auto ModulePtr = std::make_shared<lldb_private::Module>(Spec); 727 // Fetch symbol vendor before we get the section list to give the symbol 728 // vendor a chance to populate it. 729 ModulePtr->GetSymbolVendor(); 730 SectionList *Sections = ModulePtr->GetSectionList(); 731 if (!Sections) { 732 llvm::errs() << "Could not load sections for module " << File << "\n"; 733 HadErrors = 1; 734 continue; 735 } 736 737 Printer.formatLine("Architecture: {0}", 738 ModulePtr->GetArchitecture().GetTriple().getTriple()); 739 Printer.formatLine("UUID: {0}", ModulePtr->GetUUID().GetAsString()); 740 741 size_t Count = Sections->GetNumSections(0); 742 Printer.formatLine("Showing {0} sections", Count); 743 for (size_t I = 0; I < Count; ++I) { 744 AutoIndent Indent(Printer, 2); 745 auto S = Sections->GetSectionAtIndex(I); 746 assert(S); 747 Printer.formatLine("Index: {0}", I); 748 Printer.formatLine("Name: {0}", S->GetName().GetStringRef()); 749 Printer.formatLine("Type: {0}", S->GetTypeAsCString()); 750 Printer.formatLine("VM size: {0}", S->GetByteSize()); 751 Printer.formatLine("File size: {0}", S->GetFileSize()); 752 753 if (opts::object::SectionContents) { 754 DataExtractor Data; 755 S->GetSectionData(Data); 756 ArrayRef<uint8_t> Bytes = {Data.GetDataStart(), Data.GetDataEnd()}; 757 Printer.formatBinary("Data: ", Bytes, 0); 758 } 759 Printer.NewLine(); 760 } 761 } 762 return HadErrors; 763 } 764 765 /// Check if two half-open intervals intersect: 766 /// http://world.std.com/~swmcd/steven/tech/interval.html 767 bool opts::irmemorymap::areAllocationsOverlapping(const AllocationT &L, 768 const AllocationT &R) { 769 return R.first < L.second && L.first < R.second; 770 } 771 772 bool opts::irmemorymap::evalMalloc(StringRef Line, 773 IRMemoryMapTestState &State) { 774 // ::= <label> = malloc <size> <alignment> 775 StringRef Label; 776 std::tie(Label, Line) = Line.split('='); 777 if (Line.empty()) 778 return false; 779 Label = Label.trim(); 780 Line = Line.trim(); 781 size_t Size; 782 uint8_t Alignment; 783 int Matches = sscanf(Line.data(), "malloc %zu %hhu", &Size, &Alignment); 784 if (Matches != 2) 785 return false; 786 787 outs() << formatv("Command: {0} = malloc(size={1}, alignment={2})\n", Label, 788 Size, Alignment); 789 if (!isPowerOf2_32(Alignment)) { 790 outs() << "Malloc error: alignment is not a power of 2\n"; 791 exit(1); 792 } 793 794 IRMemoryMap::AllocationPolicy AP = 795 UseHostOnlyAllocationPolicy ? IRMemoryMap::eAllocationPolicyHostOnly 796 : IRMemoryMap::eAllocationPolicyProcessOnly; 797 798 // Issue the malloc in the target process with "-rw" permissions. 799 const uint32_t Permissions = 0x3; 800 const bool ZeroMemory = false; 801 Status ST; 802 addr_t Addr = 803 State.Map.Malloc(Size, Alignment, Permissions, AP, ZeroMemory, ST); 804 if (ST.Fail()) { 805 outs() << formatv("Malloc error: {0}\n", ST); 806 return true; 807 } 808 809 // Print the result of the allocation before checking its validity. 810 outs() << formatv("Malloc: address = {0:x}\n", Addr); 811 812 // Check that the allocation is aligned. 813 if (!Addr || Addr % Alignment != 0) { 814 outs() << "Malloc error: zero or unaligned allocation detected\n"; 815 exit(1); 816 } 817 818 // Check that the allocation does not overlap another allocation. Do so by 819 // testing each allocation which may cover the interval [Addr, EndOfRegion). 820 addr_t EndOfRegion = Addr + Size; 821 auto Probe = State.Allocations.begin(); 822 Probe.advanceTo(Addr); //< First interval s.t stop >= Addr. 823 AllocationT NewAllocation = {Addr, EndOfRegion}; 824 while (Probe != State.Allocations.end() && Probe.start() < EndOfRegion) { 825 AllocationT ProbeAllocation = {Probe.start(), Probe.stop()}; 826 if (areAllocationsOverlapping(ProbeAllocation, NewAllocation)) { 827 outs() << "Malloc error: overlapping allocation detected" 828 << formatv(", previous allocation at [{0:x}, {1:x})\n", 829 Probe.start(), Probe.stop()); 830 exit(1); 831 } 832 ++Probe; 833 } 834 835 // Insert the new allocation into the interval map. Use unique allocation IDs 836 // to inhibit interval coalescing. 837 static unsigned AllocationID = 0; 838 if (Size) 839 State.Allocations.insert(Addr, EndOfRegion, AllocationID++); 840 841 // Store the label -> address mapping. 842 State.Label2AddrMap[Label] = Addr; 843 844 return true; 845 } 846 847 bool opts::irmemorymap::evalFree(StringRef Line, IRMemoryMapTestState &State) { 848 // ::= free <label> 849 if (!Line.consume_front("free")) 850 return false; 851 StringRef Label = Line.trim(); 852 853 outs() << formatv("Command: free({0})\n", Label); 854 auto LabelIt = State.Label2AddrMap.find(Label); 855 if (LabelIt == State.Label2AddrMap.end()) { 856 outs() << "Free error: Invalid allocation label\n"; 857 exit(1); 858 } 859 860 Status ST; 861 addr_t Addr = LabelIt->getValue(); 862 State.Map.Free(Addr, ST); 863 if (ST.Fail()) { 864 outs() << formatv("Free error: {0}\n", ST); 865 exit(1); 866 } 867 868 // Erase the allocation from the live interval map. 869 auto Interval = State.Allocations.find(Addr); 870 if (Interval != State.Allocations.end()) { 871 outs() << formatv("Free: [{0:x}, {1:x})\n", Interval.start(), 872 Interval.stop()); 873 Interval.erase(); 874 } 875 876 return true; 877 } 878 879 int opts::irmemorymap::evaluateMemoryMapCommands(Debugger &Dbg) { 880 // Set up a Target. 881 TargetSP Target = opts::createTarget(Dbg, irmemorymap::Target); 882 883 // Set up a Process. In order to allocate memory within a target, this 884 // process must be alive and must support JIT'ing. 885 CommandReturnObject Result; 886 Dbg.SetAsyncExecution(false); 887 CommandInterpreter &CI = Dbg.GetCommandInterpreter(); 888 auto IssueCmd = [&](const char *Cmd) -> bool { 889 return CI.HandleCommand(Cmd, eLazyBoolNo, Result); 890 }; 891 if (!IssueCmd("b main") || !IssueCmd("run")) { 892 outs() << formatv("Failed: {0}\n", Result.GetErrorData()); 893 exit(1); 894 } 895 896 ProcessSP Process = Target->GetProcessSP(); 897 if (!Process || !Process->IsAlive() || !Process->CanJIT()) { 898 outs() << "Cannot use process to test IRMemoryMap\n"; 899 exit(1); 900 } 901 902 // Set up an IRMemoryMap and associated testing state. 903 IRMemoryMapTestState State(Target); 904 905 // Parse and apply commands from the command file. 906 std::unique_ptr<MemoryBuffer> MB = opts::openFile(irmemorymap::CommandFile); 907 StringRef Rest = MB->getBuffer(); 908 while (!Rest.empty()) { 909 StringRef Line; 910 std::tie(Line, Rest) = Rest.split('\n'); 911 Line = Line.ltrim(); 912 913 if (Line.empty() || Line[0] == '#') 914 continue; 915 916 if (evalMalloc(Line, State)) 917 continue; 918 919 if (evalFree(Line, State)) 920 continue; 921 922 errs() << "Could not parse line: " << Line << "\n"; 923 exit(1); 924 } 925 return 0; 926 } 927 928 int main(int argc, const char *argv[]) { 929 StringRef ToolName = argv[0]; 930 sys::PrintStackTraceOnErrorSignal(ToolName); 931 PrettyStackTraceProgram X(argc, argv); 932 llvm_shutdown_obj Y; 933 934 cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n"); 935 936 SystemLifetimeManager DebuggerLifetime; 937 DebuggerLifetime.Initialize(llvm::make_unique<SystemInitializerTest>(), 938 nullptr); 939 CleanUp TerminateDebugger([&] { DebuggerLifetime.Terminate(); }); 940 941 auto Dbg = lldb_private::Debugger::CreateInstance(); 942 943 if (!opts::Log.empty()) 944 Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, errs()); 945 946 if (opts::BreakpointSubcommand) 947 return opts::breakpoint::evaluateBreakpoints(*Dbg); 948 if (opts::ObjectFileSubcommand) 949 return dumpObjectFiles(*Dbg); 950 if (opts::SymbolsSubcommand) 951 return opts::symbols::dumpSymbols(*Dbg); 952 if (opts::IRMemoryMapSubcommand) 953 return opts::irmemorymap::evaluateMemoryMapCommands(*Dbg); 954 955 WithColor::error() << "No command specified.\n"; 956 return 1; 957 } 958