From a7861783828182425c2dd7ec8dbc716843ff0f48 Mon Sep 17 00:00:00 2001 From: Jack Nagel Date: Fri, 25 May 2012 23:44:11 -0500 Subject: [PATCH] Pathname: add Mach-O module The MachO module contains methods for learning about Mach-O binaries, and can be used where one might normally shell out to file(1). Signed-off-by: Jack Nagel --- Library/Homebrew/extend/pathname.rb | 7 ++ Library/Homebrew/mach.rb | 93 ++++++++++++++++ Library/Homebrew/test/mach/a.out | Bin 0 -> 25072 bytes Library/Homebrew/test/mach/fat.dylib | Bin 0 -> 16452 bytes Library/Homebrew/test/mach/i386.dylib | Bin 0 -> 4164 bytes Library/Homebrew/test/mach/x86_64.dylib | Bin 0 -> 4176 bytes Library/Homebrew/test/test_mach.rb | 140 ++++++++++++++++++++++++ 7 files changed, 240 insertions(+) create mode 100644 Library/Homebrew/mach.rb create mode 100755 Library/Homebrew/test/mach/a.out create mode 100644 Library/Homebrew/test/mach/fat.dylib create mode 100644 Library/Homebrew/test/mach/i386.dylib create mode 100644 Library/Homebrew/test/mach/x86_64.dylib create mode 100644 Library/Homebrew/test/test_mach.rb diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index 98618be416..bd0e6154e3 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -1,8 +1,11 @@ require 'pathname' require 'bottles' +require 'mach' # we enhance pathname to make our code more readable class Pathname + include MachO + def install *sources results = [] sources.each do |src| @@ -268,6 +271,10 @@ class Pathname end end + def text_executable? + %r[#!\s*(/.+)+] === open('r') { |f| f.readline } + end + def incremental_hash(hasher) incr_hash = hasher.new self.open('r') do |f| diff --git a/Library/Homebrew/mach.rb b/Library/Homebrew/mach.rb new file mode 100644 index 0000000000..e24cc1bc5e --- /dev/null +++ b/Library/Homebrew/mach.rb @@ -0,0 +1,93 @@ +module MachO + # Mach-O binary methods, see: + # /usr/include/mach-o/loader.h + # /usr/include/mach-o/fat.h + + def mach_data + @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." + end + + 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 + else :dunno + end + + mach_data << { :arch => arch, :type => type } + end + mach_data + rescue + # read() will raise if it sees EOF, which should only happen if the + # file is < 8 bytes. Otherwise, we raise if the file is not a Mach-O + # binary. In both cases, we want to return an empty array. + [] + end + end + + def archs + mach_data.map{ |m| m.fetch :arch } + end + + def arch + case archs.length + when 0 then :dunno + when 1 then archs.first + else :universal + end + end + + def universal? + arch == :universal + end + + def i386? + arch == :i386 + end + + def x86_64? + arch == :x86_64 + end + + def ppc7400? + arch == :ppc7400 + end + + def ppc64? + arch == :ppc64 + end + + def dylib? + mach_data.map{ |m| m.fetch :type }.include? :dylib + end + + def mach_o_executable? + mach_data.map{ |m| m.fetch :type }.include? :executable + end +end diff --git a/Library/Homebrew/test/mach/a.out b/Library/Homebrew/test/mach/a.out new file mode 100755 index 0000000000000000000000000000000000000000..18e0e982f8b8bfc9060361c83a0e8347a53842f4 GIT binary patch literal 25072 zcmeHOU2IfE6rODhR48Q$HP+bTt?6np1e!=pYoggAg(X0(P?BnB#%;T_CEIPY-Iij+ zY_ecnYfWE$=fMXbYVe`@V8D_<)cBKNB5y_|DG`%Ki6Sx7@4I)Vy}kVde%K06NfFcPEnliL}el|Bh48;Xr;0I(Tt1 zOY_FjF_203q`J(*;5g1e2fC{>%zWh6r}bd!cu%TR_oR;Yp-oW7S?GvCem0=Pr_TMx zm^&A{8d@5BPaM?ke3-ew<y3+ApJrqw5@ZAghmr))1`o~O>C9PAK2X8w1 zGwB67${eMN(YP$2gL7bYYMqQPr=!B?s0irb+Olgz>&|#44uPTIw^TbG6x9J8wmnNg zXnqU(_crZo+_l%P>smZOKjkPjfku2U+gf@=sVtk!lA~1lEQ31u3h+Bna_RHC`TSk* z>rlq3lUSgifYlHcm}By0=}2Oh3$g_>Fvp$_U)Y~lAYimLgE;< zWPfSfefgQoZ$B`-<7`LAXVsALQ`PFV%-!EE$HcL?atiN+ux=M4j%5cD-%T9W6`VvK znj0U+c<97HCegcX=QfPBr(LN>(Sq-O$C;aNutI`>ARq_`0)l`bAP5Kog218(98>wL zxgVx;*TW-iMfr;A(F4W#{nbUe$Zy8^ zH^#;eqx<#pDe7+hfca?l1>_eS{~&{g`2#nnHlaFl;AXz@M*dRnLV4TdOoZo_nTUg2 zscvT1xTo&s7Wf+3ZXOI~B0M6E#S+P6-&W^%Upm=YwbtEkbL&p>m)tV*Ovx=Y({Xbw zWSvKZ67&qay}`^9HqSi&)F5p|sztKIbM9M9?A2`>DFp#RKoAfF1OY)n5D)|e0YN|z z5CjAPLEzp;U}Ka<<>b?e>WLY0QM=J`@{}@$O=ysq+rw zK~v{FMg;Z35H2|IS8wFJy%ej!0X5D)|e0YN|z5CjAPK|l}? z1Ox#=;BFB3!t?(R!9gI)1NnL+2WRZlMhVZ;F{DLf08AVAz-;PE71UFM7X*FS+1~As zGx|I-Jbj#3Az2^hm0|?O;n+-la9MYWy!8Wj1wJ2r@}951ZM|@O)o`MqK00QQEbnpf zzxKrqP_|O+K&{b7UuqJ0;yz0Y#e|4^t*8zCYN1t~%^VW%7FTQm`y>_lwj9)PNYRtH(pX+QX zS}B&H#^^J{QRMyK$@S}>iH_-6`}O(b8#v~bVjN;dpTou=@_v1ubS|I!-3Q_w zoWMMQCr!JP^Vi}Z9Q3b4HjI)O(f@w}JYB7_Revx3p&R|}{|=~|CB{EENQ=cku#t^{ zxbo_)H-6tzyZgPtE14&6YEh9=em2G9sgsp|NmAR2EV%wiC7c!JBhVGv)OnH z-pcasQ%DdH1Ox#=KoAfF1c84WfnzF`zZ!$ber)7qacp!joWGU(ICTEI!dU3%SpKUY zi(DDeiOf7p=EG{Po@L*TdYiso3b#%_yw1e&fw?HFZA()>l84yAW=h z9Gi)hVs|?e2_x@jzksj){?W>-kTx8eiF}RnZv6GRU9)!B`Jf67heP3#HN|5XANQvW3MilP=n2zKHI#;5D|mMOVtZk9bI$`To6R|) z)s!!p(yFngJ;y#}&UaQWr63>(2m*qDARq_`0)l`bAP5Kof`A|(2;6%JEb9MX1E2po zpZ|X};Q!Ch_$Olk#w%fqoUVjY8v}63f#geO-!S{uvB-^AM%^lHR;4t8n)?a*EX$kSGKFT@S}3EF!+2LJ#7 literal 0 HcmV?d00001 diff --git a/Library/Homebrew/test/mach/fat.dylib b/Library/Homebrew/test/mach/fat.dylib new file mode 100644 index 0000000000000000000000000000000000000000..6886a6a8bc3af320086b5ad9fac5ecfb2c0e36cb GIT binary patch literal 16452 zcmeI2&r4KM6vxk-DIIdmw~#RUNl3H^HE1!ls&qgpVi3up$39r1+Uro zM?}z~C|W5ILahpF)uLS+cL^>DF+SH<7@I7$ux#!;d&b{yRW^?YDH|xtU zMI_;fG^0hbi6d76ZPjS+j#xt-ZZ7jk+EVp zS|4x4#ye*pf*-wGJWkXHH|%Z9rGd*AvwZ^*yNFkv&DjURO>u8XtM*Q)cBqEqXdSsV znlDXEbe-xd%xYKUn8?mmqH8 z#Yk?coOy63u`j>&ae2B^$8Zj5!Y?koY|5y`TAZgPF{iB~-QLt>x4t3t>g-gxIM#I` zdS_iA$5j!>)h2}j3JH(^36KB@kN^pg011!)3H&7j!~OoMKUed;YQ?K1y{iA^`YYs9 z2km*{7I_cy-qUKKp3OPYN3NOHe8{y~pt?ai*sdLjbNh-oGp^&Nn^TKAgZv7y=f8y# zt&{V6-Fu1NR^vT6pjZ zLGf05YNJ{|?k^yXYW<6Pr*KHu!R}P!Z&crZtk0sp4!e`!{HQ5!TZ0dZ#v*+>|EFv2 z?YcKuom7i@_wTB?r$6)#6(5~-p0_=`zx3?wneA%sxLf*_ntQz7zUA9#9101L011!) z36KB@kN^pg011%5&l4E-R~J5~D%o^pFy#-{{A{(7ttGS7h1aPc|8W4xG?F>!6PpyH ezs(;9wwz|8{=awx<7knaqV|uF@w)#`HUIDT`nQ4r literal 0 HcmV?d00001 diff --git a/Library/Homebrew/test/mach/i386.dylib b/Library/Homebrew/test/mach/i386.dylib new file mode 100644 index 0000000000000000000000000000000000000000..0304dca0127367e67773cd96f0ae652acf2b5b0a GIT binary patch literal 4164 zcmeHKO-n*S6unQ&Bn@4(2r7z@Xc1b_qFR;@k}`q}+Qg7N1)&uDpj-rkv@kdRil9Y7 zv}zaBE@;j-k9|Ul$ElL$rr$yU=>OJ2Gh)g0*J@Au8r{cIum9i(9tfey9bPmDZ z8rL|xfjISF!uu}+N^QlqH_d3wc?0imBMOuEXRae7Fy??UpcCh6$WbPl&gH_3VXF*N zWJaX2fStaAUTjBxSaTE(?RjYWK41svmQF{ffA>y*dmJgO>wjHOq^?$tyTIke{q6Hg z2r=G6Jp5(s14{sNc^{wa467lLQXwC~3yIxwp_n=juQ_j?MFwjGvHbcw#I$GzGy|Fe z&46Y=GoTsJ3}^;41DXNN!2cQ8tG!j-)Hk9%wJR?TeI&6eA2R-e2Fj~ogo>{{KL z!yAWb4s*nfJrvXCVDHCJ*BR&G^oXGjEla#^X-sj4E6WAYizV&Zn4M)>+PRp1EmbI% Lk}8P-J(ZVlm%mWy literal 0 HcmV?d00001 diff --git a/Library/Homebrew/test/mach/x86_64.dylib b/Library/Homebrew/test/mach/x86_64.dylib new file mode 100644 index 0000000000000000000000000000000000000000..781b41cb4b979f1c7e4b69868b450586512551d7 GIT binary patch literal 4176 zcmeHKO-mb56upzQCe&DG5sIRSNGYzOLKj)~OGr>8*a&XqHDM++pa~>1XbOQW+Cu22 zKcYXtZA%x0{s7nR+;k~)DMhO1%zIXGEN|h)e*F zfa8?NCvoA4%mPJ6M5*ffZZ%5XUUbIqr-S6GBKFgaD#t%m2 z3+E>HU#8y+bBS^MZOJ~d zPu@6Nsm=1%#`>Fb%w5da*j_Og$s6dtu_<`Vzzm@CTpihO)*J11VXffx;EF7X3|4V+ zr(rHf<0p=K&LE&)#LgL$Km|yeo*2(hp4{!vp@ePh|l^vB^-