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