Path: blob/main/crates/cranelift/src/debug/transform/range_info_builder.rs
1693 views
use super::Reader;1use super::address_transform::AddressTransform;2use anyhow::Error;3use gimli::{AttributeValue, DebuggingInformationEntry, RangeListsOffset, Unit, write};4use wasmtime_environ::DefinedFuncIndex;56pub(crate) enum RangeInfoBuilder {7Undefined,8Position(u64),9Ranges(Vec<(u64, u64)>),10Function(DefinedFuncIndex),11}1213impl RangeInfoBuilder {14pub(crate) fn from<R>(15dwarf: &gimli::Dwarf<R>,16unit: &Unit<R, R::Offset>,17entry: &DebuggingInformationEntry<R>,18) -> Result<Self, Error>19where20R: Reader,21{22if let Some(AttributeValue::RangeListsRef(r)) = entry.attr_value(gimli::DW_AT_ranges)? {23let r = dwarf.ranges_offset_from_raw(unit, r);24return RangeInfoBuilder::from_ranges_ref(dwarf, unit, r);25};2627let low_pc =28if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)? {29addr30} else if let Some(AttributeValue::DebugAddrIndex(i)) =31entry.attr_value(gimli::DW_AT_low_pc)?32{33dwarf.address(unit, i)?34} else {35return Ok(RangeInfoBuilder::Undefined);36};3738Ok(39if let Some(AttributeValue::Udata(u)) = entry.attr_value(gimli::DW_AT_high_pc)? {40RangeInfoBuilder::Ranges(vec![(low_pc, low_pc + u)])41} else {42RangeInfoBuilder::Position(low_pc)43},44)45}4647pub(crate) fn from_ranges_ref<R>(48dwarf: &gimli::Dwarf<R>,49unit: &Unit<R, R::Offset>,50ranges: RangeListsOffset,51) -> Result<Self, Error>52where53R: Reader,54{55let mut ranges = dwarf.ranges(unit, ranges)?;56let mut result = Vec::new();57while let Some(range) = ranges.next()? {58if range.begin >= range.end {59// ignore empty ranges60}61result.push((range.begin, range.end));62}6364Ok(if result.is_empty() {65RangeInfoBuilder::Undefined66} else {67RangeInfoBuilder::Ranges(result)68})69}7071pub(crate) fn from_subprogram_die<R>(72dwarf: &gimli::Dwarf<R>,73unit: &Unit<R, R::Offset>,74entry: &DebuggingInformationEntry<R>,75addr_tr: &AddressTransform,76) -> Result<Self, Error>77where78R: Reader,79{80let addr =81if let Some(AttributeValue::Addr(addr)) = entry.attr_value(gimli::DW_AT_low_pc)? {82addr83} else if let Some(AttributeValue::DebugAddrIndex(i)) =84entry.attr_value(gimli::DW_AT_low_pc)?85{86dwarf.address(unit, i)?87} else if let Some(AttributeValue::RangeListsRef(r)) =88entry.attr_value(gimli::DW_AT_ranges)?89{90let r = dwarf.ranges_offset_from_raw(unit, r);91let mut ranges = dwarf.ranges(unit, r)?;92if let Some(range) = ranges.next()? {93range.begin94} else {95return Ok(RangeInfoBuilder::Undefined);96}97} else {98return Ok(RangeInfoBuilder::Undefined);99};100101let index = addr_tr.find_func_index(addr);102if index.is_none() {103return Ok(RangeInfoBuilder::Undefined);104}105Ok(RangeInfoBuilder::Function(index.unwrap()))106}107108pub(crate) fn build(109&self,110addr_tr: &AddressTransform,111out_unit: &mut write::Unit,112current_scope_id: write::UnitEntryId,113) {114match self {115RangeInfoBuilder::Undefined => (),116RangeInfoBuilder::Position(pc) => {117let addr = addr_tr118.translate(*pc)119.unwrap_or(write::Address::Constant(0));120let current_scope = out_unit.get_mut(current_scope_id);121current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));122}123RangeInfoBuilder::Ranges(ranges) => {124let mut result = Vec::new();125for (begin, end) in ranges {126result.extend(addr_tr.translate_ranges(*begin, *end));127}128129// If we're seeing the ranges for a `DW_TAG_compile_unit` DIE130// then don't use `DW_AT_low_pc` and `DW_AT_high_pc`. These131// attributes, if set, will configure the base address of all132// location lists that this unit refers to. Currently this133// debug transform does not take this base address into account134// when generate the `.debug_loc` section. Consequently when a135// compile unit is configured here the `DW_AT_ranges` attribute136// is unconditionally used instead of137// `DW_AT_low_pc`/`DW_AT_high_pc`.138let is_attr_for_compile_unit =139out_unit.get(current_scope_id).tag() == gimli::DW_TAG_compile_unit;140141if result.len() != 1 || is_attr_for_compile_unit {142let range_list = result143.iter()144.map(|tr| write::Range::StartLength {145begin: tr.0,146length: tr.1,147})148.collect::<Vec<_>>();149let range_list_id = out_unit.ranges.add(write::RangeList(range_list));150let current_scope = out_unit.get_mut(current_scope_id);151current_scope.set(152gimli::DW_AT_ranges,153write::AttributeValue::RangeListRef(range_list_id),154);155} else {156let current_scope = out_unit.get_mut(current_scope_id);157current_scope.set(158gimli::DW_AT_low_pc,159write::AttributeValue::Address(result[0].0),160);161current_scope.set(162gimli::DW_AT_high_pc,163write::AttributeValue::Udata(result[0].1),164);165}166}167RangeInfoBuilder::Function(index) => {168let symbol = addr_tr.map()[*index].symbol;169let range = addr_tr.func_range(*index);170let addr = write::Address::Symbol {171symbol,172addend: range.0 as i64,173};174let len = (range.1 - range.0) as u64;175let current_scope = out_unit.get_mut(current_scope_id);176current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr));177current_scope.set(gimli::DW_AT_high_pc, write::AttributeValue::Udata(len));178}179}180}181182pub(crate) fn get_ranges(&self, addr_tr: &AddressTransform) -> Vec<(u64, u64)> {183match self {184RangeInfoBuilder::Undefined | RangeInfoBuilder::Position(_) => vec![],185RangeInfoBuilder::Ranges(ranges) => ranges.clone(),186RangeInfoBuilder::Function(index) => {187let range = addr_tr.func_source_range(*index);188vec![(range.0, range.1)]189}190}191}192193pub(crate) fn build_ranges(194&self,195addr_tr: &AddressTransform,196out_range_lists: &mut write::RangeListTable,197) -> write::RangeListId {198if let RangeInfoBuilder::Ranges(ranges) = self {199let mut range_list = Vec::new();200for (begin, end) in ranges {201assert!(begin < end);202range_list.extend(addr_tr.translate_ranges(*begin, *end).map(|tr| {203write::Range::StartLength {204begin: tr.0,205length: tr.1,206}207}));208}209out_range_lists.add(write::RangeList(range_list))210} else {211unreachable!();212}213}214}215216217