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}
428