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
17using namespace llvm;
18using namespace llvm::logicalview;
19
20#define DEBUG_TYPE "Line"
21
22namespace {
23const char *const KindBasicBlock = "BasicBlock";
24const char *const KindDiscriminator = "Discriminator";
25const char *const KindEndSequence = "EndSequence";
26const char *const KindEpilogueBegin = "EpilogueBegin";
27const char *const KindLineDebug = "Line";
28const char *const KindLineSource = "Code";
29const char *const KindNewStatement = "NewStatement";
30const char *const KindPrologueEnd = "PrologueEnd";
31const char *const KindUndefined = "Undefined";
32const char *const KindAlwaysStepInto = "AlwaysStepInto"; // CodeView
33const char *const KindNeverStepInto = "NeverStepInto"; // CodeView
34} // end anonymous namespace
35
36//===----------------------------------------------------------------------===//
37// Logical line.
38//===----------------------------------------------------------------------===//
39// Return a string representation for the line kind.
40const 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
49LVLineDispatch 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.
62std::string LVLine::noLineAsString(bool ShowZero) const {
63 if (options().getInternalNone())
64 return LVObject::noLineAsString(ShowZero);
65 return (ShowZero || options().getAttributeZero()) ? (" 0 ")
66 : (" - ");
67}
68
69void 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
96LVLine *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
120bool LVLine::equals(const LVLine *Line) const {
121 return LVElement::equals(Element: Line);
122}
123
124bool 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
136void LVLine::report(LVComparePass Pass) {
137 getComparator().printItem(Element: this, Pass);
138}
139
140void LVLine::print(raw_ostream &OS, bool Full) const {
141 if (getReader().doPrintLine(Line: this)) {
142 getReaderCompileUnit()->incrementPrintedLines();
143 LVElement::print(OS, Full);
144 printExtra(OS, Full);
145 }
146}
147
148//===----------------------------------------------------------------------===//
149// DWARF line record.
150//===----------------------------------------------------------------------===//
151std::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
193bool LVLineDebug::equals(const LVLine *Line) const {
194 if (!LVLine::equals(Line))
195 return false;
196 return getFilenameIndex() == Line->getFilenameIndex();
197}
198
199void LVLineDebug::printExtra(raw_ostream &OS, bool Full) const {
200 OS << formattedKind(Kind: 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(Name: getPathname());
207 }
208 OS << "\n";
209}
210
211//===----------------------------------------------------------------------===//
212// Assembler line extracted from the ELF .text section.
213//===----------------------------------------------------------------------===//
214bool LVLineAssembler::equals(const LVLine *Line) const {
215 return LVLine::equals(Line);
216}
217
218void LVLineAssembler::printExtra(raw_ostream &OS, bool Full) const {
219 OS << formattedKind(Kind: kind());
220 OS << " " << formattedName(Name: getName());
221 OS << "\n";
222}
223