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 | /// 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)] |
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. |
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, |
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 | |