1use alloc::vec::Vec;
2use core::ops::{Deref, DerefMut};
3
4use crate::common::{Encoding, RangeListsOffset, SectionId};
5use crate::write::{Address, BaseId, Error, FnvIndexSet, Result, Section, Sections, Writer};
6
7define_section!(
8 DebugRanges,
9 RangeListsOffset,
10 "A writable `.debug_ranges` section."
11);
12define_section!(
13 DebugRngLists,
14 RangeListsOffset,
15 "A writable `.debug_rnglists` section."
16);
17
18define_offsets!(
19 RangeListOffsets: RangeListId => RangeListsOffset,
20 "The section offsets of a series of range lists within the `.debug_ranges` or `.debug_rnglists` sections."
21);
22
23define_id!(
24 RangeListId,
25 "An identifier for a range list in a `RangeListTable`."
26);
27
28#[derive(Debug, Default)]
30pub struct RangeListTable {
31 base_id: BaseId,
32 ranges: FnvIndexSet<RangeList>,
33}
34
35impl RangeListTable {
36 pub fn add(&mut self, range_list: RangeList) -> RangeListId {
38 let (index, _) = self.ranges.insert_full(range_list);
39 RangeListId::new(self.base_id, index)
40 }
41
42 #[inline]
48 pub fn get(&self, id: RangeListId) -> &RangeList {
49 debug_assert_eq!(self.base_id, id.base_id);
50 &self.ranges[id.index]
51 }
52
53 pub(crate) fn write<W: Writer>(
55 &self,
56 sections: &mut Sections<W>,
57 encoding: Encoding,
58 ) -> Result<RangeListOffsets> {
59 if self.ranges.is_empty() {
60 return Ok(RangeListOffsets::none());
61 }
62
63 match encoding.version {
64 2..=4 => self.write_ranges(&mut sections.debug_ranges, encoding.address_size),
65 5 => self.write_rnglists(&mut sections.debug_rnglists, encoding),
66 _ => Err(Error::UnsupportedVersion(encoding.version)),
67 }
68 }
69
70 fn write_ranges<W: Writer>(
72 &self,
73 w: &mut DebugRanges<W>,
74 address_size: u8,
75 ) -> Result<RangeListOffsets> {
76 let mut offsets = Vec::new();
77 for range_list in self.ranges.iter() {
78 offsets.push(w.offset());
79 for range in &range_list.0 {
80 match *range {
84 Range::BaseAddress { address } => {
85 let marker = !0 >> (64 - address_size * 8);
86 w.write_udata(marker, address_size)?;
87 w.write_address(address, address_size)?;
88 }
89 Range::OffsetPair { begin, end } => {
90 if begin == end {
91 return Err(Error::InvalidRange);
92 }
93 w.write_udata(begin, address_size)?;
94 w.write_udata(end, address_size)?;
95 }
96 Range::StartEnd { begin, end } => {
97 if begin == end {
98 return Err(Error::InvalidRange);
99 }
100 w.write_address(begin, address_size)?;
101 w.write_address(end, address_size)?;
102 }
103 Range::StartLength { begin, length } => {
104 let end = match begin {
105 Address::Constant(begin) => Address::Constant(begin + length),
106 Address::Symbol { symbol, addend } => Address::Symbol {
107 symbol,
108 addend: addend + length as i64,
109 },
110 };
111 if begin == end {
112 return Err(Error::InvalidRange);
113 }
114 w.write_address(begin, address_size)?;
115 w.write_address(end, address_size)?;
116 }
117 }
118 }
119 w.write_udata(0, address_size)?;
120 w.write_udata(0, address_size)?;
121 }
122 Ok(RangeListOffsets {
123 base_id: self.base_id,
124 offsets,
125 })
126 }
127
128 fn write_rnglists<W: Writer>(
130 &self,
131 w: &mut DebugRngLists<W>,
132 encoding: Encoding,
133 ) -> Result<RangeListOffsets> {
134 let mut offsets = Vec::new();
135
136 if encoding.version != 5 {
137 return Err(Error::NeedVersion(5));
138 }
139
140 let length_offset = w.write_initial_length(encoding.format)?;
141 let length_base = w.len();
142
143 w.write_u16(encoding.version)?;
144 w.write_u8(encoding.address_size)?;
145 w.write_u8(0)?; w.write_u32(0)?; for range_list in self.ranges.iter() {
150 offsets.push(w.offset());
151 for range in &range_list.0 {
152 match *range {
153 Range::BaseAddress { address } => {
154 w.write_u8(crate::constants::DW_RLE_base_address.0)?;
155 w.write_address(address, encoding.address_size)?;
156 }
157 Range::OffsetPair { begin, end } => {
158 w.write_u8(crate::constants::DW_RLE_offset_pair.0)?;
159 w.write_uleb128(begin)?;
160 w.write_uleb128(end)?;
161 }
162 Range::StartEnd { begin, end } => {
163 w.write_u8(crate::constants::DW_RLE_start_end.0)?;
164 w.write_address(begin, encoding.address_size)?;
165 w.write_address(end, encoding.address_size)?;
166 }
167 Range::StartLength { begin, length } => {
168 w.write_u8(crate::constants::DW_RLE_start_length.0)?;
169 w.write_address(begin, encoding.address_size)?;
170 w.write_uleb128(length)?;
171 }
172 }
173 }
174
175 w.write_u8(crate::constants::DW_RLE_end_of_list.0)?;
176 }
177
178 let length = (w.len() - length_base) as u64;
179 w.write_initial_length_at(length_offset, length, encoding.format)?;
180
181 Ok(RangeListOffsets {
182 base_id: self.base_id,
183 offsets,
184 })
185 }
186}
187
188#[derive(Clone, Debug, Eq, PartialEq, Hash)]
190pub struct RangeList(pub Vec<Range>);
191
192#[derive(Clone, Debug, Eq, PartialEq, Hash)]
194pub enum Range {
195 BaseAddress {
197 address: Address,
199 },
200 OffsetPair {
202 begin: u64,
204 end: u64,
206 },
207 StartEnd {
209 begin: Address,
211 end: Address,
213 },
214 StartLength {
216 begin: Address,
218 length: u64,
220 },
221}
222
223#[cfg(feature = "read")]
224mod convert {
225 use super::*;
226
227 use crate::read::{self, Reader};
228 use crate::write::{ConvertError, ConvertResult};
229
230 impl RangeList {
231 pub(crate) fn from<R: Reader<Offset = usize>>(
233 mut from: read::RawRngListIter<R>,
234 from_unit: read::UnitRef<'_, R>,
235 convert_address: &dyn Fn(u64) -> Option<Address>,
236 ) -> ConvertResult<Self> {
237 let convert_address = |x| convert_address(x).ok_or(ConvertError::InvalidAddress);
238 let mut have_base_address = from_unit.low_pc != 0;
246 let mut ranges = Vec::new();
247 while let Some(from_range) = from.next()? {
248 let range = match from_range {
249 read::RawRngListEntry::AddressOrOffsetPair { begin, end } => {
250 let begin = convert_address(begin)?;
257 let end = convert_address(end)?;
258 if have_base_address {
262 let (Address::Constant(begin_offset), Address::Constant(end_offset)) =
263 (begin, end)
264 else {
265 return Err(ConvertError::InvalidRangeRelativeAddress);
268 };
269 Range::OffsetPair {
270 begin: begin_offset,
271 end: end_offset,
272 }
273 } else {
274 Range::StartEnd { begin, end }
275 }
276 }
277 read::RawRngListEntry::BaseAddress { addr } => {
278 have_base_address = true;
279 let address = convert_address(addr)?;
280 Range::BaseAddress { address }
281 }
282 read::RawRngListEntry::BaseAddressx { addr } => {
283 have_base_address = true;
284 let address = convert_address(from_unit.address(addr)?)?;
285 Range::BaseAddress { address }
286 }
287 read::RawRngListEntry::StartxEndx { begin, end } => {
288 let begin = convert_address(from_unit.address(begin)?)?;
289 let end = convert_address(from_unit.address(end)?)?;
290 Range::StartEnd { begin, end }
291 }
292 read::RawRngListEntry::StartxLength { begin, length } => {
293 let begin = convert_address(from_unit.address(begin)?)?;
294 Range::StartLength { begin, length }
295 }
296 read::RawRngListEntry::OffsetPair { begin, end } => {
297 Range::OffsetPair { begin, end }
298 }
299 read::RawRngListEntry::StartEnd { begin, end } => {
300 let begin = convert_address(begin)?;
301 let end = convert_address(end)?;
302 Range::StartEnd { begin, end }
303 }
304 read::RawRngListEntry::StartLength { begin, length } => {
305 let begin = convert_address(begin)?;
306 Range::StartLength { begin, length }
307 }
308 };
309 match range {
311 Range::StartLength { length: 0, .. } => continue,
312 Range::StartEnd { begin, end, .. } if begin == end => continue,
313 Range::OffsetPair { begin, end, .. } if begin == end => continue,
314 _ => (),
315 }
316 ranges.push(range);
317 }
318 Ok(RangeList(ranges))
319 }
320 }
321}
322
323#[cfg(test)]
324#[cfg(feature = "read")]
325mod tests {
326 use super::*;
327 use crate::LittleEndian;
328 use crate::common::{
329 DebugAbbrevOffset, DebugAddrBase, DebugLocListsBase, DebugRngListsBase,
330 DebugStrOffsetsBase, Format, UnitSectionOffset,
331 };
332 use crate::read;
333 use crate::write::{EndianVec, Range, RangeListTable};
334 use alloc::sync::Arc;
335
336 #[test]
337 fn test_range() {
338 for &version in &[2, 3, 4, 5] {
339 for &address_size in &[4, 8] {
340 for &format in &[Format::Dwarf32, Format::Dwarf64] {
341 let encoding = Encoding {
342 format,
343 version,
344 address_size,
345 };
346
347 let mut range_list = RangeList(vec![
348 Range::StartLength {
349 begin: Address::Constant(6666),
350 length: 7777,
351 },
352 Range::StartEnd {
353 begin: Address::Constant(4444),
354 end: Address::Constant(5555),
355 },
356 Range::BaseAddress {
357 address: Address::Constant(1111),
358 },
359 Range::OffsetPair {
360 begin: 2222,
361 end: 3333,
362 },
363 ]);
364
365 let mut ranges = RangeListTable::default();
366 let range_list_id = ranges.add(range_list.clone());
367
368 let mut sections = Sections::new(EndianVec::new(LittleEndian));
369 let range_list_offsets = ranges.write(&mut sections, encoding).unwrap();
370
371 let read_debug_ranges =
372 read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian);
373 let read_debug_rnglists =
374 read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian);
375 let read_ranges = read::RangeLists::new(read_debug_ranges, read_debug_rnglists);
376 let offset = range_list_offsets.get(range_list_id);
377 let read_range_list = read_ranges.raw_ranges(offset, encoding).unwrap();
378
379 let dwarf = read::Dwarf {
380 ranges: read_ranges,
381 ..Default::default()
382 };
383 let unit = read::Unit {
384 header: read::UnitHeader::new(
385 encoding,
386 0,
387 read::UnitType::Compilation,
388 DebugAbbrevOffset(0),
389 SectionId::DebugInfo,
390 UnitSectionOffset(0),
391 read::EndianSlice::default(),
392 ),
393 abbreviations: Arc::new(read::Abbreviations::default()),
394 name: None,
395 comp_dir: None,
396 low_pc: 0,
397 str_offsets_base: DebugStrOffsetsBase(0),
398 addr_base: DebugAddrBase(0),
399 loclists_base: DebugLocListsBase(0),
400 rnglists_base: DebugRngListsBase(0),
401 line_program: None,
402 dwo_id: None,
403 };
404 let convert_range_list =
405 RangeList::from(read_range_list, unit.unit_ref(&dwarf), &|address| {
406 Some(Address::Constant(address))
407 })
408 .unwrap();
409
410 if version <= 4 {
411 range_list.0[0] = Range::StartEnd {
412 begin: Address::Constant(6666),
413 end: Address::Constant(6666 + 7777),
414 };
415 }
416 assert_eq!(range_list, convert_range_list);
417 }
418 }
419 }
420 }
421}