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