1 use alloc::vec::Vec; 2 use indexmap::IndexSet; 3 use std::ops::{Deref, DerefMut}; 4 5 use crate::common::{Encoding, RangeListsOffset, SectionId}; 6 use crate::write::{Address, BaseId, Error, Result, Section, Sections, Writer}; 7 8 define_section!( 9 DebugRanges, 10 RangeListsOffset, 11 "A writable `.debug_ranges` section." 12 ); 13 define_section!( 14 DebugRngLists, 15 RangeListsOffset, 16 "A writable `.debug_rnglists` section." 17 ); 18 19 define_offsets!( 20 RangeListOffsets: RangeListId => RangeListsOffset, 21 "The section offsets of a series of range lists within the `.debug_ranges` or `.debug_rnglists` sections." 22 ); 23 24 define_id!( 25 RangeListId, 26 "An identifier for a range list in a `RangeListTable`." 27 ); 28 29 /// A table of range lists that will be stored in a `.debug_ranges` or `.debug_rnglists` section. 30 #[derive(Debug, Default)] 31 pub struct RangeListTable { 32 base_id: BaseId, 33 ranges: IndexSet<RangeList>, 34 } 35 36 impl RangeListTable { 37 /// Add a range list to the table. add(&mut self, range_list: RangeList) -> RangeListId38 pub fn add(&mut self, range_list: RangeList) -> RangeListId { 39 let (index, _) = self.ranges.insert_full(range_list); 40 RangeListId::new(self.base_id, index) 41 } 42 43 /// Write the range list table to the appropriate section for the given DWARF version. write<W: Writer>( &self, sections: &mut Sections<W>, encoding: Encoding, ) -> Result<RangeListOffsets>44 pub(crate) fn write<W: Writer>( 45 &self, 46 sections: &mut Sections<W>, 47 encoding: Encoding, 48 ) -> Result<RangeListOffsets> { 49 if self.ranges.is_empty() { 50 return Ok(RangeListOffsets::none()); 51 } 52 53 match encoding.version { 54 2..=4 => self.write_ranges(&mut sections.debug_ranges, encoding.address_size), 55 5 => self.write_rnglists(&mut sections.debug_rnglists, encoding), 56 _ => Err(Error::UnsupportedVersion(encoding.version)), 57 } 58 } 59 60 /// Write the range list table to the `.debug_ranges` section. write_ranges<W: Writer>( &self, w: &mut DebugRanges<W>, address_size: u8, ) -> Result<RangeListOffsets>61 fn write_ranges<W: Writer>( 62 &self, 63 w: &mut DebugRanges<W>, 64 address_size: u8, 65 ) -> Result<RangeListOffsets> { 66 let mut offsets = Vec::new(); 67 for range_list in self.ranges.iter() { 68 offsets.push(w.offset()); 69 for range in &range_list.0 { 70 // Note that we must ensure none of the ranges have both begin == 0 and end == 0. 71 // We do this by ensuring that begin != end, which is a bit more restrictive 72 // than required, but still seems reasonable. 73 match *range { 74 Range::BaseAddress { address } => { 75 let marker = !0 >> (64 - address_size * 8); 76 w.write_udata(marker, address_size)?; 77 w.write_address(address, address_size)?; 78 } 79 Range::OffsetPair { begin, end } => { 80 if begin == end { 81 return Err(Error::InvalidRange); 82 } 83 w.write_udata(begin, address_size)?; 84 w.write_udata(end, address_size)?; 85 } 86 Range::StartEnd { begin, end } => { 87 if begin == end { 88 return Err(Error::InvalidRange); 89 } 90 w.write_address(begin, address_size)?; 91 w.write_address(end, address_size)?; 92 } 93 Range::StartLength { begin, length } => { 94 let end = match begin { 95 Address::Constant(begin) => Address::Constant(begin + length), 96 Address::Symbol { symbol, addend } => Address::Symbol { 97 symbol, 98 addend: addend + length as i64, 99 }, 100 }; 101 if begin == end { 102 return Err(Error::InvalidRange); 103 } 104 w.write_address(begin, address_size)?; 105 w.write_address(end, address_size)?; 106 } 107 } 108 } 109 w.write_udata(0, address_size)?; 110 w.write_udata(0, address_size)?; 111 } 112 Ok(RangeListOffsets { 113 base_id: self.base_id, 114 offsets, 115 }) 116 } 117 118 /// Write the range list table to the `.debug_rnglists` section. write_rnglists<W: Writer>( &self, w: &mut DebugRngLists<W>, encoding: Encoding, ) -> Result<RangeListOffsets>119 fn write_rnglists<W: Writer>( 120 &self, 121 w: &mut DebugRngLists<W>, 122 encoding: Encoding, 123 ) -> Result<RangeListOffsets> { 124 let mut offsets = Vec::new(); 125 126 if encoding.version != 5 { 127 return Err(Error::NeedVersion(5)); 128 } 129 130 let length_offset = w.write_initial_length(encoding.format)?; 131 let length_base = w.len(); 132 133 w.write_u16(encoding.version)?; 134 w.write_u8(encoding.address_size)?; 135 w.write_u8(0)?; // segment_selector_size 136 w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28) 137 // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list 138 139 for range_list in self.ranges.iter() { 140 offsets.push(w.offset()); 141 for range in &range_list.0 { 142 match *range { 143 Range::BaseAddress { address } => { 144 w.write_u8(crate::constants::DW_RLE_base_address.0)?; 145 w.write_address(address, encoding.address_size)?; 146 } 147 Range::OffsetPair { begin, end } => { 148 w.write_u8(crate::constants::DW_RLE_offset_pair.0)?; 149 w.write_uleb128(begin)?; 150 w.write_uleb128(end)?; 151 } 152 Range::StartEnd { begin, end } => { 153 w.write_u8(crate::constants::DW_RLE_start_end.0)?; 154 w.write_address(begin, encoding.address_size)?; 155 w.write_address(end, encoding.address_size)?; 156 } 157 Range::StartLength { begin, length } => { 158 w.write_u8(crate::constants::DW_RLE_start_length.0)?; 159 w.write_address(begin, encoding.address_size)?; 160 w.write_uleb128(length)?; 161 } 162 } 163 } 164 165 w.write_u8(crate::constants::DW_RLE_end_of_list.0)?; 166 } 167 168 let length = (w.len() - length_base) as u64; 169 w.write_initial_length_at(length_offset, length, encoding.format)?; 170 171 Ok(RangeListOffsets { 172 base_id: self.base_id, 173 offsets, 174 }) 175 } 176 } 177 178 /// A range list that will be stored in a `.debug_ranges` or `.debug_rnglists` section. 179 #[derive(Clone, Debug, Eq, PartialEq, Hash)] 180 pub struct RangeList(pub Vec<Range>); 181 182 /// A single range. 183 #[derive(Clone, Debug, Eq, PartialEq, Hash)] 184 pub enum Range { 185 /// DW_RLE_base_address 186 BaseAddress { 187 /// Base address. 188 address: Address, 189 }, 190 /// DW_RLE_offset_pair 191 OffsetPair { 192 /// Start of range relative to base address. 193 begin: u64, 194 /// End of range relative to base address. 195 end: u64, 196 }, 197 /// DW_RLE_start_end 198 StartEnd { 199 /// Start of range. 200 begin: Address, 201 /// End of range. 202 end: Address, 203 }, 204 /// DW_RLE_start_length 205 StartLength { 206 /// Start of range. 207 begin: Address, 208 /// Length of range. 209 length: u64, 210 }, 211 } 212 213 #[cfg(feature = "read")] 214 mod convert { 215 use super::*; 216 217 use crate::read::{self, Reader}; 218 use crate::write::{ConvertError, ConvertResult, ConvertUnitContext}; 219 220 impl RangeList { 221 /// Create a range list by reading the data from the give range list iter. from<R: Reader<Offset = usize>>( mut from: read::RawRngListIter<R>, context: &ConvertUnitContext<R>, ) -> ConvertResult<Self>222 pub(crate) fn from<R: Reader<Offset = usize>>( 223 mut from: read::RawRngListIter<R>, 224 context: &ConvertUnitContext<R>, 225 ) -> ConvertResult<Self> { 226 let mut have_base_address = context.base_address != Address::Constant(0); 227 let convert_address = 228 |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); 229 let mut ranges = Vec::new(); 230 while let Some(from_range) = from.next()? { 231 let range = match from_range { 232 read::RawRngListEntry::AddressOrOffsetPair { begin, end } => { 233 // These were parsed as addresses, even if they are offsets. 234 let begin = convert_address(begin)?; 235 let end = convert_address(end)?; 236 match (begin, end) { 237 (Address::Constant(begin_offset), Address::Constant(end_offset)) => { 238 if have_base_address { 239 Range::OffsetPair { 240 begin: begin_offset, 241 end: end_offset, 242 } 243 } else { 244 Range::StartEnd { begin, end } 245 } 246 } 247 _ => { 248 if have_base_address { 249 // At least one of begin/end is an address, but we also have 250 // a base address. Adding addresses is undefined. 251 return Err(ConvertError::InvalidRangeRelativeAddress); 252 } 253 Range::StartEnd { begin, end } 254 } 255 } 256 } 257 read::RawRngListEntry::BaseAddress { addr } => { 258 have_base_address = true; 259 let address = convert_address(addr)?; 260 Range::BaseAddress { address } 261 } 262 read::RawRngListEntry::BaseAddressx { addr } => { 263 have_base_address = true; 264 let address = convert_address(context.dwarf.address(context.unit, addr)?)?; 265 Range::BaseAddress { address } 266 } 267 read::RawRngListEntry::StartxEndx { begin, end } => { 268 let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; 269 let end = convert_address(context.dwarf.address(context.unit, end)?)?; 270 Range::StartEnd { begin, end } 271 } 272 read::RawRngListEntry::StartxLength { begin, length } => { 273 let begin = convert_address(context.dwarf.address(context.unit, begin)?)?; 274 Range::StartLength { begin, length } 275 } 276 read::RawRngListEntry::OffsetPair { begin, end } => { 277 Range::OffsetPair { begin, end } 278 } 279 read::RawRngListEntry::StartEnd { begin, end } => { 280 let begin = convert_address(begin)?; 281 let end = convert_address(end)?; 282 Range::StartEnd { begin, end } 283 } 284 read::RawRngListEntry::StartLength { begin, length } => { 285 let begin = convert_address(begin)?; 286 Range::StartLength { begin, length } 287 } 288 }; 289 // Filtering empty ranges out. 290 match range { 291 Range::StartLength { length, .. } if length == 0 => continue, 292 Range::StartEnd { begin, end, .. } if begin == end => continue, 293 Range::OffsetPair { begin, end, .. } if begin == end => continue, 294 _ => (), 295 } 296 ranges.push(range); 297 } 298 Ok(RangeList(ranges)) 299 } 300 } 301 } 302 303 #[cfg(test)] 304 #[cfg(feature = "read")] 305 mod tests { 306 use super::*; 307 use crate::common::{ 308 DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase, 309 DebugStrOffsetsBase, Format, UnitSectionOffset, 310 }; 311 use crate::read; 312 use crate::write::{ 313 ConvertUnitContext, EndianVec, LineStringTable, LocationListTable, Range, RangeListTable, 314 StringTable, 315 }; 316 use crate::LittleEndian; 317 use std::collections::HashMap; 318 319 #[test] test_range()320 fn test_range() { 321 let mut line_strings = LineStringTable::default(); 322 let mut strings = StringTable::default(); 323 324 for &version in &[2, 3, 4, 5] { 325 for &address_size in &[4, 8] { 326 for &format in &[Format::Dwarf32, Format::Dwarf64] { 327 let encoding = Encoding { 328 format, 329 version, 330 address_size, 331 }; 332 333 let mut range_list = RangeList(vec![ 334 Range::StartLength { 335 begin: Address::Constant(6666), 336 length: 7777, 337 }, 338 Range::StartEnd { 339 begin: Address::Constant(4444), 340 end: Address::Constant(5555), 341 }, 342 Range::BaseAddress { 343 address: Address::Constant(1111), 344 }, 345 Range::OffsetPair { 346 begin: 2222, 347 end: 3333, 348 }, 349 ]); 350 351 let mut ranges = RangeListTable::default(); 352 let range_list_id = ranges.add(range_list.clone()); 353 354 let mut sections = Sections::new(EndianVec::new(LittleEndian)); 355 let range_list_offsets = ranges.write(&mut sections, encoding).unwrap(); 356 357 let read_debug_ranges = 358 read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian); 359 let read_debug_rnglists = 360 read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian); 361 let read_ranges = read::RangeLists::new(read_debug_ranges, read_debug_rnglists); 362 let offset = range_list_offsets.get(range_list_id); 363 let read_range_list = read_ranges.raw_ranges(offset, encoding).unwrap(); 364 365 let dwarf = read::Dwarf { 366 ranges: read_ranges, 367 ..Default::default() 368 }; 369 let unit = read::Unit { 370 offset: UnitSectionOffset::DebugInfoOffset(DebugInfoOffset(0)), 371 header: read::UnitHeader::new( 372 encoding, 373 0, 374 DebugAbbrevOffset(0), 375 read::EndianSlice::default(), 376 ), 377 abbreviations: read::Abbreviations::default(), 378 name: None, 379 comp_dir: None, 380 low_pc: 0, 381 str_offsets_base: DebugStrOffsetsBase(0), 382 addr_base: DebugAddrBase(0), 383 loclists_base: DebugLocListsBase(0), 384 rnglists_base: DebugRngListsBase(0), 385 line_program: None, 386 }; 387 let context = ConvertUnitContext { 388 dwarf: &dwarf, 389 unit: &unit, 390 line_strings: &mut line_strings, 391 strings: &mut strings, 392 ranges: &mut ranges, 393 locations: &mut LocationListTable::default(), 394 convert_address: &|address| Some(Address::Constant(address)), 395 base_address: Address::Constant(0), 396 line_program_offset: None, 397 line_program_files: Vec::new(), 398 entry_ids: &HashMap::new(), 399 }; 400 let convert_range_list = RangeList::from(read_range_list, &context).unwrap(); 401 402 if version <= 4 { 403 range_list.0[0] = Range::StartEnd { 404 begin: Address::Constant(6666), 405 end: Address::Constant(6666 + 7777), 406 }; 407 } 408 assert_eq!(range_list, convert_range_list); 409 } 410 } 411 } 412 } 413 } 414