1 use super::address_transform::AddressTransform; 2 use super::{DebugInputContext, Reader}; 3 use anyhow::Error; 4 use gimli::{write, AttributeValue, DebuggingInformationEntry, RangeListsOffset, Unit}; 5 use wasmtime_environ::{DefinedFuncIndex, EntityRef}; 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<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 } 222