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