import ast import distutils.spawn import signal import subprocess import sys def execute_command(cmd, input_str=None): """ Execute a command, capture and return its output. """ kwargs = { 'stdin': subprocess.PIPE, 'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE, } p = subprocess.Popen(cmd, **kwargs) out, err = p.communicate(input=input_str) exitCode = p.wait() if exitCode == -signal.SIGINT: raise KeyboardInterrupt return out, err, exitCode def execute_command_verbose(cmd, input_str=None): """ Execute a command and print its output on failure. """ out, err, exitCode = execute_command(cmd, input_str=input_str) if exitCode != 0: report = "Command: %s\n" % ' '.join(["'%s'" % a for a in cmd]) report += "Exit Code: %d\n" % exitCode if out: report += "Standard Output:\n--\n%s--" % out if err: report += "Standard Error:\n--\n%s--" % err report += "\n\nFailed!" sys.stderr.write('%s\n' % report) return out, err, exitCode def read_syms_from_list(slist): """ Read a list of symbols from a list of strings. Each string is one symbol. """ return [ast.literal_eval(l) for l in slist] def read_syms_from_file(filename): """ Read a list of symbols in from a file. """ with open(filename, 'r') as f: data = f.read() return read_syms_from_list(data.splitlines()) def read_blacklist(filename): with open(filename, 'r') as f: data = f.read() lines = [l.strip() for l in data.splitlines() if l.strip()] lines = [l for l in lines if not l.startswith('#')] return lines def write_syms(sym_list, out=None, names_only=False): """ Write a list of symbols to the file named by out. """ out_str = '' out_list = sym_list if names_only: out_list = [sym['name'] for sym in sym_list] out_list.sort() for sym in out_list: out_str += '%s\n' % sym if out is None: sys.stdout.write(out_str) else: with open(out, 'w') as f: f.write(out_str) _cppfilt_exe = distutils.spawn.find_executable('c++filt') def demangle_symbol(symbol): if _cppfilt_exe is None: return symbol out, _, exit_code = execute_command_verbose( [_cppfilt_exe], input_str=symbol) if exit_code != 0: return symbol return out def is_elf(filename): with open(filename, 'r') as f: magic_bytes = f.read(4) return magic_bytes == '\x7fELF' def is_mach_o(filename): with open(filename, 'r') as f: magic_bytes = f.read(4) return magic_bytes in [ '\xfe\xed\xfa\xce', # MH_MAGIC '\xce\xfa\xed\xfe', # MH_CIGAM '\xfe\xed\xfa\xcf', # MH_MAGIC_64 '\xcf\xfa\xed\xfe', # MH_CIGAM_64 '\xca\xfe\xba\xbe', # FAT_MAGIC '\xbe\xba\xfe\xca' # FAT_CIGAM ] def is_library_file(filename): if sys.platform == 'darwin': return is_mach_o(filename) else: return is_elf(filename) def extract_or_load(filename): import sym_check.extract if is_library_file(filename): return sym_check.extract.extract_symbols(filename) return read_syms_from_file(filename)