diff --git a/src/read/loclists.rs b/src/read/loclists.rs index 0ec7eab0..57f0e487 100644 --- a/src/read/loclists.rs +++ b/src/read/loclists.rs @@ -576,6 +576,11 @@ impl LocListIter { raw_loc: RawLocListEntry, ) -> Result>> { let mask = !0 >> (64 - self.raw.encoding.address_size * 8); + let tombstone = if self.raw.encoding.version <= 4 { + mask - 1 + } else { + mask + }; let (range, data) = match raw_loc { RawLocListEntry::BaseAddress { addr } => { @@ -609,6 +614,9 @@ impl LocListIter { ), RawLocListEntry::AddressOrOffsetPair { begin, end, data } | RawLocListEntry::OffsetPair { begin, end, data } => { + if self.base_address == tombstone { + return Ok(None); + } let mut range = Range { begin, end }; range.add_base_address(self.base_address, self.raw.encoding.address_size); (range, data) @@ -624,6 +632,10 @@ impl LocListIter { } }; + if range.begin == tombstone { + return Ok(None); + } + if range.begin > range.end { self.raw.input.empty(); return Err(Error::InvalidLocationAddressRange); @@ -664,6 +676,7 @@ mod tests { #[test] fn test_loclists_32() { + let tombstone = !0u32; let encoding = Encoding { format: Format::Dwarf32, version: 5, @@ -674,7 +687,9 @@ mod tests { .L32(0x0300_0000) .L32(0x0301_0300) .L32(0x0301_0400) - .L32(0x0301_0500); + .L32(0x0301_0500) + .L32(tombstone) + .L32(0x0301_0600); let buf = section.get_contents().unwrap(); let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); let debug_addr_base = DebugAddrBase(0); @@ -718,6 +733,25 @@ mod tests { .L8(2).uleb(1).uleb(2).uleb(4).L32(12) // A StartxLength .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13) + + // Tombstone entries, all of which should be ignored. + // A BaseAddressx that is a tombstone. + .L8(1).uleb(4) + .L8(4).uleb(0x11100).uleb(0x11200).uleb(4).L32(20) + // A BaseAddress that is a tombstone. + .L8(6).L32(tombstone) + .L8(4).uleb(0x11300).uleb(0x11400).uleb(4).L32(21) + // A StartxEndx that is a tombstone. + .L8(2).uleb(4).uleb(5).uleb(4).L32(22) + // A StartxLength that is a tombstone. + .L8(3).uleb(4).uleb(0x100).uleb(4).L32(23) + // A StartEnd that is a tombstone. + .L8(7).L32(tombstone).L32(0x201_1500).uleb(4).L32(24) + // A StartLength that is a tombstone. + .L8(8).L32(tombstone).uleb(0x100).uleb(4).L32(25) + // A StartEnd (not ignored) + .L8(7).L32(0x201_1600).L32(0x201_1700).uleb(4).L32(26) + // A range end. .L8(0) // Some extra data. @@ -875,6 +909,18 @@ mod tests { })) ); + // A StartEnd location following the tombstones + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0201_1600, + end: 0x0201_1700, + }, + data: Expression(EndianSlice::new(&[26, 0, 0, 0], LittleEndian)), + })) + ); + // A location list end. assert_eq!(locations.next(), Ok(None)); @@ -893,6 +939,7 @@ mod tests { #[test] fn test_loclists_64() { + let tombstone = !0u64; let encoding = Encoding { format: Format::Dwarf64, version: 5, @@ -903,7 +950,9 @@ mod tests { .L64(0x0300_0000) .L64(0x0301_0300) .L64(0x0301_0400) - .L64(0x0301_0500); + .L64(0x0301_0500) + .L64(tombstone) + .L64(0x0301_0600); let buf = section.get_contents().unwrap(); let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); let debug_addr_base = DebugAddrBase(0); @@ -948,6 +997,25 @@ mod tests { .L8(2).uleb(1).uleb(2).uleb(4).L32(12) // A StartxLength .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13) + + // Tombstone entries, all of which should be ignored. + // A BaseAddressx that is a tombstone. + .L8(1).uleb(4) + .L8(4).uleb(0x11100).uleb(0x11200).uleb(4).L32(20) + // A BaseAddress that is a tombstone. + .L8(6).L64(tombstone) + .L8(4).uleb(0x11300).uleb(0x11400).uleb(4).L32(21) + // A StartxEndx that is a tombstone. + .L8(2).uleb(4).uleb(5).uleb(4).L32(22) + // A StartxLength that is a tombstone. + .L8(3).uleb(4).uleb(0x100).uleb(4).L32(23) + // A StartEnd that is a tombstone. + .L8(7).L64(tombstone).L64(0x201_1500).uleb(4).L32(24) + // A StartLength that is a tombstone. + .L8(8).L64(tombstone).uleb(0x100).uleb(4).L32(25) + // A StartEnd (not ignored) + .L8(7).L64(0x201_1600).L64(0x201_1700).uleb(4).L32(26) + // A range end. .L8(0) // Some extra data. @@ -1105,6 +1173,18 @@ mod tests { })) ); + // A StartEnd location following the tombstones + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0201_1600, + end: 0x0201_1700, + }, + data: Expression(EndianSlice::new(&[26, 0, 0, 0], LittleEndian)), + })) + ); + // A location list end. assert_eq!(locations.next(), Ok(None)); @@ -1123,6 +1203,7 @@ mod tests { #[test] fn test_location_list_32() { + let tombstone = !0u32 - 1; let start = Label::new(); let first = Label::new(); #[rustfmt::skip] @@ -1144,6 +1225,11 @@ mod tests { // A location range that ends at -1. .L32(0xffff_ffff).L32(0x0000_0000) .L32(0).L32(0xffff_ffff).L16(4).L32(7) + // A normal location with tombstone. + .L32(tombstone).L32(tombstone).L16(4).L32(8) + // A base address selection with tombstone followed by a normal location. + .L32(0xffff_ffff).L32(tombstone) + .L32(0x10a00).L32(0x10b00).L16(4).L32(9) // A location list end. .L32(0).L32(0) // Some extra data. @@ -1253,6 +1339,7 @@ mod tests { #[test] fn test_location_list_64() { + let tombstone = !0u64 - 1; let start = Label::new(); let first = Label::new(); #[rustfmt::skip] @@ -1274,6 +1361,11 @@ mod tests { // A location range that ends at -1. .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000) .L64(0).L64(0xffff_ffff_ffff_ffff).L16(4).L32(7) + // A normal location with tombstone. + .L64(tombstone).L64(tombstone).L16(4).L32(8) + // A base address selection with tombstone followed by a normal location. + .L64(0xffff_ffff_ffff_ffff).L64(tombstone) + .L64(0x10a00).L64(0x10b00).L16(4).L32(9) // A location list end. .L64(0).L64(0) // Some extra data. diff --git a/src/read/rnglists.rs b/src/read/rnglists.rs index bef50ac0..98840be7 100644 --- a/src/read/rnglists.rs +++ b/src/read/rnglists.rs @@ -510,6 +510,11 @@ impl RngListIter { #[doc(hidden)] pub fn convert_raw(&mut self, raw_range: RawRngListEntry) -> Result> { let mask = !0 >> (64 - self.raw.encoding.address_size * 8); + let tombstone = if self.raw.encoding.version <= 4 { + mask - 1 + } else { + mask + }; let range = match raw_range { RawRngListEntry::BaseAddress { addr } => { @@ -532,6 +537,9 @@ impl RngListIter { } RawRngListEntry::AddressOrOffsetPair { begin, end } | RawRngListEntry::OffsetPair { begin, end } => { + if self.base_address == tombstone { + return Ok(None); + } let mut range = Range { begin, end }; range.add_base_address(self.base_address, self.raw.encoding.address_size); range @@ -543,6 +551,10 @@ impl RngListIter { } }; + if range.begin == tombstone { + return Ok(None); + } + if range.begin > range.end { self.raw.input.empty(); return Err(Error::InvalidAddressRange); @@ -628,6 +640,7 @@ mod tests { #[test] fn test_rnglists_32() { + let tombstone = !0u32; let encoding = Encoding { format: Format::Dwarf32, version: 5, @@ -637,7 +650,9 @@ mod tests { .L32(0x0300_0000) .L32(0x0301_0300) .L32(0x0301_0400) - .L32(0x0301_0500); + .L32(0x0301_0500) + .L32(tombstone) + .L32(0x0301_0600); let buf = section.get_contents().unwrap(); let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); let debug_addr_base = DebugAddrBase(0); @@ -655,7 +670,7 @@ mod tests { .L8(0) .L32(0) .mark(&first) - // OffsetPair + // An OffsetPair using the unit base address. .L8(4).uleb(0x10200).uleb(0x10300) // A base address selection followed by an OffsetPair. .L8(5).L32(0x0200_0000) @@ -681,6 +696,25 @@ mod tests { .L8(2).uleb(1).uleb(2) // A StartxLength .L8(3).uleb(3).uleb(0x100) + + // Tombstone entries, all of which should be ignored. + // A BaseAddressx that is a tombstone. + .L8(1).uleb(4) + .L8(4).uleb(0x11100).uleb(0x11200) + // A BaseAddress that is a tombstone. + .L8(5).L32(tombstone) + .L8(4).uleb(0x11300).uleb(0x11400) + // A StartxEndx that is a tombstone. + .L8(2).uleb(4).uleb(5) + // A StartxLength that is a tombstone. + .L8(3).uleb(4).uleb(0x100) + // A StartEnd that is a tombstone. + .L8(6).L32(tombstone).L32(0x201_1500) + // A StartLength that is a tombstone. + .L8(7).L32(tombstone).uleb(0x100) + // A StartEnd (not ignored) + .L8(6).L32(0x201_1600).L32(0x201_1700) + // A range end. .L8(0) // Some extra data. @@ -802,6 +836,15 @@ mod tests { })) ); + // A StartEnd range following the tombstones + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x0201_1600, + end: 0x0201_1700, + })) + ); + // A range end. assert_eq!(ranges.next(), Ok(None)); @@ -820,6 +863,7 @@ mod tests { #[test] fn test_rnglists_64() { + let tombstone = !0u64; let encoding = Encoding { format: Format::Dwarf64, version: 5, @@ -829,7 +873,9 @@ mod tests { .L64(0x0300_0000) .L64(0x0301_0300) .L64(0x0301_0400) - .L64(0x0301_0500); + .L64(0x0301_0500) + .L64(tombstone) + .L64(0x0301_0600); let buf = section.get_contents().unwrap(); let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); let debug_addr_base = DebugAddrBase(0); @@ -848,7 +894,7 @@ mod tests { .L8(0) .L32(0) .mark(&first) - // OffsetPair + // An OffsetPair using the unit base address. .L8(4).uleb(0x10200).uleb(0x10300) // A base address selection followed by an OffsetPair. .L8(5).L64(0x0200_0000) @@ -874,6 +920,25 @@ mod tests { .L8(2).uleb(1).uleb(2) // A StartxLength .L8(3).uleb(3).uleb(0x100) + + // Tombstone entries, all of which should be ignored. + // A BaseAddressx that is a tombstone. + .L8(1).uleb(4) + .L8(4).uleb(0x11100).uleb(0x11200) + // A BaseAddress that is a tombstone. + .L8(5).L64(tombstone) + .L8(4).uleb(0x11300).uleb(0x11400) + // A StartxEndx that is a tombstone. + .L8(2).uleb(4).uleb(5) + // A StartxLength that is a tombstone. + .L8(3).uleb(4).uleb(0x100) + // A StartEnd that is a tombstone. + .L8(6).L64(tombstone).L64(0x201_1500) + // A StartLength that is a tombstone. + .L8(7).L64(tombstone).uleb(0x100) + // A StartEnd (not ignored) + .L8(6).L64(0x201_1600).L64(0x201_1700) + // A range end. .L8(0) // Some extra data. @@ -995,6 +1060,15 @@ mod tests { })) ); + // A StartEnd range following the tombstones + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x0201_1600, + end: 0x0201_1700, + })) + ); + // A range end. assert_eq!(ranges.next(), Ok(None)); @@ -1045,6 +1119,7 @@ mod tests { #[test] fn test_ranges_32() { + let tombstone = !0u32 - 1; let start = Label::new(); let first = Label::new(); #[rustfmt::skip] @@ -1066,6 +1141,11 @@ mod tests { // A range that ends at -1. .L32(0xffff_ffff).L32(0x0000_0000) .L32(0).L32(0xffff_ffff) + // A normal range with tombstone. + .L32(tombstone).L32(tombstone) + // A base address selection with tombstone followed by a normal range. + .L32(0xffff_ffff).L32(tombstone) + .L32(0x10a00).L32(0x10b00) // A range end. .L32(0).L32(0) // Some extra data. @@ -1157,6 +1237,7 @@ mod tests { #[test] fn test_ranges_64() { + let tombstone = !0u64 - 1; let start = Label::new(); let first = Label::new(); #[rustfmt::skip] @@ -1178,6 +1259,11 @@ mod tests { // A range that ends at -1. .L64(0xffff_ffff_ffff_ffff).L64(0x0000_0000) .L64(0).L64(0xffff_ffff_ffff_ffff) + // A normal range with tombstone. + .L64(tombstone).L64(tombstone) + // A base address selection with tombstone followed by a normal range. + .L64(0xffff_ffff_ffff_ffff).L64(tombstone) + .L64(0x10a00).L64(0x10b00) // A range end. .L64(0).L64(0) // Some extra data.