]> git.proxmox.com Git - rustc.git/blob - vendor/object-0.26.2/src/read/macho/section.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / vendor / object-0.26.2 / src / read / macho / section.rs
1 use core::fmt::Debug;
2 use core::{fmt, result, slice, str};
3
4 use crate::endian::{self, Endianness};
5 use crate::macho;
6 use crate::pod::Pod;
7 use crate::read::{
8 self, CompressedData, CompressedFileRange, ObjectSection, ReadError, ReadRef, Result,
9 SectionFlags, SectionIndex, SectionKind,
10 };
11
12 use super::{MachHeader, MachOFile, MachORelocationIterator};
13
14 /// An iterator over the sections of a `MachOFile32`.
15 pub type MachOSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
16 MachOSectionIterator<'data, 'file, macho::MachHeader32<Endian>, R>;
17 /// An iterator over the sections of a `MachOFile64`.
18 pub type MachOSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
19 MachOSectionIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
20
21 /// An iterator over the sections of a `MachOFile`.
22 pub struct MachOSectionIterator<'data, 'file, Mach, R = &'data [u8]>
23 where
24 'data: 'file,
25 Mach: MachHeader,
26 R: ReadRef<'data>,
27 {
28 pub(super) file: &'file MachOFile<'data, Mach, R>,
29 pub(super) iter: slice::Iter<'file, MachOSectionInternal<'data, Mach>>,
30 }
31
32 impl<'data, 'file, Mach, R> fmt::Debug for MachOSectionIterator<'data, 'file, Mach, R>
33 where
34 Mach: MachHeader,
35 R: ReadRef<'data>,
36 {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 // It's painful to do much better than this
39 f.debug_struct("MachOSectionIterator").finish()
40 }
41 }
42
43 impl<'data, 'file, Mach, R> Iterator for MachOSectionIterator<'data, 'file, Mach, R>
44 where
45 Mach: MachHeader,
46 R: ReadRef<'data>,
47 {
48 type Item = MachOSection<'data, 'file, Mach, R>;
49
50 fn next(&mut self) -> Option<Self::Item> {
51 self.iter.next().map(|&internal| MachOSection {
52 file: self.file,
53 internal,
54 })
55 }
56 }
57
58 /// A section of a `MachOFile32`.
59 pub type MachOSection32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
60 MachOSection<'data, 'file, macho::MachHeader32<Endian>, R>;
61 /// A section of a `MachOFile64`.
62 pub type MachOSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
63 MachOSection<'data, 'file, macho::MachHeader64<Endian>, R>;
64
65 /// A section of a `MachOFile`.
66 #[derive(Debug)]
67 pub struct MachOSection<'data, 'file, Mach, R = &'data [u8]>
68 where
69 'data: 'file,
70 Mach: MachHeader,
71 R: ReadRef<'data>,
72 {
73 pub(super) file: &'file MachOFile<'data, Mach, R>,
74 pub(super) internal: MachOSectionInternal<'data, Mach>,
75 }
76
77 impl<'data, 'file, Mach, R> MachOSection<'data, 'file, Mach, R>
78 where
79 Mach: MachHeader,
80 R: ReadRef<'data>,
81 {
82 fn bytes(&self) -> Result<&'data [u8]> {
83 self.internal
84 .section
85 .data(self.file.endian, self.file.data)
86 .read_error("Invalid Mach-O section size or offset")
87 }
88 }
89
90 impl<'data, 'file, Mach, R> read::private::Sealed for MachOSection<'data, 'file, Mach, R>
91 where
92 Mach: MachHeader,
93 R: ReadRef<'data>,
94 {
95 }
96
97 impl<'data, 'file, Mach, R> ObjectSection<'data> for MachOSection<'data, 'file, Mach, R>
98 where
99 Mach: MachHeader,
100 R: ReadRef<'data>,
101 {
102 type RelocationIterator = MachORelocationIterator<'data, 'file, Mach, R>;
103
104 #[inline]
105 fn index(&self) -> SectionIndex {
106 self.internal.index
107 }
108
109 #[inline]
110 fn address(&self) -> u64 {
111 self.internal.section.addr(self.file.endian).into()
112 }
113
114 #[inline]
115 fn size(&self) -> u64 {
116 self.internal.section.size(self.file.endian).into()
117 }
118
119 #[inline]
120 fn align(&self) -> u64 {
121 1 << self.internal.section.align(self.file.endian)
122 }
123
124 #[inline]
125 fn file_range(&self) -> Option<(u64, u64)> {
126 self.internal.section.file_range(self.file.endian)
127 }
128
129 #[inline]
130 fn data(&self) -> Result<&'data [u8]> {
131 self.bytes()
132 }
133
134 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
135 Ok(read::util::data_range(
136 self.bytes()?,
137 self.address(),
138 address,
139 size,
140 ))
141 }
142
143 #[inline]
144 fn compressed_file_range(&self) -> Result<CompressedFileRange> {
145 Ok(CompressedFileRange::none(self.file_range()))
146 }
147
148 #[inline]
149 fn compressed_data(&self) -> Result<CompressedData<'data>> {
150 self.data().map(CompressedData::none)
151 }
152
153 #[inline]
154 fn name(&self) -> Result<&str> {
155 str::from_utf8(self.internal.section.name())
156 .ok()
157 .read_error("Non UTF-8 Mach-O section name")
158 }
159
160 #[inline]
161 fn segment_name(&self) -> Result<Option<&str>> {
162 Ok(Some(
163 str::from_utf8(self.internal.section.segment_name())
164 .ok()
165 .read_error("Non UTF-8 Mach-O segment name")?,
166 ))
167 }
168
169 fn kind(&self) -> SectionKind {
170 self.internal.kind
171 }
172
173 fn relocations(&self) -> MachORelocationIterator<'data, 'file, Mach, R> {
174 MachORelocationIterator {
175 file: self.file,
176 relocations: self
177 .internal
178 .section
179 .relocations(self.file.endian, self.file.data)
180 .unwrap_or(&[])
181 .iter(),
182 }
183 }
184
185 fn flags(&self) -> SectionFlags {
186 SectionFlags::MachO {
187 flags: self.internal.section.flags(self.file.endian),
188 }
189 }
190 }
191
192 #[derive(Debug, Clone, Copy)]
193 pub(super) struct MachOSectionInternal<'data, Mach: MachHeader> {
194 pub index: SectionIndex,
195 pub kind: SectionKind,
196 pub section: &'data Mach::Section,
197 }
198
199 impl<'data, Mach: MachHeader> MachOSectionInternal<'data, Mach> {
200 pub(super) fn parse(index: SectionIndex, section: &'data Mach::Section) -> Self {
201 // TODO: we don't validate flags, should we?
202 let kind = match (section.segment_name(), section.name()) {
203 (b"__TEXT", b"__text") => SectionKind::Text,
204 (b"__TEXT", b"__const") => SectionKind::ReadOnlyData,
205 (b"__TEXT", b"__cstring") => SectionKind::ReadOnlyString,
206 (b"__TEXT", b"__literal4") => SectionKind::ReadOnlyData,
207 (b"__TEXT", b"__literal8") => SectionKind::ReadOnlyData,
208 (b"__TEXT", b"__literal16") => SectionKind::ReadOnlyData,
209 (b"__TEXT", b"__eh_frame") => SectionKind::ReadOnlyData,
210 (b"__TEXT", b"__gcc_except_tab") => SectionKind::ReadOnlyData,
211 (b"__DATA", b"__data") => SectionKind::Data,
212 (b"__DATA", b"__const") => SectionKind::ReadOnlyData,
213 (b"__DATA", b"__bss") => SectionKind::UninitializedData,
214 (b"__DATA", b"__common") => SectionKind::Common,
215 (b"__DATA", b"__thread_data") => SectionKind::Tls,
216 (b"__DATA", b"__thread_bss") => SectionKind::UninitializedTls,
217 (b"__DATA", b"__thread_vars") => SectionKind::TlsVariables,
218 (b"__DWARF", _) => SectionKind::Debug,
219 _ => SectionKind::Unknown,
220 };
221 MachOSectionInternal {
222 index,
223 kind,
224 section,
225 }
226 }
227 }
228
229 /// A trait for generic access to `Section32` and `Section64`.
230 #[allow(missing_docs)]
231 pub trait Section: Debug + Pod {
232 type Word: Into<u64>;
233 type Endian: endian::Endian;
234
235 fn sectname(&self) -> &[u8; 16];
236 fn segname(&self) -> &[u8; 16];
237 fn addr(&self, endian: Self::Endian) -> Self::Word;
238 fn size(&self, endian: Self::Endian) -> Self::Word;
239 fn offset(&self, endian: Self::Endian) -> u32;
240 fn align(&self, endian: Self::Endian) -> u32;
241 fn reloff(&self, endian: Self::Endian) -> u32;
242 fn nreloc(&self, endian: Self::Endian) -> u32;
243 fn flags(&self, endian: Self::Endian) -> u32;
244
245 /// Return the `sectname` bytes up until the null terminator.
246 fn name(&self) -> &[u8] {
247 let sectname = &self.sectname()[..];
248 match memchr::memchr(b'\0', sectname) {
249 Some(end) => &sectname[..end],
250 None => sectname,
251 }
252 }
253
254 /// Return the `segname` bytes up until the null terminator.
255 fn segment_name(&self) -> &[u8] {
256 let segname = &self.segname()[..];
257 match memchr::memchr(b'\0', segname) {
258 Some(end) => &segname[..end],
259 None => segname,
260 }
261 }
262
263 /// Return the offset and size of the section in the file.
264 ///
265 /// Returns `None` for sections that have no data in the file.
266 fn file_range(&self, endian: Self::Endian) -> Option<(u64, u64)> {
267 match self.flags(endian) & macho::SECTION_TYPE {
268 macho::S_ZEROFILL | macho::S_GB_ZEROFILL | macho::S_THREAD_LOCAL_ZEROFILL => None,
269 _ => Some((self.offset(endian).into(), self.size(endian).into())),
270 }
271 }
272
273 /// Return the section data.
274 ///
275 /// Returns `Ok(&[])` if the section has no data.
276 /// Returns `Err` for invalid values.
277 fn data<'data, R: ReadRef<'data>>(
278 &self,
279 endian: Self::Endian,
280 data: R,
281 ) -> result::Result<&'data [u8], ()> {
282 if let Some((offset, size)) = self.file_range(endian) {
283 data.read_bytes_at(offset, size)
284 } else {
285 Ok(&[])
286 }
287 }
288
289 /// Return the relocation array.
290 ///
291 /// Returns `Err` for invalid values.
292 fn relocations<'data, R: ReadRef<'data>>(
293 &self,
294 endian: Self::Endian,
295 data: R,
296 ) -> Result<&'data [macho::Relocation<Self::Endian>]> {
297 data.read_slice_at(self.reloff(endian).into(), self.nreloc(endian) as usize)
298 .read_error("Invalid Mach-O relocations offset or number")
299 }
300 }
301
302 impl<Endian: endian::Endian> Section for macho::Section32<Endian> {
303 type Word = u32;
304 type Endian = Endian;
305
306 fn sectname(&self) -> &[u8; 16] {
307 &self.sectname
308 }
309 fn segname(&self) -> &[u8; 16] {
310 &self.segname
311 }
312 fn addr(&self, endian: Self::Endian) -> Self::Word {
313 self.addr.get(endian)
314 }
315 fn size(&self, endian: Self::Endian) -> Self::Word {
316 self.size.get(endian)
317 }
318 fn offset(&self, endian: Self::Endian) -> u32 {
319 self.offset.get(endian)
320 }
321 fn align(&self, endian: Self::Endian) -> u32 {
322 self.align.get(endian)
323 }
324 fn reloff(&self, endian: Self::Endian) -> u32 {
325 self.reloff.get(endian)
326 }
327 fn nreloc(&self, endian: Self::Endian) -> u32 {
328 self.nreloc.get(endian)
329 }
330 fn flags(&self, endian: Self::Endian) -> u32 {
331 self.flags.get(endian)
332 }
333 }
334
335 impl<Endian: endian::Endian> Section for macho::Section64<Endian> {
336 type Word = u64;
337 type Endian = Endian;
338
339 fn sectname(&self) -> &[u8; 16] {
340 &self.sectname
341 }
342 fn segname(&self) -> &[u8; 16] {
343 &self.segname
344 }
345 fn addr(&self, endian: Self::Endian) -> Self::Word {
346 self.addr.get(endian)
347 }
348 fn size(&self, endian: Self::Endian) -> Self::Word {
349 self.size.get(endian)
350 }
351 fn offset(&self, endian: Self::Endian) -> u32 {
352 self.offset.get(endian)
353 }
354 fn align(&self, endian: Self::Endian) -> u32 {
355 self.align.get(endian)
356 }
357 fn reloff(&self, endian: Self::Endian) -> u32 {
358 self.reloff.get(endian)
359 }
360 fn nreloc(&self, endian: Self::Endian) -> u32 {
361 self.nreloc.get(endian)
362 }
363 fn flags(&self, endian: Self::Endian) -> u32 {
364 self.flags.get(endian)
365 }
366 }