1 | use gimli::{Encoding, EndianSlice, RunTimeEndian, UnitIndex}; |
2 | use object::{Endianness, ObjectSection}; |
3 | |
4 | use crate::{relocate::RelocationMap, Session}; |
5 | |
6 | /// Helper trait to translate between `object`'s `Endianness` and `gimli`'s `RunTimeEndian`. |
7 | pub(crate) trait EndianityExt { |
8 | fn as_runtime_endian(&self) -> RunTimeEndian; |
9 | } |
10 | |
11 | impl 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. |
21 | pub(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 | |
35 | impl<'input, 'session: 'input, S> CompressedDataRangeExt<'input, 'session> for S |
36 | where |
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`. |
65 | pub(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 | |
73 | impl<'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 | |
85 | impl<'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. |
98 | pub(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 | |
120 | impl 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 | } |
145 | |