2 use core
::{fmt, result, slice, str}
;
4 use crate::endian
::{self, Endianness}
;
8 self, CompressedData
, CompressedFileRange
, ObjectSection
, ReadError
, ReadRef
, Result
,
9 SectionFlags
, SectionIndex
, SectionKind
,
12 use super::{MachHeader, MachOFile, MachORelocationIterator}
;
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
>;
21 /// An iterator over the sections of a `MachOFile`.
22 pub struct MachOSectionIterator
<'data
, 'file
, Mach
, R
= &'data
[u8]>
28 pub(super) file
: &'file MachOFile
<'data
, Mach
, R
>,
29 pub(super) iter
: slice
::Iter
<'file
, MachOSectionInternal
<'data
, Mach
>>,
32 impl<'data
, 'file
, Mach
, R
> fmt
::Debug
for MachOSectionIterator
<'data
, 'file
, Mach
, R
>
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()
43 impl<'data
, 'file
, Mach
, R
> Iterator
for MachOSectionIterator
<'data
, 'file
, Mach
, R
>
48 type Item
= MachOSection
<'data
, 'file
, Mach
, R
>;
50 fn next(&mut self) -> Option
<Self::Item
> {
51 self.iter
.next().map(|&internal
| MachOSection
{
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
>;
65 /// A section of a `MachOFile`.
67 pub struct MachOSection
<'data
, 'file
, Mach
, R
= &'data
[u8]>
73 pub(super) file
: &'file MachOFile
<'data
, Mach
, R
>,
74 pub(super) internal
: MachOSectionInternal
<'data
, Mach
>,
77 impl<'data
, 'file
, Mach
, R
> MachOSection
<'data
, 'file
, Mach
, R
>
82 fn bytes(&self) -> Result
<&'data
[u8]> {
85 .data(self.file
.endian
, self.file
.data
)
86 .read_error("Invalid Mach-O section size or offset")
90 impl<'data
, 'file
, Mach
, R
> read
::private
::Sealed
for MachOSection
<'data
, 'file
, Mach
, R
>
97 impl<'data
, 'file
, Mach
, R
> ObjectSection
<'data
> for MachOSection
<'data
, 'file
, Mach
, R
>
102 type RelocationIterator
= MachORelocationIterator
<'data
, 'file
, Mach
, R
>;
105 fn index(&self) -> SectionIndex
{
110 fn address(&self) -> u64 {
111 self.internal
.section
.addr(self.file
.endian
).into()
115 fn size(&self) -> u64 {
116 self.internal
.section
.size(self.file
.endian
).into()
120 fn align(&self) -> u64 {
121 1 << self.internal
.section
.align(self.file
.endian
)
125 fn file_range(&self) -> Option
<(u64, u64)> {
126 self.internal
.section
.file_range(self.file
.endian
)
130 fn data(&self) -> Result
<&'data
[u8]> {
134 fn data_range(&self, address
: u64, size
: u64) -> Result
<Option
<&'data
[u8]>> {
135 Ok(read
::util
::data_range(
144 fn compressed_file_range(&self) -> Result
<CompressedFileRange
> {
145 Ok(CompressedFileRange
::none(self.file_range()))
149 fn compressed_data(&self) -> Result
<CompressedData
<'data
>> {
150 self.data().map(CompressedData
::none
)
154 fn name(&self) -> Result
<&str> {
155 str::from_utf8(self.internal
.section
.name())
157 .read_error("Non UTF-8 Mach-O section name")
161 fn segment_name(&self) -> Result
<Option
<&str>> {
163 str::from_utf8(self.internal
.section
.segment_name())
165 .read_error("Non UTF-8 Mach-O segment name")?
,
169 fn kind(&self) -> SectionKind
{
173 fn relocations(&self) -> MachORelocationIterator
<'data
, 'file
, Mach
, R
> {
174 MachORelocationIterator
{
179 .relocations(self.file
.endian
, self.file
.data
)
185 fn flags(&self) -> SectionFlags
{
186 SectionFlags
::MachO
{
187 flags
: self.internal
.section
.flags(self.file
.endian
),
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
,
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
,
221 MachOSectionInternal
{
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
;
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;
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
) => §name
[..end
],
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
],
263 /// Return the offset and size of the section in the file.
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())),
273 /// Return the section data.
275 /// Returns `Ok(&[])` if the section has no data.
276 /// Returns `Err` for invalid values.
277 fn data
<'data
, R
: ReadRef
<'data
>>(
279 endian
: Self::Endian
,
281 ) -> result
::Result
<&'data
[u8], ()> {
282 if let Some((offset
, size
)) = self.file_range(endian
) {
283 data
.read_bytes_at(offset
, size
)
289 /// Return the relocation array.
291 /// Returns `Err` for invalid values.
292 fn relocations
<'data
, R
: ReadRef
<'data
>>(
294 endian
: Self::Endian
,
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")
302 impl<Endian
: endian
::Endian
> Section
for macho
::Section32
<Endian
> {
304 type Endian
= Endian
;
306 fn sectname(&self) -> &[u8; 16] {
309 fn segname(&self) -> &[u8; 16] {
312 fn addr(&self, endian
: Self::Endian
) -> Self::Word
{
313 self.addr
.get(endian
)
315 fn size(&self, endian
: Self::Endian
) -> Self::Word
{
316 self.size
.get(endian
)
318 fn offset(&self, endian
: Self::Endian
) -> u32 {
319 self.offset
.get(endian
)
321 fn align(&self, endian
: Self::Endian
) -> u32 {
322 self.align
.get(endian
)
324 fn reloff(&self, endian
: Self::Endian
) -> u32 {
325 self.reloff
.get(endian
)
327 fn nreloc(&self, endian
: Self::Endian
) -> u32 {
328 self.nreloc
.get(endian
)
330 fn flags(&self, endian
: Self::Endian
) -> u32 {
331 self.flags
.get(endian
)
335 impl<Endian
: endian
::Endian
> Section
for macho
::Section64
<Endian
> {
337 type Endian
= Endian
;
339 fn sectname(&self) -> &[u8; 16] {
342 fn segname(&self) -> &[u8; 16] {
345 fn addr(&self, endian
: Self::Endian
) -> Self::Word
{
346 self.addr
.get(endian
)
348 fn size(&self, endian
: Self::Endian
) -> Self::Word
{
349 self.size
.get(endian
)
351 fn offset(&self, endian
: Self::Endian
) -> u32 {
352 self.offset
.get(endian
)
354 fn align(&self, endian
: Self::Endian
) -> u32 {
355 self.align
.get(endian
)
357 fn reloff(&self, endian
: Self::Endian
) -> u32 {
358 self.reloff
.get(endian
)
360 fn nreloc(&self, endian
: Self::Endian
) -> u32 {
361 self.nreloc
.get(endian
)
363 fn flags(&self, endian
: Self::Endian
) -> u32 {
364 self.flags
.get(endian
)