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; 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 149 // If we're seeing the ranges for a `DW_TAG_compile_unit` DIE 150 // then don't use `DW_AT_low_pc` and `DW_AT_high_pc`. These 151 // attributes, if set, will configure the base address of all 152 // location lists that this unit refers to. Currently this 153 // debug transform does not take this base address into account 154 // when generate the `.debug_loc` section. Consequently when a 155 // compile unit is configured here the `DW_AT_ranges` attribute 156 // is unconditionally used instead of 157 // `DW_AT_low_pc`/`DW_AT_high_pc`. 158 let is_attr_for_compile_unit = 159 out_unit.get(current_scope_id).tag() == gimli::DW_TAG_compile_unit; 160 161 if result.len() != 1 || is_attr_for_compile_unit { 162 let range_list = result 163 .iter() 164 .map(|tr| write::Range::StartLength { 165 begin: tr.0, 166 length: tr.1, 167 }) 168 .collect::<Vec<_>>(); 169 let range_list_id = out_unit.ranges.add(write::RangeList(range_list)); 170 let current_scope = out_unit.get_mut(current_scope_id); 171 current_scope.set( 172 gimli::DW_AT_ranges, 173 write::AttributeValue::RangeListRef(range_list_id), 174 ); 175 } else { 176 let current_scope = out_unit.get_mut(current_scope_id); 177 current_scope.set( 178 gimli::DW_AT_low_pc, 179 write::AttributeValue::Address(result[0].0), 180 ); 181 current_scope.set( 182 gimli::DW_AT_high_pc, 183 write::AttributeValue::Udata(result[0].1), 184 ); 185 } 186 } 187 RangeInfoBuilder::Function(index) => { 188 let symbol = addr_tr.map()[*index].symbol; 189 let range = addr_tr.func_range(*index); 190 let addr = write::Address::Symbol { 191 symbol, 192 addend: range.0 as i64, 193 }; 194 let len = (range.1 - range.0) as u64; 195 let current_scope = out_unit.get_mut(current_scope_id); 196 current_scope.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(addr)); 197 current_scope.set(gimli::DW_AT_high_pc, write::AttributeValue::Udata(len)); 198 } 199 } 200 } 201 202 pub(crate) fn get_ranges(&self, addr_tr: &AddressTransform) -> Vec<(u64, u64)> { 203 match self { 204 RangeInfoBuilder::Undefined | RangeInfoBuilder::Position(_) => vec![], 205 RangeInfoBuilder::Ranges(ranges) => ranges.clone(), 206 RangeInfoBuilder::Function(index) => { 207 let range = addr_tr.func_source_range(*index); 208 vec![(range.0, range.1)] 209 } 210 } 211 } 212 213 pub(crate) fn build_ranges( 214 &self, 215 addr_tr: &AddressTransform, 216 out_range_lists: &mut write::RangeListTable, 217 ) -> write::RangeListId { 218 if let RangeInfoBuilder::Ranges(ranges) = self { 219 let mut range_list = Vec::new(); 220 for (begin, end) in ranges { 221 assert!(begin < end); 222 range_list.extend(addr_tr.translate_ranges(*begin, *end).map(|tr| { 223 write::Range::StartLength { 224 begin: tr.0, 225 length: tr.1, 226 } 227 })); 228 } 229 out_range_lists.add(write::RangeList(range_list)) 230 } else { 231 unreachable!(); 232 } 233 } 234 } 235