1 use core::fmt::Debug; 2 use core::{result, str}; 3 4 use crate::endian::{self, Endianness}; 5 use crate::macho; 6 use crate::pod::{Bytes, Pod}; 7 use crate::read::{self, ObjectSegment, ReadError, Result}; 8 9 use super::{MachHeader, MachOFile, MachOLoadCommand, MachOLoadCommandIterator, Section}; 10 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>>; 17 18 /// An iterator over the segments of a `MachOFile`. 19 #[derive(Debug)] 20 pub struct MachOSegmentIterator<'data, 'file, Mach> 21 where 22 'data: 'file, 23 Mach: MachHeader, 24 { 25 pub(super) file: &'file MachOFile<'data, Mach>, 26 pub(super) commands: MachOLoadCommandIterator<'data, Mach::Endian>, 27 } 28 29 impl<'data, 'file, Mach: MachHeader> Iterator for MachOSegmentIterator<'data, 'file, Mach> { 30 type Item = MachOSegment<'data, 'file, Mach>; 31 next(&mut self) -> Option<Self::Item>32 fn next(&mut self) -> Option<Self::Item> { 33 loop { 34 let command = self.commands.next().ok()??; 35 if let Ok(Some((segment, _))) = Mach::Segment::from_command(command) { 36 return Some(MachOSegment { 37 file: self.file, 38 segment, 39 }); 40 } 41 } 42 } 43 } 44 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>>; 51 52 /// A segment of a `MachOFile`. 53 #[derive(Debug)] 54 pub struct MachOSegment<'data, 'file, Mach> 55 where 56 'data: 'file, 57 Mach: MachHeader, 58 { 59 file: &'file MachOFile<'data, Mach>, 60 segment: &'data Mach::Segment, 61 } 62 63 impl<'data, 'file, Mach: MachHeader> MachOSegment<'data, 'file, Mach> { bytes(&self) -> Result<Bytes<'data>>64 fn bytes(&self) -> Result<Bytes<'data>> { 65 self.segment 66 .data(self.file.endian, self.file.data) 67 .read_error("Invalid Mach-O segment size or offset") 68 } 69 } 70 71 impl<'data, 'file, Mach: MachHeader> read::private::Sealed for MachOSegment<'data, 'file, Mach> {} 72 73 impl<'data, 'file, Mach: MachHeader> ObjectSegment<'data> for MachOSegment<'data, 'file, Mach> { 74 #[inline] address(&self) -> u6475 fn address(&self) -> u64 { 76 self.segment.vmaddr(self.file.endian).into() 77 } 78 79 #[inline] size(&self) -> u6480 fn size(&self) -> u64 { 81 self.segment.vmsize(self.file.endian).into() 82 } 83 84 #[inline] align(&self) -> u6485 fn align(&self) -> u64 { 86 // Page size. 87 0x1000 88 } 89 90 #[inline] file_range(&self) -> (u64, u64)91 fn file_range(&self) -> (u64, u64) { 92 self.segment.file_range(self.file.endian) 93 } 94 data(&self) -> Result<&'data [u8]>95 fn data(&self) -> Result<&'data [u8]> { 96 Ok(self.bytes()?.0) 97 } 98 data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>99 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { 100 Ok(read::data_range( 101 self.bytes()?, 102 self.address(), 103 address, 104 size, 105 )) 106 } 107 108 #[inline] name(&self) -> Result<Option<&str>>109 fn name(&self) -> Result<Option<&str>> { 110 Ok(Some( 111 str::from_utf8(self.segment.name()) 112 .ok() 113 .read_error("Non UTF-8 Mach-O segment name")?, 114 )) 115 } 116 } 117 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>; 124 from_command(command: MachOLoadCommand<Self::Endian>) -> Result<Option<(&Self, Bytes)>>125 fn from_command(command: MachOLoadCommand<Self::Endian>) -> Result<Option<(&Self, Bytes)>>; 126 cmd(&self, endian: Self::Endian) -> u32127 fn cmd(&self, endian: Self::Endian) -> u32; cmdsize(&self, endian: Self::Endian) -> u32128 fn cmdsize(&self, endian: Self::Endian) -> u32; segname(&self) -> &[u8; 16]129 fn segname(&self) -> &[u8; 16]; vmaddr(&self, endian: Self::Endian) -> Self::Word130 fn vmaddr(&self, endian: Self::Endian) -> Self::Word; vmsize(&self, endian: Self::Endian) -> Self::Word131 fn vmsize(&self, endian: Self::Endian) -> Self::Word; fileoff(&self, endian: Self::Endian) -> Self::Word132 fn fileoff(&self, endian: Self::Endian) -> Self::Word; filesize(&self, endian: Self::Endian) -> Self::Word133 fn filesize(&self, endian: Self::Endian) -> Self::Word; maxprot(&self, endian: Self::Endian) -> u32134 fn maxprot(&self, endian: Self::Endian) -> u32; initprot(&self, endian: Self::Endian) -> u32135 fn initprot(&self, endian: Self::Endian) -> u32; nsects(&self, endian: Self::Endian) -> u32136 fn nsects(&self, endian: Self::Endian) -> u32; flags(&self, endian: Self::Endian) -> u32137 fn flags(&self, endian: Self::Endian) -> u32; 138 139 /// Return the `segname` bytes up until the null terminator. name(&self) -> &[u8]140 fn name(&self) -> &[u8] { 141 let segname = &self.segname()[..]; 142 match segname.iter().position(|&x| x == 0) { 143 Some(end) => &segname[..end], 144 None => segname, 145 } 146 } 147 148 /// Return the offset and size of the segment in the file. file_range(&self, endian: Self::Endian) -> (u64, u64)149 fn file_range(&self, endian: Self::Endian) -> (u64, u64) { 150 (self.fileoff(endian).into(), self.filesize(endian).into()) 151 } 152 153 /// Get the segment data from the file data. 154 /// 155 /// Returns `Err` for invalid values. data<'data>( &self, endian: Self::Endian, data: Bytes<'data>, ) -> result::Result<Bytes<'data>, ()>156 fn data<'data>( 157 &self, 158 endian: Self::Endian, 159 data: Bytes<'data>, 160 ) -> result::Result<Bytes<'data>, ()> { 161 let (offset, size) = self.file_range(endian); 162 data.read_bytes_at(offset as usize, size as usize) 163 } 164 165 /// Get the array of sections from the data following the segment command. 166 /// 167 /// Returns `Err` for invalid values. sections<'data>( &self, endian: Self::Endian, data: Bytes<'data>, ) -> Result<&'data [Self::Section]>168 fn sections<'data>( 169 &self, 170 endian: Self::Endian, 171 data: Bytes<'data>, 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") 175 } 176 } 177 178 impl<Endian: endian::Endian> Segment for macho::SegmentCommand32<Endian> { 179 type Word = u32; 180 type Endian = Endian; 181 type Section = macho::Section32<Self::Endian>; 182 from_command(command: MachOLoadCommand<Self::Endian>) -> Result<Option<(&Self, Bytes)>>183 fn from_command(command: MachOLoadCommand<Self::Endian>) -> Result<Option<(&Self, Bytes)>> { 184 command.segment_32() 185 } 186 cmd(&self, endian: Self::Endian) -> u32187 fn cmd(&self, endian: Self::Endian) -> u32 { 188 self.cmd.get(endian) 189 } cmdsize(&self, endian: Self::Endian) -> u32190 fn cmdsize(&self, endian: Self::Endian) -> u32 { 191 self.cmdsize.get(endian) 192 } segname(&self) -> &[u8; 16]193 fn segname(&self) -> &[u8; 16] { 194 &self.segname 195 } vmaddr(&self, endian: Self::Endian) -> Self::Word196 fn vmaddr(&self, endian: Self::Endian) -> Self::Word { 197 self.vmaddr.get(endian) 198 } vmsize(&self, endian: Self::Endian) -> Self::Word199 fn vmsize(&self, endian: Self::Endian) -> Self::Word { 200 self.vmsize.get(endian) 201 } fileoff(&self, endian: Self::Endian) -> Self::Word202 fn fileoff(&self, endian: Self::Endian) -> Self::Word { 203 self.fileoff.get(endian) 204 } filesize(&self, endian: Self::Endian) -> Self::Word205 fn filesize(&self, endian: Self::Endian) -> Self::Word { 206 self.filesize.get(endian) 207 } maxprot(&self, endian: Self::Endian) -> u32208 fn maxprot(&self, endian: Self::Endian) -> u32 { 209 self.maxprot.get(endian) 210 } initprot(&self, endian: Self::Endian) -> u32211 fn initprot(&self, endian: Self::Endian) -> u32 { 212 self.initprot.get(endian) 213 } nsects(&self, endian: Self::Endian) -> u32214 fn nsects(&self, endian: Self::Endian) -> u32 { 215 self.nsects.get(endian) 216 } flags(&self, endian: Self::Endian) -> u32217 fn flags(&self, endian: Self::Endian) -> u32 { 218 self.flags.get(endian) 219 } 220 } 221 222 impl<Endian: endian::Endian> Segment for macho::SegmentCommand64<Endian> { 223 type Word = u64; 224 type Endian = Endian; 225 type Section = macho::Section64<Self::Endian>; 226 from_command(command: MachOLoadCommand<Self::Endian>) -> Result<Option<(&Self, Bytes)>>227 fn from_command(command: MachOLoadCommand<Self::Endian>) -> Result<Option<(&Self, Bytes)>> { 228 command.segment_64() 229 } 230 cmd(&self, endian: Self::Endian) -> u32231 fn cmd(&self, endian: Self::Endian) -> u32 { 232 self.cmd.get(endian) 233 } cmdsize(&self, endian: Self::Endian) -> u32234 fn cmdsize(&self, endian: Self::Endian) -> u32 { 235 self.cmdsize.get(endian) 236 } segname(&self) -> &[u8; 16]237 fn segname(&self) -> &[u8; 16] { 238 &self.segname 239 } vmaddr(&self, endian: Self::Endian) -> Self::Word240 fn vmaddr(&self, endian: Self::Endian) -> Self::Word { 241 self.vmaddr.get(endian) 242 } vmsize(&self, endian: Self::Endian) -> Self::Word243 fn vmsize(&self, endian: Self::Endian) -> Self::Word { 244 self.vmsize.get(endian) 245 } fileoff(&self, endian: Self::Endian) -> Self::Word246 fn fileoff(&self, endian: Self::Endian) -> Self::Word { 247 self.fileoff.get(endian) 248 } filesize(&self, endian: Self::Endian) -> Self::Word249 fn filesize(&self, endian: Self::Endian) -> Self::Word { 250 self.filesize.get(endian) 251 } maxprot(&self, endian: Self::Endian) -> u32252 fn maxprot(&self, endian: Self::Endian) -> u32 { 253 self.maxprot.get(endian) 254 } initprot(&self, endian: Self::Endian) -> u32255 fn initprot(&self, endian: Self::Endian) -> u32 { 256 self.initprot.get(endian) 257 } nsects(&self, endian: Self::Endian) -> u32258 fn nsects(&self, endian: Self::Endian) -> u32 { 259 self.nsects.get(endian) 260 } flags(&self, endian: Self::Endian) -> u32261 fn flags(&self, endian: Self::Endian) -> u32 { 262 self.flags.get(endian) 263 } 264 } 265