-
Notifications
You must be signed in to change notification settings - Fork 0
/
DwarfTag.hpp
171 lines (169 loc) · 6.03 KB
/
DwarfTag.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#pragma once
#include <llvm/BinaryFormat/Dwarf.h>
#include <llvm/DebugInfo/DWARF/DWARFDataExtractor.h>
#include <llvm/DebugInfo/DWARF/DWARFDie.h>
#include <llvm/DebugInfo/DWARF/DWARFExpression.h>
#include <llvm/DebugInfo/DWARF/DWARFUnit.h>
// use uint64_t for size_t to analyze 64-bit elf on 32-bit machine
inline uint64_t GetDW_AT_byte_size(llvm::DWARFDie die) {
return die.find(llvm::dwarf::DW_AT_byte_size)
.value()
.getAsUnsignedConstant()
.value();
}
inline const char *GetDW_AT_name(llvm::DWARFDie die) {
return die.find(llvm::dwarf::DW_AT_name)->getAsCString().get();
}
inline llvm::DWARFDie GetDW_AT_type(llvm::DWARFDie die) {
return die.getAttributeValueAsReferencedDie(llvm::dwarf::DW_AT_type);
}
// resolve DW_TAG_typedef to base type/array type/structure type
inline llvm::DWARFDie ResolveTypedef(llvm::DWARFDie type) {
while (type.getTag() == llvm::dwarf::DW_TAG_typedef) {
type = GetDW_AT_type(type);
}
return type;
}
struct DwarfTagArrayType { // DW_TAG_array_type
llvm::DWARFDie die;
DwarfTagArrayType(llvm::DWARFDie die) : die{die} {
assert(die.getTag() == llvm::dwarf::DW_TAG_array_type);
}
// DWARF5 standard says array_type must have DW_AT_name. but dump doesn't show
// DW_AT_name
llvm::DWARFDie ElementType() const { // array must have type
return GetDW_AT_type(die);
}
uint64_t Length() const {
for (auto child = die.getFirstChild(); child; child = child.getSibling()) {
switch (child.getTag()) { // the length is in subrange or enumeration
case llvm::dwarf::DW_TAG_subrange_type: { // gcc uses this
auto value = child.find(llvm::dwarf::DW_AT_upper_bound).value();
return value.getAsUnsignedConstant().value() + 1;
} break;
case llvm::dwarf::DW_TAG_enumeration_type:
// TODO
break;
default:
break;
}
}
assert(0);
}
};
struct DwarfTagMember { // DW_TAG_member
llvm::DWARFDie die;
DwarfTagMember(llvm::DWARFDie die) : die{die} {
assert(die.getTag() == llvm::dwarf::DW_TAG_member);
}
const char *Name() const { // member must have name, unless anonymous union
return GetDW_AT_name(die);
}
llvm::DWARFDie Type() const { // member must have type
return GetDW_AT_type(die);
}
uint64_t MemberOffset()
const { // output of offsetof()
// TODO bitfield has no data_member_location
// member that has offset=0 may have no data_member_location
// 如果是DW_AT_data_member_location [DW_FORM_block1]
// (DW_OP_plus_uconst
// 0x0),用getAsUnsignedConstant或getRawUValue读到的都是2不对,应该是0
// 看DWARFDie.cpp的dumpLocationExpr
// 是{23, 00},其中23表示DW_OP_plus_uconst,DW_OP_plus_uconst 00表示offset=0
auto form = die.find(llvm::dwarf::DW_AT_data_member_location).value();
// DW_AT_data_member_location may be a integer constant
auto us = form.getAsUnsignedConstant();
if (us)
return us.value();
// DW_AT_data_member_location may be a location description
// auto expectLoc = die.getLocations(llvm::dwarf::DW_AT_data_location);
// auto loc = expectLoc.get();
// for (auto &le : loc) {
// }
// exit(0);
auto blk = form.getAsBlock();
if (blk) {
auto b = blk.value();
// if (b[0] == llvm::dwarf::DW_OP_plus_uconst) {
// return b[1]; // 还是不对,可能是不止一个字节,应该要用LEB128来读
// }
// 用form.extractValue读的返回值不对
auto u = die.getDwarfUnit();
// auto de1 = u->getDebugInfoExtractor();
llvm::DWARFDataExtractor de2{b, u->isLittleEndian(),
u->getAddressByteSize()};
llvm::DWARFExpression exp{de2, u->getAddressByteSize(), u->getFormat()};
auto it = exp.begin();
// DWARFUnit::updateVariableDieMap
if (it->getCode() == llvm::dwarf::DW_OP_plus_uconst) {
++it;
auto offset = it->getRawOperand(0);
return offset;
}
// exp.print(llvm::outs(), {}, u);
// exit(0);
// uint64_t offset = 0;
// bool ok = form.extractValue(de1, &offset, u->getFormParams(), u);
// assert(ok && "cannot extract block value");
// return form.getRawUValue();
}
assert(0 && "Unknown offset");
}
};
struct DwarfTagStructureType {
llvm::DWARFDie die;
// use `for(auto child = getChild(); child; child = child.getSibling())` to
// iterate members
DwarfTagStructureType(llvm::DWARFDie die) : die{die} {
assert(die.getTag() == llvm::dwarf::DW_TAG_structure_type);
}
uint64_t ByteSize() const { return GetDW_AT_byte_size(die); }
const char *TagName() const {
auto value = die.find(llvm::dwarf::DW_AT_name);
if (value) {
return value->getAsCString().get();
}
return "(anonymous)";
}
};
struct DwarfTagTypedef {
llvm::DWARFDie die;
DwarfTagTypedef(llvm::DWARFDie die) : die{die} {
assert(die.getTag() == llvm::dwarf::DW_TAG_typedef);
}
llvm::DWARFDie Type() { return GetDW_AT_type(die); }
llvm::DWARFDie ResolvedType() {
llvm::DWARFDie d = GetDW_AT_type(die);
while (d.getTag() == llvm::dwarf::DW_TAG_typedef) {
d = GetDW_AT_type(d);
}
return d;
}
const char *Name() const { return GetDW_AT_name(die); }
};
struct DwarfTagBaseType {
llvm::DWARFDie die;
DwarfTagBaseType(llvm::DWARFDie die) : die{die} {
assert(die.getTag() == llvm::dwarf::DW_TAG_base_type);
}
const char *Name() const { return GetDW_AT_name(die); }
uint64_t ByteSize() const { return GetDW_AT_byte_size(die); }
// DW_AT_encoding: DW_ATE_float, DW_ATE_signed, DW_ATE_unsigned, etc
};
struct DwarfTagEnumerationType {
llvm::DWARFDie die;
DwarfTagEnumerationType(llvm::DWARFDie die) : die{die} {
assert(die.getTag() == llvm::dwarf::DW_TAG_enumeration_type);
}
const char *TagName() const {
auto value = die.find(llvm::dwarf::DW_AT_name);
if (value) {
return value->getAsCString().get();
}
return "(anonymous)";
}
// may be invalid
llvm::DWARFDie UnderlyingType() const { return GetDW_AT_type(die); }
uint64_t ByteSize() const { return GetDW_AT_byte_size(die); }
};