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 { from(entry: &write::ConvertUnitEntry<Reader<'_>>) -> Result<Self, Error>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 from_ranges_ref( unit: UnitRef<'_, Reader<'_>>, ranges: RangeListsOffset, ) -> Result<Self, Error>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 from_subprogram_die( entry: &write::ConvertUnitEntry<Reader<'_>>, addr_tr: &AddressTransform, ) -> Result<Self, Error>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 build( &self, addr_tr: &AddressTransform, out_unit: &mut write::Unit, current_scope_id: write::UnitEntryId, )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 get_ranges(&self, addr_tr: &AddressTransform) -> Vec<(u64, u64)>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 build_ranges( &self, addr_tr: &AddressTransform, out_range_lists: &mut write::RangeListTable, ) -> write::RangeListId177 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