Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/cranelift/src/debug/transform/range_info_builder.rs
1693 views
1
use super::Reader;
2
use super::address_transform::AddressTransform;
3
use anyhow::Error;
4
use gimli::{AttributeValue, DebuggingInformationEntry, RangeListsOffset, Unit, write};
5
use wasmtime_environ::DefinedFuncIndex;
6
7
pub(crate) enum RangeInfoBuilder {
8
Undefined,
9
Position(u64),
10
Ranges(Vec<(u64, u64)>),
11
Function(DefinedFuncIndex),
12
}
13
14
impl RangeInfoBuilder {
15
pub(crate) fn from<R>(
16
dwarf: &gimli::Dwarf<R>,
17
unit: &Unit<R, R::Offset>,
18
entry: &DebuggingInformationEntry<R>,
19
) -> Result<Self, Error>
20
where
21
R: Reader,
22
{
23
if let Some(AttributeValue::RangeListsRef(r)) = entry.attr_value(gimli::DW_AT_ranges)? {
24
let r = dwarf.ranges_offset_from_raw(unit, r);
25
return RangeInfoBuilder::from_ranges_ref(dwarf, unit, r);
26
};
27
28
let low_pc =
29
if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)? {
30
addr
31
} else if let Some(AttributeValue::DebugAddrIndex(i)) =
32
entry.attr_value(gimli::DW_AT_low_pc)?
33
{
34
dwarf.address(unit, i)?
35
} else {
36
return Ok(RangeInfoBuilder::Undefined);
37
};
38
39
Ok(
40
if let Some(AttributeValue::Udata(u)) = entry.attr_value(gimli::DW_AT_high_pc)? {
41
RangeInfoBuilder::Ranges(vec![(low_pc, low_pc + u)])
42
} else {
43
RangeInfoBuilder::Position(low_pc)
44
},
45
)
46
}
47
48
pub(crate) fn from_ranges_ref<R>(
49
dwarf: &gimli::Dwarf<R>,
50
unit: &Unit<R, R::Offset>,
51
ranges: RangeListsOffset,
52
) -> Result<Self, Error>
53
where
54
R: Reader,
55
{
56
let mut ranges = dwarf.ranges(unit, ranges)?;
57
let mut result = Vec::new();
58
while let Some(range) = ranges.next()? {
59
if range.begin >= range.end {
60
// ignore empty ranges
61
}
62
result.push((range.begin, range.end));
63
}
64
65
Ok(if result.is_empty() {
66
RangeInfoBuilder::Undefined
67
} else {
68
RangeInfoBuilder::Ranges(result)
69
})
70
}
71
72
pub(crate) fn from_subprogram_die<R>(
73
dwarf: &gimli::Dwarf<R>,
74
unit: &Unit<R, R::Offset>,
75
entry: &DebuggingInformationEntry<R>,
76
addr_tr: &AddressTransform,
77
) -> Result<Self, Error>
78
where
79
R: Reader,
80
{
81
let addr =
82
if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)? {
83
addr
84
} else if let Some(AttributeValue::DebugAddrIndex(i)) =
85
entry.attr_value(gimli::DW_AT_low_pc)?
86
{
87
dwarf.address(unit, i)?
88
} else if let Some(AttributeValue::RangeListsRef(r)) =
89
entry.attr_value(gimli::DW_AT_ranges)?
90
{
91
let r = dwarf.ranges_offset_from_raw(unit, r);
92
let mut ranges = dwarf.ranges(unit, r)?;
93
if let Some(range) = ranges.next()? {
94
range.begin
95
} else {
96
return Ok(RangeInfoBuilder::Undefined);
97
}
98
} else {
99
return Ok(RangeInfoBuilder::Undefined);
100
};
101
102
let index = addr_tr.find_func_index(addr);
103
if index.is_none() {
104
return Ok(RangeInfoBuilder::Undefined);
105
}
106
Ok(RangeInfoBuilder::Function(index.unwrap()))
107
}
108
109
pub(crate) fn build(
110
&self,
111
addr_tr: &AddressTransform,
112
out_unit: &mut write::Unit,
113
current_scope_id: write::UnitEntryId,
114
) {
115
match self {
116
RangeInfoBuilder::Undefined => (),
117
RangeInfoBuilder::Position(pc) => {
118
let addr = addr_tr
119
.translate(*pc)
120
.unwrap_or(write::Address::Constant(0));
121
let current_scope = out_unit.get_mut(current_scope_id);
122
current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));
123
}
124
RangeInfoBuilder::Ranges(ranges) => {
125
let mut result = Vec::new();
126
for (begin, end) in ranges {
127
result.extend(addr_tr.translate_ranges(*begin, *end));
128
}
129
130
// If we're seeing the ranges for a `DW_TAG_compile_unit` DIE
131
// then don't use `DW_AT_low_pc` and `DW_AT_high_pc`. These
132
// attributes, if set, will configure the base address of all
133
// location lists that this unit refers to. Currently this
134
// debug transform does not take this base address into account
135
// when generate the `.debug_loc` section. Consequently when a
136
// compile unit is configured here the `DW_AT_ranges` attribute
137
// is unconditionally used instead of
138
// `DW_AT_low_pc`/`DW_AT_high_pc`.
139
let is_attr_for_compile_unit =
140
out_unit.get(current_scope_id).tag() == gimli::DW_TAG_compile_unit;
141
142
if result.len() != 1 || is_attr_for_compile_unit {
143
let range_list = result
144
.iter()
145
.map(|tr| write::Range::StartLength {
146
begin: tr.0,
147
length: tr.1,
148
})
149
.collect::<Vec<_>>();
150
let range_list_id = out_unit.ranges.add(write::RangeList(range_list));
151
let current_scope = out_unit.get_mut(current_scope_id);
152
current_scope.set(
153
gimli::DW_AT_ranges,
154
write::AttributeValue::RangeListRef(range_list_id),
155
);
156
} else {
157
let current_scope = out_unit.get_mut(current_scope_id);
158
current_scope.set(
159
gimli::DW_AT_low_pc,
160
write::AttributeValue::Address(result[0].0),
161
);
162
current_scope.set(
163
gimli::DW_AT_high_pc,
164
write::AttributeValue::Udata(result[0].1),
165
);
166
}
167
}
168
RangeInfoBuilder::Function(index) => {
169
let symbol = addr_tr.map()[*index].symbol;
170
let range = addr_tr.func_range(*index);
171
let addr = write::Address::Symbol {
172
symbol,
173
addend: range.0 as i64,
174
};
175
let len = (range.1 - range.0) as u64;
176
let current_scope = out_unit.get_mut(current_scope_id);
177
current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));
178
current_scope.set(gimli::DW_AT_high_pc, write::AttributeValue::Udata(len));
179
}
180
}
181
}
182
183
pub(crate) fn get_ranges(&self, addr_tr: &AddressTransform) -> Vec<(u64, u64)> {
184
match self {
185
RangeInfoBuilder::Undefined | RangeInfoBuilder::Position(_) => vec![],
186
RangeInfoBuilder::Ranges(ranges) => ranges.clone(),
187
RangeInfoBuilder::Function(index) => {
188
let range = addr_tr.func_source_range(*index);
189
vec![(range.0, range.1)]
190
}
191
}
192
}
193
194
pub(crate) fn build_ranges(
195
&self,
196
addr_tr: &AddressTransform,
197
out_range_lists: &mut write::RangeListTable,
198
) -> write::RangeListId {
199
if let RangeInfoBuilder::Ranges(ranges) = self {
200
let mut range_list = Vec::new();
201
for (begin, end) in ranges {
202
assert!(begin < end);
203
range_list.extend(addr_tr.translate_ranges(*begin, *end).map(|tr| {
204
write::Range::StartLength {
205
begin: tr.0,
206
length: tr.1,
207
}
208
}));
209
}
210
out_range_lists.add(write::RangeList(range_list))
211
} else {
212
unreachable!();
213
}
214
}
215
}
216
217