| //===-- LVLine.cpp --------------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This implements the LVLine class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/DebugInfo/LogicalView/Core/LVLine.h" | |
| #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" | |
| #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" | |
| using namespace llvm; | |
| using namespace llvm::logicalview; | |
| #define DEBUG_TYPE "Line" | |
| namespace { | |
| const char *const KindBasicBlock = "BasicBlock"; | |
| const char *const KindDiscriminator = "Discriminator"; | |
| const char *const KindEndSequence = "EndSequence"; | |
| const char *const KindEpilogueBegin = "EpilogueBegin"; | |
| const char *const KindLineDebug = "Line"; | |
| const char *const KindLineSource = "Code"; | |
| const char *const KindNewStatement = "NewStatement"; | |
| const char *const KindPrologueEnd = "PrologueEnd"; | |
| const char *const KindUndefined = "Undefined"; | |
| const char *const KindAlwaysStepInto = "AlwaysStepInto"; // CodeView | |
| const char *const KindNeverStepInto = "NeverStepInto"; // CodeView | |
| } // end anonymous namespace | |
| //===----------------------------------------------------------------------===// | |
| // Logical line. | |
| //===----------------------------------------------------------------------===// | |
| // Return a string representation for the line kind. | |
| const char *LVLine::kind() const { | |
| const char *Kind = KindUndefined; | |
| if (getIsLineDebug()) | |
| Kind = KindLineDebug; | |
| else if (getIsLineAssembler()) | |
| Kind = KindLineSource; | |
| return Kind; | |
| } | |
| LVLineDispatch LVLine::Dispatch = { | |
| {LVLineKind::IsBasicBlock, &LVLine::getIsBasicBlock}, | |
| {LVLineKind::IsDiscriminator, &LVLine::getIsDiscriminator}, | |
| {LVLineKind::IsEndSequence, &LVLine::getIsEndSequence}, | |
| {LVLineKind::IsLineDebug, &LVLine::getIsLineDebug}, | |
| {LVLineKind::IsLineAssembler, &LVLine::getIsLineAssembler}, | |
| {LVLineKind::IsNewStatement, &LVLine::getIsNewStatement}, | |
| {LVLineKind::IsEpilogueBegin, &LVLine::getIsEpilogueBegin}, | |
| {LVLineKind::IsPrologueEnd, &LVLine::getIsPrologueEnd}, | |
| {LVLineKind::IsAlwaysStepInto, &LVLine::getIsAlwaysStepInto}, | |
| {LVLineKind::IsNeverStepInto, &LVLine::getIsNeverStepInto}}; | |
| // String used as padding for printing elements with no line number. | |
| std::string LVLine::noLineAsString(bool ShowZero) const { | |
| if (options().getInternalNone()) | |
| return LVObject::noLineAsString(ShowZero); | |
| return (ShowZero || options().getAttributeZero()) ? (" 0 ") | |
| : (" - "); | |
| } | |
| void LVLine::markMissingParents(const LVLines *References, | |
| const LVLines *Targets) { | |
| if (!(References && Targets)) | |
| return; | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[LVLine::markMissingParents]\n"; | |
| for (const LVLine *Reference : *References) | |
| dbgs() << "References: " | |
| << "Kind = " << formattedKind(Reference->kind()) << ", " | |
| << "Line = " << Reference->getLineNumber() << "\n"; | |
| for (const LVLine *Target : *Targets) | |
| dbgs() << "Targets : " | |
| << "Kind = " << formattedKind(Target->kind()) << ", " | |
| << "Line = " << Target->getLineNumber() << "\n"; | |
| }); | |
| for (LVLine *Reference : *References) { | |
| LLVM_DEBUG({ | |
| dbgs() << "Search Reference: Line = " << Reference->getLineNumber() | |
| << "\n"; | |
| }); | |
| if (!Reference->findIn(Targets)) | |
| Reference->markBranchAsMissing(); | |
| } | |
| } | |
| LVLine *LVLine::findIn(const LVLines *Targets) const { | |
| if (!Targets) | |
| return nullptr; | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[LVLine::findIn]\n" | |
| << "Reference: " | |
| << "Level = " << getLevel() << ", " | |
| << "Kind = " << formattedKind(kind()) << ", " | |
| << "Line = " << getLineNumber() << "\n"; | |
| for (const LVLine *Target : *Targets) | |
| dbgs() << "Target : " | |
| << "Level = " << Target->getLevel() << ", " | |
| << "Kind = " << formattedKind(Target->kind()) << ", " | |
| << "Line = " << Target->getLineNumber() << "\n"; | |
| }); | |
| for (LVLine *Line : *Targets) | |
| if (equals(Line)) | |
| return Line; | |
| return nullptr; | |
| } | |
| bool LVLine::equals(const LVLine *Line) const { | |
| return LVElement::equals(Line); | |
| } | |
| bool LVLine::equals(const LVLines *References, const LVLines *Targets) { | |
| if (!References && !Targets) | |
| return true; | |
| if (References && Targets && References->size() == Targets->size()) { | |
| for (const LVLine *Reference : *References) | |
| if (!Reference->findIn(Targets)) | |
| return false; | |
| return true; | |
| } | |
| return false; | |
| } | |
| void LVLine::report(LVComparePass Pass) { | |
| getComparator().printItem(this, Pass); | |
| } | |
| void LVLine::print(raw_ostream &OS, bool Full) const { | |
| if (getReader().doPrintLine(this)) { | |
| getReaderCompileUnit()->incrementPrintedLines(); | |
| LVElement::print(OS, Full); | |
| printExtra(OS, Full); | |
| } | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // DWARF line record. | |
| //===----------------------------------------------------------------------===// | |
| std::string LVLineDebug::statesInfo(bool Formatted) const { | |
| // Returns the DWARF extra qualifiers. | |
| std::string String; | |
| raw_string_ostream Stream(String); | |
| std::string Separator = Formatted ? " " : ""; | |
| if (getIsNewStatement()) { | |
| Stream << Separator << "{" << KindNewStatement << "}"; | |
| Separator = " "; | |
| } | |
| if (getIsDiscriminator()) { | |
| Stream << Separator << "{" << KindDiscriminator << "}"; | |
| Separator = " "; | |
| } | |
| if (getIsBasicBlock()) { | |
| Stream << Separator << "{" << KindBasicBlock << "}"; | |
| Separator = " "; | |
| } | |
| if (getIsEndSequence()) { | |
| Stream << Separator << "{" << KindEndSequence << "}"; | |
| Separator = " "; | |
| } | |
| if (getIsEpilogueBegin()) { | |
| Stream << Separator << "{" << KindEpilogueBegin << "}"; | |
| Separator = " "; | |
| } | |
| if (getIsPrologueEnd()) { | |
| Stream << Separator << "{" << KindPrologueEnd << "}"; | |
| Separator = " "; | |
| } | |
| if (getIsAlwaysStepInto()) { | |
| Stream << Separator << "{" << KindAlwaysStepInto << "}"; | |
| Separator = " "; | |
| } | |
| if (getIsNeverStepInto()) { | |
| Stream << Separator << "{" << KindNeverStepInto << "}"; | |
| Separator = " "; | |
| } | |
| return String; | |
| } | |
| bool LVLineDebug::equals(const LVLine *Line) const { | |
| if (!LVLine::equals(Line)) | |
| return false; | |
| return getFilenameIndex() == Line->getFilenameIndex(); | |
| } | |
| void LVLineDebug::printExtra(raw_ostream &OS, bool Full) const { | |
| OS << formattedKind(kind()); | |
| if (options().getAttributeQualifier()) { | |
| // The qualifier includes the states information and the source filename | |
| // that contains the line element. | |
| OS << statesInfo(/*Formatted=*/true); | |
| OS << " " << formattedName(getPathname()); | |
| } | |
| OS << "\n"; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Assembler line extracted from the ELF .text section. | |
| //===----------------------------------------------------------------------===// | |
| bool LVLineAssembler::equals(const LVLine *Line) const { | |
| return LVLine::equals(Line); | |
| } | |
| void LVLineAssembler::printExtra(raw_ostream &OS, bool Full) const { | |
| OS << formattedKind(kind()); | |
| OS << " " << formattedName(getName()); | |
| OS << "\n"; | |
| } |