Path: blob/main/crates/cranelift/src/debug/transform/range_info_builder.rs
3068 views
use super::address_transform::AddressTransform;1use crate::debug::Reader;2use gimli::{AttributeValue, RangeListsOffset, UnitRef, write};3use wasmtime_environ::DefinedFuncIndex;4use wasmtime_environ::error::Error;56pub(crate) enum RangeInfoBuilder {7Undefined,8Position(u64),9Ranges(Vec<(u64, u64)>),10Function(DefinedFuncIndex),11}1213impl RangeInfoBuilder {14pub(crate) fn from(entry: &write::ConvertUnitEntry<Reader<'_>>) -> Result<Self, Error> {15if let Some(AttributeValue::RangeListsRef(r)) = entry.attr_value(gimli::DW_AT_ranges) {16let r = entry.read_unit.ranges_offset_from_raw(r);17return RangeInfoBuilder::from_ranges_ref(entry.read_unit, r);18};1920let low_pc = if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)21{22addr23} else if let Some(AttributeValue::DebugAddrIndex(i)) =24entry.attr_value(gimli::DW_AT_low_pc)25{26entry.read_unit.address(i)?27} else {28return Ok(RangeInfoBuilder::Undefined);29};3031Ok(32if let Some(AttributeValue::Udata(u)) = entry.attr_value(gimli::DW_AT_high_pc) {33RangeInfoBuilder::Ranges(vec![(low_pc, low_pc + u)])34} else {35RangeInfoBuilder::Position(low_pc)36},37)38}3940pub(crate) fn from_ranges_ref(41unit: UnitRef<'_, Reader<'_>>,42ranges: RangeListsOffset,43) -> Result<Self, Error> {44let mut ranges = unit.ranges(ranges)?;45let mut result = Vec::new();46while let Some(range) = ranges.next()? {47if range.begin >= range.end {48// ignore empty ranges49}50result.push((range.begin, range.end));51}5253Ok(if result.is_empty() {54RangeInfoBuilder::Undefined55} else {56RangeInfoBuilder::Ranges(result)57})58}5960pub(crate) fn from_subprogram_die(61entry: &write::ConvertUnitEntry<Reader<'_>>,62addr_tr: &AddressTransform,63) -> Result<Self, Error> {64let unit = entry.read_unit;65let addr = if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc) {66addr67} else if let Some(AttributeValue::DebugAddrIndex(i)) =68entry.attr_value(gimli::DW_AT_low_pc)69{70unit.address(i)?71} else if let Some(AttributeValue::RangeListsRef(r)) = entry.attr_value(gimli::DW_AT_ranges)72{73let r = unit.ranges_offset_from_raw(r);74let mut ranges = unit.ranges(r)?;75if let Some(range) = ranges.next()? {76range.begin77} else {78return Ok(RangeInfoBuilder::Undefined);79}80} else {81return Ok(RangeInfoBuilder::Undefined);82};8384let index = addr_tr.find_func_index(addr);85if index.is_none() {86return Ok(RangeInfoBuilder::Undefined);87}88Ok(RangeInfoBuilder::Function(index.unwrap()))89}9091pub(crate) fn build(92&self,93addr_tr: &AddressTransform,94out_unit: &mut write::Unit,95current_scope_id: write::UnitEntryId,96) {97match self {98RangeInfoBuilder::Undefined => (),99RangeInfoBuilder::Position(pc) => {100let addr = addr_tr101.translate(*pc)102.unwrap_or(write::Address::Constant(0));103let current_scope = out_unit.get_mut(current_scope_id);104current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));105}106RangeInfoBuilder::Ranges(ranges) => {107let mut result = Vec::new();108for (begin, end) in ranges {109result.extend(addr_tr.translate_ranges(*begin, *end));110}111112// If we're seeing the ranges for a `DW_TAG_compile_unit` DIE113// then don't use `DW_AT_low_pc` and `DW_AT_high_pc`. These114// attributes, if set, will configure the base address of all115// location lists that this unit refers to. Currently this116// debug transform does not take this base address into account117// when generate the `.debug_loc` section. Consequently when a118// compile unit is configured here the `DW_AT_ranges` attribute119// is unconditionally used instead of120// `DW_AT_low_pc`/`DW_AT_high_pc`.121let is_attr_for_compile_unit =122out_unit.get(current_scope_id).tag() == gimli::DW_TAG_compile_unit;123124if result.len() != 1 || is_attr_for_compile_unit {125let range_list = result126.iter()127.map(|tr| write::Range::StartLength {128begin: tr.0,129length: tr.1,130})131.collect::<Vec<_>>();132let range_list_id = out_unit.ranges.add(write::RangeList(range_list));133let current_scope = out_unit.get_mut(current_scope_id);134current_scope.set(135gimli::DW_AT_ranges,136write::AttributeValue::RangeListRef(range_list_id),137);138} else {139let current_scope = out_unit.get_mut(current_scope_id);140current_scope.set(141gimli::DW_AT_low_pc,142write::AttributeValue::Address(result[0].0),143);144current_scope.set(145gimli::DW_AT_high_pc,146write::AttributeValue::Udata(result[0].1),147);148}149}150RangeInfoBuilder::Function(index) => {151let symbol = addr_tr.map()[*index].symbol;152let range = addr_tr.func_range(*index);153let addr = write::Address::Symbol {154symbol,155addend: range.0 as i64,156};157let len = (range.1 - range.0) as u64;158let current_scope = out_unit.get_mut(current_scope_id);159current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));160current_scope.set(gimli::DW_AT_high_pc, write::AttributeValue::Udata(len));161}162}163}164165pub(crate) fn get_ranges(&self, addr_tr: &AddressTransform) -> Vec<(u64, u64)> {166match self {167RangeInfoBuilder::Undefined | RangeInfoBuilder::Position(_) => vec![],168RangeInfoBuilder::Ranges(ranges) => ranges.clone(),169RangeInfoBuilder::Function(index) => {170let range = addr_tr.func_source_range(*index);171vec![(range.0, range.1)]172}173}174}175176pub(crate) fn build_ranges(177&self,178addr_tr: &AddressTransform,179out_range_lists: &mut write::RangeListTable,180) -> write::RangeListId {181if let RangeInfoBuilder::Ranges(ranges) = self {182let mut range_list = Vec::new();183for (begin, end) in ranges {184assert!(begin < end);185range_list.extend(addr_tr.translate_ranges(*begin, *end).map(|tr| {186write::Range::StartLength {187begin: tr.0,188length: tr.1,189}190}));191}192out_range_lists.add(write::RangeList(range_list))193} else {194unreachable!();195}196}197}198199200