1 //===-- LVLine.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 // This implements the LVLine class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
14 #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
15 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
16 
17 using namespace llvm;
18 using namespace llvm::logicalview;
19 
20 #define DEBUG_TYPE "Line"
21 
22 namespace {
23 const char *const KindBasicBlock = "BasicBlock";
24 const char *const KindDiscriminator = "Discriminator";
25 const char *const KindEndSequence = "EndSequence";
26 const char *const KindEpilogueBegin = "EpilogueBegin";
27 const char *const KindLineDebug = "Line";
28 const char *const KindLineSource = "Code";
29 const char *const KindNewStatement = "NewStatement";
30 const char *const KindPrologueEnd = "PrologueEnd";
31 const char *const KindUndefined = "Undefined";
32 const char *const KindAlwaysStepInto = "AlwaysStepInto"; // CodeView
33 const char *const KindNeverStepInto = "NeverStepInto";   // CodeView
34 } // end anonymous namespace
35 
36 //===----------------------------------------------------------------------===//
37 // Logical line.
38 //===----------------------------------------------------------------------===//
39 // Return a string representation for the line kind.
kind() const40 const char *LVLine::kind() const {
41   const char *Kind = KindUndefined;
42   if (getIsLineDebug())
43     Kind = KindLineDebug;
44   else if (getIsLineAssembler())
45     Kind = KindLineSource;
46   return Kind;
47 }
48 
49 LVLineDispatch LVLine::Dispatch = {
50     {LVLineKind::IsBasicBlock, &LVLine::getIsBasicBlock},
51     {LVLineKind::IsDiscriminator, &LVLine::getIsDiscriminator},
52     {LVLineKind::IsEndSequence, &LVLine::getIsEndSequence},
53     {LVLineKind::IsLineDebug, &LVLine::getIsLineDebug},
54     {LVLineKind::IsLineAssembler, &LVLine::getIsLineAssembler},
55     {LVLineKind::IsNewStatement, &LVLine::getIsNewStatement},
56     {LVLineKind::IsEpilogueBegin, &LVLine::getIsEpilogueBegin},
57     {LVLineKind::IsPrologueEnd, &LVLine::getIsPrologueEnd},
58     {LVLineKind::IsAlwaysStepInto, &LVLine::getIsAlwaysStepInto},
59     {LVLineKind::IsNeverStepInto, &LVLine::getIsNeverStepInto}};
60 
61 // String used as padding for printing elements with no line number.
noLineAsString(bool ShowZero) const62 std::string LVLine::noLineAsString(bool ShowZero) const {
63   if (options().getInternalNone())
64     return LVObject::noLineAsString(ShowZero);
65   return (ShowZero || options().getAttributeZero()) ? ("    0   ")
66                                                     : ("    -   ");
67 }
68 
markMissingParents(const LVLines * References,const LVLines * Targets)69 void LVLine::markMissingParents(const LVLines *References,
70                                 const LVLines *Targets) {
71   if (!(References && Targets))
72     return;
73 
74   LLVM_DEBUG({
75     dbgs() << "\n[LVLine::markMissingParents]\n";
76     for (const LVLine *Reference : *References)
77       dbgs() << "References: "
78              << "Kind = " << formattedKind(Reference->kind()) << ", "
79              << "Line = " << Reference->getLineNumber() << "\n";
80     for (const LVLine *Target : *Targets)
81       dbgs() << "Targets   : "
82              << "Kind = " << formattedKind(Target->kind()) << ", "
83              << "Line = " << Target->getLineNumber() << "\n";
84   });
85 
86   for (LVLine *Reference : *References) {
87     LLVM_DEBUG({
88       dbgs() << "Search Reference: Line = " << Reference->getLineNumber()
89              << "\n";
90     });
91     if (!Reference->findIn(Targets))
92       Reference->markBranchAsMissing();
93   }
94 }
95 
findIn(const LVLines * Targets) const96 LVLine *LVLine::findIn(const LVLines *Targets) const {
97   if (!Targets)
98     return nullptr;
99 
100   LLVM_DEBUG({
101     dbgs() << "\n[LVLine::findIn]\n"
102            << "Reference: "
103            << "Level = " << getLevel() << ", "
104            << "Kind = " << formattedKind(kind()) << ", "
105            << "Line = " << getLineNumber() << "\n";
106     for (const LVLine *Target : *Targets)
107       dbgs() << "Target   : "
108              << "Level = " << Target->getLevel() << ", "
109              << "Kind = " << formattedKind(Target->kind()) << ", "
110              << "Line = " << Target->getLineNumber() << "\n";
111   });
112 
113   for (LVLine *Line : *Targets)
114     if (equals(Line))
115       return Line;
116 
117   return nullptr;
118 }
119 
equals(const LVLine * Line) const120 bool LVLine::equals(const LVLine *Line) const {
121   return LVElement::equals(Line);
122 }
123 
equals(const LVLines * References,const LVLines * Targets)124 bool LVLine::equals(const LVLines *References, const LVLines *Targets) {
125   if (!References && !Targets)
126     return true;
127   if (References && Targets && References->size() == Targets->size()) {
128     for (const LVLine *Reference : *References)
129       if (!Reference->findIn(Targets))
130         return false;
131     return true;
132   }
133   return false;
134 }
135 
report(LVComparePass Pass)136 void LVLine::report(LVComparePass Pass) {
137   getComparator().printItem(this, Pass);
138 }
139 
print(raw_ostream & OS,bool Full) const140 void LVLine::print(raw_ostream &OS, bool Full) const {
141   if (getReader().doPrintLine(this)) {
142     getReaderCompileUnit()->incrementPrintedLines();
143     LVElement::print(OS, Full);
144     printExtra(OS, Full);
145   }
146 }
147 
148 //===----------------------------------------------------------------------===//
149 // DWARF line record.
150 //===----------------------------------------------------------------------===//
statesInfo(bool Formatted) const151 std::string LVLineDebug::statesInfo(bool Formatted) const {
152   // Returns the DWARF extra qualifiers.
153   std::string String;
154   raw_string_ostream Stream(String);
155 
156   std::string Separator = Formatted ? " " : "";
157   if (getIsNewStatement()) {
158     Stream << Separator << "{" << KindNewStatement << "}";
159     Separator = " ";
160   }
161   if (getIsDiscriminator()) {
162     Stream << Separator << "{" << KindDiscriminator << "}";
163     Separator = " ";
164   }
165   if (getIsBasicBlock()) {
166     Stream << Separator << "{" << KindBasicBlock << "}";
167     Separator = " ";
168   }
169   if (getIsEndSequence()) {
170     Stream << Separator << "{" << KindEndSequence << "}";
171     Separator = " ";
172   }
173   if (getIsEpilogueBegin()) {
174     Stream << Separator << "{" << KindEpilogueBegin << "}";
175     Separator = " ";
176   }
177   if (getIsPrologueEnd()) {
178     Stream << Separator << "{" << KindPrologueEnd << "}";
179     Separator = " ";
180   }
181   if (getIsAlwaysStepInto()) {
182     Stream << Separator << "{" << KindAlwaysStepInto << "}";
183     Separator = " ";
184   }
185   if (getIsNeverStepInto()) {
186     Stream << Separator << "{" << KindNeverStepInto << "}";
187     Separator = " ";
188   }
189 
190   return String;
191 }
192 
equals(const LVLine * Line) const193 bool LVLineDebug::equals(const LVLine *Line) const {
194   if (!LVLine::equals(Line))
195     return false;
196   return getFilenameIndex() == Line->getFilenameIndex();
197 }
198 
printExtra(raw_ostream & OS,bool Full) const199 void LVLineDebug::printExtra(raw_ostream &OS, bool Full) const {
200   OS << formattedKind(kind());
201 
202   if (options().getAttributeQualifier()) {
203     // The qualifier includes the states information and the source filename
204     // that contains the line element.
205     OS << statesInfo(/*Formatted=*/true);
206     OS << " " << formattedName(getPathname());
207   }
208   OS << "\n";
209 }
210 
211 //===----------------------------------------------------------------------===//
212 // Assembler line extracted from the ELF .text section.
213 //===----------------------------------------------------------------------===//
equals(const LVLine * Line) const214 bool LVLineAssembler::equals(const LVLine *Line) const {
215   return LVLine::equals(Line);
216 }
217 
printExtra(raw_ostream & OS,bool Full) const218 void LVLineAssembler::printExtra(raw_ostream &OS, bool Full) const {
219   OS << formattedKind(kind());
220   OS << " " << formattedName(getName());
221   OS << "\n";
222 }
223