atom_macho/load_command/
mod.rs

1pub mod build_version;
2pub mod dysymtab;
3pub mod segment64;
4pub mod source_version;
5pub mod symtab;
6pub mod unix_thread;
7pub mod uuid;
8
9pub use self::{
10    build_version::{BuildToolVersion, BuildVersionCommand},
11    dysymtab::DysymtabCommand,
12    segment64::{Section64, SegmentCommand64},
13    source_version::SourceVersionCommand,
14    symtab::SymtabCommand,
15    unix_thread::UnixThreadCommand,
16    uuid::UuidCommand,
17};
18
19use crate::io::{Endian, ReadExt as _};
20use byteorder::{BigEndian, LittleEndian, WriteBytesExt as _};
21use std::io::{Read, Write};
22
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub enum LoadCommand {
25    Segment64(SegmentCommand64, Vec<Section64>),
26    Symtab(SymtabCommand),
27    UnixThread(UnixThreadCommand),
28    Dysymtab(DysymtabCommand),
29    Uuid(UuidCommand),
30    BuildVersion(BuildVersionCommand, Vec<BuildToolVersion>),
31    SourceVersion(SourceVersionCommand),
32    Unsupported(u32, Vec<u8>),
33}
34
35impl LoadCommand {
36    pub fn cmd(&self) -> u32 {
37        use LoadCommand as LC;
38
39        match self {
40            LC::Segment64(cmd, _) => cmd.cmd,
41            LC::Symtab(cmd) => cmd.cmd,
42            LC::UnixThread(cmd) => cmd.cmd,
43            LC::Dysymtab(cmd) => cmd.cmd,
44            LC::Uuid(cmd) => cmd.cmd,
45            LC::BuildVersion(cmd, _) => cmd.cmd,
46            LC::SourceVersion(cmd) => cmd.cmd,
47            LC::Unsupported(cmd, _) => *cmd,
48        }
49    }
50
51    pub fn cmd_size(&self) -> u32 {
52        use LoadCommand as LC;
53
54        match self {
55            LC::Segment64(cmd, _) => cmd.cmdsize,
56            LC::Symtab(cmd) => cmd.cmdsize,
57            LC::UnixThread(cmd) => cmd.cmdsize,
58            LC::Dysymtab(cmd) => cmd.cmdsize,
59            LC::Uuid(cmd) => cmd.cmdsize,
60            LC::BuildVersion(cmd, _) => cmd.cmdsize,
61            LC::SourceVersion(cmd) => cmd.cmdsize,
62            LC::Unsupported(_, data) => data.len() as u32 - 8,
63        }
64    }
65
66    pub fn read_from_in<R: Read>(read: &mut R, endian: Endian) -> Self {
67        use LoadCommand as LC;
68
69        let cmd = read.read_u32_in(endian);
70
71        let mut cmd_bytes = [0u8; 4];
72        match endian {
73            Endian::Little => (&mut cmd_bytes[..]).write_u32::<LittleEndian>(cmd).unwrap(),
74            Endian::Big => (&mut cmd_bytes[..]).write_u32::<BigEndian>(cmd).unwrap(),
75        };
76
77        let mut read = cmd_bytes.chain(read);
78
79        match cmd {
80            SegmentCommand64::TYPE => {
81                let cmd = SegmentCommand64::read_from_in(&mut read, endian);
82
83                let mut sections = Vec::with_capacity(cmd.nsects as usize);
84                for _ in 0..cmd.nsects {
85                    sections.push(Section64::read_from_in(&mut read, endian));
86                }
87
88                LC::Segment64(cmd, sections)
89            }
90            SymtabCommand::TYPE => {
91                let cmd = SymtabCommand::read_from_in(&mut read, endian);
92                LC::Symtab(cmd)
93            }
94            UnixThreadCommand::TYPE => {
95                let cmd = UnixThreadCommand::read_from_in(&mut read, endian);
96                LC::UnixThread(cmd)
97            }
98            DysymtabCommand::TYPE => {
99                let cmd = DysymtabCommand::read_from_in(&mut read, endian);
100                LC::Dysymtab(cmd)
101            }
102            UuidCommand::TYPE => {
103                let cmd = UuidCommand::read_from_in(&mut read, endian);
104                LC::Uuid(cmd)
105            }
106            BuildVersionCommand::TYPE => {
107                let cmd = BuildVersionCommand::read_from_in(&mut read, endian);
108
109                let mut tools = Vec::with_capacity(cmd.ntools as usize);
110                for _ in 0..cmd.ntools {
111                    tools.push(BuildToolVersion::read_from_in(&mut read, endian));
112                }
113                LC::BuildVersion(cmd, tools)
114            }
115            SourceVersionCommand::TYPE => {
116                let cmd = SourceVersionCommand::read_from_in(&mut read, endian);
117                LC::SourceVersion(cmd)
118            }
119            _ => {
120                let _cmd = read.read_u32_in(endian);
121                let cmdsize = read.read_u32_in(endian) as usize;
122                let mut data = Vec::with_capacity(cmdsize - 8);
123                data.resize(cmdsize - 8, 0);
124                read.read_exact(&mut data).unwrap();
125                LC::Unsupported(cmd, data)
126            }
127        }
128    }
129
130    pub fn write_into<W: Write>(&self, write: &mut W) {
131        use LoadCommand as LC;
132
133        match self {
134            LC::Segment64(cmd, sections) => {
135                cmd.write_into(write);
136                for section in sections.iter() {
137                    section.write_into(write);
138                }
139            }
140            LC::Symtab(cmd) => {
141                cmd.write_into(write);
142            }
143            LC::UnixThread(cmd) => {
144                cmd.write_into(write);
145            }
146            LC::Dysymtab(cmd) => {
147                cmd.write_into(write);
148            }
149            LC::Uuid(cmd) => {
150                cmd.write_into(write);
151            }
152            LC::BuildVersion(cmd, tools) => {
153                cmd.write_into(write);
154                for tool in tools.iter() {
155                    tool.write_into(write);
156                }
157            }
158            LC::SourceVersion(cmd) => {
159                cmd.write_into(write);
160            }
161            LC::Unsupported(_, _) => {
162                panic!("Unsupported LoadCommand is unwritable");
163            }
164        }
165    }
166}