| 
									
										
										
										
											2016-01-26 11:57:58 -05:00
										 |  |  | module CctoolsMachO | 
					
						
							| 
									
										
										
										
											2015-08-29 10:56:24 +01:00
										 |  |  |   # @private | 
					
						
							| 
									
										
										
										
											2013-12-14 09:35:58 -06:00
										 |  |  |   OTOOL_RX = /\t(.*) \(compatibility version (?:\d+\.)*\d+, current version (?:\d+\.)*\d+\)/ | 
					
						
							| 
									
										
										
										
											2013-12-14 09:35:58 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-25 23:44:11 -05:00
										 |  |  |   # Mach-O binary methods, see: | 
					
						
							|  |  |  |   # /usr/include/mach-o/loader.h | 
					
						
							|  |  |  |   # /usr/include/mach-o/fat.h | 
					
						
							| 
									
										
										
										
											2015-08-29 10:56:24 +01:00
										 |  |  |   # @private | 
					
						
							| 
									
										
										
										
											2012-05-25 23:44:11 -05:00
										 |  |  |   def mach_data | 
					
						
							| 
									
										
										
										
											2014-10-11 01:45:41 -05:00
										 |  |  |     @mach_data ||= begin | 
					
						
							|  |  |  |       offsets = [] | 
					
						
							|  |  |  |       mach_data = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       header = read(8).unpack("N2") | 
					
						
							|  |  |  |       case header[0] | 
					
						
							|  |  |  |       when 0xcafebabe # universal | 
					
						
							|  |  |  |         header[1].times do |i| | 
					
						
							|  |  |  |           # header[1] is the number of struct fat_arch in the file. | 
					
						
							|  |  |  |           # Each struct fat_arch is 20 bytes, and the 'offset' member | 
					
						
							|  |  |  |           # begins 8 bytes into the struct, with an additional 8 byte | 
					
						
							|  |  |  |           # offset due to the struct fat_header at the beginning of | 
					
						
							|  |  |  |           # the file. | 
					
						
							|  |  |  |           offsets << read(4, 20*i + 16).unpack("N")[0] | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       when 0xcefaedfe, 0xcffaedfe, 0xfeedface, 0xfeedfacf # Single arch | 
					
						
							|  |  |  |         offsets << 0
 | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         raise "Not a Mach-O binary." | 
					
						
							| 
									
										
										
										
											2012-05-25 23:44:11 -05:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-11 01:45:41 -05:00
										 |  |  |       offsets.each do |offset| | 
					
						
							|  |  |  |         arch = case read(8, offset).unpack("N2") | 
					
						
							|  |  |  |           when [0xcefaedfe, 0x07000000] then :i386 | 
					
						
							|  |  |  |           when [0xcffaedfe, 0x07000001] then :x86_64 | 
					
						
							|  |  |  |           when [0xfeedface, 0x00000012] then :ppc7400 | 
					
						
							|  |  |  |           when [0xfeedfacf, 0x01000012] then :ppc64 | 
					
						
							|  |  |  |           else :dunno | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         type = case read(4, offset + 12).unpack("N")[0] | 
					
						
							|  |  |  |           when 0x00000002, 0x02000000 then :executable | 
					
						
							|  |  |  |           when 0x00000006, 0x06000000 then :dylib | 
					
						
							|  |  |  |           when 0x00000008, 0x08000000 then :bundle | 
					
						
							|  |  |  |           else :dunno | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mach_data << { :arch => arch, :type => type } | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       mach_data | 
					
						
							|  |  |  |     rescue | 
					
						
							|  |  |  |       [] | 
					
						
							| 
									
										
										
										
											2012-05-25 23:44:11 -05:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-29 10:56:24 +01:00
										 |  |  |   # @private | 
					
						
							| 
									
										
										
										
											2014-04-13 13:53:46 -05:00
										 |  |  |   class Metadata | 
					
						
							|  |  |  |     attr_reader :path, :dylib_id, :dylibs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def initialize(path) | 
					
						
							|  |  |  |       @path = path | 
					
						
							|  |  |  |       @dylib_id, @dylibs = parse_otool_L_output | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def parse_otool_L_output | 
					
						
							| 
									
										
										
										
											2015-10-16 17:19:02 +08:00
										 |  |  |       args = ["-L", path.expand_path.to_s] | 
					
						
							|  |  |  |       libs = Utils.popen_read(OS::Mac.otool, *args).split("\n") | 
					
						
							| 
									
										
										
										
											2014-12-11 13:59:12 +00:00
										 |  |  |       unless $?.success? | 
					
						
							| 
									
										
										
										
											2015-10-16 17:19:02 +08:00
										 |  |  |         raise ErrorDuringExecution.new(OS::Mac.otool, args) | 
					
						
							| 
									
										
										
										
											2014-12-11 13:59:12 +00:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-04-13 13:53:46 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       libs.shift # first line is the filename | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       id = libs.shift[OTOOL_RX, 1] if path.dylib? | 
					
						
							|  |  |  |       libs.map! { |lib| lib[OTOOL_RX, 1] }.compact! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return id, libs | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-29 10:56:24 +01:00
										 |  |  |   # @private | 
					
						
							| 
									
										
										
										
											2014-04-13 13:53:46 -05:00
										 |  |  |   def mach_metadata | 
					
						
							|  |  |  |     @mach_metadata ||= Metadata.new(self) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-14 09:35:58 -06:00
										 |  |  |   # Returns an array containing all dynamically-linked libraries, based on the | 
					
						
							|  |  |  |   # output of otool. This returns the install names, so these are not guaranteed | 
					
						
							|  |  |  |   # to be absolute paths. | 
					
						
							|  |  |  |   # Returns an empty array both for software that links against no libraries, | 
					
						
							|  |  |  |   # and for non-mach objects. | 
					
						
							| 
									
										
										
										
											2015-08-29 10:56:24 +01:00
										 |  |  |   # @private | 
					
						
							| 
									
										
										
										
											2013-12-14 09:35:58 -06:00
										 |  |  |   def dynamically_linked_libraries | 
					
						
							| 
									
										
										
										
											2014-04-13 13:53:46 -05:00
										 |  |  |     mach_metadata.dylibs | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-12-14 09:35:58 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-29 10:56:24 +01:00
										 |  |  |   # @private | 
					
						
							| 
									
										
										
										
											2014-04-13 13:53:46 -05:00
										 |  |  |   def dylib_id | 
					
						
							|  |  |  |     mach_metadata.dylib_id | 
					
						
							| 
									
										
										
										
											2013-12-14 09:35:58 -06:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-05-25 23:44:11 -05:00
										 |  |  | end |