1use crate::error::Result;
4use crate::patch::{Location, Rooted};
5use goblin::container::{Container, Ctx, Endian};
6use goblin::mach::load_command::{CommandVariant, SymtabCommand};
7use goblin::mach::symbols::Nlist;
8use goblin::mach::MachO;
9use scroll::ctx::{SizeWith, TryFromCtx};
10use scroll::Pread;
11
12fn context_from_macho(macho: &MachO) -> Ctx {
13 let container = if macho.is_64 {
14 Container::Big
15 } else {
16 Container::Little
17 };
18 let endian = if macho.little_endian {
19 Endian::Little
20 } else {
21 Endian::Big
22 };
23 Ctx::new(container, endian)
24}
25
26pub struct SymtabIter<'a> {
28 bytes: &'a [u8],
29 ctx: Ctx,
30 symoff: usize,
31 stroff: usize,
32 count: usize,
33 index: usize,
34}
35
36impl<'a> SymtabIter<'a> {
37 pub fn from_load_command(bytes: &'a [u8], command: &SymtabCommand, ctx: Ctx) -> Self {
41 Self {
42 bytes,
43 ctx,
44 symoff: command.symoff as usize,
45 stroff: command.stroff as usize,
46 count: command.nsyms as usize,
47 index: 0,
48 }
49 }
50
51 pub fn from_mach(bytes: &'a [u8], mach: &MachO) -> Option<Self> {
55 let ctx = context_from_macho(mach);
56 for command in &mach.load_commands {
57 if let CommandVariant::Symtab(command) = command.command {
58 return Some(Self::from_load_command(bytes, &command, ctx));
59 }
60 }
61 None
62 }
63}
64
65impl<'a> std::iter::Iterator for SymtabIter<'a> {
66 type Item = Result<(Option<Rooted<&'a str>>, Rooted<Nlist>)>;
67
68 fn next(&mut self) -> Option<Self::Item> {
69 if self.index >= self.count {
70 None
71 } else {
72 Some((|| {
73 let nlist_offset = self.symoff + self.index * Nlist::size_with(&self.ctx);
74 self.index += 1;
75 let nlist = {
76 let (nlist, nlist_size) =
77 Nlist::try_from_ctx(&self.bytes[nlist_offset..], self.ctx)?;
78 let location = Location {
79 offset: nlist_offset,
80 size: nlist_size,
81 ctx: self.ctx,
82 };
83 Rooted::new(location, nlist)
84 };
85 let name = if nlist.n_strx != 0 {
86 let offset = self.stroff + nlist.n_strx as usize;
87 let name: &str = self.bytes.pread(offset)?;
88 let location = Location {
89 offset,
90 size: name.len(),
91 ctx: self.ctx,
92 };
93 Some(Rooted::new(location, name))
94 } else {
95 None
96 };
97 Ok((name, nlist))
98 })())
99 }
100 }
101}