wasmtime_cranelift/debug/transform/
range_info_builder.rs

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