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