1use std::fmt;
2
3use time::macros::format_description;
4
5use crate::commands::{LcString, LoadCommand, Section};
6use crate::consts::*;
7use crate::loader::{ArHeader, FatHeader, MachCommand, MachHeader};
8use crate::symbol::Symbol;
9
10impl fmt::Display for MachHeader {
11 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
12 writeln!(f, "Mach header")?;
13 writeln!(
14 f,
15 " magic cputype cpusubtype caps filetype ncmds sizeofcmds \
16 flags"
17 )?;
18 writeln!(
19 f,
20 " 0x{:08x} {:7} {:10} 0x{:02x} {:10} {:5} {:10} 0x{:08x}",
21 self.magic,
22 self.cputype,
23 get_cpu_subtype_type(self.cpusubtype),
24 get_cpu_subtype_feature(self.cpusubtype),
25 self.filetype,
26 self.ncmds,
27 self.sizeofcmds,
28 self.flags
29 )
30 }
31}
32
33impl fmt::Display for FatHeader {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 writeln!(f, "Fat headers")?;
36 writeln!(f, "fat_magic 0x{:08x}", self.magic)?;
37 writeln!(f, "nfat_arch {}", self.archs.len())?;
38
39 for (i, arch) in self.archs.iter().enumerate() {
40 writeln!(f, "architecture {}", i)?;
41 writeln!(f, " cputype {}", arch.cputype)?;
42 writeln!(f, " cpusubtype {}", get_cpu_subtype_type(arch.cpusubtype))?;
43 writeln!(f, " capabilities 0x{:x}", get_cpu_subtype_feature(arch.cpusubtype))?;
44 writeln!(f, " offset {}", arch.offset)?;
45 writeln!(f, " size {}", arch.size)?;
46 writeln!(f, " align 2^{} ({})", arch.align, 1 << arch.align)?;
47 }
48
49 Ok(())
50 }
51}
52
53impl fmt::Display for ArHeader {
54 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55 writeln!(
56 f,
57 "0{:o} {:3}/{:<3} {:5} {} {}",
58 self.ar_mode, self.ar_uid, self.ar_gid, self.ar_size, self.ar_date, self.ar_name
59 )
60 }
61}
62
63impl MachCommand {
64 fn print_segment_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 let MachCommand(ref cmd, cmdsize) = *self;
66
67 match *cmd {
68 LoadCommand::Segment {
69 ref segname,
70 vmaddr,
71 vmsize,
72 fileoff,
73 filesize,
74 maxprot,
75 initprot,
76 flags,
77 ref sections,
78 }
79 | LoadCommand::Segment64 {
80 ref segname,
81 vmaddr,
82 vmsize,
83 fileoff,
84 filesize,
85 maxprot,
86 initprot,
87 flags,
88 ref sections,
89 } => {
90 let is_64bit = cmd.cmd() == LC_SEGMENT_64;
91
92 writeln!(f, " cmd {}", cmd.name())?;
93 writeln!(f, " cmdsize {}", cmdsize)?;
94 writeln!(f, " segname {}", segname)?;
95 if is_64bit {
96 writeln!(f, " vmaddr 0x{:016x}", vmaddr)?;
97 writeln!(f, " vmsize 0x{:016x}", vmsize)?;
98 } else {
99 writeln!(f, " vmaddr 0x{:08x}", vmaddr)?;
100 writeln!(f, " vmsize 0x{:08x}", vmsize)?;
101 }
102 writeln!(f, " fileoff {}", fileoff)?;
103 writeln!(f, " filesize {}", filesize)?;
104 writeln!(f, " maxprot 0x{:08x}", maxprot)?;
105 writeln!(f, " initprot 0x{:08x}", initprot)?;
106 writeln!(f, " nsects {}", sections.len())?;
107 writeln!(f, " flags 0x{:x}", flags.bits())?;
108
109 for section in sections {
110 writeln!(f, "Section")?;
111 writeln!(f, " sectname {}", section.sectname)?;
112 writeln!(
113 f,
114 " segname {}{}",
115 section.segname,
116 if *segname != section.segname {
117 " (does not match segment)"
118 } else {
119 ""
120 }
121 )?;
122 if is_64bit {
123 writeln!(f, " addr 0x{:016x}", section.addr)?;
124 writeln!(f, " size 0x{:016x}", section.size)?;
125 } else {
126 writeln!(f, " addr 0x{:08x}", section.addr)?;
127 writeln!(f, " size 0x{:08x}", section.size)?;
128 }
129 writeln!(f, " offset {}", section.offset)?;
130 writeln!(f, " align 2^{} ({})", section.align, 1 << section.align)?;
131 writeln!(f, " reloff {}", section.reloff)?;
132 writeln!(f, " nreloc {}", section.nreloc)?;
133 let flags: u32 = section.flags.into();
134 writeln!(f, " flags 0x{:08x}", flags)?;
135 writeln!(
136 f,
137 " reserved1 {}{}",
138 section.reserved1,
139 match section.flags.sect_type() {
140 S_SYMBOL_STUBS
141 | S_LAZY_SYMBOL_POINTERS
142 | S_LAZY_DYLIB_SYMBOL_POINTERS
143 | S_NON_LAZY_SYMBOL_POINTERS => " (index into indirect symbol table)",
144 _ => "",
145 }
146 )?;
147 writeln!(
148 f,
149 " reserved2 {}{}",
150 section.reserved2,
151 if section.flags.sect_type() == S_SYMBOL_STUBS {
152 " (size of stubs)"
153 } else {
154 ""
155 }
156 )?;
157 }
158
159 Ok(())
160 }
161 _ => {
162 unreachable!();
163 }
164 }
165 }
166
167 fn print_dyld_info_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
168 let MachCommand(ref cmd, cmdsize) = *self;
169
170 if let LoadCommand::DyldInfo {
171 rebase_off,
172 rebase_size,
173 bind_off,
174 bind_size,
175 weak_bind_off,
176 weak_bind_size,
177 lazy_bind_off,
178 lazy_bind_size,
179 export_off,
180 export_size,
181 } = *cmd
182 {
183 writeln!(f, " cmd {}", cmd.name())?;
184 writeln!(f, " cmdsize {}", cmdsize)?;
185 writeln!(f, " rebase_off 0x{:08x}", rebase_off)?;
186 writeln!(f, " rebase_size {}", rebase_size)?;
187 writeln!(f, " bind_off 0x{:08x}", bind_off)?;
188 writeln!(f, " bind_size {}", bind_size)?;
189 writeln!(f, " weak_bind_off 0x{:08x}", weak_bind_off)?;
190 writeln!(f, " weak_bind_size {}", weak_bind_size)?;
191 writeln!(f, " lazy_bind_off 0x{:08x}", lazy_bind_off)?;
192 writeln!(f, " lazy_bind_size {}", lazy_bind_size)?;
193 writeln!(f, " export_off 0x{:08x}", export_off)?;
194 writeln!(f, " export_size {}", export_size)?;
195
196 Ok(())
197 } else {
198 unreachable!();
199 }
200 }
201
202 fn print_symtab_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
203 let MachCommand(ref cmd, cmdsize) = *self;
204
205 if let LoadCommand::SymTab {
206 symoff,
207 nsyms,
208 stroff,
209 strsize,
210 } = *cmd
211 {
212 writeln!(f, " cmd {}", cmd.name())?;
213 writeln!(f, " cmdsize {}", cmdsize)?;
214 writeln!(f, " symoff {}", symoff)?;
215 writeln!(f, " nsyms {}", nsyms)?;
216 writeln!(f, " stroff {}", stroff)?;
217 writeln!(f, " strsize {}", strsize)?;
218
219 Ok(())
220 } else {
221 unreachable!();
222 }
223 }
224
225 fn print_dysymtab_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
226 let MachCommand(ref cmd, cmdsize) = *self;
227
228 if let LoadCommand::DySymTab {
229 ilocalsym,
230 nlocalsym,
231 iextdefsym,
232 nextdefsym,
233 iundefsym,
234 nundefsym,
235 tocoff,
236 ntoc,
237 modtaboff,
238 nmodtab,
239 extrefsymoff,
240 nextrefsyms,
241 indirectsymoff,
242 nindirectsyms,
243 extreloff,
244 nextrel,
245 locreloff,
246 nlocrel,
247 } = *cmd
248 {
249 writeln!(f, " cmd {}", cmd.name())?;
250 writeln!(f, " cmdsize {}", cmdsize)?;
251 writeln!(f, " ilocalsym {}", ilocalsym)?;
252 writeln!(f, " nlocalsym {}", nlocalsym)?;
253 writeln!(f, " iextdefsym {}", iextdefsym)?;
254 writeln!(f, " nextdefsym {}", nextdefsym)?;
255 writeln!(f, " iundefsym {}", iundefsym)?;
256 writeln!(f, " nundefsym {}", nundefsym)?;
257 writeln!(f, " tocoff {}", tocoff)?;
258 writeln!(f, " ntoc {}", ntoc)?;
259 writeln!(f, " modtaboff {}", modtaboff)?;
260 writeln!(f, " nmodtab {}", nmodtab)?;
261 writeln!(f, " extrefsymoff {}", extrefsymoff)?;
262 writeln!(f, " nextrefsyms {}", nextrefsyms)?;
263 writeln!(f, " indirectsymoff {}", indirectsymoff)?;
264 writeln!(f, " nindirectsyms {}", nindirectsyms)?;
265 writeln!(f, " extreloff {}", extreloff)?;
266 writeln!(f, " nextrel {}", nextrel)?;
267 writeln!(f, " locreloff {}", locreloff)?;
268 writeln!(f, " nlocrel {}", nlocrel)?;
269
270 Ok(())
271 } else {
272 unreachable!();
273 }
274 }
275
276 fn print_dylinker_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
277 let MachCommand(ref cmd, cmdsize) = *self;
278
279 match *cmd {
280 LoadCommand::IdDyLinker(LcString(off, ref name))
281 | LoadCommand::LoadDyLinker(LcString(off, ref name))
282 | LoadCommand::DyLdEnv(LcString(off, ref name)) => {
283 writeln!(f, " cmd {}", cmd.name())?;
284 writeln!(f, " cmdsize {}", cmdsize)?;
285 writeln!(f, " name {} (offset {})", name, off)?;
286
287 Ok(())
288 }
289 _ => {
290 unreachable!();
291 }
292 }
293 }
294
295 fn print_fvmlib_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
296 let MachCommand(ref cmd, cmdsize) = *self;
297
298 match *cmd {
299 LoadCommand::IdFvmLib(ref fvmlib) | LoadCommand::LoadFvmLib(ref fvmlib) => {
300 writeln!(f, " cmd {}", cmd.name())?;
301 writeln!(f, " cmdsize {}", cmdsize)?;
302 writeln!(f, " minor version {}", fvmlib.minor_version)?;
303 writeln!(f, " header addr 0x{:08x}", fvmlib.header_addr)?;
304
305 Ok(())
306 }
307 _ => {
308 unreachable!();
309 }
310 }
311 }
312
313 fn print_dylib_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
314 let time_format = format_description!(
315 "[weekday repr:short] [month repr:short] [day padding:space] [hour]:[minute]:[second] [year] UTC"
316 );
317
318 let MachCommand(ref cmd, cmdsize) = *self;
319
320 match *cmd {
321 LoadCommand::IdDyLib(ref dylib)
322 | LoadCommand::LoadDyLib(ref dylib)
323 | LoadCommand::LoadWeakDyLib(ref dylib)
324 | LoadCommand::ReexportDyLib(ref dylib)
325 | LoadCommand::LoadUpwardDylib(ref dylib)
326 | LoadCommand::LazyLoadDylib(ref dylib) => {
327 writeln!(f, " cmd {}", cmd.name())?;
328 writeln!(f, " cmdsize {}", cmdsize)?;
329 writeln!(f, " name {} (offset {})", dylib.name, dylib.name.0)?;
330 let ts = time::OffsetDateTime::from_unix_timestamp(i64::from(dylib.timestamp)).unwrap();
331 writeln!(
332 f,
333 " time stamp {} {}",
334 dylib.timestamp,
335 ts.format(&time_format).unwrap()
336 )?;
337 writeln!(
338 f,
339 " current version {}.{}.{}",
340 dylib.current_version.major(),
341 dylib.current_version.minor(),
342 dylib.current_version.release()
343 )?;
344 writeln!(
345 f,
346 "compatibility version {}.{}.{}",
347 dylib.compatibility_version.major(),
348 dylib.compatibility_version.minor(),
349 dylib.compatibility_version.release()
350 )?;
351
352 Ok(())
353 }
354 _ => {
355 unreachable!();
356 }
357 }
358 }
359
360 fn print_rpath_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
361 let MachCommand(ref cmd, cmdsize) = *self;
362
363 if let LoadCommand::Rpath(ref path) = *cmd {
364 writeln!(f, " cmd {}", cmd.name())?;
365 writeln!(f, " cmdsize {}", cmdsize)?;
366 writeln!(f, " path {}", path)?;
367
368 Ok(())
369 } else {
370 unreachable!();
371 }
372 }
373
374 fn print_version_min_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
375 let MachCommand(ref cmd, cmdsize) = *self;
376
377 if let LoadCommand::VersionMin { version, sdk, .. } = *cmd {
378 writeln!(f, " cmd {}", cmd.name())?;
379 writeln!(f, " cmdsize {}", cmdsize)?;
380 writeln!(f, " version {}", version)?;
381 writeln!(f, " sdk {}", sdk)?;
382
383 Ok(())
384 } else {
385 unreachable!();
386 }
387 }
388
389 fn print_source_version_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
390 let MachCommand(ref cmd, cmdsize) = *self;
391
392 if let LoadCommand::SourceVersion(version) = *cmd {
393 writeln!(f, " cmd {}", cmd.name())?;
394 writeln!(f, " cmdsize {}", cmdsize)?;
395 writeln!(f, " version {}", version)?;
396
397 Ok(())
398 } else {
399 unreachable!();
400 }
401 }
402
403 fn print_uuid_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
404 let MachCommand(ref cmd, cmdsize) = *self;
405
406 if let LoadCommand::Uuid(ref uuid) = *cmd {
407 writeln!(f, " cmd {}", cmd.name())?;
408 writeln!(f, " cmdsize {}", cmdsize)?;
409 writeln!(f, " uuid {}", uuid.to_string().to_uppercase())?;
410
411 Ok(())
412 } else {
413 unreachable!();
414 }
415 }
416
417 fn print_entry_point_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
418 let MachCommand(ref cmd, cmdsize) = *self;
419
420 if let LoadCommand::EntryPoint { entryoff, stacksize } = *cmd {
421 writeln!(f, " cmd {}", cmd.name())?;
422 writeln!(f, " cmdsize {}", cmdsize)?;
423 writeln!(f, " entryoff {}", entryoff)?;
424 writeln!(f, " stacksize {}", stacksize)?;
425
426 Ok(())
427 } else {
428 unreachable!();
429 }
430 }
431
432 fn print_linkedit_data_command(&self, f: &mut fmt::Formatter) -> fmt::Result {
433 let MachCommand(ref cmd, cmdsize) = *self;
434
435 match *cmd {
436 LoadCommand::CodeSignature(ref data)
437 | LoadCommand::SegmentSplitInfo(ref data)
438 | LoadCommand::FunctionStarts(ref data)
439 | LoadCommand::DataInCode(ref data)
440 | LoadCommand::DylibCodeSignDrs(ref data)
441 | LoadCommand::LinkerOptimizationHint(ref data) => {
442 writeln!(f, " cmd {}", cmd.name())?;
443 writeln!(f, " cmdsize {}", cmdsize)?;
444 writeln!(f, " dataoff {}", data.off)?;
445 writeln!(f, " datasize {}", data.size)?;
446
447 Ok(())
448 }
449 _ => {
450 unreachable!();
451 }
452 }
453 }
454
455 fn print_build_version(&self, f: &mut fmt::Formatter) -> fmt::Result {
456 let MachCommand(ref cmd, cmdsize) = *self;
457
458 match *cmd {
459 LoadCommand::BuildVersion(ref version) => {
460 writeln!(f, " cmd {}", cmd.name())?;
461 writeln!(f, " cmdsize {}", cmdsize)?;
462 writeln!(f, " platform {:?}", version.platform())?;
463 writeln!(f, " minos {}", version.minos)?;
464 writeln!(f, " sdk {}", version.sdk)?;
465 writeln!(f, " tools")?;
466
467 for tool in &version.build_tools {
468 writeln!(f, " {:?} {}", tool.tool(), tool.version)?;
469 }
470
471 Ok(())
472 }
473 _ => unreachable!(),
474 }
475 }
476}
477
478impl fmt::Display for MachCommand {
479 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
480 match self.0 {
481 LoadCommand::Segment { .. } | LoadCommand::Segment64 { .. } => self.print_segment_command(f),
482 LoadCommand::DyldInfo { .. } => self.print_dyld_info_command(f),
483 LoadCommand::SymTab { .. } => self.print_symtab_command(f),
484 LoadCommand::DySymTab { .. } => self.print_dysymtab_command(f),
485 LoadCommand::IdDyLinker(_) | LoadCommand::LoadDyLinker(_) | LoadCommand::DyLdEnv(_) => {
486 self.print_dylinker_command(f)
487 }
488 LoadCommand::IdFvmLib(_) | LoadCommand::LoadFvmLib(_) => self.print_fvmlib_command(f),
489 LoadCommand::IdDyLib(_)
490 | LoadCommand::LoadDyLib(_)
491 | LoadCommand::LoadWeakDyLib(_)
492 | LoadCommand::ReexportDyLib(_)
493 | LoadCommand::LoadUpwardDylib(_)
494 | LoadCommand::LazyLoadDylib(_) => self.print_dylib_command(f),
495 LoadCommand::Rpath(_) => self.print_rpath_command(f),
496 LoadCommand::VersionMin { .. } => self.print_version_min_command(f),
497 LoadCommand::SourceVersion(_) => self.print_source_version_command(f),
498 LoadCommand::Uuid(_) => self.print_uuid_command(f),
499 LoadCommand::EntryPoint { .. } => self.print_entry_point_command(f),
500 LoadCommand::CodeSignature(_)
501 | LoadCommand::SegmentSplitInfo(_)
502 | LoadCommand::FunctionStarts(_)
503 | LoadCommand::DataInCode(_)
504 | LoadCommand::DylibCodeSignDrs(_)
505 | LoadCommand::LinkerOptimizationHint(_) => self.print_linkedit_data_command(f),
506 LoadCommand::BuildVersion { .. } => self.print_build_version(f),
507 _ => {
508 warn!("ignore command: {:?}", self);
509
510 Ok(())
511 }
512 }
513 }
514}
515
516impl<'a> fmt::Display for Symbol<'a> {
517 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
518 match *self {
519 Symbol::Undefined { ref name, external, .. } => write!(
520 f,
521 " {} {}",
522 if external { "U" } else { "u" },
523 name.unwrap_or("")
524 ),
525 Symbol::Absolute {
526 ref name,
527 external,
528 entry,
529 ..
530 } => write!(
531 f,
532 "{:016x} {} {}",
533 entry,
534 if external { "A" } else { "a" },
535 name.unwrap_or("")
536 ),
537 Symbol::Defined {
538 ref name,
539 external,
540 ref section,
541 entry,
542 ..
543 } => {
544 let mut symtype = "s";
545
546 if let Some(ref section) = *section {
547 let Section {
548 ref sectname,
549 ref segname,
550 ..
551 } = **section;
552
553 if segname == SEG_TEXT && sectname == SECT_TEXT {
554 symtype = "t"
555 } else if segname == SEG_DATA {
556 if sectname == SECT_DATA {
557 symtype = "d"
558 } else if sectname == SECT_BSS {
559 symtype = "b"
560 } else if sectname == SECT_COMMON {
561 symtype = "c"
562 }
563 }
564 }
565
566 write!(
567 f,
568 "{:016x} {} {}",
569 entry,
570 if external {
571 symtype.to_uppercase()
572 } else {
573 symtype.to_lowercase()
574 },
575 name.unwrap_or("")
576 )
577 }
578 Symbol::Prebound { ref name, external, .. } => write!(
579 f,
580 " {} {}",
581 if external { "P" } else { "p" },
582 name.unwrap_or("")
583 ),
584 Symbol::Indirect { ref name, external, .. } => write!(
585 f,
586 " {} {}",
587 if external { "I" } else { "i" },
588 name.unwrap_or("")
589 ),
590 Symbol::Debug { ref name, addr, .. } => {
591 if addr == 0 {
592 write!(f, " d {}", name.unwrap_or(""))
593 } else {
594 write!(f, "{:016x} d {}", addr, name.unwrap_or(""))
595 }
596 }
597 }
598 }
599}
600
601#[cfg(test)]
602pub mod tests {
603 use std::io::Write;
604 use std::str;
605
606 use diff;
607
608 use crate::loader::OFile;
609
610 static HELLO_WORLD_BIN: &'static [u8] = include_bytes!("../tests/helloworld");
611 static HELLO_WORLD_LC: &'static str = include_str!("../tests/helloworld.lc");
612 static HELLO_UNIVERSAL_BIN: &'static [u8] = include_bytes!("../tests/helloworld.universal");
613 static HELLO_UNIVERSAL_I386_LC: &'static str = include_str!(
614 "../tests/helloworld.universal.\
615 i386.lc"
616 );
617 static HELLO_UNIVERSAL_X86_64_LC: &'static str = include_str!(
618 "../tests/helloworld.universal.\
619 x86_64.lc"
620 );
621 static HELLO_OBJC_BIN: &'static [u8] = include_bytes!("../tests/helloobjc");
622 static HELLO_OBJC_LC: &'static str = include_str!("../tests/helloobjc.lc");
623 static HELLO_RUST_BIN: &'static [u8] = include_bytes!("../tests/hellorust");
624 static HELLO_RUST_LC: &'static str = include_str!("../tests/hellorust.lc");
625
626 macro_rules! parse_test_file {
627 ($buf:expr) => {{
628 let _ = ::pretty_env_logger::try_init();
629
630 let mut cursor = ::std::io::Cursor::new($buf);
631
632 $crate::OFile::parse(&mut cursor).unwrap()
633 }};
634 }
635
636 macro_rules! assert_nodiff {
637 ($left:expr, $right:expr) => {{
638 let mut w = Vec::new();
639 let mut diffs = 0;
640 let left = $left.replace("\r\n", "\n").replace("Jan 1 0:", "Jan 1 00:"); let right = $right.replace("\r\n", "\n");
642
643 for diff in diff::lines(&left, &right) {
644 match diff {
645 diff::Result::Left(l) => {
646 diffs += 1;
647 writeln!(w, "-{}", l).unwrap()
648 }
649 diff::Result::Both(_, _) => {}
650 diff::Result::Right(r) => {
651 diffs += 1;
652 writeln!(w, "+{}", r).unwrap()
653 }
654 }
655 }
656
657 if diffs > 0 {
658 info!("found {} diffs:\n{}", diffs / 2, String::from_utf8(w).unwrap());
659 }
660
661 assert_eq!(&left, &right);
662 }};
663 }
664
665 #[test]
666 fn test_parse_hello_bin() {
667 if let OFile::MachFile { commands, .. } = parse_test_file!(HELLO_WORLD_BIN) {
668 let mut w = Vec::<u8>::new();
669
670 writeln!(w, "helloworld:").unwrap();
671
672 for (i, ref cmd) in commands.iter().enumerate() {
673 writeln!(w, "Load command {}", i).unwrap();
674 write!(w, "{}", cmd).unwrap();
675 }
676
677 let dump = str::from_utf8(w.as_slice()).unwrap();
678
679 assert_nodiff!(dump, HELLO_WORLD_LC);
680 } else {
681 panic!();
682 }
683 }
684
685 #[test]
686 fn test_parse_hello_objc() {
687 if let OFile::MachFile { commands, .. } = parse_test_file!(HELLO_OBJC_BIN) {
688 let mut w = Vec::<u8>::new();
689
690 writeln!(w, "helloobjc:").unwrap();
691
692 for (i, ref cmd) in commands.iter().enumerate() {
693 writeln!(w, "Load command {}", i).unwrap();
694 write!(w, "{}", cmd).unwrap();
695 }
696
697 let dump = str::from_utf8(w.as_slice()).unwrap();
698
699 assert_nodiff!(dump, HELLO_OBJC_LC);
700 } else {
701 panic!();
702 }
703 }
704
705 #[test]
706 fn test_parse_hello_rust() {
707 if let OFile::MachFile { commands, .. } = parse_test_file!(HELLO_RUST_BIN) {
708 let mut w = Vec::<u8>::new();
709
710 writeln!(w, "hellorust:").unwrap();
711
712 for (i, ref cmd) in commands.iter().enumerate() {
713 writeln!(w, "Load command {}", i).unwrap();
714 write!(w, "{}", cmd).unwrap();
715 }
716
717 let dump = str::from_utf8(w.as_slice()).unwrap();
718
719 assert_nodiff!(dump, HELLO_RUST_LC);
720 } else {
721 panic!();
722 }
723 }
724
725 #[test]
726 fn test_parse_hello_universal() {
727 if let OFile::FatFile { ref files, .. } = parse_test_file!(HELLO_UNIVERSAL_BIN) {
728 assert_eq!(files.len(), 2);
729
730 for (i, arch_dump) in [HELLO_UNIVERSAL_I386_LC, HELLO_UNIVERSAL_X86_64_LC].iter().enumerate() {
731 let mut w = Vec::<u8>::new();
732
733 writeln!(w, "helloworld.universal:").unwrap();
734
735 if let (_, OFile::MachFile { ref commands, .. }) = files[i] {
736 for (i, ref cmd) in commands.iter().enumerate() {
737 writeln!(w, "Load command {}", i).unwrap();
738 write!(w, "{}", cmd).unwrap();
739 }
740
741 let dump = str::from_utf8(w.as_slice()).unwrap();
742
743 assert_nodiff!(dump, *arch_dump);
744 } else {
745 panic!();
746 }
747 }
748 } else {
749 panic!();
750 }
751 }
752}