|  | //===-- 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"; | 
|  | } |