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}
145