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. |
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)] |
191 | pub struct RangeList(pub Vec<Range>); |
192 | |
193 | /// A single range. |
194 | #[derive (Clone, Debug, Eq, PartialEq, Hash)] |
195 | pub 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" )] |
225 | mod 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" )] |
316 | mod 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 | |