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(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(this, Pass);
138}
139
140void 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//===----------------------------------------------------------------------===//
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());
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//===----------------------------------------------------------------------===//
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());
220  OS << " " << formattedName(getName());
221  OS << "\n";
222}
223