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