gimli/write/
range.rs

1use alloc::vec::Vec;
2use indexmap::IndexSet;
3use std::ops::{Deref, DerefMut};
4
5use crate::common::{Encoding, RangeListsOffset, SectionId};
6use crate::write::{Address, BaseId, Error, Result, Section, Sections, Writer};
7
8define_section!(
9    DebugRanges,
10    RangeListsOffset,
11    "A writable `.debug_ranges` section."
12);
13define_section!(
14    DebugRngLists,
15    RangeListsOffset,
16    "A writable `.debug_rnglists` section."
17);
18
19define_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
24define_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)]
31pub struct RangeListTable {
32    base_id: BaseId,
33    ranges: IndexSet<RangeList>,
34}
35
36impl 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)]
191pub struct RangeList(pub Vec<Range>);
192
193/// A single range.
194#[derive(Clone, Debug, Eq, PartialEq, Hash)]
195pub 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")]
225mod 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")]
316mod 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}