ruby-macho 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 634d3249001bb3d3bf5782055392c8feea3d15c8
4
- data.tar.gz: bd854ada089451f23d4b253642bbb3eebcbba25f
3
+ metadata.gz: 18e0719447412b4c6fea5f4ca08f5f0e316e34c1
4
+ data.tar.gz: e42a6a11cc91a374693cd13d6d5ff8b07d5dec9c
5
5
  SHA512:
6
- metadata.gz: 06436af8d8c711a2eaa40f396020a80e15ff8f8de474e162f7f3e41d7b1a984d1218bec862d54f18bb9fe20675908ea8dfe1bcdd08b3d4bd50c8d0405daf06a5
7
- data.tar.gz: cc4846d66dc58873417d1baae77c95c7ee4678f5861e98211cb52c4a6363280490473261de8b0143080a7aae71b97e20c0d85b6e0dac5647f106918a3de68c85
6
+ metadata.gz: 6a77b43c73461ed816155a184230f27cb4a8130117f41c9f209033eb89cc09c1581849eb58b5fec55a58a7e8d444e1c0da16576fda19463b9d7c7843b0f21082
7
+ data.tar.gz: 80ac6b3e2c76001e7a61076b7a6cfc72be034f418636d1ac195ee7f24144749ad4453ec67b3d0382e325a9f99fe88e0618db92696d7881051d93f01a2ef1b8d6
@@ -15,10 +15,9 @@ module MachO
15
15
 
16
16
  # Creates a new FatFile from the given filename.
17
17
  # @param filename [String] the fat file to load from
18
- # @raise [MachO::MagicError] if the file does not have a Mach-O magic number.
19
- # @raise [MachO::MachOBinaryError] if the file is not a fat binary.
18
+ # @raise [ArgumentError] if the given filename does not exist
20
19
  def initialize(filename)
21
- raise ArgumentError.new("filename must be a String") unless filename.is_a? String
20
+ raise ArgumentError.new("#{filetype}: no such file") unless File.exist?(filename)
22
21
 
23
22
  @filename = filename
24
23
  @raw_data = open(@filename, "rb") { |f| f.read }
@@ -33,29 +32,26 @@ module MachO
33
32
  @raw_data
34
33
  end
35
34
 
35
+ # The file's type. Assumed to be the same for every Mach-O within.
36
+ # @return [String] the filetype
37
+ def filetype
38
+ machos.first.filetype
39
+ end
40
+
36
41
  # The file's dylib ID. If the file is not a dylib, returns `nil`.
37
42
  # @example
38
43
  # file.dylib_id # => 'libBar.dylib'
39
- # @return [String] the file's dylib ID
44
+ # @return [String, nil] the file's dylib ID
40
45
  def dylib_id
41
- if !machos.all?(&:dylib?)
42
- return nil
43
- end
44
-
45
- ids = machos.map(&:dylib_id)
46
-
47
- # this should never be the case, but let's be defensive
48
- if !ids.uniq!.size == 1
49
- return nil
50
- end
51
-
52
- ids.first
46
+ machos.first.dylib_id
53
47
  end
54
48
 
55
49
  # Changes the file's dylib ID to `new_id`. If the file is not a dylib, does nothing.
56
50
  # @example
57
51
  # file.dylib_id = 'libFoo.dylib'
58
52
  # @param new_id [String] the new dylib ID
53
+ # @return [void]
54
+ # @raise [ArgumentError] if `new_id` is not a String
59
55
  def dylib_id=(new_id)
60
56
  if !new_id.is_a?(String)
61
57
  raise ArgumentError.new("argument must be a String")
@@ -303,16 +303,17 @@ module MachO
303
303
  # @param offset [Fixnum] the offset to initialize with
304
304
  # @param bin [String] the binary string to initialize with
305
305
  # @return [MachO::LoadCommand] the new load command
306
- # @private
307
- def self.new_from_bin(offset, bin)
308
- self.new(offset, *bin.unpack(@format))
306
+ # @api private
307
+ def self.new_from_bin(raw_data, offset, bin)
308
+ self.new(raw_data, offset, *bin.unpack(@format))
309
309
  end
310
310
 
311
- # @param offset [Fixnum] the offset to initialize iwth
311
+ # @param offset [Fixnum] the offset to initialize with
312
312
  # @param cmd [Fixnum] the load command's identifying number
313
313
  # @param cmdsize [Fixnum] the size of the load command in bytes
314
- # @private
315
- def initialize(offset, cmd, cmdsize)
314
+ # @api private
315
+ def initialize(raw_data, offset, cmd, cmdsize)
316
+ @raw_data = raw_data
316
317
  @offset = offset
317
318
  @cmd = cmd
318
319
  @cmdsize = cmdsize
@@ -322,6 +323,33 @@ module MachO
322
323
  def to_s
323
324
  LOAD_COMMANDS[cmd]
324
325
  end
326
+
327
+ # Represents a Load Command string. A rough analogue to the lc_str
328
+ # struct used internally by OS X. This class allows ruby-macho to
329
+ # pretend that strings stored in LCs are immediately available without
330
+ # explicit operations on the raw Mach-O data.
331
+ class LCStr
332
+ # @param raw_data [String] the raw Mach-O data.
333
+ # @param lc [MachO::LoadCommand] the load command
334
+ # @param lc_str [Fixnum] the offset to the beginning of the string
335
+ # @api private
336
+ def initialize(raw_data, lc, lc_str)
337
+ @raw_data = raw_data
338
+ @lc = lc
339
+ @lc_str = lc_str
340
+ @str = @raw_data.slice(@lc.offset + @lc_str...@lc.offset + @lc.cmdsize).delete("\x00")
341
+ end
342
+
343
+ # @return [String] a string representation of the LCStr
344
+ def to_s
345
+ @str
346
+ end
347
+
348
+ # @return [Fixnum] the offset to the beginning of the string in the load command
349
+ def to_i
350
+ @lc_str
351
+ end
352
+ end
325
353
  end
326
354
 
327
355
  # A load command containing a single 128-bit unique random number identifying
@@ -333,9 +361,9 @@ module MachO
333
361
  @format = "VVa16"
334
362
  @sizeof = 24
335
363
 
336
- # @private
337
- def initialize(offset, cmd, cmdsize, uuid)
338
- super(offset, cmd, cmdsize)
364
+ # @api private
365
+ def initialize(raw_data, offset, cmd, cmdsize, uuid)
366
+ super(raw_data, offset, cmd, cmdsize)
339
367
  @uuid = uuid.unpack("C16") # re-unpack for the actual UUID array
340
368
  end
341
369
 
@@ -384,10 +412,10 @@ module MachO
384
412
  @format = "VVa16VVVVVVVV"
385
413
  @sizeof = 56
386
414
 
387
- # @private
388
- def initialize(offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
415
+ # @api private
416
+ def initialize(raw_data, offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
389
417
  filesize, maxprot, initprot, nsects, flags)
390
- super(offset, cmd, cmdsize)
418
+ super(raw_data, offset, cmd, cmdsize)
391
419
  @segname = segname
392
420
  @vmaddr = vmaddr
393
421
  @vmsize = vmsize
@@ -438,10 +466,10 @@ module MachO
438
466
  @format = "VVa16QQQQVVVV"
439
467
  @sizeof = 72
440
468
 
441
- # @private
442
- def initialize(offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
469
+ # @api private
470
+ def initialize(raw_data, offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
443
471
  filesize, maxprot, initprot, nsects, flags)
444
- super(offset, cmd, cmdsize)
472
+ super(raw_data, offset, cmd, cmdsize)
445
473
  @segname = segname
446
474
  @vmaddr = vmaddr
447
475
  @vmsize = vmsize
@@ -463,7 +491,7 @@ module MachO
463
491
  # on filetype. Corresponds to LC_ID_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB,
464
492
  # and LC_REEXPORT_DYLIB.
465
493
  class DylibCommand < LoadCommand
466
- # @return [Fixnum] the library's path name (lc_str)
494
+ # @return [MachO::LoadCommand::LCStr] the library's path name as an LCStr
467
495
  attr_reader :name
468
496
 
469
497
  # @return [Fixnum] the library's build time stamp
@@ -478,11 +506,11 @@ module MachO
478
506
  @format = "VVVVVV"
479
507
  @sizeof = 24
480
508
 
481
- # @private
482
- def initialize(offset, cmd, cmdsize, name, timestamp, current_version,
509
+ # @api private
510
+ def initialize(raw_data, offset, cmd, cmdsize, name, timestamp, current_version,
483
511
  compatibility_version)
484
- super(offset, cmd, cmdsize)
485
- @name = name
512
+ super(raw_data, offset, cmd, cmdsize)
513
+ @name = LCStr.new(raw_data, self, name)
486
514
  @timestamp = timestamp
487
515
  @current_version = current_version
488
516
  @compatibility_version = compatibility_version
@@ -493,23 +521,23 @@ module MachO
493
521
  # on filetype. Corresponds to LC_ID_DYLINKER, LC_LOAD_DYLINKER, and
494
522
  # LC_DYLD_ENVIRONMENT.
495
523
  class DylinkerCommand < LoadCommand
496
- # @return [Fixnum] the dynamic linker's path name (lc_str)
524
+ # @return [MachO::LoadCommand::LCStr] the dynamic linker's path name as an LCStr
497
525
  attr_reader :name
498
526
 
499
527
  @format = "VVV"
500
528
  @sizeof = 12
501
529
 
502
- # @private
503
- def initialize(offset, cmd, cmdsize, name)
504
- super(offset, cmd, cmdsize)
505
- @name = name
530
+ # @api private
531
+ def initialize(raw_data, offset, cmd, cmdsize, name)
532
+ super(raw_data, offset, cmd, cmdsize)
533
+ @name = LCStr.new(raw_data, self, name)
506
534
  end
507
535
  end
508
536
 
509
537
  # A load command used to indicate dynamic libraries used in prebinding.
510
538
  # Corresponds to LC_PREBOUND_DYLIB.
511
539
  class PreboundDylibCommand < LoadCommand
512
- # @return [Fixnum] the library's path name (lc_str)
540
+ # @return [MachO::LoadCommand::LCStr] the library's path name as an LCStr
513
541
  attr_reader :name
514
542
 
515
543
  # @return [Fixnum] the number of modules in the library
@@ -521,10 +549,10 @@ module MachO
521
549
  @format = "VVVVV"
522
550
  @sizeof = 20
523
551
 
524
- # @private
525
- def initialize(offset, cmd, cmdsize, name, nmodules, linked_modules)
526
- super(offset, cmd, cmdsize)
527
- @name = name
552
+ # @api private
553
+ def initialize(raw_data, offset, cmd, cmdsize, name, nmodules, linked_modules)
554
+ super(raw_data, offset, cmd, cmdsize)
555
+ @name = LCStr.new(raw_data, self, name)
528
556
  @nmodules = nmodules
529
557
  @linked_modules = linked_modules
530
558
  end
@@ -567,11 +595,11 @@ module MachO
567
595
  @format = "VVVVVVVVVV"
568
596
  @sizeof = 40
569
597
 
570
- # @private
571
- def initialize(offset, cmd, cmdsize, init_address, init_module,
598
+ # @api private
599
+ def initialize(raw_data, offset, cmd, cmdsize, init_address, init_module,
572
600
  reserved1, reserved2, reserved3, reserved4, reserved5,
573
601
  reserved6)
574
- super(offset, cmd, cmdsize)
602
+ super(raw_data, offset, cmd, cmdsize)
575
603
  @init_address = init_address
576
604
  @init_module = init_module
577
605
  @reserved1 = reserved1
@@ -614,11 +642,11 @@ module MachO
614
642
  @format = "VVQQQQQQQQ"
615
643
  @sizeof = 72
616
644
 
617
- # @private
618
- def initialize(offset, cmd, cmdsize, init_address, init_module,
645
+ # @api private
646
+ def initialize(raw_data, offset, cmd, cmdsize, init_address, init_module,
619
647
  reserved1, reserved2, reserved3, reserved4, reserved5,
620
648
  reserved6)
621
- super(offset, cmd, cmdsize)
649
+ super(raw_data, offset, cmd, cmdsize)
622
650
  @init_address = init_address
623
651
  @init_module = init_module
624
652
  @reserved1 = reserved1
@@ -633,64 +661,64 @@ module MachO
633
661
  # A load command signifying membership of a subframework containing the name
634
662
  # of an umbrella framework. Corresponds to LC_SUB_FRAMEWORK.
635
663
  class SubFrameworkCommand < LoadCommand
636
- # @return [Fixnum] the umbrella framework name (lc_str)
664
+ # @return [MachO::LoadCommand::LCStr] the umbrella framework name as an LCStr
637
665
  attr_reader :umbrella
638
666
 
639
667
  @format = "VVV"
640
668
  @sizeof = 12
641
669
 
642
- # @private
643
- def initialize(offset, cmd, cmdsize, umbrella)
644
- super(offset, cmd, cmdsize)
645
- @umbrella = umbrella
670
+ # @api private
671
+ def initialize(raw_data, offset, cmd, cmdsize, umbrella)
672
+ super(raw_data, offset, cmd, cmdsize)
673
+ @umbrella = LCStr.new(raw_data, self, umbrella)
646
674
  end
647
675
  end
648
676
 
649
677
  # A load command signifying membership of a subumbrella containing the name
650
678
  # of an umbrella framework. Corresponds to LC_SUB_UMBRELLA.
651
679
  class SubUmbrellaCommand < LoadCommand
652
- # @return [Fixnum] the subumbrella framework name (lc_str)
680
+ # @return [MachO::LoadCommand::LCStr] the subumbrella framework name as an LCStr
653
681
  attr_reader :sub_umbrella
654
682
 
655
683
  @format = "VVV"
656
684
  @sizeof = 12
657
685
 
658
- # @private
659
- def initialize(offset, cmd, cmdsize, sub_umbrella)
660
- super(offset, cmd, cmdsize)
661
- @sub_umbrella = sub_umbrella
686
+ # @api private
687
+ def initialize(raw_data, offset, cmd, cmdsize, sub_umbrella)
688
+ super(raw_data, offset, cmd, cmdsize)
689
+ @sub_umbrella = LCStr.new(raw_data, self, sub_umbrella)
662
690
  end
663
691
  end
664
692
 
665
693
  # A load command signifying a sublibrary of a shared library. Corresponds
666
694
  # to LC_SUB_LIBRARY.
667
695
  class SubLibraryCommand < LoadCommand
668
- # @return [Fixnum] the sublibrary name (lc_str)
696
+ # @return [MachO::LoadCommand::LCStr] the sublibrary name as an LCStr
669
697
  attr_reader :sub_library
670
698
 
671
699
  @format = "VVV"
672
700
  @sizeof = 12
673
701
 
674
- # @private
675
- def initialize(offset, cmd, cmdsize, sub_library)
676
- super(offset, cmd, cmdsize)
677
- @sub_library = sub_library
702
+ # @api private
703
+ def initialize(raw_data, offset, cmd, cmdsize, sub_library)
704
+ super(raw_data, offset, cmd, cmdsize)
705
+ @sub_library = LCStr.new(raw_data, self, sub_library)
678
706
  end
679
707
  end
680
708
 
681
709
  # A load command signifying a shared library that is a subframework of
682
710
  # an umbrella framework. Corresponds to LC_SUB_CLIENT.
683
711
  class SubClientCommand < LoadCommand
684
- # @return [Fixnum] the subclient name (lc_str)
712
+ # @return [MachO::LoadCommand::LCStr] the subclient name as an LCStr
685
713
  attr_reader :sub_client
686
714
 
687
715
  @format = "VVV"
688
716
  @sizeof = 12
689
717
 
690
- # @private
691
- def initialize(offset, cmd, cmdsize, sub_client)
692
- super(offset, cmd, cmdsize)
693
- @sub_client = sub_client
718
+ # @api private
719
+ def initialize(raw_data, offset, cmd, cmdsize, sub_client)
720
+ super(raw_data, offset, cmd, cmdsize)
721
+ @sub_client = LCStr.new(raw_data, self, sub_client)
694
722
  end
695
723
  end
696
724
 
@@ -712,9 +740,9 @@ module MachO
712
740
  @format = "VVVVVV"
713
741
  @sizeof = 24
714
742
 
715
- # @private
716
- def initialize(offset, cmd, cmdsize, symoff, nsyms, stroff, strsize)
717
- super(offset, cmd, cmdsize)
743
+ # @api private
744
+ def initialize(raw_data, offset, cmd, cmdsize, symoff, nsyms, stroff, strsize)
745
+ super(raw_data, offset, cmd, cmdsize)
718
746
  @symoff = symoff
719
747
  @nsyms = nsyms
720
748
  @stroff = stroff
@@ -784,12 +812,12 @@ module MachO
784
812
  @sizeof = 80
785
813
 
786
814
  # ugh
787
- # @private
788
- def initialize(offset, cmd, cmdsize, ilocalsym, nlocalsym, iextdefsym,
815
+ # @api private
816
+ def initialize(raw_data, offset, cmd, cmdsize, ilocalsym, nlocalsym, iextdefsym,
789
817
  nextdefsym, iundefsym, nundefsym, tocoff, ntoc, modtaboff,
790
818
  nmodtab, extrefsymoff, nextrefsyms, indirectsymoff,
791
819
  nindirectsyms, extreloff, nextrel, locreloff, nlocrel)
792
- super(offset, cmd, cmdsize)
820
+ super(raw_data, offset, cmd, cmdsize)
793
821
  @ilocalsym = ilocalsym
794
822
  @nlocalsym = nlocalsym
795
823
  @iextdefsym = iextdefsym
@@ -823,9 +851,9 @@ module MachO
823
851
  @format = "VVVV"
824
852
  @sizeof = 16
825
853
 
826
- # @private
827
- def initialize(offset, cmd, cmdsize, htoffset, nhints)
828
- super(offset, cmd, cmdsize)
854
+ # @api private
855
+ def initialize(raw_data, offset, cmd, cmdsize, htoffset, nhints)
856
+ super(raw_data, offset, cmd, cmdsize)
829
857
  @htoffset = htoffset
830
858
  @nhints = nhints
831
859
  end
@@ -840,9 +868,9 @@ module MachO
840
868
  @format = "VVV"
841
869
  @sizeof = 12
842
870
 
843
- # @private
844
- def initialize(offset, cmd, cmdsize, cksum)
845
- super(offset, cmd, cmdsize)
871
+ # @api private
872
+ def initialize(raw_data, offset, cmd, cmdsize, cksum)
873
+ super(raw_data, offset, cmd, cmdsize)
846
874
  @cksum = cksum
847
875
  end
848
876
  end
@@ -851,16 +879,16 @@ module MachO
851
879
  # be added to the current run path used to find @rpath prefixed dylibs.
852
880
  # Corresponds to LC_RPATH.
853
881
  class RpathCommand < LoadCommand
854
- # @return [Fixnum] the oath to add to the run path (lc_str)
882
+ # @return [MachO::LoadCommand::LCStr] the path to add to the run path as an LCStr
855
883
  attr_reader :path
856
884
 
857
885
  @format = "VVV"
858
886
  @sizeof = 12
859
887
 
860
- # @private
861
- def initialize(offset, cmd, cmdsize, path)
862
- super(offset, cmd, cmdsize)
863
- @path = path
888
+ # @api private
889
+ def initialize(raw_data, offset, cmd, cmdsize, path)
890
+ super(raw_data, offset, cmd, cmdsize)
891
+ @path = LCStr.new(raw_data, self, path)
864
892
  end
865
893
  end
866
894
 
@@ -877,9 +905,9 @@ module MachO
877
905
  @format = "VVVV"
878
906
  @sizeof = 16
879
907
 
880
- # @private
881
- def initialize(offset, cmd, cmdsize, dataoff, datasize)
882
- super(offset, cmd, cmdsize)
908
+ # @api private
909
+ def initialize(raw_data, offset, cmd, cmdsize, dataoff, datasize)
910
+ super(raw_data, offset, cmd, cmdsize)
883
911
  @dataoff = dataoff
884
912
  @datasize = datasize
885
913
  end
@@ -900,9 +928,9 @@ module MachO
900
928
  @format = "VVVVV"
901
929
  @sizeof = 20
902
930
 
903
- # @private
904
- def initialize(offset, cmd, cmdsize, cryptoff, cryptsize, cryptid)
905
- super(offset, cmd, cmdsize)
931
+ # @api private
932
+ def initialize(raw_data, offset, cmd, cmdsize, cryptoff, cryptsize, cryptid)
933
+ super(raw_data, offset, cmd, cmdsize)
906
934
  @cryptoff = cryptoff
907
935
  @cryptsize = cryptsize
908
936
  @cryptid = cryptid
@@ -927,9 +955,9 @@ module MachO
927
955
  @format = "VVVVVV"
928
956
  @sizeof = 24
929
957
 
930
- # @private
931
- def initialize(offset, cmd, cmdsize, cryptoff, cryptsize, cryptid)
932
- super(offset, cmd, cmdsize)
958
+ # @api private
959
+ def initialize(raw_data, offset, cmd, cmdsize, cryptoff, cryptsize, cryptid)
960
+ super(raw_data, offset, cmd, cmdsize)
933
961
  @cryptoff = cryptoff
934
962
  @cryptsize = cryptsize
935
963
  @cryptid = cryptid
@@ -949,9 +977,9 @@ module MachO
949
977
  @format = "VVVV"
950
978
  @sizeof = 16
951
979
 
952
- # @private
953
- def initialize(offset, cmd, cmdsize, version, sdk)
954
- super(offset, cmd, cmdsize)
980
+ # @api private
981
+ def initialize(raw_data, offset, cmd, cmdsize, version, sdk)
982
+ super(raw_data, offset, cmd, cmdsize)
955
983
  @version = version
956
984
  @sdk = sdk
957
985
  end
@@ -1016,11 +1044,11 @@ module MachO
1016
1044
  @format = "VVVVVVVVVVVV"
1017
1045
  @sizeof = 48
1018
1046
 
1019
- # @private
1020
- def initialize(offset, cmd, cmdsize, rebase_off, rebase_size, bind_off,
1047
+ # @api private
1048
+ def initialize(raw_data, offset, cmd, cmdsize, rebase_off, rebase_size, bind_off,
1021
1049
  bind_size, weak_bind_off, weak_bind_size, lazy_bind_off,
1022
1050
  lazy_bind_size, export_off, export_size)
1023
- super(offset, cmd, cmdsize)
1051
+ super(raw_data, offset, cmd, cmdsize)
1024
1052
  @rebase_off = rebase_off
1025
1053
  @rebase_size = rebase_size
1026
1054
  @bind_off = bind_off
@@ -1043,9 +1071,9 @@ module MachO
1043
1071
  @format = "VVV"
1044
1072
  @sizeof = 12
1045
1073
 
1046
- # @private
1047
- def initialize(offset, cmd, cmdsize, count)
1048
- super(offset, cmd, cmdsize)
1074
+ # @api private
1075
+ def initialize(raw_data, offset, cmd, cmdsize, count)
1076
+ super(raw_data, offset, cmd, cmdsize)
1049
1077
  @count = count
1050
1078
  end
1051
1079
  end
@@ -1061,9 +1089,9 @@ module MachO
1061
1089
  @format = "VVQQ"
1062
1090
  @sizeof = 24
1063
1091
 
1064
- # @private
1065
- def initialize(offset, cmd, cmdsize, entryoff, stacksize)
1066
- super(offset, cmd, cmdsize)
1092
+ # @api private
1093
+ def initialize(raw_data, offset, cmd, cmdsize, entryoff, stacksize)
1094
+ super(raw_data, offset, cmd, cmdsize)
1067
1095
  @entryoff = entryoff
1068
1096
  @stacksize = stacksize
1069
1097
  end
@@ -1078,9 +1106,9 @@ module MachO
1078
1106
  @format = "VVQ"
1079
1107
  @sizeof = 16
1080
1108
 
1081
- # @private
1082
- def initialize(offset, cmd, cmdsize, version)
1083
- super(offset, cmd, cmdsize)
1109
+ # @api private
1110
+ def initialize(raw_data, offset, cmd, cmdsize, version)
1111
+ super(raw_data, offset, cmd, cmdsize)
1084
1112
  @version = version
1085
1113
  end
1086
1114
 
@@ -24,9 +24,9 @@ module MachO
24
24
 
25
25
  # Creates a new FatFile from the given filename.
26
26
  # @param filename [String] the Mach-O file to load from
27
- # @todo document all the exceptions propagated here
27
+ # @raise [ArgumentError] if the given filename does not exist
28
28
  def initialize(filename)
29
- raise ArgumentError.new("filename must be a String") unless filename.is_a? String
29
+ raise ArgumentError.new("#{filetype}: no such file") unless File.exist?(filename)
30
30
 
31
31
  @filename = filename
32
32
  @raw_data = open(@filename, "rb") { |f| f.read }
@@ -34,7 +34,7 @@ module MachO
34
34
  @load_commands = get_load_commands
35
35
  end
36
36
 
37
- # @private
37
+ # @api private
38
38
  def initialize_from_bin(bin)
39
39
  @filename = nil
40
40
  @raw_data = bin
@@ -138,21 +138,15 @@ module MachO
138
138
  # The Mach-O's dylib ID, or `nil` if not a dylib.
139
139
  # @example
140
140
  # file.dylib_id # => 'libBar.dylib'
141
- # @return [String] the Mach-O's dylib ID
141
+ # @return [String, nil] the Mach-O's dylib ID
142
142
  def dylib_id
143
143
  if !dylib?
144
144
  return nil
145
145
  end
146
146
 
147
- dylib_id_cmd = command('LC_ID_DYLIB').first
148
-
149
- cmdsize = dylib_id_cmd.cmdsize
150
- offset = dylib_id_cmd.offset
151
- stroffset = dylib_id_cmd.name
147
+ dylib_id_cmd = command("LC_ID_DYLIB").first
152
148
 
153
- dylib_id = @raw_data.slice(offset + stroffset...offset + cmdsize).unpack("Z*").first
154
-
155
- dylib_id.delete("\x00")
149
+ dylib_id_cmd.name.to_s
156
150
  end
157
151
 
158
152
  # Changes the Mach-O's dylib ID to `new_id`. Does nothing if not a dylib.
@@ -160,6 +154,7 @@ module MachO
160
154
  # file.dylib_id = "libFoo.dylib"
161
155
  # @param new_id [String] the dylib's new ID
162
156
  # @return [void]
157
+ # @raise [ArgumentError] if `new_id` is not a String
163
158
  def dylib_id=(new_id)
164
159
  if !new_id.is_a?(String)
165
160
  raise ArgumentError.new("argument must be a String")
@@ -169,7 +164,7 @@ module MachO
169
164
  return nil
170
165
  end
171
166
 
172
- dylib_cmd = command('LC_ID_DYLIB').first
167
+ dylib_cmd = command("LC_ID_DYLIB").first
173
168
  old_id = dylib_id
174
169
 
175
170
  set_name_in_dylib(dylib_cmd, old_id, new_id)
@@ -179,14 +174,10 @@ module MachO
179
174
  # @return [Array<String>] an array of all shared libraries
180
175
  def linked_dylibs
181
176
  dylibs = []
182
- dylib_cmds = command('LC_LOAD_DYLIB')
177
+ dylib_cmds = command("LC_LOAD_DYLIB")
183
178
 
184
179
  dylib_cmds.each do |dylib_cmd|
185
- cmdsize = dylib_cmd.cmdsize
186
- offset = dylib_cmd.offset
187
- stroffset = dylib_cmd.name
188
-
189
- dylib = @raw_data.slice(offset + stroffset...offset + cmdsize).unpack("Z*").first
180
+ dylib = dylib_cmd.name.to_s
190
181
 
191
182
  dylibs << dylib
192
183
  end
@@ -200,6 +191,7 @@ module MachO
200
191
  # @param old_name [String] the shared library's old name
201
192
  # @param new_name [String] the shared library's new name
202
193
  # @return [void]
194
+ # @raise [MachO::DylibUnknownError] if no shared library has the old name
203
195
  def change_install_name(old_name, new_name)
204
196
  idx = linked_dylibs.index(old_name)
205
197
  raise DylibUnknownError.new(old_name) if idx.nil?
@@ -207,7 +199,7 @@ module MachO
207
199
  # this is a bit of a hack - since there is a 1-1 ordered association
208
200
  # between linked_dylibs and command('LC_LOAD_DYLIB'), we can use
209
201
  # their indices interchangeably to avoid having to loop.
210
- dylib_cmd = command('LC_LOAD_DYLIB')[idx]
202
+ dylib_cmd = command("LC_LOAD_DYLIB")[idx]
211
203
 
212
204
  set_name_in_dylib(dylib_cmd, old_name, new_name)
213
205
  end
@@ -215,6 +207,7 @@ module MachO
215
207
  alias :change_dylib :change_install_name
216
208
 
217
209
  # All sections of the segment `segment`.
210
+ # @param segment [MachO::SegmentCommand, MachO::SegmentCommand64] the segment being inspected
218
211
  # @return [Array<MachO::Section>] if the Mach-O is 32-bit
219
212
  # @return [Array<MachO::Section64>] if the Mach-O is 64-bit
220
213
  def sections(segment)
@@ -253,6 +246,7 @@ module MachO
253
246
  # Write all Mach-O data to the file used to initialize the instance.
254
247
  # @raise [MachOError] if the instance was created from a binary string
255
248
  # @return [void]
249
+ # @raise [MachO::MachOError] if the instance was initialized without a file
256
250
  # @note Overwrites all data in the file!
257
251
  def write!
258
252
  if @filename.nil?
@@ -394,7 +388,7 @@ module MachO
394
388
  # why do I do this? i don't like declaring constants below
395
389
  # classes, and i need them to resolve...
396
390
  klass = MachO.const_get "#{LC_STRUCTURES[cmd]}"
397
- command = klass.new_from_bin(offset, @raw_data.slice(offset, klass.bytesize))
391
+ command = klass.new_from_bin(@raw_data, offset, @raw_data.slice(offset, klass.bytesize))
398
392
 
399
393
  load_commands << command
400
394
  offset += command.cmdsize
@@ -417,6 +411,7 @@ module MachO
417
411
  # @param old_name [String] the old dylib name
418
412
  # @param new_name [String] the new dylib name
419
413
  # @return [void]
414
+ # @raise [MachO::HeaderPadError] if the new name exceeds the header pad buffer
420
415
  # @private
421
416
  def set_name_in_dylib(dylib_cmd, old_name, new_name)
422
417
  if magic32?
@@ -465,10 +460,10 @@ module MachO
465
460
  @raw_data[dylib_cmd.offset + 4, 4] = [new_size].pack("V")
466
461
 
467
462
  # delete the old name
468
- @raw_data.slice!(dylib_cmd.offset + dylib_cmd.name...dylib_cmd.offset + dylib_cmd.class.bytesize + old_name.size)
463
+ @raw_data.slice!(dylib_cmd.offset + dylib_cmd.name.to_i...dylib_cmd.offset + dylib_cmd.class.bytesize + old_name.size)
469
464
 
470
465
  # insert the new id
471
- @raw_data.insert(dylib_cmd.offset + dylib_cmd.name, new_name)
466
+ @raw_data.insert(dylib_cmd.offset + dylib_cmd.name.to_i, new_name)
472
467
 
473
468
  # pad/unpad after new_sizeofcmds until offsets are corrected
474
469
  null_pad = old_name.size - new_name.size
@@ -58,13 +58,43 @@ module MachO
58
58
 
59
59
  # Represents a section of a segment for 32-bit architectures.
60
60
  class Section < MachOStructure
61
- attr_reader :sectname, :segname, :addr, :size, :offset, :align, :reloff
62
- attr_reader :nreloc, :flags, :reserved1, :reserved2
61
+ # @return [String] the name of the section, including null pad bytes
62
+ attr_reader :sectname
63
+
64
+ # @return [String] the name of the segment's section, including null pad bytes
65
+ attr_reader :segname
66
+
67
+ # @return [Fixnum] the memory address of the section
68
+ attr_reader :addr
69
+
70
+ # @return [Fixnum] the size, in bytes, of the section
71
+ attr_reader :size
72
+
73
+ # @return [Fixnum] the file offset of the section
74
+ attr_reader :offset
75
+
76
+ # @return [Fixnum] the section alignment (power of 2) of the section
77
+ attr_reader :align
78
+
79
+ # @return [Fixnum] the file offset of the section's relocation entries
80
+ attr_reader :reloff
81
+
82
+ # @return [Fixnum] the number of relocation entries
83
+ attr_reader :nreloc
84
+
85
+ # @return [Fixnum] flags for type and addrributes of the section
86
+ attr_reader :flags
87
+
88
+ # @return [void] reserved (for offset or index)
89
+ attr_reader :reserved1
90
+
91
+ # @return [void] reserved (for count or sizeof)
92
+ attr_reader :reserved2
63
93
 
64
94
  @format = "a16a16VVVVVVVVV"
65
95
  @sizeof = 68
66
96
 
67
- # @private
97
+ # @api private
68
98
  def initialize(sectname, segname, addr, size, offset, align, reloff,
69
99
  nreloc, flags, reserved1, reserved2)
70
100
  @sectname = sectname
@@ -101,13 +131,46 @@ module MachO
101
131
 
102
132
  # Represents a section of a segment for 64-bit architectures.
103
133
  class Section64 < MachOStructure
104
- attr_reader :sectname, :segname, :addr, :size, :offset, :align, :reloff
105
- attr_reader :nreloc, :flags, :reserved1, :reserved2, :reserved3
134
+ # @return [String] the name of the section, including null pad bytes
135
+ attr_reader :sectname
136
+
137
+ # @return [String] the name of the segment's section, including null pad bytes
138
+ attr_reader :segname
139
+
140
+ # @return [Fixnum] the memory address of the section
141
+ attr_reader :addr
142
+
143
+ # @return [Fixnum] the size, in bytes, of the section
144
+ attr_reader :size
145
+
146
+ # @return [Fixnum] the file offset of the section
147
+ attr_reader :offset
148
+
149
+ # @return [Fixnum] the section alignment (power of 2) of the section
150
+ attr_reader :align
151
+
152
+ # @return [Fixnum] the file offset of the section's relocation entries
153
+ attr_reader :reloff
154
+
155
+ # @return [Fixnum] the number of relocation entries
156
+ attr_reader :nreloc
157
+
158
+ # @return [Fixnum] flags for type and addrributes of the section
159
+ attr_reader :flags
160
+
161
+ # @return [void] reserved (for offset or index)
162
+ attr_reader :reserved1
163
+
164
+ # @return [void] reserved (for count or sizeof)
165
+ attr_reader :reserved2
166
+
167
+ # @return [void] reserved
168
+ attr_reader :reserved3
106
169
 
107
170
  @format = "a16a16QQVVVVVVVV"
108
171
  @sizeof = 80
109
172
 
110
- # @private
173
+ # @api private
111
174
  def initialize(sectname, segname, addr, size, offset, align, reloff,
112
175
  nreloc, flags, reserved1, reserved2, reserved3)
113
176
  @sectname = sectname
@@ -12,6 +12,7 @@ module MachO
12
12
  end
13
13
 
14
14
  # @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
15
+ # @api private
15
16
  def self.new_from_bin(bin)
16
17
  self.new(*bin.unpack(@format))
17
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-macho
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Woodruff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-25 00:00:00.000000000 Z
11
+ date: 2015-10-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A library for viewing and manipulating Mach-O files in Ruby.
14
14
  email: william@tuffbizz.com