2 use core
::{result, str}
;
4 use crate::endian
::{self, Endianness}
;
6 use crate::pod
::{Bytes, Pod}
;
7 use crate::read
::{self, ObjectSegment, ReadError, Result}
;
9 use super::{MachHeader, MachOFile, MachOLoadCommand, MachOLoadCommandIterator, Section}
;
11 /// An iterator over the segments of a `MachOFile32`.
12 pub type MachOSegmentIterator32
<'data
, 'file
, Endian
= Endianness
> =
13 MachOSegmentIterator
<'data
, 'file
, macho
::MachHeader32
<Endian
>>;
14 /// An iterator over the segments of a `MachOFile64`.
15 pub type MachOSegmentIterator64
<'data
, 'file
, Endian
= Endianness
> =
16 MachOSegmentIterator
<'data
, 'file
, macho
::MachHeader64
<Endian
>>;
18 /// An iterator over the segments of a `MachOFile`.
20 pub struct MachOSegmentIterator
<'data
, 'file
, Mach
>
25 pub(super) file
: &'file MachOFile
<'data
, Mach
>,
26 pub(super) commands
: MachOLoadCommandIterator
<'data
, Mach
::Endian
>,
29 impl<'data
, 'file
, Mach
: MachHeader
> Iterator
for MachOSegmentIterator
<'data
, 'file
, Mach
> {
30 type Item
= MachOSegment
<'data
, 'file
, Mach
>;
32 fn next(&mut self) -> Option
<Self::Item
> {
34 let command
= self.commands
.next().ok()??
;
35 if let Ok(Some((segment
, _
))) = Mach
::Segment
::from_command(command
) {
36 return Some(MachOSegment
{
45 /// A segment of a `MachOFile32`.
46 pub type MachOSegment32
<'data
, 'file
, Endian
= Endianness
> =
47 MachOSegment
<'data
, 'file
, macho
::MachHeader32
<Endian
>>;
48 /// A segment of a `MachOFile64`.
49 pub type MachOSegment64
<'data
, 'file
, Endian
= Endianness
> =
50 MachOSegment
<'data
, 'file
, macho
::MachHeader64
<Endian
>>;
52 /// A segment of a `MachOFile`.
54 pub struct MachOSegment
<'data
, 'file
, Mach
>
59 file
: &'file MachOFile
<'data
, Mach
>,
60 segment
: &'data Mach
::Segment
,
63 impl<'data
, 'file
, Mach
: MachHeader
> MachOSegment
<'data
, 'file
, Mach
> {
64 fn bytes(&self) -> Result
<Bytes
<'data
>> {
66 .data(self.file
.endian
, self.file
.data
)
67 .read_error("Invalid Mach-O segment size or offset")
71 impl<'data
, 'file
, Mach
: MachHeader
> read
::private
::Sealed
for MachOSegment
<'data
, 'file
, Mach
> {}
73 impl<'data
, 'file
, Mach
: MachHeader
> ObjectSegment
<'data
> for MachOSegment
<'data
, 'file
, Mach
> {
75 fn address(&self) -> u64 {
76 self.segment
.vmaddr(self.file
.endian
).into()
80 fn size(&self) -> u64 {
81 self.segment
.vmsize(self.file
.endian
).into()
85 fn align(&self) -> u64 {
91 fn file_range(&self) -> (u64, u64) {
92 self.segment
.file_range(self.file
.endian
)
95 fn data(&self) -> Result
<&'data
[u8]> {
99 fn data_range(&self, address
: u64, size
: u64) -> Result
<Option
<&'data
[u8]>> {
109 fn name(&self) -> Result
<Option
<&str>> {
111 str::from_utf8(self.segment
.name())
113 .read_error("Non UTF-8 Mach-O segment name")?
,
118 /// A trait for generic access to `SegmentCommand32` and `SegmentCommand64`.
119 #[allow(missing_docs)]
120 pub trait Segment
: Debug
+ Pod
{
121 type Word
: Into
<u64>;
122 type Endian
: endian
::Endian
;
123 type Section
: Section
<Endian
= Self::Endian
>;
125 fn from_command(command
: MachOLoadCommand
<Self::Endian
>) -> Result
<Option
<(&Self, Bytes
)>>;
127 fn cmd(&self, endian
: Self::Endian
) -> u32;
128 fn cmdsize(&self, endian
: Self::Endian
) -> u32;
129 fn segname(&self) -> &[u8; 16];
130 fn vmaddr(&self, endian
: Self::Endian
) -> Self::Word
;
131 fn vmsize(&self, endian
: Self::Endian
) -> Self::Word
;
132 fn fileoff(&self, endian
: Self::Endian
) -> Self::Word
;
133 fn filesize(&self, endian
: Self::Endian
) -> Self::Word
;
134 fn maxprot(&self, endian
: Self::Endian
) -> u32;
135 fn initprot(&self, endian
: Self::Endian
) -> u32;
136 fn nsects(&self, endian
: Self::Endian
) -> u32;
137 fn flags(&self, endian
: Self::Endian
) -> u32;
139 /// Return the `segname` bytes up until the null terminator.
140 fn name(&self) -> &[u8] {
141 let segname
= &self.segname()[..];
142 match segname
.iter().position(|&x
| x
== 0) {
143 Some(end
) => &segname
[..end
],
148 /// Return the offset and size of the segment in the file.
149 fn file_range(&self, endian
: Self::Endian
) -> (u64, u64) {
150 (self.fileoff(endian
).into(), self.filesize(endian
).into())
153 /// Get the segment data from the file data.
155 /// Returns `Err` for invalid values.
158 endian
: Self::Endian
,
160 ) -> result
::Result
<Bytes
<'data
>, ()> {
161 let (offset
, size
) = self.file_range(endian
);
162 data
.read_bytes_at(offset
as usize, size
as usize)
165 /// Get the array of sections from the data following the segment command.
167 /// Returns `Err` for invalid values.
170 endian
: Self::Endian
,
172 ) -> Result
<&'data
[Self::Section
]> {
173 data
.read_slice_at(0, self.nsects(endian
) as usize)
174 .read_error("Invalid Mach-O number of sections")
178 impl<Endian
: endian
::Endian
> Segment
for macho
::SegmentCommand32
<Endian
> {
180 type Endian
= Endian
;
181 type Section
= macho
::Section32
<Self::Endian
>;
183 fn from_command(command
: MachOLoadCommand
<Self::Endian
>) -> Result
<Option
<(&Self, Bytes
)>> {
187 fn cmd(&self, endian
: Self::Endian
) -> u32 {
190 fn cmdsize(&self, endian
: Self::Endian
) -> u32 {
191 self.cmdsize
.get(endian
)
193 fn segname(&self) -> &[u8; 16] {
196 fn vmaddr(&self, endian
: Self::Endian
) -> Self::Word
{
197 self.vmaddr
.get(endian
)
199 fn vmsize(&self, endian
: Self::Endian
) -> Self::Word
{
200 self.vmsize
.get(endian
)
202 fn fileoff(&self, endian
: Self::Endian
) -> Self::Word
{
203 self.fileoff
.get(endian
)
205 fn filesize(&self, endian
: Self::Endian
) -> Self::Word
{
206 self.filesize
.get(endian
)
208 fn maxprot(&self, endian
: Self::Endian
) -> u32 {
209 self.maxprot
.get(endian
)
211 fn initprot(&self, endian
: Self::Endian
) -> u32 {
212 self.initprot
.get(endian
)
214 fn nsects(&self, endian
: Self::Endian
) -> u32 {
215 self.nsects
.get(endian
)
217 fn flags(&self, endian
: Self::Endian
) -> u32 {
218 self.flags
.get(endian
)
222 impl<Endian
: endian
::Endian
> Segment
for macho
::SegmentCommand64
<Endian
> {
224 type Endian
= Endian
;
225 type Section
= macho
::Section64
<Self::Endian
>;
227 fn from_command(command
: MachOLoadCommand
<Self::Endian
>) -> Result
<Option
<(&Self, Bytes
)>> {
231 fn cmd(&self, endian
: Self::Endian
) -> u32 {
234 fn cmdsize(&self, endian
: Self::Endian
) -> u32 {
235 self.cmdsize
.get(endian
)
237 fn segname(&self) -> &[u8; 16] {
240 fn vmaddr(&self, endian
: Self::Endian
) -> Self::Word
{
241 self.vmaddr
.get(endian
)
243 fn vmsize(&self, endian
: Self::Endian
) -> Self::Word
{
244 self.vmsize
.get(endian
)
246 fn fileoff(&self, endian
: Self::Endian
) -> Self::Word
{
247 self.fileoff
.get(endian
)
249 fn filesize(&self, endian
: Self::Endian
) -> Self::Word
{
250 self.filesize
.get(endian
)
252 fn maxprot(&self, endian
: Self::Endian
) -> u32 {
253 self.maxprot
.get(endian
)
255 fn initprot(&self, endian
: Self::Endian
) -> u32 {
256 self.initprot
.get(endian
)
258 fn nsects(&self, endian
: Self::Endian
) -> u32 {
259 self.nsects
.get(endian
)
261 fn flags(&self, endian
: Self::Endian
) -> u32 {
262 self.flags
.get(endian
)