python/mozbuild/mozpack/executables.py

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

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

mercurial