thorin/
ext.rs

1use gimli::{Encoding, EndianSlice, RunTimeEndian, UnitIndex};
2use object::{Endianness, ObjectSection};
3
4use crate::{relocate::RelocationMap, Session};
5
6/// Helper trait to translate between `object`'s `Endianness` and `gimli`'s `RunTimeEndian`.
7pub(crate) trait EndianityExt {
8    fn as_runtime_endian(&self) -> RunTimeEndian;
9}
10
11impl EndianityExt for Endianness {
12    fn as_runtime_endian(&self) -> RunTimeEndian {
13        match *self {
14            Endianness::Little => RunTimeEndian::Little,
15            Endianness::Big => RunTimeEndian::Big,
16        }
17    }
18}
19
20/// Helper trait to add `compressed_data_range` function to `ObjectSection` types.
21pub(crate) trait CompressedDataRangeExt<'input, 'session: 'input>:
22    ObjectSection<'input>
23{
24    /// Return the decompressed contents of the section data in the given range.
25    ///
26    /// Decompression happens only if the data is compressed.
27    fn compressed_data_range(
28        &self,
29        sess: &'session impl Session<RelocationMap>,
30        address: u64,
31        size: u64,
32    ) -> object::Result<Option<&'input [u8]>>;
33}
34
35impl<'input, 'session: 'input, S> CompressedDataRangeExt<'input, 'session> for S
36where
37    S: ObjectSection<'input>,
38{
39    fn compressed_data_range(
40        &self,
41        sess: &'session impl Session<RelocationMap>,
42        address: u64,
43        size: u64,
44    ) -> object::Result<Option<&'input [u8]>> {
45        let data = self.compressed_data()?.decompress()?;
46
47        /// Originally from `object::read::util`, used in `ObjectSection::data_range`, but not
48        /// public.
49        fn data_range(
50            data: &[u8],
51            data_address: u64,
52            range_address: u64,
53            size: u64,
54        ) -> Option<&[u8]> {
55            let offset = range_address.checked_sub(data_address)?;
56            data.get(offset.try_into().ok()?..)?.get(..size.try_into().ok()?)
57        }
58
59        let data_ref = sess.alloc_owned_cow(data);
60        Ok(data_range(data_ref, self.address(), address, size))
61    }
62}
63
64/// Helper trait that abstracts over `gimli::DebugCuIndex` and `gimli::DebugTuIndex`.
65pub(crate) trait IndexSectionExt<'input, Endian: gimli::Endianity, R: gimli::Reader>:
66    gimli::Section<R>
67{
68    fn new(section: &'input [u8], endian: Endian) -> Self;
69
70    fn index(self) -> gimli::read::Result<UnitIndex<R>>;
71}
72
73impl<'input, Endian: gimli::Endianity> IndexSectionExt<'input, Endian, EndianSlice<'input, Endian>>
74    for gimli::DebugCuIndex<EndianSlice<'input, Endian>>
75{
76    fn new(section: &'input [u8], endian: Endian) -> Self {
77        Self::new(section, endian)
78    }
79
80    fn index(self) -> gimli::read::Result<UnitIndex<EndianSlice<'input, Endian>>> {
81        Self::index(self)
82    }
83}
84
85impl<'input, Endian: gimli::Endianity> IndexSectionExt<'input, Endian, EndianSlice<'input, Endian>>
86    for gimli::DebugTuIndex<EndianSlice<'input, Endian>>
87{
88    fn new(section: &'input [u8], endian: Endian) -> Self {
89        Self::new(section, endian)
90    }
91
92    fn index(self) -> gimli::read::Result<UnitIndex<EndianSlice<'input, Endian>>> {
93        Self::index(self)
94    }
95}
96
97/// Helper trait to add DWARF package specific functions to the `Encoding` type.
98pub(crate) trait PackageFormatExt {
99    /// Returns `true` if this `Encoding` would produce to a DWARF 5-standardized package file.
100    ///
101    /// See Sec 7.3.5 and Appendix F of the [DWARF specification].
102    ///
103    /// [DWARF specification]: https://dwarfstd.org/doc/DWARF5.pdf
104    fn is_std_dwarf_package_format(&self) -> bool;
105
106    /// Returns `true` if this `Encoding` would produce a GNU Extension DWARF package file
107    /// (preceded standardized version from DWARF 5).
108    ///
109    /// See [specification](https://gcc.gnu.org/wiki/DebugFissionDWP).
110    fn is_gnu_extension_dwarf_package_format(&self) -> bool;
111
112    /// Returns index version of DWARF package for this `Encoding`.
113    fn dwarf_package_index_version(&self) -> u16;
114
115    /// Returns `true` if the dwarf package index version provided is compatible with this
116    /// `Encoding`.
117    fn is_compatible_dwarf_package_index_version(&self, index_version: u16) -> bool;
118}
119
120impl PackageFormatExt for Encoding {
121    fn is_gnu_extension_dwarf_package_format(&self) -> bool {
122        !self.is_std_dwarf_package_format()
123    }
124
125    fn is_std_dwarf_package_format(&self) -> bool {
126        self.version >= 5
127    }
128
129    fn dwarf_package_index_version(&self) -> u16 {
130        if self.is_gnu_extension_dwarf_package_format() {
131            2
132        } else {
133            5
134        }
135    }
136
137    fn is_compatible_dwarf_package_index_version(&self, index_version: u16) -> bool {
138        if self.is_gnu_extension_dwarf_package_format() {
139            index_version == 2
140        } else {
141            index_version >= 5
142        }
143    }
144}