Skip to content

Commit 3c397c9

Browse files
[llvm-debuginfo-analyzer] (04/09) - Locations and ranges
llvm-debuginfo-analyzer is a command line tool that processes debug info contained in a binary file and produces a debug information format agnostic “Logical View”, which is a high-level semantic representation of the debug info, independent of the low-level format. The code has been divided into the following patches: 1) Interval tree 2) Driver and documentation 3) Logical elements 4) Locations and ranges 5) Select elements 6) Warning and internal options 7) Compare elements 8) ELF Reader 9) CodeView Reader Full details: https://discourse.llvm.org/t/llvm-dev-rfc-llvm-dva-debug-information-visual-analyzer/62570 This patch: Locations and ranges - All functionality for logical debug locations and ranges: LVLocation, LVRanges. Reviewed By: psamolysov, probinson Differential Revision: https://reviews.llvm.org/D125779
1 parent 3f59734 commit 3c397c9

File tree

17 files changed

+2159
-7
lines changed

17 files changed

+2159
-7
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
//===-- LVLocation.h --------------------------------------------*- C++ -*-===//
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 file defines the LVOperation and LVLocation classes, which are used
10+
// to describe variable locations.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVLOCATION_H
15+
#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVLOCATION_H
16+
17+
#include "llvm/DebugInfo/LogicalView/Core/LVObject.h"
18+
19+
namespace llvm {
20+
namespace logicalview {
21+
22+
// The DW_AT_data_member_location attribute is a simple member offset.
23+
const LVSmall LVLocationMemberOffset = 0;
24+
25+
class LVOperation final {
26+
// To describe an operation:
27+
// OpCode
28+
// Operands[0]: First operand.
29+
// Operands[1]: Second operand.
30+
// OP_bregx, OP_bit_piece, OP_[GNU_]const_type,
31+
// OP_[GNU_]deref_type, OP_[GNU_]entry_value, OP_implicit_value,
32+
// OP_[GNU_]implicit_pointer, OP_[GNU_]regval_type, OP_xderef_type.
33+
LVSmall Opcode = 0;
34+
uint64_t Operands[2];
35+
36+
public:
37+
LVOperation() = delete;
38+
LVOperation(LVSmall Opcode, LVUnsigned Operand1, LVUnsigned Operand2)
39+
: Opcode(Opcode) {
40+
Operands[0] = Operand1;
41+
Operands[1] = Operand2;
42+
}
43+
LVOperation(const LVOperation &) = delete;
44+
LVOperation &operator=(const LVOperation &) = delete;
45+
~LVOperation() = default;
46+
47+
LVSmall getOpcode() const { return Opcode; }
48+
uint64_t getOperand1() const { return Operands[0]; }
49+
uint64_t getOperand2() const { return Operands[1]; }
50+
std::string getOperandsDWARFInfo();
51+
std::string getOperandsCodeViewInfo();
52+
53+
void print(raw_ostream &OS, bool Full = true) const;
54+
55+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
56+
void dump() { print(dbgs()); }
57+
#endif
58+
};
59+
60+
class LVLocation : public LVObject {
61+
enum class Property {
62+
IsAddressRange,
63+
IsBaseClassOffset,
64+
IsBaseClassStep,
65+
IsClassOffset,
66+
IsFixedAddress,
67+
IsLocationSimple,
68+
IsGapEntry,
69+
IsOperation,
70+
IsOperationList,
71+
IsRegister,
72+
IsStackOffset,
73+
IsDiscardedRange,
74+
IsInvalidRange,
75+
IsInvalidLower,
76+
IsInvalidUpper,
77+
IsCallSite,
78+
LastEntry
79+
};
80+
// Typed bitvector with properties for this location.
81+
LVProperties<Property> Properties;
82+
83+
// True if the location it is associated with a debug range.
84+
bool hasAssociatedRange() const {
85+
return !getIsClassOffset() && !getIsDiscardedRange();
86+
}
87+
88+
protected:
89+
// Line numbers associated with locations ranges.
90+
LVLine *LowerLine = nullptr;
91+
LVLine *UpperLine = nullptr;
92+
93+
// Active range:
94+
// LowPC: an offset from an applicable base address, not a PC value.
95+
// HighPC: an offset from an applicable base address, or a length.
96+
LVAddress LowPC = 0;
97+
LVAddress HighPC = 0;
98+
99+
void setKind();
100+
101+
public:
102+
LVLocation() : LVObject() { setIsLocation(); }
103+
LVLocation(const LVLocation &) = delete;
104+
LVLocation &operator=(const LVLocation &) = delete;
105+
virtual ~LVLocation() = default;
106+
107+
PROPERTY(Property, IsAddressRange);
108+
PROPERTY(Property, IsBaseClassOffset);
109+
PROPERTY(Property, IsBaseClassStep);
110+
PROPERTY_1(Property, IsClassOffset, IsLocationSimple);
111+
PROPERTY_1(Property, IsFixedAddress, IsLocationSimple);
112+
PROPERTY(Property, IsLocationSimple);
113+
PROPERTY(Property, IsGapEntry);
114+
PROPERTY(Property, IsOperationList);
115+
PROPERTY(Property, IsOperation);
116+
PROPERTY(Property, IsRegister);
117+
PROPERTY_1(Property, IsStackOffset, IsLocationSimple);
118+
PROPERTY(Property, IsDiscardedRange);
119+
PROPERTY(Property, IsInvalidRange);
120+
PROPERTY(Property, IsInvalidLower);
121+
PROPERTY(Property, IsInvalidUpper);
122+
PROPERTY(Property, IsCallSite);
123+
124+
const char *kind() const override;
125+
// Mark the locations that have only DW_OP_fbreg as stack offset based.
126+
virtual void updateKind() {}
127+
128+
// Line numbers for locations.
129+
const LVLine *getLowerLine() const { return LowerLine; }
130+
void setLowerLine(LVLine *Line) { LowerLine = Line; }
131+
const LVLine *getUpperLine() const { return UpperLine; }
132+
void setUpperLine(LVLine *Line) { UpperLine = Line; }
133+
134+
// Addresses for locations.
135+
LVAddress getLowerAddress() const override { return LowPC; }
136+
void setLowerAddress(LVAddress Address) override { LowPC = Address; }
137+
LVAddress getUpperAddress() const override { return HighPC; }
138+
void setUpperAddress(LVAddress Address) override { HighPC = Address; }
139+
140+
std::string getIntervalInfo() const;
141+
142+
bool validateRanges();
143+
144+
// In order to calculate a symbol coverage (percentage), take the ranges
145+
// and obtain the number of units (bytes) covered by those ranges. We can't
146+
// use the line numbers, because they can be zero or invalid.
147+
// We return:
148+
// false: No locations or multiple locations.
149+
// true: a single location.
150+
static bool calculateCoverage(LVLocations *Locations, unsigned &Factor,
151+
float &Percentage);
152+
153+
virtual void addObject(LVAddress LowPC, LVAddress HighPC,
154+
LVUnsigned SectionOffset, uint64_t LocDescOffset) {}
155+
virtual void addObject(LVSmall Opcode, LVUnsigned Operand1,
156+
LVUnsigned Operand2) {}
157+
158+
static void print(LVLocations *Locations, raw_ostream &OS, bool Full = true);
159+
void printInterval(raw_ostream &OS, bool Full = true) const;
160+
void printRaw(raw_ostream &OS, bool Full = true) const;
161+
virtual void printRawExtra(raw_ostream &OS, bool Full = true) const {}
162+
163+
void print(raw_ostream &OS, bool Full = true) const override;
164+
void printExtra(raw_ostream &OS, bool Full = true) const override;
165+
166+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
167+
void dump() const override { print(dbgs()); }
168+
#endif
169+
};
170+
171+
class LVLocationSymbol final : public LVLocation {
172+
// Location descriptors for the active range.
173+
LVAutoOperations *Entries = nullptr;
174+
175+
void updateKind() override;
176+
177+
public:
178+
LVLocationSymbol() : LVLocation() {}
179+
LVLocationSymbol(const LVLocationSymbol &) = delete;
180+
LVLocationSymbol &operator=(const LVLocationSymbol &) = delete;
181+
~LVLocationSymbol() { delete Entries; };
182+
183+
void addObject(LVAddress LowPC, LVAddress HighPC, LVUnsigned SectionOffset,
184+
uint64_t LocDescOffset) override;
185+
void addObject(LVSmall Opcode, LVUnsigned Operand1,
186+
LVUnsigned Operand2) override;
187+
188+
void printRawExtra(raw_ostream &OS, bool Full = true) const override;
189+
void printExtra(raw_ostream &OS, bool Full = true) const override;
190+
};
191+
192+
} // end namespace logicalview
193+
} // end namespace llvm
194+
195+
#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVLOCATION_H

llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ const LVAddress MaxAddress = std::numeric_limits<uint64_t>::max();
102102

103103
enum class LVBinaryType { NONE, ELF, COFF };
104104

105+
// Validate functions.
106+
using LVValidLocation = bool (LVLocation::*)();
107+
105108
// Keep counters of objects.
106109
struct LVCounter {
107110
unsigned Lines = 0;
@@ -258,6 +261,11 @@ class LVObject {
258261
void setParent(LVSymbol *Symbol);
259262
void resetParent() { Parent = {nullptr}; }
260263

264+
virtual LVAddress getLowerAddress() const { return 0; }
265+
virtual void setLowerAddress(LVAddress Address) {}
266+
virtual LVAddress getUpperAddress() const { return 0; }
267+
virtual void setUpperAddress(LVAddress Address) {}
268+
261269
uint32_t getLineNumber() const { return LineNumber; }
262270
void setLineNumber(uint32_t Number) { LineNumber = Number; }
263271

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//===-- LVRange.h -----------------------------------------------*- C++ -*-===//
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 file defines the LVRange class, which is used to describe a debug
10+
// information range.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVRANGE_H
15+
#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVRANGE_H
16+
17+
#include "llvm/ADT/IntervalTree.h"
18+
#include "llvm/DebugInfo/LogicalView/Core/LVObject.h"
19+
20+
namespace llvm {
21+
namespace logicalview {
22+
23+
using LVAddressRange = std::pair<LVAddress, LVAddress>;
24+
25+
class LVRangeEntry final {
26+
LVAddress Lower = 0;
27+
LVAddress Upper = 0;
28+
LVScope *Scope = nullptr;
29+
30+
public:
31+
using RangeType = LVAddress;
32+
33+
LVRangeEntry() = delete;
34+
LVRangeEntry(LVAddress LowerAddress, LVAddress UpperAddress, LVScope *Scope)
35+
: Lower(LowerAddress), Upper(UpperAddress), Scope(Scope) {}
36+
37+
RangeType lower() const { return Lower; }
38+
RangeType upper() const { return Upper; }
39+
LVAddressRange addressRange() const {
40+
return LVAddressRange(lower(), upper());
41+
}
42+
LVScope *scope() const { return Scope; }
43+
};
44+
45+
// Class to represent a list of range addresses associated with a
46+
// scope; the addresses are stored in ascending order and can overlap.
47+
using LVRangeEntries = std::vector<LVRangeEntry>;
48+
49+
class LVRange final : public LVObject {
50+
/// Map of where a user value is live, and its location.
51+
using LVRangesTree = IntervalTree<LVAddress, LVScope *>;
52+
using LVAllocator = LVRangesTree::Allocator;
53+
54+
LVAllocator Allocator;
55+
LVRangesTree RangesTree;
56+
LVRangeEntries RangeEntries;
57+
LVAddress Lower = MaxAddress;
58+
LVAddress Upper = 0;
59+
60+
public:
61+
LVRange() : LVObject(), RangesTree(Allocator) {}
62+
LVRange(const LVRange &) = delete;
63+
LVRange &operator=(const LVRange &) = delete;
64+
~LVRange() = default;
65+
66+
void addEntry(LVScope *Scope, LVAddress LowerAddress, LVAddress UpperAddress);
67+
void addEntry(LVScope *Scope);
68+
LVScope *getEntry(LVAddress Address) const;
69+
LVScope *getEntry(LVAddress LowerAddress, LVAddress UpperAddress) const;
70+
bool hasEntry(LVAddress Low, LVAddress High) const;
71+
LVAddress getLower() const { return Lower; }
72+
LVAddress getUpper() const { return Upper; }
73+
74+
const LVRangeEntries &getEntries() const { return RangeEntries; }
75+
76+
void clear() {
77+
RangeEntries.clear();
78+
Lower = MaxAddress;
79+
Upper = 0;
80+
}
81+
bool empty() const { return RangeEntries.empty(); }
82+
void sort();
83+
84+
void startSearch();
85+
void endSearch() {}
86+
87+
void print(raw_ostream &OS, bool Full = true) const override;
88+
void printExtra(raw_ostream &OS, bool Full = true) const override {}
89+
90+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
91+
void dump() const override { print(dbgs()); }
92+
#endif
93+
};
94+
95+
} // end namespace logicalview
96+
} // end namespace llvm
97+
98+
#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVRANGE_H

llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVREADER_H
1616

1717
#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
18+
#include "llvm/DebugInfo/LogicalView/Core/LVRange.h"
1819
#include "llvm/Support/Error.h"
1920
#include "llvm/Support/ScopedPrinter.h"
2021
#include "llvm/Support/ToolOutputFile.h"
@@ -127,6 +128,11 @@ class LVReader {
127128
Error doPrint();
128129
Error doLoad();
129130

131+
virtual std::string getRegisterName(LVSmall Opcode, uint64_t Operands[2]) {
132+
llvm_unreachable("Invalid instance reader.");
133+
return {};
134+
}
135+
130136
virtual bool isSystemEntry(LVElement *Element, StringRef Name = {}) {
131137
return false;
132138
};
@@ -136,6 +142,7 @@ class LVReader {
136142

137143
// Conditions to print an object.
138144
bool doPrintLine(const LVLine *Line) const { return true; }
145+
bool doPrintLocation(const LVLocation *Location) const { return true; }
139146
bool doPrintScope(const LVScope *Scope) const { return true; }
140147
bool doPrintSymbol(const LVSymbol *Symbol) const { return true; }
141148
bool doPrintType(const LVType *Type) const { return true; }

0 commit comments

Comments
 (0)