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 /// Write the range list table to the appropriate section for the given DWARF version.
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.
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.
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)]
180pub struct RangeList(pub Vec<Range>);
181
182/// A single range.
183#[derive(Clone, Debug, Eq, PartialEq, Hash)]
184pub 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")]
214mod 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.
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")]
305mod tests {
306 use super::*;
307 use crate::common::{
308 DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
309 DebugStrOffsetsBase, Format,
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 use std::sync::Arc;
319
320 #[test]
321 fn test_range() {
322 let mut line_strings = LineStringTable::default();
323 let mut strings = StringTable::default();
324
325 for &version in &[2, 3, 4, 5] {
326 for &address_size in &[4, 8] {
327 for &format in &[Format::Dwarf32, Format::Dwarf64] {
328 let encoding = Encoding {
329 format,
330 version,
331 address_size,
332 };
333
334 let mut range_list = RangeList(vec![
335 Range::StartLength {
336 begin: Address::Constant(6666),
337 length: 7777,
338 },
339 Range::StartEnd {
340 begin: Address::Constant(4444),
341 end: Address::Constant(5555),
342 },
343 Range::BaseAddress {
344 address: Address::Constant(1111),
345 },
346 Range::OffsetPair {
347 begin: 2222,
348 end: 3333,
349 },
350 ]);
351
352 let mut ranges = RangeListTable::default();
353 let range_list_id = ranges.add(range_list.clone());
354
355 let mut sections = Sections::new(EndianVec::new(LittleEndian));
356 let range_list_offsets = ranges.write(&mut sections, encoding).unwrap();
357
358 let read_debug_ranges =
359 read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian);
360 let read_debug_rnglists =
361 read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian);
362 let read_ranges = read::RangeLists::new(read_debug_ranges, read_debug_rnglists);
363 let offset = range_list_offsets.get(range_list_id);
364 let read_range_list = read_ranges.raw_ranges(offset, encoding).unwrap();
365
366 let dwarf = read::Dwarf {
367 ranges: read_ranges,
368 ..Default::default()
369 };
370 let unit = read::Unit {
371 header: read::UnitHeader::new(
372 encoding,
373 0,
374 read::UnitType::Compilation,
375 DebugAbbrevOffset(0),
376 DebugInfoOffset(0).into(),
377 read::EndianSlice::default(),
378 ),
379 abbreviations: Arc::new(read::Abbreviations::default()),
380 name: None,
381 comp_dir: None,
382 low_pc: 0,
383 str_offsets_base: DebugStrOffsetsBase(0),
384 addr_base: DebugAddrBase(0),
385 loclists_base: DebugLocListsBase(0),
386 rnglists_base: DebugRngListsBase(0),
387 line_program: None,
388 dwo_id: None,
389 };
390 let context = ConvertUnitContext {
391 dwarf: &dwarf,
392 unit: &unit,
393 line_strings: &mut line_strings,
394 strings: &mut strings,
395 ranges: &mut ranges,
396 locations: &mut LocationListTable::default(),
397 convert_address: &|address| Some(Address::Constant(address)),
398 base_address: Address::Constant(0),
399 line_program_offset: None,
400 line_program_files: Vec::new(),
401 entry_ids: &HashMap::new(),
402 };
403 let convert_range_list = RangeList::from(read_range_list, &context).unwrap();
404
405 if version <= 4 {
406 range_list.0[0] = Range::StartEnd {
407 begin: Address::Constant(6666),
408 end: Address::Constant(6666 + 7777),
409 };
410 }
411 assert_eq!(range_list, convert_range_list);
412 }
413 }
414 }
415 }
416}
417