1use alloc::vec::Vec;
2use core::ops::{Deref, DerefMut};
3
4use crate::common::{Encoding, LocationListsOffset, SectionId};
5use crate::write::{
6 Address, BaseId, DebugInfoFixup, Error, Expression, FnvIndexSet, Result, Section, Sections,
7 UnitOffsets, Writer,
8};
9
10define_section!(
11 DebugLoc,
12 LocationListsOffset,
13 "A writable `.debug_loc` section."
14);
15define_section!(
16 DebugLocLists,
17 LocationListsOffset,
18 "A writable `.debug_loclists` section."
19);
20
21define_offsets!(
22 LocationListOffsets: LocationListId => LocationListsOffset,
23 "The section offsets of a series of location lists within the `.debug_loc` or `.debug_loclists` sections."
24);
25
26define_id!(
27 LocationListId,
28 "An identifier for a location list in a `LocationListTable`."
29);
30
31#[derive(Debug, Default)]
33pub struct LocationListTable {
34 base_id: BaseId,
35 locations: FnvIndexSet<LocationList>,
36}
37
38impl LocationListTable {
39 pub fn add(&mut self, loc_list: LocationList) -> LocationListId {
41 let (index, _) = self.locations.insert_full(loc_list);
42 LocationListId::new(self.base_id, index)
43 }
44
45 #[inline]
51 pub fn get(&self, id: LocationListId) -> &LocationList {
52 debug_assert_eq!(self.base_id, id.base_id);
53 &self.locations[id.index]
54 }
55
56 pub(crate) fn write<W: Writer>(
58 &self,
59 sections: &mut Sections<W>,
60 encoding: Encoding,
61 unit_offsets: Option<&UnitOffsets>,
62 ) -> Result<LocationListOffsets> {
63 if self.locations.is_empty() {
64 return Ok(LocationListOffsets::none());
65 }
66
67 match encoding.version {
68 2..=4 => self.write_loc(
69 &mut sections.debug_loc,
70 &mut sections.debug_loc_fixups,
71 encoding,
72 unit_offsets,
73 ),
74 5 => self.write_loclists(
75 &mut sections.debug_loclists,
76 &mut sections.debug_loclists_fixups,
77 encoding,
78 unit_offsets,
79 ),
80 _ => Err(Error::UnsupportedVersion(encoding.version)),
81 }
82 }
83
84 fn write_loc<W: Writer>(
86 &self,
87 w: &mut DebugLoc<W>,
88 refs: &mut Vec<DebugInfoFixup>,
89 encoding: Encoding,
90 unit_offsets: Option<&UnitOffsets>,
91 ) -> Result<LocationListOffsets> {
92 let address_size = encoding.address_size;
93 let mut offsets = Vec::new();
94 for loc_list in self.locations.iter() {
95 offsets.push(w.offset());
96 for loc in &loc_list.0 {
97 match *loc {
101 Location::BaseAddress { address } => {
102 let marker = !0 >> (64 - address_size * 8);
103 w.write_udata(marker, address_size)?;
104 w.write_address(address, address_size)?;
105 }
106 Location::OffsetPair {
107 begin,
108 end,
109 ref data,
110 } => {
111 if begin == end {
112 return Err(Error::InvalidRange);
113 }
114 w.write_udata(begin, address_size)?;
115 w.write_udata(end, address_size)?;
116 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
117 }
118 Location::StartEnd {
119 begin,
120 end,
121 ref data,
122 } => {
123 if begin == end {
124 return Err(Error::InvalidRange);
125 }
126 w.write_address(begin, address_size)?;
127 w.write_address(end, address_size)?;
128 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
129 }
130 Location::StartLength {
131 begin,
132 length,
133 ref data,
134 } => {
135 let end = match begin {
136 Address::Constant(begin) => Address::Constant(begin + length),
137 Address::Symbol { symbol, addend } => Address::Symbol {
138 symbol,
139 addend: addend + length as i64,
140 },
141 };
142 if begin == end {
143 return Err(Error::InvalidRange);
144 }
145 w.write_address(begin, address_size)?;
146 w.write_address(end, address_size)?;
147 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
148 }
149 Location::DefaultLocation { .. } => {
150 return Err(Error::InvalidRange);
151 }
152 }
153 }
154 w.write_udata(0, address_size)?;
155 w.write_udata(0, address_size)?;
156 }
157 Ok(LocationListOffsets {
158 base_id: self.base_id,
159 offsets,
160 })
161 }
162
163 fn write_loclists<W: Writer>(
165 &self,
166 w: &mut DebugLocLists<W>,
167 refs: &mut Vec<DebugInfoFixup>,
168 encoding: Encoding,
169 unit_offsets: Option<&UnitOffsets>,
170 ) -> Result<LocationListOffsets> {
171 let mut offsets = Vec::new();
172
173 if encoding.version != 5 {
174 return Err(Error::NeedVersion(5));
175 }
176
177 let length_offset = w.write_initial_length(encoding.format)?;
178 let length_base = w.len();
179
180 w.write_u16(encoding.version)?;
181 w.write_u8(encoding.address_size)?;
182 w.write_u8(0)?; w.write_u32(0)?; for loc_list in self.locations.iter() {
187 offsets.push(w.offset());
188 for loc in &loc_list.0 {
189 match *loc {
190 Location::BaseAddress { address } => {
191 w.write_u8(crate::constants::DW_LLE_base_address.0)?;
192 w.write_address(address, encoding.address_size)?;
193 }
194 Location::OffsetPair {
195 begin,
196 end,
197 ref data,
198 } => {
199 w.write_u8(crate::constants::DW_LLE_offset_pair.0)?;
200 w.write_uleb128(begin)?;
201 w.write_uleb128(end)?;
202 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
203 }
204 Location::StartEnd {
205 begin,
206 end,
207 ref data,
208 } => {
209 w.write_u8(crate::constants::DW_LLE_start_end.0)?;
210 w.write_address(begin, encoding.address_size)?;
211 w.write_address(end, encoding.address_size)?;
212 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
213 }
214 Location::StartLength {
215 begin,
216 length,
217 ref data,
218 } => {
219 w.write_u8(crate::constants::DW_LLE_start_length.0)?;
220 w.write_address(begin, encoding.address_size)?;
221 w.write_uleb128(length)?;
222 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
223 }
224 Location::DefaultLocation { ref data } => {
225 w.write_u8(crate::constants::DW_LLE_default_location.0)?;
226 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
227 }
228 }
229 }
230
231 w.write_u8(crate::constants::DW_LLE_end_of_list.0)?;
232 }
233
234 let length = (w.len() - length_base) as u64;
235 w.write_initial_length_at(length_offset, length, encoding.format)?;
236
237 Ok(LocationListOffsets {
238 base_id: self.base_id,
239 offsets,
240 })
241 }
242}
243
244#[derive(Clone, Debug, Eq, PartialEq, Hash)]
246pub struct LocationList(pub Vec<Location>);
247
248#[derive(Clone, Debug, Eq, PartialEq, Hash)]
250pub enum Location {
251 BaseAddress {
253 address: Address,
255 },
256 OffsetPair {
258 begin: u64,
260 end: u64,
262 data: Expression,
264 },
265 StartEnd {
267 begin: Address,
269 end: Address,
271 data: Expression,
273 },
274 StartLength {
276 begin: Address,
278 length: u64,
280 data: Expression,
282 },
283 DefaultLocation {
285 data: Expression,
287 },
288}
289
290fn write_expression<W: Writer>(
291 w: &mut W,
292 refs: &mut Vec<DebugInfoFixup>,
293 encoding: Encoding,
294 unit_offsets: Option<&UnitOffsets>,
295 val: &Expression,
296) -> Result<()> {
297 let size = val.size(encoding, unit_offsets)? as u64;
298 if encoding.version <= 4 {
299 w.write_udata(size, 2)?;
300 } else {
301 w.write_uleb128(size)?;
302 }
303 val.write(w, Some(refs), encoding, unit_offsets)?;
304 Ok(())
305}
306
307#[cfg(feature = "read")]
308mod convert {
309 use super::*;
310
311 use crate::read::{self, Reader};
312 use crate::write::{ConvertDebugInfoRef, ConvertError, ConvertResult};
313
314 impl LocationList {
315 pub(crate) fn from<R: Reader<Offset = usize>>(
317 mut from: read::RawLocListIter<R>,
318 from_unit: read::UnitRef<'_, R>,
319 convert_address: &dyn Fn(u64) -> Option<Address>,
320 convert_debug_info_ref: &dyn ConvertDebugInfoRef,
321 ) -> ConvertResult<Self> {
322 let convert_expression = |x| {
323 Expression::from(
324 x,
325 from_unit.encoding(),
326 Some(from_unit),
327 convert_address,
328 convert_debug_info_ref,
329 )
330 };
331 let convert_address = |x| convert_address(x).ok_or(ConvertError::InvalidAddress);
332 let mut have_base_address = from_unit.low_pc != 0;
333 let mut loc_list = Vec::new();
334 while let Some(from_loc) = from.next()? {
335 let loc = match from_loc {
336 read::RawLocListEntry::AddressOrOffsetPair { begin, end, data } => {
337 let begin = convert_address(begin)?;
339 let end = convert_address(end)?;
340 let data = convert_expression(data)?;
341 if have_base_address {
342 let (Address::Constant(begin_offset), Address::Constant(end_offset)) =
343 (begin, end)
344 else {
345 return Err(ConvertError::InvalidRangeRelativeAddress);
346 };
347 Location::OffsetPair {
348 begin: begin_offset,
349 end: end_offset,
350 data,
351 }
352 } else {
353 Location::StartEnd { begin, end, data }
354 }
355 }
356 read::RawLocListEntry::BaseAddress { addr } => {
357 have_base_address = true;
358 let address = convert_address(addr)?;
359 Location::BaseAddress { address }
360 }
361 read::RawLocListEntry::BaseAddressx { addr } => {
362 have_base_address = true;
363 let address = convert_address(from_unit.address(addr)?)?;
364 Location::BaseAddress { address }
365 }
366 read::RawLocListEntry::StartxEndx { begin, end, data } => {
367 let begin = convert_address(from_unit.address(begin)?)?;
368 let end = convert_address(from_unit.address(end)?)?;
369 let data = convert_expression(data)?;
370 Location::StartEnd { begin, end, data }
371 }
372 read::RawLocListEntry::StartxLength {
373 begin,
374 length,
375 data,
376 } => {
377 let begin = convert_address(from_unit.address(begin)?)?;
378 let data = convert_expression(data)?;
379 Location::StartLength {
380 begin,
381 length,
382 data,
383 }
384 }
385 read::RawLocListEntry::OffsetPair { begin, end, data } => {
386 let data = convert_expression(data)?;
387 Location::OffsetPair { begin, end, data }
388 }
389 read::RawLocListEntry::StartEnd { begin, end, data } => {
390 let begin = convert_address(begin)?;
391 let end = convert_address(end)?;
392 let data = convert_expression(data)?;
393 Location::StartEnd { begin, end, data }
394 }
395 read::RawLocListEntry::StartLength {
396 begin,
397 length,
398 data,
399 } => {
400 let begin = convert_address(begin)?;
401 let data = convert_expression(data)?;
402 Location::StartLength {
403 begin,
404 length,
405 data,
406 }
407 }
408 read::RawLocListEntry::DefaultLocation { data } => {
409 let data = convert_expression(data)?;
410 Location::DefaultLocation { data }
411 }
412 };
413 match loc {
416 Location::StartLength { length: 0, .. } => continue,
417 Location::StartEnd { begin, end, .. } if begin == end => continue,
418 Location::OffsetPair { begin, end, .. } if begin == end => continue,
419 _ => (),
420 }
421 loc_list.push(loc);
422 }
423 Ok(LocationList(loc_list))
424 }
425 }
426}
427
428#[cfg(test)]
429#[cfg(feature = "read")]
430mod tests {
431 use super::*;
432 use crate::LittleEndian;
433 use crate::common::{
434 DebugAbbrevOffset, DebugAddrBase, DebugLocListsBase, DebugRngListsBase,
435 DebugStrOffsetsBase, Format, UnitSectionOffset,
436 };
437 use crate::read;
438 use crate::write::{EndianVec, NoConvertDebugInfoRef};
439 use alloc::sync::Arc;
440
441 #[test]
442 fn test_loc_list() {
443 let mut expression = Expression::new();
444 expression.op_constu(0);
445
446 for &version in &[2, 3, 4, 5] {
447 for &address_size in &[4, 8] {
448 for &format in &[Format::Dwarf32, Format::Dwarf64] {
449 let encoding = Encoding {
450 format,
451 version,
452 address_size,
453 };
454
455 let mut loc_list = LocationList(vec![
456 Location::StartLength {
457 begin: Address::Constant(6666),
458 length: 7777,
459 data: expression.clone(),
460 },
461 Location::StartEnd {
462 begin: Address::Constant(4444),
463 end: Address::Constant(5555),
464 data: expression.clone(),
465 },
466 Location::BaseAddress {
467 address: Address::Constant(1111),
468 },
469 Location::OffsetPair {
470 begin: 2222,
471 end: 3333,
472 data: expression.clone(),
473 },
474 ]);
475 if version >= 5 {
476 loc_list.0.push(Location::DefaultLocation {
477 data: expression.clone(),
478 });
479 }
480
481 let mut locations = LocationListTable::default();
482 let loc_list_id = locations.add(loc_list.clone());
483
484 let mut sections = Sections::new(EndianVec::new(LittleEndian));
485 let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap();
486 assert!(sections.debug_loc_fixups.is_empty());
487 assert!(sections.debug_loclists_fixups.is_empty());
488
489 let read_debug_loc =
490 read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian);
491 let read_debug_loclists =
492 read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian);
493 let read_loc = read::LocationLists::new(read_debug_loc, read_debug_loclists);
494 let offset = loc_list_offsets.get(loc_list_id);
495 let read_loc_list = read_loc.raw_locations(offset, encoding).unwrap();
496
497 let dwarf = read::Dwarf {
498 locations: read_loc,
499 ..Default::default()
500 };
501 let unit = read::Unit {
502 header: read::UnitHeader::new(
503 encoding,
504 0,
505 read::UnitType::Compilation,
506 DebugAbbrevOffset(0),
507 SectionId::DebugInfo,
508 UnitSectionOffset(0),
509 read::EndianSlice::default(),
510 ),
511 abbreviations: Arc::new(read::Abbreviations::default()),
512 name: None,
513 comp_dir: None,
514 low_pc: 0,
515 str_offsets_base: DebugStrOffsetsBase(0),
516 addr_base: DebugAddrBase(0),
517 loclists_base: DebugLocListsBase(0),
518 rnglists_base: DebugRngListsBase(0),
519 line_program: None,
520 dwo_id: None,
521 };
522 let convert_loc_list = LocationList::from(
523 read_loc_list,
524 unit.unit_ref(&dwarf),
525 &|address| Some(Address::Constant(address)),
526 &NoConvertDebugInfoRef,
527 )
528 .unwrap();
529
530 if version <= 4 {
531 loc_list.0[0] = Location::StartEnd {
532 begin: Address::Constant(6666),
533 end: Address::Constant(6666 + 7777),
534 data: expression.clone(),
535 };
536 }
537 assert_eq!(loc_list, convert_loc_list);
538 }
539 }
540 }
541 }
542}