2 use indexmap
::IndexSet
;
3 use std
::ops
::{Deref, DerefMut}
;
5 use crate::common
::{Encoding, LocationListsOffset, SectionId}
;
7 Address
, BaseId
, DebugInfoReference
, Error
, Expression
, Result
, Section
, Sections
, UnitOffsets
,
14 "A writable `.debug_loc` section."
19 "A writable `.debug_loclists` section."
23 LocationListOffsets
: LocationListId
=> LocationListsOffset
,
24 "The section offsets of a series of location lists within the `.debug_loc` or `.debug_loclists` sections."
29 "An identifier for a location list in a `LocationListTable`."
32 /// A table of location lists that will be stored in a `.debug_loc` or `.debug_loclists` section.
33 #[derive(Debug, Default)]
34 pub struct LocationListTable
{
36 locations
: IndexSet
<LocationList
>,
39 impl LocationListTable
{
40 /// Add a location list to the table.
41 pub fn add(&mut self, loc_list
: LocationList
) -> LocationListId
{
42 let (index
, _
) = self.locations
.insert_full(loc_list
);
43 LocationListId
::new(self.base_id
, index
)
46 /// Write the location list table to the appropriate section for the given DWARF version.
47 pub(crate) fn write
<W
: Writer
>(
49 sections
: &mut Sections
<W
>,
51 unit_offsets
: Option
<&UnitOffsets
>,
52 ) -> Result
<LocationListOffsets
> {
53 if self.locations
.is_empty() {
54 return Ok(LocationListOffsets
::none());
57 match encoding
.version
{
58 2..=4 => self.write_loc(
59 &mut sections
.debug_loc
,
60 &mut sections
.debug_loc_refs
,
64 5 => self.write_loclists(
65 &mut sections
.debug_loclists
,
66 &mut sections
.debug_loclists_refs
,
70 _
=> Err(Error
::UnsupportedVersion(encoding
.version
)),
74 /// Write the location list table to the `.debug_loc` section.
75 fn write_loc
<W
: Writer
>(
78 refs
: &mut Vec
<DebugInfoReference
>,
80 unit_offsets
: Option
<&UnitOffsets
>,
81 ) -> Result
<LocationListOffsets
> {
82 let address_size
= encoding
.address_size
;
83 let mut offsets
= Vec
::new();
84 for loc_list
in self.locations
.iter() {
85 offsets
.push(w
.offset());
86 for loc
in &loc_list
.0 {
87 // Note that we must ensure none of the ranges have both begin == 0 and end == 0.
88 // We do this by ensuring that begin != end, which is a bit more restrictive
89 // than required, but still seems reasonable.
91 Location
::BaseAddress { address }
=> {
92 let marker
= !0 >> (64 - address_size
* 8);
93 w
.write_udata(marker
, address_size
)?
;
94 w
.write_address(address
, address_size
)?
;
96 Location
::OffsetPair
{
102 return Err(Error
::InvalidRange
);
104 w
.write_udata(begin
, address_size
)?
;
105 w
.write_udata(end
, address_size
)?
;
106 write_expression(&mut w
.0, refs
, encoding
, unit_offsets
, data
)?
;
114 return Err(Error
::InvalidRange
);
116 w
.write_address(begin
, address_size
)?
;
117 w
.write_address(end
, address_size
)?
;
118 write_expression(&mut w
.0, refs
, encoding
, unit_offsets
, data
)?
;
120 Location
::StartLength
{
125 let end
= match begin
{
126 Address
::Constant(begin
) => Address
::Constant(begin
+ length
),
127 Address
::Symbol { symbol, addend }
=> Address
::Symbol
{
129 addend
: addend
+ length
as i64,
133 return Err(Error
::InvalidRange
);
135 w
.write_address(begin
, address_size
)?
;
136 w
.write_address(end
, address_size
)?
;
137 write_expression(&mut w
.0, refs
, encoding
, unit_offsets
, data
)?
;
139 Location
::DefaultLocation { .. }
=> {
140 return Err(Error
::InvalidRange
);
144 w
.write_udata(0, address_size
)?
;
145 w
.write_udata(0, address_size
)?
;
147 Ok(LocationListOffsets
{
148 base_id
: self.base_id
,
153 /// Write the location list table to the `.debug_loclists` section.
154 fn write_loclists
<W
: Writer
>(
156 w
: &mut DebugLocLists
<W
>,
157 refs
: &mut Vec
<DebugInfoReference
>,
159 unit_offsets
: Option
<&UnitOffsets
>,
160 ) -> Result
<LocationListOffsets
> {
161 let mut offsets
= Vec
::new();
163 if encoding
.version
!= 5 {
164 return Err(Error
::NeedVersion(5));
167 let length_offset
= w
.write_initial_length(encoding
.format
)?
;
168 let length_base
= w
.len();
170 w
.write_u16(encoding
.version
)?
;
171 w
.write_u8(encoding
.address_size
)?
;
172 w
.write_u8(0)?
; // segment_selector_size
173 w
.write_u32(0)?
; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28)
174 // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list
176 for loc_list
in self.locations
.iter() {
177 offsets
.push(w
.offset());
178 for loc
in &loc_list
.0 {
180 Location
::BaseAddress { address }
=> {
181 w
.write_u8(crate::constants
::DW_LLE_base_address
.0)?
;
182 w
.write_address(address
, encoding
.address_size
)?
;
184 Location
::OffsetPair
{
189 w
.write_u8(crate::constants
::DW_LLE_offset_pair
.0)?
;
190 w
.write_uleb128(begin
)?
;
191 w
.write_uleb128(end
)?
;
192 write_expression(&mut w
.0, refs
, encoding
, unit_offsets
, data
)?
;
199 w
.write_u8(crate::constants
::DW_LLE_start_end
.0)?
;
200 w
.write_address(begin
, encoding
.address_size
)?
;
201 w
.write_address(end
, encoding
.address_size
)?
;
202 write_expression(&mut w
.0, refs
, encoding
, unit_offsets
, data
)?
;
204 Location
::StartLength
{
209 w
.write_u8(crate::constants
::DW_LLE_start_length
.0)?
;
210 w
.write_address(begin
, encoding
.address_size
)?
;
211 w
.write_uleb128(length
)?
;
212 write_expression(&mut w
.0, refs
, encoding
, unit_offsets
, data
)?
;
214 Location
::DefaultLocation { ref data }
=> {
215 w
.write_u8(crate::constants
::DW_LLE_default_location
.0)?
;
216 write_expression(&mut w
.0, refs
, encoding
, unit_offsets
, data
)?
;
221 w
.write_u8(crate::constants
::DW_LLE_end_of_list
.0)?
;
224 let length
= (w
.len() - length_base
) as u64;
225 w
.write_initial_length_at(length_offset
, length
, encoding
.format
)?
;
227 Ok(LocationListOffsets
{
228 base_id
: self.base_id
,
234 /// A locations list that will be stored in a `.debug_loc` or `.debug_loclists` section.
235 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
236 pub struct LocationList(pub Vec
<Location
>);
238 /// A single location.
239 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
241 /// DW_LLE_base_address
246 /// DW_LLE_offset_pair
248 /// Start of range relative to base address.
250 /// End of range relative to base address.
252 /// Location description.
261 /// Location description.
264 /// DW_LLE_start_length
270 /// Location description.
273 /// DW_LLE_default_location
275 /// Location description.
280 fn write_expression
<W
: Writer
>(
282 refs
: &mut Vec
<DebugInfoReference
>,
284 unit_offsets
: Option
<&UnitOffsets
>,
287 let size
= val
.size(encoding
, unit_offsets
) as u64;
288 if encoding
.version
<= 4 {
289 w
.write_udata(size
, 2)?
;
291 w
.write_uleb128(size
)?
;
293 val
.write(w
, Some(refs
), encoding
, unit_offsets
)?
;
297 #[cfg(feature = "read")]
301 use crate::read
::{self, Reader}
;
302 use crate::write
::{ConvertError, ConvertResult, ConvertUnitContext}
;
305 /// Create a location list by reading the data from the give location list iter.
306 pub(crate) fn from
<R
: Reader
<Offset
= usize>>(
307 mut from
: read
::RawLocListIter
<R
>,
308 context
: &ConvertUnitContext
<R
>,
309 ) -> ConvertResult
<Self> {
310 let mut have_base_address
= context
.base_address
!= Address
::Constant(0);
311 let convert_address
=
312 |x
| (context
.convert_address
)(x
).ok_or(ConvertError
::InvalidAddress
);
313 let convert_expression
= |x
| {
316 context
.unit
.encoding(),
319 Some(context
.entry_ids
),
320 context
.convert_address
,
323 let mut loc_list
= Vec
::new();
324 while let Some(from_loc
) = from
.next()?
{
325 let loc
= match from_loc
{
326 read
::RawLocListEntry
::AddressOrOffsetPair { begin, end, data }
=> {
327 // These were parsed as addresses, even if they are offsets.
328 let begin
= convert_address(begin
)?
;
329 let end
= convert_address(end
)?
;
330 let data
= convert_expression(data
)?
;
332 (Address
::Constant(begin_offset
), Address
::Constant(end_offset
)) => {
333 if have_base_address
{
334 Location
::OffsetPair
{
340 Location
::StartEnd { begin, end, data }
344 if have_base_address
{
345 // At least one of begin/end is an address, but we also have
346 // a base address. Adding addresses is undefined.
347 return Err(ConvertError
::InvalidRangeRelativeAddress
);
349 Location
::StartEnd { begin, end, data }
353 read
::RawLocListEntry
::BaseAddress { addr }
=> {
354 have_base_address
= true;
355 let address
= convert_address(addr
)?
;
356 Location
::BaseAddress { address }
358 read
::RawLocListEntry
::BaseAddressx { addr }
=> {
359 have_base_address
= true;
360 let address
= convert_address(context
.dwarf
.address(context
.unit
, addr
)?
)?
;
361 Location
::BaseAddress { address }
363 read
::RawLocListEntry
::StartxEndx { begin, end, data }
=> {
364 let begin
= convert_address(context
.dwarf
.address(context
.unit
, begin
)?
)?
;
365 let end
= convert_address(context
.dwarf
.address(context
.unit
, end
)?
)?
;
366 let data
= convert_expression(data
)?
;
367 Location
::StartEnd { begin, end, data }
369 read
::RawLocListEntry
::StartxLength
{
374 let begin
= convert_address(context
.dwarf
.address(context
.unit
, begin
)?
)?
;
375 let data
= convert_expression(data
)?
;
376 Location
::StartLength
{
382 read
::RawLocListEntry
::OffsetPair { begin, end, data }
=> {
383 let data
= convert_expression(data
)?
;
384 Location
::OffsetPair { begin, end, data }
386 read
::RawLocListEntry
::StartEnd { begin, end, data }
=> {
387 let begin
= convert_address(begin
)?
;
388 let end
= convert_address(end
)?
;
389 let data
= convert_expression(data
)?
;
390 Location
::StartEnd { begin, end, data }
392 read
::RawLocListEntry
::StartLength
{
397 let begin
= convert_address(begin
)?
;
398 let data
= convert_expression(data
)?
;
399 Location
::StartLength
{
405 read
::RawLocListEntry
::DefaultLocation { data }
=> {
406 let data
= convert_expression(data
)?
;
407 Location
::DefaultLocation { data }
410 // In some cases, existing data may contain begin == end, filtering
413 Location
::StartLength { length, .. }
if length
== 0 => continue,
414 Location
::StartEnd { begin, end, .. }
if begin
== end
=> continue,
415 Location
::OffsetPair { begin, end, .. }
if begin
== end
=> continue,
420 Ok(LocationList(loc_list
))
426 #[cfg(feature = "read")]
430 DebugAbbrevOffset
, DebugAddrBase
, DebugInfoOffset
, DebugLocListsBase
, DebugRngListsBase
,
431 DebugStrOffsetsBase
, Format
,
435 ConvertUnitContext
, EndianVec
, LineStringTable
, RangeListTable
, StringTable
,
437 use crate::LittleEndian
;
438 use std
::collections
::HashMap
;
442 let mut line_strings
= LineStringTable
::default();
443 let mut strings
= StringTable
::default();
444 let mut expression
= Expression
::new();
445 expression
.op_constu(0);
447 for &version
in &[2, 3, 4, 5] {
448 for &address_size
in &[4, 8] {
449 for &format
in &[Format
::Dwarf32
, Format
::Dwarf64
] {
450 let encoding
= Encoding
{
456 let mut loc_list
= LocationList(vec
![
457 Location
::StartLength
{
458 begin
: Address
::Constant(6666),
460 data
: expression
.clone(),
463 begin
: Address
::Constant(4444),
464 end
: Address
::Constant(5555),
465 data
: expression
.clone(),
467 Location
::BaseAddress
{
468 address
: Address
::Constant(1111),
470 Location
::OffsetPair
{
473 data
: expression
.clone(),
477 loc_list
.0.push(Location
::DefaultLocation
{
478 data
: expression
.clone(),
482 let mut locations
= LocationListTable
::default();
483 let loc_list_id
= locations
.add(loc_list
.clone());
485 let mut sections
= Sections
::new(EndianVec
::new(LittleEndian
));
486 let loc_list_offsets
= locations
.write(&mut sections
, encoding
, None
).unwrap();
487 assert
!(sections
.debug_loc_refs
.is_empty());
488 assert
!(sections
.debug_loclists_refs
.is_empty());
491 read
::DebugLoc
::new(sections
.debug_loc
.slice(), LittleEndian
);
492 let read_debug_loclists
=
493 read
::DebugLocLists
::new(sections
.debug_loclists
.slice(), LittleEndian
);
494 let read_loc
= read
::LocationLists
::new(read_debug_loc
, read_debug_loclists
);
495 let offset
= loc_list_offsets
.get(loc_list_id
);
496 let read_loc_list
= read_loc
.raw_locations(offset
, encoding
).unwrap();
498 let dwarf
= read
::Dwarf
{
502 let unit
= read
::Unit
{
503 header
: read
::UnitHeader
::new(
506 read
::UnitType
::Compilation
,
507 DebugAbbrevOffset(0),
508 DebugInfoOffset(0).into(),
509 read
::EndianSlice
::default(),
511 abbreviations
: read
::Abbreviations
::default(),
515 str_offsets_base
: DebugStrOffsetsBase(0),
516 addr_base
: DebugAddrBase(0),
517 loclists_base
: DebugLocListsBase(0),
518 rnglists_base
: DebugRngListsBase(0),
522 let context
= ConvertUnitContext
{
525 line_strings
: &mut line_strings
,
526 strings
: &mut strings
,
527 ranges
: &mut RangeListTable
::default(),
528 locations
: &mut locations
,
529 convert_address
: &|address
| Some(Address
::Constant(address
)),
530 base_address
: Address
::Constant(0),
531 line_program_offset
: None
,
532 line_program_files
: Vec
::new(),
533 entry_ids
: &HashMap
::new(),
535 let convert_loc_list
= LocationList
::from(read_loc_list
, &context
).unwrap();
538 loc_list
.0[0] = Location
::StartEnd
{
539 begin
: Address
::Constant(6666),
540 end
: Address
::Constant(6666 + 7777),
541 data
: expression
.clone(),
544 assert_eq
!(loc_list
, convert_loc_list
);