1 //===-- lib/DebugInfo/Symbolize/MarkupFilter.cpp -------------------------===// 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 /// \file 10 /// This file defines the implementation of a filter that replaces symbolizer 11 /// markup with human-readable expressions. 12 /// 13 /// See https://llvm.org/docs/SymbolizerMarkupFormat.html 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #include "llvm/DebugInfo/Symbolize/MarkupFilter.h" 18 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/ADT/StringExtras.h" 21 #include "llvm/ADT/StringSwitch.h" 22 #include "llvm/DebugInfo/DIContext.h" 23 #include "llvm/DebugInfo/Symbolize/Markup.h" 24 #include "llvm/DebugInfo/Symbolize/Symbolize.h" 25 #include "llvm/Demangle/Demangle.h" 26 #include "llvm/Support/Error.h" 27 #include "llvm/Support/FormatVariadic.h" 28 #include "llvm/Support/WithColor.h" 29 #include "llvm/Support/raw_ostream.h" 30 #include <optional> 31 32 using namespace llvm; 33 using namespace llvm::symbolize; 34 35 MarkupFilter::MarkupFilter(raw_ostream &OS, LLVMSymbolizer &Symbolizer, 36 std::optional<bool> ColorsEnabled) 37 : OS(OS), Symbolizer(Symbolizer), 38 ColorsEnabled( 39 ColorsEnabled.value_or(WithColor::defaultAutoDetectFunction()(OS))) {} 40 41 void MarkupFilter::filter(std::string &&InputLine) { 42 Line = std::move(InputLine); 43 resetColor(); 44 45 Parser.parseLine(Line); 46 SmallVector<MarkupNode> DeferredNodes; 47 // See if the line is a contextual (i.e. contains a contextual element). 48 // In this case, anything after the contextual element is elided, or the whole 49 // line may be elided. 50 while (std::optional<MarkupNode> Node = Parser.nextNode()) { 51 // If this was a contextual line, then summarily stop processing. 52 if (tryContextualElement(*Node, DeferredNodes)) 53 return; 54 // This node may yet be part of an elided contextual line. 55 DeferredNodes.push_back(*Node); 56 } 57 58 // This was not a contextual line, so nothing in it should be elided. 59 endAnyModuleInfoLine(); 60 for (const MarkupNode &Node : DeferredNodes) 61 filterNode(Node); 62 } 63 64 void MarkupFilter::finish() { 65 Parser.flush(); 66 while (std::optional<MarkupNode> Node = Parser.nextNode()) 67 filterNode(*Node); 68 endAnyModuleInfoLine(); 69 resetColor(); 70 Modules.clear(); 71 MMaps.clear(); 72 } 73 74 // See if the given node is a contextual element and handle it if so. This may 75 // either output or defer the element; in the former case, it will first emit 76 // any DeferredNodes. 77 // 78 // Returns true if the given element was a contextual element. In this case, 79 // DeferredNodes should be considered handled and should not be emitted. The 80 // rest of the containing line must also be ignored in case the element was 81 // deferred to a following line. 82 bool MarkupFilter::tryContextualElement( 83 const MarkupNode &Node, const SmallVector<MarkupNode> &DeferredNodes) { 84 if (tryMMap(Node, DeferredNodes)) 85 return true; 86 if (tryReset(Node, DeferredNodes)) 87 return true; 88 return tryModule(Node, DeferredNodes); 89 } 90 91 bool MarkupFilter::tryMMap(const MarkupNode &Node, 92 const SmallVector<MarkupNode> &DeferredNodes) { 93 if (Node.Tag != "mmap") 94 return false; 95 std::optional<MMap> ParsedMMap = parseMMap(Node); 96 if (!ParsedMMap) 97 return true; 98 99 if (const MMap *M = getOverlappingMMap(*ParsedMMap)) { 100 WithColor::error(errs()) 101 << formatv("overlapping mmap: #{0:x} [{1:x}-{2:x}]\n", M->Mod->ID, 102 M->Addr, M->Addr + M->Size - 1); 103 reportLocation(Node.Fields[0].begin()); 104 return true; 105 } 106 107 auto Res = MMaps.emplace(ParsedMMap->Addr, std::move(*ParsedMMap)); 108 assert(Res.second && "Overlap check should ensure emplace succeeds."); 109 MMap &MMap = Res.first->second; 110 111 if (!MIL || MIL->Mod != MMap.Mod) { 112 endAnyModuleInfoLine(); 113 for (const MarkupNode &Node : DeferredNodes) 114 filterNode(Node); 115 beginModuleInfoLine(MMap.Mod); 116 OS << "; adds"; 117 } 118 MIL->MMaps.push_back(&MMap); 119 return true; 120 } 121 122 bool MarkupFilter::tryReset(const MarkupNode &Node, 123 const SmallVector<MarkupNode> &DeferredNodes) { 124 if (Node.Tag != "reset") 125 return false; 126 if (!checkNumFields(Node, 0)) 127 return true; 128 129 if (!Modules.empty() || !MMaps.empty()) { 130 endAnyModuleInfoLine(); 131 for (const MarkupNode &Node : DeferredNodes) 132 filterNode(Node); 133 printRawElement(Node); 134 OS << lineEnding(); 135 136 Modules.clear(); 137 MMaps.clear(); 138 } 139 return true; 140 } 141 142 bool MarkupFilter::tryModule(const MarkupNode &Node, 143 const SmallVector<MarkupNode> &DeferredNodes) { 144 if (Node.Tag != "module") 145 return false; 146 std::optional<Module> ParsedModule = parseModule(Node); 147 if (!ParsedModule) 148 return true; 149 150 auto Res = Modules.try_emplace( 151 ParsedModule->ID, std::make_unique<Module>(std::move(*ParsedModule))); 152 if (!Res.second) { 153 WithColor::error(errs()) << "duplicate module ID\n"; 154 reportLocation(Node.Fields[0].begin()); 155 return true; 156 } 157 Module &Module = *Res.first->second; 158 159 endAnyModuleInfoLine(); 160 for (const MarkupNode &Node : DeferredNodes) 161 filterNode(Node); 162 beginModuleInfoLine(&Module); 163 OS << "; BuildID="; 164 printValue(toHex(Module.BuildID, /*LowerCase=*/true)); 165 return true; 166 } 167 168 void MarkupFilter::beginModuleInfoLine(const Module *M) { 169 highlight(); 170 OS << "[[[ELF module"; 171 printValue(formatv(" #{0:x} ", M->ID)); 172 OS << '"'; 173 printValue(M->Name); 174 OS << '"'; 175 MIL = ModuleInfoLine{M}; 176 } 177 178 void MarkupFilter::endAnyModuleInfoLine() { 179 if (!MIL) 180 return; 181 llvm::stable_sort(MIL->MMaps, [](const MMap *A, const MMap *B) { 182 return A->Addr < B->Addr; 183 }); 184 for (const MMap *M : MIL->MMaps) { 185 OS << (M == MIL->MMaps.front() ? ' ' : ','); 186 OS << '['; 187 printValue(formatv("{0:x}", M->Addr)); 188 OS << '-'; 189 printValue(formatv("{0:x}", M->Addr + M->Size - 1)); 190 OS << "]("; 191 printValue(M->Mode); 192 OS << ')'; 193 } 194 OS << "]]]" << lineEnding(); 195 restoreColor(); 196 MIL.reset(); 197 } 198 199 // Handle a node that is known not to be a contextual element. 200 void MarkupFilter::filterNode(const MarkupNode &Node) { 201 if (!checkTag(Node)) 202 return; 203 if (tryPresentation(Node)) 204 return; 205 if (trySGR(Node)) 206 return; 207 208 OS << Node.Text; 209 } 210 211 bool MarkupFilter::tryPresentation(const MarkupNode &Node) { 212 if (trySymbol(Node)) 213 return true; 214 if (tryPC(Node)) 215 return true; 216 if (tryBackTrace(Node)) 217 return true; 218 return tryData(Node); 219 } 220 221 bool MarkupFilter::trySymbol(const MarkupNode &Node) { 222 if (Node.Tag != "symbol") 223 return false; 224 if (!checkNumFields(Node, 1)) 225 return true; 226 227 highlight(); 228 OS << llvm::demangle(Node.Fields.front().str()); 229 restoreColor(); 230 return true; 231 } 232 233 bool MarkupFilter::tryPC(const MarkupNode &Node) { 234 if (Node.Tag != "pc") 235 return false; 236 if (!checkNumFieldsAtLeast(Node, 1)) 237 return true; 238 warnNumFieldsAtMost(Node, 2); 239 240 std::optional<uint64_t> Addr = parseAddr(Node.Fields[0]); 241 if (!Addr) 242 return true; 243 244 // PC addresses that aren't part of a backtrace are assumed to be precise code 245 // locations. 246 PCType Type = PCType::PreciseCode; 247 if (Node.Fields.size() == 2) { 248 std::optional<PCType> ParsedType = parsePCType(Node.Fields[1]); 249 if (!ParsedType) 250 return true; 251 Type = *ParsedType; 252 } 253 *Addr = adjustAddr(*Addr, Type); 254 255 const MMap *MMap = getContainingMMap(*Addr); 256 if (!MMap) { 257 WithColor::error() << "no mmap covers address\n"; 258 reportLocation(Node.Fields[0].begin()); 259 printRawElement(Node); 260 return true; 261 } 262 263 Expected<DILineInfo> LI = Symbolizer.symbolizeCode( 264 MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)}); 265 if (!LI) { 266 WithColor::defaultErrorHandler(LI.takeError()); 267 printRawElement(Node); 268 return true; 269 } 270 if (!*LI) { 271 printRawElement(Node); 272 return true; 273 } 274 275 highlight(); 276 printValue(LI->FunctionName); 277 OS << '['; 278 printValue(LI->FileName); 279 OS << ':'; 280 printValue(Twine(LI->Line)); 281 OS << ']'; 282 restoreColor(); 283 return true; 284 } 285 286 bool MarkupFilter::tryBackTrace(const MarkupNode &Node) { 287 if (Node.Tag != "bt") 288 return false; 289 if (!checkNumFieldsAtLeast(Node, 2)) 290 return true; 291 warnNumFieldsAtMost(Node, 3); 292 293 std::optional<uint64_t> FrameNumber = parseFrameNumber(Node.Fields[0]); 294 if (!FrameNumber) 295 return true; 296 297 std::optional<uint64_t> Addr = parseAddr(Node.Fields[1]); 298 if (!Addr) 299 return true; 300 301 // Backtrace addresses are assumed to be return addresses by default. 302 PCType Type = PCType::ReturnAddress; 303 if (Node.Fields.size() == 3) { 304 std::optional<PCType> ParsedType = parsePCType(Node.Fields[2]); 305 if (!ParsedType) 306 return true; 307 Type = *ParsedType; 308 } 309 *Addr = adjustAddr(*Addr, Type); 310 311 const MMap *MMap = getContainingMMap(*Addr); 312 if (!MMap) { 313 WithColor::error() << "no mmap covers address\n"; 314 reportLocation(Node.Fields[0].begin()); 315 printRawElement(Node); 316 return true; 317 } 318 uint64_t MRA = MMap->getModuleRelativeAddr(*Addr); 319 320 Expected<DIInliningInfo> II = 321 Symbolizer.symbolizeInlinedCode(MMap->Mod->BuildID, {MRA}); 322 if (!II) { 323 WithColor::defaultErrorHandler(II.takeError()); 324 printRawElement(Node); 325 return true; 326 } 327 328 highlight(); 329 for (unsigned I = 0, E = II->getNumberOfFrames(); I != E; ++I) { 330 auto Header = formatv("{0, +6}", formatv("#{0}", FrameNumber)).sstr<16>(); 331 // Don't highlight the # sign as a value. 332 size_t NumberIdx = Header.find("#") + 1; 333 OS << Header.substr(0, NumberIdx); 334 printValue(Header.substr(NumberIdx)); 335 if (I == E - 1) { 336 OS << " "; 337 } else { 338 OS << '.'; 339 printValue(formatv("{0, -2}", I + 1)); 340 } 341 printValue(formatv(" {0:x16} ", *Addr)); 342 343 DILineInfo LI = II->getFrame(I); 344 if (LI) { 345 printValue(LI.FunctionName); 346 OS << ' '; 347 printValue(LI.FileName); 348 OS << ':'; 349 printValue(Twine(LI.Line)); 350 OS << ':'; 351 printValue(Twine(LI.Column)); 352 OS << ' '; 353 } 354 OS << '('; 355 printValue(MMap->Mod->Name); 356 OS << "+"; 357 printValue(formatv("{0:x}", MRA)); 358 OS << ')'; 359 if (I != E - 1) 360 OS << lineEnding(); 361 } 362 restoreColor(); 363 return true; 364 } 365 366 bool MarkupFilter::tryData(const MarkupNode &Node) { 367 if (Node.Tag != "data") 368 return false; 369 if (!checkNumFields(Node, 1)) 370 return true; 371 std::optional<uint64_t> Addr = parseAddr(Node.Fields[0]); 372 if (!Addr) 373 return true; 374 375 const MMap *MMap = getContainingMMap(*Addr); 376 if (!MMap) { 377 WithColor::error() << "no mmap covers address\n"; 378 reportLocation(Node.Fields[0].begin()); 379 printRawElement(Node); 380 return true; 381 } 382 383 Expected<DIGlobal> Symbol = Symbolizer.symbolizeData( 384 MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)}); 385 if (!Symbol) { 386 WithColor::defaultErrorHandler(Symbol.takeError()); 387 printRawElement(Node); 388 return true; 389 } 390 391 highlight(); 392 OS << Symbol->Name; 393 restoreColor(); 394 return true; 395 } 396 397 bool MarkupFilter::trySGR(const MarkupNode &Node) { 398 if (Node.Text == "\033[0m") { 399 resetColor(); 400 return true; 401 } 402 if (Node.Text == "\033[1m") { 403 Bold = true; 404 if (ColorsEnabled) 405 OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, Bold); 406 return true; 407 } 408 auto SGRColor = StringSwitch<std::optional<raw_ostream::Colors>>(Node.Text) 409 .Case("\033[30m", raw_ostream::Colors::BLACK) 410 .Case("\033[31m", raw_ostream::Colors::RED) 411 .Case("\033[32m", raw_ostream::Colors::GREEN) 412 .Case("\033[33m", raw_ostream::Colors::YELLOW) 413 .Case("\033[34m", raw_ostream::Colors::BLUE) 414 .Case("\033[35m", raw_ostream::Colors::MAGENTA) 415 .Case("\033[36m", raw_ostream::Colors::CYAN) 416 .Case("\033[37m", raw_ostream::Colors::WHITE) 417 .Default(std::nullopt); 418 if (SGRColor) { 419 Color = *SGRColor; 420 if (ColorsEnabled) 421 OS.changeColor(*Color); 422 return true; 423 } 424 425 return false; 426 } 427 428 // Begin highlighting text by picking a different color than the current color 429 // state. 430 void MarkupFilter::highlight() { 431 if (!ColorsEnabled) 432 return; 433 OS.changeColor(Color == raw_ostream::Colors::BLUE ? raw_ostream::Colors::CYAN 434 : raw_ostream::Colors::BLUE, 435 Bold); 436 } 437 438 // Begin highlighting a field within a highlighted markup string. 439 void MarkupFilter::highlightValue() { 440 if (!ColorsEnabled) 441 return; 442 OS.changeColor(raw_ostream::Colors::GREEN, Bold); 443 } 444 445 // Set the output stream's color to the current color and bold state of the SGR 446 // abstract machine. 447 void MarkupFilter::restoreColor() { 448 if (!ColorsEnabled) 449 return; 450 if (Color) { 451 OS.changeColor(*Color, Bold); 452 } else { 453 OS.resetColor(); 454 if (Bold) 455 OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, Bold); 456 } 457 } 458 459 // Set the SGR and output stream's color and bold states back to the default. 460 void MarkupFilter::resetColor() { 461 if (!Color && !Bold) 462 return; 463 Color.reset(); 464 Bold = false; 465 if (ColorsEnabled) 466 OS.resetColor(); 467 } 468 469 void MarkupFilter::printRawElement(const MarkupNode &Element) { 470 highlight(); 471 OS << "[[["; 472 printValue(Element.Tag); 473 for (StringRef Field : Element.Fields) { 474 OS << ':'; 475 printValue(Field); 476 } 477 OS << "]]]"; 478 restoreColor(); 479 } 480 481 void MarkupFilter::printValue(Twine Value) { 482 highlightValue(); 483 OS << Value; 484 highlight(); 485 } 486 487 // This macro helps reduce the amount of indirection done through Optional 488 // below, since the usual case upon returning a std::nullopt Optional is to 489 // return std::nullopt. 490 #define ASSIGN_OR_RETURN_NONE(TYPE, NAME, EXPR) \ 491 auto NAME##Opt = (EXPR); \ 492 if (!NAME##Opt) \ 493 return std::nullopt; \ 494 TYPE NAME = std::move(*NAME##Opt) 495 496 std::optional<MarkupFilter::Module> 497 MarkupFilter::parseModule(const MarkupNode &Element) const { 498 if (!checkNumFieldsAtLeast(Element, 3)) 499 return std::nullopt; 500 ASSIGN_OR_RETURN_NONE(uint64_t, ID, parseModuleID(Element.Fields[0])); 501 StringRef Name = Element.Fields[1]; 502 StringRef Type = Element.Fields[2]; 503 if (Type != "elf") { 504 WithColor::error() << "unknown module type\n"; 505 reportLocation(Type.begin()); 506 return std::nullopt; 507 } 508 if (!checkNumFields(Element, 4)) 509 return std::nullopt; 510 SmallVector<uint8_t> BuildID = parseBuildID(Element.Fields[3]); 511 if (BuildID.empty()) 512 return std::nullopt; 513 return Module{ID, Name.str(), std::move(BuildID)}; 514 } 515 516 std::optional<MarkupFilter::MMap> 517 MarkupFilter::parseMMap(const MarkupNode &Element) const { 518 if (!checkNumFieldsAtLeast(Element, 3)) 519 return std::nullopt; 520 ASSIGN_OR_RETURN_NONE(uint64_t, Addr, parseAddr(Element.Fields[0])); 521 ASSIGN_OR_RETURN_NONE(uint64_t, Size, parseSize(Element.Fields[1])); 522 StringRef Type = Element.Fields[2]; 523 if (Type != "load") { 524 WithColor::error() << "unknown mmap type\n"; 525 reportLocation(Type.begin()); 526 return std::nullopt; 527 } 528 if (!checkNumFields(Element, 6)) 529 return std::nullopt; 530 ASSIGN_OR_RETURN_NONE(uint64_t, ID, parseModuleID(Element.Fields[3])); 531 ASSIGN_OR_RETURN_NONE(std::string, Mode, parseMode(Element.Fields[4])); 532 auto It = Modules.find(ID); 533 if (It == Modules.end()) { 534 WithColor::error() << "unknown module ID\n"; 535 reportLocation(Element.Fields[3].begin()); 536 return std::nullopt; 537 } 538 ASSIGN_OR_RETURN_NONE(uint64_t, ModuleRelativeAddr, 539 parseAddr(Element.Fields[5])); 540 return MMap{Addr, Size, It->second.get(), std::move(Mode), 541 ModuleRelativeAddr}; 542 } 543 544 // Parse an address (%p in the spec). 545 std::optional<uint64_t> MarkupFilter::parseAddr(StringRef Str) const { 546 if (Str.empty()) { 547 reportTypeError(Str, "address"); 548 return std::nullopt; 549 } 550 if (all_of(Str, [](char C) { return C == '0'; })) 551 return 0; 552 if (!Str.starts_with("0x")) { 553 reportTypeError(Str, "address"); 554 return std::nullopt; 555 } 556 uint64_t Addr; 557 if (Str.drop_front(2).getAsInteger(16, Addr)) { 558 reportTypeError(Str, "address"); 559 return std::nullopt; 560 } 561 return Addr; 562 } 563 564 // Parse a module ID (%i in the spec). 565 std::optional<uint64_t> MarkupFilter::parseModuleID(StringRef Str) const { 566 uint64_t ID; 567 if (Str.getAsInteger(0, ID)) { 568 reportTypeError(Str, "module ID"); 569 return std::nullopt; 570 } 571 return ID; 572 } 573 574 // Parse a size (%i in the spec). 575 std::optional<uint64_t> MarkupFilter::parseSize(StringRef Str) const { 576 uint64_t ID; 577 if (Str.getAsInteger(0, ID)) { 578 reportTypeError(Str, "size"); 579 return std::nullopt; 580 } 581 return ID; 582 } 583 584 // Parse a frame number (%i in the spec). 585 std::optional<uint64_t> MarkupFilter::parseFrameNumber(StringRef Str) const { 586 uint64_t ID; 587 if (Str.getAsInteger(10, ID)) { 588 reportTypeError(Str, "frame number"); 589 return std::nullopt; 590 } 591 return ID; 592 } 593 594 // Parse a build ID (%x in the spec). 595 object::BuildID MarkupFilter::parseBuildID(StringRef Str) const { 596 object::BuildID BID = llvm::object::parseBuildID(Str); 597 if (BID.empty()) 598 reportTypeError(Str, "build ID"); 599 return BID; 600 } 601 602 // Parses the mode string for an mmap element. 603 std::optional<std::string> MarkupFilter::parseMode(StringRef Str) const { 604 if (Str.empty()) { 605 reportTypeError(Str, "mode"); 606 return std::nullopt; 607 } 608 609 // Pop off each of r/R, w/W, and x/X from the front, in that order. 610 StringRef Remainder = Str; 611 Remainder.consume_front_insensitive("r"); 612 Remainder.consume_front_insensitive("w"); 613 Remainder.consume_front_insensitive("x"); 614 615 // If anything remains, then the string wasn't a mode. 616 if (!Remainder.empty()) { 617 reportTypeError(Str, "mode"); 618 return std::nullopt; 619 } 620 621 // Normalize the mode. 622 return Str.lower(); 623 } 624 625 std::optional<MarkupFilter::PCType> 626 MarkupFilter::parsePCType(StringRef Str) const { 627 std::optional<MarkupFilter::PCType> Type = 628 StringSwitch<std::optional<MarkupFilter::PCType>>(Str) 629 .Case("ra", MarkupFilter::PCType::ReturnAddress) 630 .Case("pc", MarkupFilter::PCType::PreciseCode) 631 .Default(std::nullopt); 632 if (!Type) 633 reportTypeError(Str, "PC type"); 634 return Type; 635 } 636 637 bool MarkupFilter::checkTag(const MarkupNode &Node) const { 638 if (any_of(Node.Tag, [](char C) { return C < 'a' || C > 'z'; })) { 639 WithColor::error(errs()) << "tags must be all lowercase characters\n"; 640 reportLocation(Node.Tag.begin()); 641 return false; 642 } 643 return true; 644 } 645 646 bool MarkupFilter::checkNumFields(const MarkupNode &Element, 647 size_t Size) const { 648 if (Element.Fields.size() != Size) { 649 bool Warn = Element.Fields.size() > Size; 650 WithColor(errs(), Warn ? HighlightColor::Warning : HighlightColor::Error) 651 << (Warn ? "warning: " : "error: ") << "expected " << Size 652 << " field(s); found " << Element.Fields.size() << "\n"; 653 reportLocation(Element.Tag.end()); 654 return Warn; 655 } 656 return true; 657 } 658 659 bool MarkupFilter::checkNumFieldsAtLeast(const MarkupNode &Element, 660 size_t Size) const { 661 if (Element.Fields.size() < Size) { 662 WithColor::error(errs()) 663 << "expected at least " << Size << " field(s); found " 664 << Element.Fields.size() << "\n"; 665 reportLocation(Element.Tag.end()); 666 return false; 667 } 668 return true; 669 } 670 671 void MarkupFilter::warnNumFieldsAtMost(const MarkupNode &Element, 672 size_t Size) const { 673 if (Element.Fields.size() <= Size) 674 return; 675 WithColor::warning(errs()) 676 << "expected at most " << Size << " field(s); found " 677 << Element.Fields.size() << "\n"; 678 reportLocation(Element.Tag.end()); 679 } 680 681 void MarkupFilter::reportTypeError(StringRef Str, StringRef TypeName) const { 682 WithColor::error(errs()) << "expected " << TypeName << "; found '" << Str 683 << "'\n"; 684 reportLocation(Str.begin()); 685 } 686 687 // Prints two lines that point out the given location in the current Line using 688 // a caret. The iterator must be within the bounds of the most recent line 689 // passed to beginLine(). 690 void MarkupFilter::reportLocation(StringRef::iterator Loc) const { 691 errs() << Line; 692 WithColor(errs().indent(Loc - StringRef(Line).begin()), 693 HighlightColor::String) 694 << '^'; 695 errs() << '\n'; 696 } 697 698 // Checks for an existing mmap that overlaps the given one and returns a 699 // pointer to one of them. 700 const MarkupFilter::MMap * 701 MarkupFilter::getOverlappingMMap(const MMap &Map) const { 702 // If the given map contains the start of another mmap, they overlap. 703 auto I = MMaps.upper_bound(Map.Addr); 704 if (I != MMaps.end() && Map.contains(I->second.Addr)) 705 return &I->second; 706 707 // If no element starts inside the given mmap, the only possible overlap would 708 // be if the preceding mmap contains the start point of the given mmap. 709 if (I != MMaps.begin()) { 710 --I; 711 if (I->second.contains(Map.Addr)) 712 return &I->second; 713 } 714 return nullptr; 715 } 716 717 // Returns the MMap that contains the given address or nullptr if none. 718 const MarkupFilter::MMap *MarkupFilter::getContainingMMap(uint64_t Addr) const { 719 // Find the first mmap starting >= Addr. 720 auto I = MMaps.lower_bound(Addr); 721 if (I != MMaps.end() && I->second.contains(Addr)) 722 return &I->second; 723 724 // The previous mmap is the last one starting < Addr. 725 if (I == MMaps.begin()) 726 return nullptr; 727 --I; 728 return I->second.contains(Addr) ? &I->second : nullptr; 729 } 730 731 uint64_t MarkupFilter::adjustAddr(uint64_t Addr, PCType Type) const { 732 // Decrementing return addresses by one moves them into the call instruction. 733 // The address doesn't have to be the start of the call instruction, just some 734 // byte on the inside. Subtracting one avoids needing detailed instruction 735 // length information here. 736 return Type == MarkupFilter::PCType::ReturnAddress ? Addr - 1 : Addr; 737 } 738 739 StringRef MarkupFilter::lineEnding() const { 740 return StringRef(Line).ends_with("\r\n") ? "\r\n" : "\n"; 741 } 742 743 bool MarkupFilter::MMap::contains(uint64_t Addr) const { 744 return this->Addr <= Addr && Addr < this->Addr + Size; 745 } 746 747 // Returns the module-relative address for a given virtual address. 748 uint64_t MarkupFilter::MMap::getModuleRelativeAddr(uint64_t Addr) const { 749 return Addr - this->Addr + ModuleRelativeAddr; 750 } 751