1 use core
::marker
::PhantomData
;
3 use crate::endian
::Endian
;
6 use crate::read
::macho
::{MachHeader, SymbolTable}
;
7 use crate::read
::{ReadError, Result, StringTable}
;
9 /// An iterator over the load commands of a `MachHeader`.
10 #[derive(Debug, Default, Clone, Copy)]
11 pub struct MachOLoadCommandIterator
<'data
, E
: Endian
> {
17 impl<'data
, E
: Endian
> MachOLoadCommandIterator
<'data
, E
> {
18 pub(super) fn new(endian
: E
, data
: Bytes
<'data
>, ncmds
: u32) -> Self {
19 MachOLoadCommandIterator
{
26 /// Return the next load command.
27 pub fn next(&mut self) -> Result
<Option
<MachOLoadCommand
<'data
, E
>>> {
33 .read_at
::<macho
::LoadCommand
<E
>>(0)
34 .read_error("Invalid Mach-O load command header")?
;
35 let cmd
= header
.cmd
.get(self.endian
);
36 let cmdsize
= header
.cmdsize
.get(self.endian
) as usize;
40 .read_error("Invalid Mach-O load command size")?
;
42 Ok(Some(MachOLoadCommand
{
45 marker
: Default
::default(),
50 /// A parsed `LoadCommand`.
51 #[derive(Debug, Clone, Copy)]
52 pub struct MachOLoadCommand
<'data
, E
: Endian
> {
54 // Includes the header.
56 marker
: PhantomData
<E
>,
59 impl<'data
, E
: Endian
> MachOLoadCommand
<'data
, E
> {
60 /// Try to parse this command as a `SegmentCommand32`.
61 pub fn segment_32(self) -> Result
<Option
<(&'data macho
::SegmentCommand32
<E
>, Bytes
<'data
>)>> {
62 if self.cmd
== macho
::LC_SEGMENT
{
63 let mut data
= self.data
;
66 .read_error("Invalid Mach-O LC_SEGMENT command size")?
;
67 Ok(Some((command
, data
)))
73 /// Try to parse this command as a `SymtabCommand`.
74 pub fn symtab(self) -> Result
<Option
<&'data macho
::SymtabCommand
<E
>>> {
75 if self.cmd
== macho
::LC_SYMTAB
{
80 .read_error("Invalid Mach-O LC_SYMTAB command size"),
88 /// Try to parse this command as a `UuidCommand`.
89 pub fn uuid(self) -> Result
<Option
<&'data macho
::UuidCommand
<E
>>> {
90 if self.cmd
== macho
::LC_UUID
{
95 .read_error("Invalid Mach-O LC_UUID command size"),
103 /// Try to parse this command as a `SegmentCommand64`.
104 pub fn segment_64(self) -> Result
<Option
<(&'data macho
::SegmentCommand64
<E
>, Bytes
<'data
>)>> {
105 if self.cmd
== macho
::LC_SEGMENT_64
{
106 let mut data
= self.data
;
109 .read_error("Invalid Mach-O LC_SEGMENT_64 command size")?
;
110 Ok(Some((command
, data
)))
116 /// Try to parse this command as an `EntryPointCommand`.
117 pub fn entry_point(self) -> Result
<Option
<&'data macho
::EntryPointCommand
<E
>>> {
118 if self.cmd
== macho
::LC_MAIN
{
123 .read_error("Invalid Mach-O LC_MAIN command size"),
132 impl<E
: Endian
> macho
::SymtabCommand
<E
> {
133 /// Return the symbol table that this command references.
134 pub fn symbols
<'data
, Mach
: MachHeader
<Endian
= E
>>(
138 ) -> Result
<SymbolTable
<'data
, Mach
>> {
141 self.symoff
.get(endian
) as usize,
142 self.nsyms
.get(endian
) as usize,
144 .read_error("Invalid Mach-O symbol table offset or size")?
;
147 self.stroff
.get(endian
) as usize,
148 self.strsize
.get(endian
) as usize,
150 .read_error("Invalid Mach-O string table offset or size")?
;
151 let strings
= StringTable
::new(strings
);
152 Ok(SymbolTable
::new(symbols
, strings
))