]> git.proxmox.com Git - rustc.git/blob - vendor/goblin/src/mach/segment.rs
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / vendor / goblin / src / mach / segment.rs
1 use scroll::ctx::{self, SizeWith};
2 use scroll::{Pread, Pwrite};
3
4 use log::{debug, warn};
5
6 use alloc::boxed::Box;
7 use alloc::vec::Vec;
8 use core::fmt;
9 use core::ops::{Deref, DerefMut};
10
11 use crate::container;
12 use crate::error;
13
14 use crate::mach::constants::{SECTION_TYPE, S_GB_ZEROFILL, S_THREAD_LOCAL_ZEROFILL, S_ZEROFILL};
15 use crate::mach::load_command::{
16 Section32, Section64, SegmentCommand32, SegmentCommand64, LC_SEGMENT, LC_SEGMENT_64,
17 SIZEOF_SECTION_32, SIZEOF_SECTION_64, SIZEOF_SEGMENT_COMMAND_32, SIZEOF_SEGMENT_COMMAND_64,
18 };
19 use crate::mach::relocation::RelocationInfo;
20
21 pub struct RelocationIterator<'a> {
22 data: &'a [u8],
23 nrelocs: usize,
24 offset: usize,
25 count: usize,
26 ctx: scroll::Endian,
27 }
28
29 impl<'a> Iterator for RelocationIterator<'a> {
30 type Item = error::Result<RelocationInfo>;
31 fn next(&mut self) -> Option<Self::Item> {
32 if self.count >= self.nrelocs {
33 None
34 } else {
35 self.count += 1;
36 match self.data.gread_with(&mut self.offset, self.ctx) {
37 Ok(res) => Some(Ok(res)),
38 Err(e) => Some(Err(e.into())),
39 }
40 }
41 }
42 }
43
44 /// Generalized 32/64 bit Section
45 #[derive(Default)]
46 pub struct Section {
47 /// name of this section
48 pub sectname: [u8; 16],
49 /// segment this section goes in
50 pub segname: [u8; 16],
51 /// memory address of this section
52 pub addr: u64,
53 /// size in bytes of this section
54 pub size: u64,
55 /// file offset of this section
56 pub offset: u32,
57 /// section alignment (power of 2)
58 pub align: u32,
59 /// file offset of relocation entries
60 pub reloff: u32,
61 /// number of relocation entries
62 pub nreloc: u32,
63 /// flags (section type and attributes
64 pub flags: u32,
65 }
66
67 impl Section {
68 /// The name of this section
69 pub fn name(&self) -> error::Result<&str> {
70 Ok(self.sectname.pread::<&str>(0)?)
71 }
72 /// The containing segment's name
73 pub fn segname(&self) -> error::Result<&str> {
74 Ok(self.segname.pread::<&str>(0)?)
75 }
76 /// Iterate this sections relocations given `data`; `data` must be the original binary
77 pub fn iter_relocations<'b>(
78 &self,
79 data: &'b [u8],
80 ctx: container::Ctx,
81 ) -> RelocationIterator<'b> {
82 let offset = self.reloff as usize;
83 debug!(
84 "Relocations for {} starting at offset: {:#x}",
85 self.name().unwrap_or("BAD_SECTION_NAME"),
86 offset
87 );
88 RelocationIterator {
89 offset,
90 nrelocs: self.nreloc as usize,
91 count: 0,
92 data,
93 ctx: ctx.le,
94 }
95 }
96 }
97
98 impl From<Section> for Section64 {
99 fn from(section: Section) -> Self {
100 Section64 {
101 sectname: section.sectname,
102 segname: section.segname,
103 addr: section.addr as u64,
104 size: section.size as u64,
105 offset: section.offset,
106 align: section.align,
107 reloff: section.reloff,
108 nreloc: section.nreloc,
109 flags: section.flags,
110 reserved1: 0,
111 reserved2: 0,
112 reserved3: 0,
113 }
114 }
115 }
116
117 impl From<Section> for Section32 {
118 fn from(section: Section) -> Self {
119 Section32 {
120 sectname: section.sectname,
121 segname: section.segname,
122 addr: section.addr as u32,
123 size: section.size as u32,
124 offset: section.offset,
125 align: section.align,
126 reloff: section.reloff,
127 nreloc: section.nreloc,
128 flags: section.flags,
129 reserved1: 0,
130 reserved2: 0,
131 }
132 }
133 }
134
135 impl fmt::Debug for Section {
136 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
137 fmt.debug_struct("Section")
138 .field("sectname", &self.name().unwrap())
139 .field("segname", &self.segname().unwrap())
140 .field("addr", &self.addr)
141 .field("size", &self.size)
142 .field("offset", &self.offset)
143 .field("align", &self.align)
144 .field("reloff", &self.reloff)
145 .field("nreloc", &self.nreloc)
146 .field("flags", &self.flags)
147 .finish()
148 }
149 }
150
151 impl From<Section32> for Section {
152 fn from(section: Section32) -> Self {
153 Section {
154 sectname: section.sectname,
155 segname: section.segname,
156 addr: u64::from(section.addr),
157 size: u64::from(section.size),
158 offset: section.offset,
159 align: section.align,
160 reloff: section.reloff,
161 nreloc: section.nreloc,
162 flags: section.flags,
163 }
164 }
165 }
166
167 impl From<Section64> for Section {
168 fn from(section: Section64) -> Self {
169 Section {
170 sectname: section.sectname,
171 segname: section.segname,
172 addr: section.addr,
173 size: section.size,
174 offset: section.offset,
175 align: section.align,
176 reloff: section.reloff,
177 nreloc: section.nreloc,
178 flags: section.flags,
179 }
180 }
181 }
182
183 impl<'a> ctx::TryFromCtx<'a, container::Ctx> for Section {
184 type Error = crate::error::Error;
185 fn try_from_ctx(bytes: &'a [u8], ctx: container::Ctx) -> Result<(Self, usize), Self::Error> {
186 match ctx.container {
187 container::Container::Little => {
188 let section = Section::from(bytes.pread_with::<Section32>(0, ctx.le)?);
189 Ok((section, SIZEOF_SECTION_32))
190 }
191 container::Container::Big => {
192 let section = Section::from(bytes.pread_with::<Section64>(0, ctx.le)?);
193 Ok((section, SIZEOF_SECTION_64))
194 }
195 }
196 }
197 }
198
199 impl ctx::SizeWith<container::Ctx> for Section {
200 fn size_with(ctx: &container::Ctx) -> usize {
201 match ctx.container {
202 container::Container::Little => SIZEOF_SECTION_32,
203 container::Container::Big => SIZEOF_SECTION_64,
204 }
205 }
206 }
207
208 impl ctx::TryIntoCtx<container::Ctx> for Section {
209 type Error = crate::error::Error;
210 fn try_into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) -> Result<usize, Self::Error> {
211 if ctx.is_big() {
212 bytes.pwrite_with::<Section64>(self.into(), 0, ctx.le)?;
213 } else {
214 bytes.pwrite_with::<Section32>(self.into(), 0, ctx.le)?;
215 }
216 Ok(Self::size_with(&ctx))
217 }
218 }
219
220 impl ctx::IntoCtx<container::Ctx> for Section {
221 fn into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) {
222 bytes.pwrite_with(self, 0, ctx).unwrap();
223 }
224 }
225
226 pub struct SectionIterator<'a> {
227 data: &'a [u8],
228 count: usize,
229 offset: usize,
230 idx: usize,
231 ctx: container::Ctx,
232 }
233
234 pub type SectionData<'a> = &'a [u8];
235
236 impl<'a> ::core::iter::ExactSizeIterator for SectionIterator<'a> {
237 fn len(&self) -> usize {
238 self.count
239 }
240 }
241
242 impl<'a> Iterator for SectionIterator<'a> {
243 type Item = error::Result<(Section, SectionData<'a>)>;
244 fn next(&mut self) -> Option<Self::Item> {
245 if self.idx >= self.count {
246 None
247 } else {
248 self.idx += 1;
249 match self.data.gread_with::<Section>(&mut self.offset, self.ctx) {
250 Ok(section) => {
251 let section_type = section.flags & SECTION_TYPE;
252 let data = if section_type == S_ZEROFILL
253 || section_type == S_GB_ZEROFILL
254 || section_type == S_THREAD_LOCAL_ZEROFILL
255 {
256 &[]
257 } else {
258 // it's not uncommon to encounter macho files where files are
259 // truncated but the sections are still remaining in the header.
260 // Because of this we want to not panic here but instead just
261 // slice down to a empty data slice. This way only if code
262 // actually needs to access those sections it will fall over.
263 self.data
264 .get(section.offset as usize..)
265 .unwrap_or_else(|| {
266 warn!(
267 "section #{} offset {} out of bounds",
268 self.idx, section.offset
269 );
270 &[]
271 })
272 .get(..section.size as usize)
273 .unwrap_or_else(|| {
274 warn!("section #{} size {} out of bounds", self.idx, section.size);
275 &[]
276 })
277 };
278 Some(Ok((section, data)))
279 }
280 Err(e) => Some(Err(e)),
281 }
282 }
283 }
284 }
285
286 impl<'a, 'b> IntoIterator for &'b Segment<'a> {
287 type Item = error::Result<(Section, SectionData<'a>)>;
288 type IntoIter = SectionIterator<'a>;
289 fn into_iter(self) -> Self::IntoIter {
290 SectionIterator {
291 data: self.raw_data,
292 count: self.nsects as usize,
293 offset: self.offset + Segment::size_with(&self.ctx),
294 idx: 0,
295 ctx: self.ctx,
296 }
297 }
298 }
299
300 /// Generalized 32/64 bit Segment Command
301 pub struct Segment<'a> {
302 pub cmd: u32,
303 pub cmdsize: u32,
304 pub segname: [u8; 16],
305 pub vmaddr: u64,
306 pub vmsize: u64,
307 pub fileoff: u64,
308 pub filesize: u64,
309 pub maxprot: u32,
310 pub initprot: u32,
311 pub nsects: u32,
312 pub flags: u32,
313 pub data: &'a [u8],
314 offset: usize,
315 raw_data: &'a [u8],
316 ctx: container::Ctx,
317 }
318
319 impl<'a> From<Segment<'a>> for SegmentCommand64 {
320 fn from(segment: Segment<'a>) -> Self {
321 SegmentCommand64 {
322 cmd: segment.cmd,
323 cmdsize: segment.cmdsize,
324 segname: segment.segname,
325 vmaddr: segment.vmaddr as u64,
326 vmsize: segment.vmsize as u64,
327 fileoff: segment.fileoff as u64,
328 filesize: segment.filesize as u64,
329 maxprot: segment.maxprot,
330 initprot: segment.initprot,
331 nsects: segment.nsects,
332 flags: segment.flags,
333 }
334 }
335 }
336
337 impl<'a> From<Segment<'a>> for SegmentCommand32 {
338 fn from(segment: Segment<'a>) -> Self {
339 SegmentCommand32 {
340 cmd: segment.cmd,
341 cmdsize: segment.cmdsize,
342 segname: segment.segname,
343 vmaddr: segment.vmaddr as u32,
344 vmsize: segment.vmsize as u32,
345 fileoff: segment.fileoff as u32,
346 filesize: segment.filesize as u32,
347 maxprot: segment.maxprot,
348 initprot: segment.initprot,
349 nsects: segment.nsects,
350 flags: segment.flags,
351 }
352 }
353 }
354
355 impl<'a> fmt::Debug for Segment<'a> {
356 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
357 fmt.debug_struct("Segment")
358 .field("cmd", &self.cmd)
359 .field("cmdsize", &self.cmdsize)
360 .field("segname", &self.segname.pread::<&str>(0).unwrap())
361 .field("vmaddr", &self.vmaddr)
362 .field("vmsize", &self.vmsize)
363 .field("fileoff", &self.fileoff)
364 .field("filesize", &self.filesize)
365 .field("maxprot", &self.maxprot)
366 .field("initprot", &self.initprot)
367 .field("nsects", &self.nsects)
368 .field("flags", &self.flags)
369 .field("data", &self.data.len())
370 .field(
371 "sections()",
372 &self.sections().map(|sections| {
373 sections
374 .into_iter()
375 .map(|(section, _)| section)
376 .collect::<Vec<_>>()
377 }),
378 )
379 .finish()
380 }
381 }
382
383 impl<'a> ctx::SizeWith<container::Ctx> for Segment<'a> {
384 fn size_with(ctx: &container::Ctx) -> usize {
385 match ctx.container {
386 container::Container::Little => SIZEOF_SEGMENT_COMMAND_32,
387 container::Container::Big => SIZEOF_SEGMENT_COMMAND_64,
388 }
389 }
390 }
391
392 impl<'a> ctx::TryIntoCtx<container::Ctx> for Segment<'a> {
393 type Error = crate::error::Error;
394 fn try_into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) -> Result<usize, Self::Error> {
395 let segment_size = Self::size_with(&ctx);
396 // should be able to write the section data inline after this, but not working at the moment
397 //let section_size = bytes.pwrite(data, segment_size)?;
398 //debug!("Segment size: {} raw section data size: {}", segment_size, data.len());
399 if ctx.is_big() {
400 bytes.pwrite_with::<SegmentCommand64>(self.into(), 0, ctx.le)?;
401 } else {
402 bytes.pwrite_with::<SegmentCommand32>(self.into(), 0, ctx.le)?;
403 }
404 //debug!("Section size: {}", section_size);
405 Ok(segment_size)
406 }
407 }
408
409 impl<'a> ctx::IntoCtx<container::Ctx> for Segment<'a> {
410 fn into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) {
411 bytes.pwrite_with(self, 0, ctx).unwrap();
412 }
413 }
414
415 /// Read data that belongs to a segment if the offset is within the boundaries of bytes.
416 fn segment_data(bytes: &[u8], fileoff: u64, filesize: u64) -> Result<&[u8], error::Error> {
417 let data: &[u8] = if filesize != 0 {
418 bytes.pread_with(fileoff as usize, filesize as usize)?
419 } else {
420 &[]
421 };
422 Ok(data)
423 }
424
425 impl<'a> Segment<'a> {
426 /// Create a new, blank segment, with cmd either `LC_SEGMENT_64`, or `LC_SEGMENT`, depending on `ctx`.
427 /// **NB** You are responsible for providing a correctly marshalled byte array as the sections. You should not use this for anything other than writing.
428 pub fn new(ctx: container::Ctx, sections: &'a [u8]) -> Self {
429 Segment {
430 cmd: if ctx.is_big() {
431 LC_SEGMENT_64
432 } else {
433 LC_SEGMENT
434 },
435 cmdsize: (Self::size_with(&ctx) + sections.len()) as u32,
436 segname: [0; 16],
437 vmaddr: 0,
438 vmsize: 0,
439 fileoff: 0,
440 filesize: 0,
441 maxprot: 0,
442 initprot: 0,
443 nsects: 0,
444 flags: 0,
445 data: sections,
446 offset: 0,
447 raw_data: &[],
448 ctx,
449 }
450 }
451 /// Get the name of this segment
452 pub fn name(&self) -> error::Result<&str> {
453 Ok(self.segname.pread::<&str>(0)?)
454 }
455 /// Get the sections from this segment, erroring if any section couldn't be retrieved
456 pub fn sections(&self) -> error::Result<Vec<(Section, SectionData<'a>)>> {
457 let mut sections = Vec::new();
458 for section in self.into_iter() {
459 sections.push(section?);
460 }
461 Ok(sections)
462 }
463 /// Convert the raw C 32-bit segment command to a generalized version
464 pub fn from_32(
465 bytes: &'a [u8],
466 segment: &SegmentCommand32,
467 offset: usize,
468 ctx: container::Ctx,
469 ) -> Result<Self, error::Error> {
470 Ok(Segment {
471 cmd: segment.cmd,
472 cmdsize: segment.cmdsize,
473 segname: segment.segname,
474 vmaddr: u64::from(segment.vmaddr),
475 vmsize: u64::from(segment.vmsize),
476 fileoff: u64::from(segment.fileoff),
477 filesize: u64::from(segment.filesize),
478 maxprot: segment.maxprot,
479 initprot: segment.initprot,
480 nsects: segment.nsects,
481 flags: segment.flags,
482 data: segment_data(
483 bytes,
484 u64::from(segment.fileoff),
485 u64::from(segment.filesize),
486 )?,
487 offset,
488 raw_data: bytes,
489 ctx,
490 })
491 }
492 /// Convert the raw C 64-bit segment command to a generalized version
493 pub fn from_64(
494 bytes: &'a [u8],
495 segment: &SegmentCommand64,
496 offset: usize,
497 ctx: container::Ctx,
498 ) -> Result<Self, error::Error> {
499 Ok(Segment {
500 cmd: segment.cmd,
501 cmdsize: segment.cmdsize,
502 segname: segment.segname,
503 vmaddr: segment.vmaddr,
504 vmsize: segment.vmsize,
505 fileoff: segment.fileoff,
506 filesize: segment.filesize,
507 maxprot: segment.maxprot,
508 initprot: segment.initprot,
509 nsects: segment.nsects,
510 flags: segment.flags,
511 data: segment_data(bytes, segment.fileoff, segment.filesize)?,
512 offset,
513 raw_data: bytes,
514 ctx,
515 })
516 }
517 }
518
519 #[derive(Debug, Default)]
520 /// An opaque 32/64-bit container for Mach-o segments
521 pub struct Segments<'a> {
522 segments: Vec<Segment<'a>>,
523 ctx: container::Ctx,
524 }
525
526 impl<'a> Deref for Segments<'a> {
527 type Target = Vec<Segment<'a>>;
528 fn deref(&self) -> &Self::Target {
529 &self.segments
530 }
531 }
532
533 impl<'a> DerefMut for Segments<'a> {
534 fn deref_mut(&mut self) -> &mut Self::Target {
535 &mut self.segments
536 }
537 }
538
539 impl<'a, 'b> IntoIterator for &'b Segments<'a> {
540 type Item = &'b Segment<'a>;
541 type IntoIter = ::core::slice::Iter<'b, Segment<'a>>;
542 fn into_iter(self) -> Self::IntoIter {
543 self.segments.iter()
544 }
545 }
546
547 impl<'a> Segments<'a> {
548 /// Construct a new generalized segment container from this `ctx`
549 pub fn new(ctx: container::Ctx) -> Self {
550 Segments {
551 segments: Vec::new(),
552 ctx,
553 }
554 }
555 /// Get every section from every segment
556 // thanks to SpaceManic for figuring out the 'b lifetimes here :)
557 pub fn sections<'b>(&'b self) -> Box<dyn Iterator<Item = SectionIterator<'a>> + 'b> {
558 Box::new(self.segments.iter().map(|segment| segment.into_iter()))
559 }
560 }