macho2/command/
function_starts.rs1use std::io::{Read, Seek, SeekFrom};
2
3
4use crate::{helpers::read_uleb_many, macho::MachOResult};
5
6use super::{linkedit_data::LinkeditDataCommand, pad_to_size, LCLoadCommand, LoadCommandParser, LoadCommandResolver};
7
8#[derive(Debug, PartialEq, Eq)]
9pub struct FunctionOffset {
10 pub offset: u64,
11 pub size: u64,
12}
13
14#[derive(Debug, PartialEq, Eq)]
15pub struct FunctionStartsCommand {
16 pub cmd: LCLoadCommand,
17 pub cmdsize: u32,
18 pub dataoff: u32,
19 pub datasize: u32,
20}
21
22impl LoadCommandParser for FunctionStartsCommand {
23 fn parse(ldcmd: &[u8]) -> MachOResult<Self> {
24 let (_, linkeditcmd) = LinkeditDataCommand::parse(ldcmd)?;
25 Ok(
26 FunctionStartsCommand {
27 cmd: linkeditcmd.cmd,
28 cmdsize: linkeditcmd.cmdsize,
29 dataoff: linkeditcmd.dataoff,
30 datasize: linkeditcmd.datasize,
31 },
32 )
33 }
34
35 fn serialize(&self) -> Vec<u8> {
36 let mut buf = Vec::new();
37 buf.extend(self.cmd.serialize());
38 buf.extend(self.cmdsize.to_le_bytes());
39 buf.extend(self.dataoff.to_le_bytes());
40 buf.extend(self.datasize.to_le_bytes());
41 pad_to_size(&mut buf, self.cmdsize as usize);
42 buf
43 }
44}
45
46#[derive(Debug, PartialEq, Eq)]
47pub struct FunctionStartsCommandResolved {
48 pub funcs: Vec<FunctionOffset>,
49}
50
51impl<T: Read + Seek> LoadCommandResolver<T, FunctionStartsCommandResolved> for FunctionStartsCommand {
52 fn resolve(&self, buf: &mut T) -> MachOResult<FunctionStartsCommandResolved> {
53 let mut funcs_blob = vec![0u8; self.datasize as usize];
54 buf.seek(SeekFrom::Start(self.dataoff as u64))
55 .unwrap();
56 buf.read_exact(&mut funcs_blob).unwrap();
57
58 let (_, funcs) = read_uleb_many(&funcs_blob).unwrap();
59
60 let funcs: Vec<u64> = funcs.into_iter().skip_while(|&x| x == 0).collect();
62
63 let mut state: u64 = 0;
64 let mut results = vec![];
65 for func in funcs.windows(2) {
66 state = state.wrapping_add(func[0]);
67 results.push(FunctionOffset {
68 offset: state,
69 size: func[1],
70 });
71 }
72
73 Ok(
74 FunctionStartsCommandResolved {
75 funcs: results
76 },
77 )
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::command::LCLoadCommand;
85
86 #[test]
87 fn test_function_starts() {
88 let func_starts = FunctionStartsCommand {
89 cmd: LCLoadCommand::LcFunctionStarts,
90 cmdsize: 0x10,
91 dataoff: 0x20,
92 datasize: 0x30,
93 };
94
95 let serialized = func_starts.serialize();
96 let deserialized = FunctionStartsCommand::parse(&serialized).unwrap();
97 assert_eq!(func_starts, deserialized);
98 }
99}