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