|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 import os |
|
6 import struct |
|
7 import subprocess |
|
8 from mozpack.errors import errors |
|
9 |
|
10 MACHO_SIGNATURES = [ |
|
11 0xfeedface, # mach-o 32-bits big endian |
|
12 0xcefaedfe, # mach-o 32-bits little endian |
|
13 0xfeedfacf, # mach-o 64-bits big endian |
|
14 0xcffaedfe, # mach-o 64-bits little endian |
|
15 ] |
|
16 |
|
17 FAT_SIGNATURE = 0xcafebabe # mach-o FAT binary |
|
18 |
|
19 ELF_SIGNATURE = 0x7f454c46 # Elf binary |
|
20 |
|
21 UNKNOWN = 0 |
|
22 MACHO = 1 |
|
23 ELF = 2 |
|
24 |
|
25 def get_type(path): |
|
26 ''' |
|
27 Check the signature of the give file and returns what kind of executable |
|
28 matches. |
|
29 ''' |
|
30 with open(path, 'rb') as f: |
|
31 signature = f.read(4) |
|
32 if len(signature) < 4: |
|
33 return UNKNOWN |
|
34 signature = struct.unpack('>L', signature)[0] |
|
35 if signature == ELF_SIGNATURE: |
|
36 return ELF |
|
37 if signature in MACHO_SIGNATURES: |
|
38 return MACHO |
|
39 if signature != FAT_SIGNATURE: |
|
40 return UNKNOWN |
|
41 # We have to sanity check the second four bytes, because Java class |
|
42 # files use the same magic number as Mach-O fat binaries. |
|
43 # This logic is adapted from file(1), which says that Mach-O uses |
|
44 # these bytes to count the number of architectures within, while |
|
45 # Java uses it for a version number. Conveniently, there are only |
|
46 # 18 labelled Mach-O architectures, and Java's first released |
|
47 # class format used the version 43.0. |
|
48 num = f.read(4) |
|
49 if len(num) < 4: |
|
50 return UNKNOWN |
|
51 num = struct.unpack('>L', num)[0] |
|
52 if num < 20: |
|
53 return MACHO |
|
54 return UNKNOWN |
|
55 |
|
56 |
|
57 def is_executable(path): |
|
58 ''' |
|
59 Return whether a given file path points to an executable or a library, |
|
60 where an executable or library is identified by: |
|
61 - the file extension on OS/2 and WINNT |
|
62 - the file signature on OS/X and ELF systems (GNU/Linux, Android, BSD, |
|
63 Solaris) |
|
64 |
|
65 As this function is intended for use to choose between the ExecutableFile |
|
66 and File classes in FileFinder, and choosing ExecutableFile only matters |
|
67 on OS/2, OS/X, ELF and WINNT (in GCC build) systems, we don't bother |
|
68 detecting other kind of executables. |
|
69 ''' |
|
70 from buildconfig import substs |
|
71 if not os.path.exists(path): |
|
72 return False |
|
73 |
|
74 if substs['OS_ARCH'] == 'WINNT': |
|
75 return path.lower().endswith((substs['DLL_SUFFIX'], |
|
76 substs['BIN_SUFFIX'])) |
|
77 |
|
78 return get_type(path) != UNKNOWN |
|
79 |
|
80 |
|
81 def may_strip(path): |
|
82 ''' |
|
83 Return whether strip() should be called |
|
84 ''' |
|
85 from buildconfig import substs |
|
86 return not substs['PKG_SKIP_STRIP'] |
|
87 |
|
88 |
|
89 def strip(path): |
|
90 ''' |
|
91 Execute the STRIP command with STRIP_FLAGS on the given path. |
|
92 ''' |
|
93 from buildconfig import substs |
|
94 strip = substs['STRIP'] |
|
95 flags = substs['STRIP_FLAGS'].split() if 'STRIP_FLAGS' in substs else [] |
|
96 cmd = [strip] + flags + [path] |
|
97 if subprocess.call(cmd) != 0: |
|
98 errors.fatal('Error executing ' + ' '.join(cmd)) |
|
99 |
|
100 |
|
101 def may_elfhack(path): |
|
102 ''' |
|
103 Return whether elfhack() should be called |
|
104 ''' |
|
105 # elfhack only supports libraries. We should check the ELF header for |
|
106 # the right flag, but checking the file extension works too. |
|
107 from buildconfig import substs |
|
108 return 'USE_ELF_HACK' in substs and substs['USE_ELF_HACK'] and \ |
|
109 path.endswith(substs['DLL_SUFFIX']) |
|
110 |
|
111 |
|
112 def elfhack(path): |
|
113 ''' |
|
114 Execute the elfhack command on the given path. |
|
115 ''' |
|
116 from buildconfig import topobjdir |
|
117 cmd = [os.path.join(topobjdir, 'build/unix/elfhack/elfhack'), path] |
|
118 if 'ELF_HACK_FLAGS' in os.environ: |
|
119 cmd[1:0] = os.environ['ELF_HACK_FLAGS'].split() |
|
120 if subprocess.call(cmd) != 0: |
|
121 errors.fatal('Error executing ' + ' '.join(cmd)) |