diff -r 509e4801c378 -r 22878952f6e2 srcanamdw/codescanner/pyinstaller/bindepend.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srcanamdw/codescanner/pyinstaller/bindepend.py Thu Feb 18 12:29:02 2010 +0530 @@ -0,0 +1,330 @@ +#! /usr/bin/env python +# Find external dependencies of binary libraries. +# Copyright (C) 2005, Giovanni Bajo +# Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +# use dumpbin.exe (if present) to find the binary +# dependencies of an extension module. +# if dumpbin not available, pick apart the PE hdr of the binary +# while this appears to work well, it is complex and subject to +# problems with changes to PE hdrs (ie, this works only on 32 bit Intel +# Windows format binaries) +# +# Note also that you should check the results to make sure that the +# dlls are redistributable. I've listed most of the common MS dlls +# under "excludes" below; add to this list as necessary (or use the +# "excludes" option in the INSTALL section of the config file). + +import os +import time +import string +import sys +import re + +seen = {} +_bpath = None +iswin = sys.platform[:3] == 'win' +cygwin = sys.platform == 'cygwin' +excludes = {'KERNEL32.DLL':1, + 'ADVAPI.DLL':1, + 'MSVCRT.DLL':1, + 'ADVAPI32.DLL':1, + 'COMCTL32.DLL':1, + 'CRTDLL.DLL':1, + 'GDI32.DLL':1, + 'MFC42.DLL':1, + 'NTDLL.DLL':1, + 'OLE32.DLL':1, + 'OLEAUT32.DLL':1, + 'RPCRT4.DLL':1, + 'SHELL32.DLL':1, + 'USER32.DLL':1, + 'WINSPOOL.DRV':1, + 'WS2HELP.DLL':1, + 'WS2_32.DLL':1, + 'WSOCK32.DLL':1, + 'MSWSOCK.DLL':1, + 'WINMM.DLL':1, + 'COMDLG32.DLL':1, +## 'ZLIB.DLL':1, # test with python 1.5.2 + 'ODBC32.DLL':1, + 'VERSION.DLL':1, + 'IMM32.DLL':1, + 'DDRAW.DLL':1, + 'DCIMAN32.DLL':1, + 'OPENGL32.DLL':1, + 'GLU32.DLL':1, + 'GLUB32.DLL':1, + '/usr/lib':1, + '/lib':1,} + +def getfullnameof(mod, xtrapath = None): + """Return the full path name of MOD. + + MOD is the basename of a dll or pyd. + XTRAPATH is a path or list of paths to search first. + Return the full path name of MOD. + Will search the full Windows search path, as well as sys.path""" + epath = getWindowsPath() + sys.path + if xtrapath is not None: + if type(xtrapath) == type(''): + epath.insert(0, xtrapath) + else: + epath = xtrapath + epath + for p in epath: + npth = os.path.join(p, mod) + if os.path.exists(npth): + return npth + return '' + +def getImports1(pth): + """Find the binary dependencies of PTH. + + This implementation (not used right now) uses the MSVC utility dumpbin""" + import tempfile + rslt = [] + tmpf = tempfile.mktemp() + os.system('dumpbin /IMPORTS "%s" >%s' %(pth, tmpf)) + time.sleep(0.1) + txt = open(tmpf,'r').readlines() + os.remove(tmpf) + i = 0 + while i < len(txt): + tokens = string.split(txt[i]) + if len(tokens) == 1 and string.find(tokens[0], '.') > 0: + rslt.append(string.strip(tokens[0])) + i = i + 1 + return rslt + +def getImports2x(pth): + """Find the binary dependencies of PTH. + + This implementation walks through the PE header""" + import struct + rslt = [] + try: + f = open(pth, 'rb').read() + pehdrd = struct.unpack('l', f[60:64])[0] #after the MSDOS loader is the offset of the peheader + magic = struct.unpack('l', f[pehdrd:pehdrd+4])[0] # pehdr starts with magic 'PE\000\000' (or 17744) + # then 20 bytes of COFF header + numsecs = struct.unpack('h', f[pehdrd+6:pehdrd+8])[0] # whence we get number of sections + opthdrmagic = struct.unpack('h', f[pehdrd+24:pehdrd+26])[0] + if opthdrmagic == 0x10b: # PE32 format + numdictoffset = 116 + importoffset = 128 + elif opthdrmagic == 0x20b: # PE32+ format + numdictoffset = 132 + importoffset = 148 + else: + print "E: bindepend cannot analyze %s - unknown header format! %x" % (pth, opthdrmagic) + return rslt + numdirs = struct.unpack('l', f[pehdrd+numdictoffset:pehdrd+numdictoffset+4])[0] + idata = '' + if magic == 17744: + importsec, sz = struct.unpack('2l', f[pehdrd+importoffset:pehdrd+importoffset+8]) + if sz == 0: + return rslt + secttbl = pehdrd + numdictoffset + 4 + 8*numdirs + secttblfmt = '8s7l2h' + seclist = [] + for i in range(numsecs): + seclist.append(struct.unpack(secttblfmt, f[secttbl+i*40:secttbl+(i+1)*40])) + #nm, vsz, va, rsz, praw, preloc, plnnums, qrelocs, qlnnums, flags \ + # = seclist[-1] + for i in range(len(seclist)-1): + if seclist[i][2] <= importsec < seclist[i+1][2]: + break + vbase = seclist[i][2] + raw = seclist[i][4] + idatastart = raw + importsec - vbase + idata = f[idatastart:idatastart+seclist[i][1]] + i = 0 + while 1: + chunk = idata[i*20:(i+1)*20] + if len(chunk) != 20: + print "E: premature end of import table (chunk is %d, not 20)" % len(chunk) + break + vsa = struct.unpack('5l', chunk)[3] + if vsa == 0: + break + sa = raw + vsa - vbase + end = string.find(f, '\000', sa) + nm = f[sa:end] + if nm: + rslt.append(nm) + i = i + 1 + else: + print "E: bindepend cannot analyze %s - file is not in PE format!" % pth + except IOError: + print "E: bindepend cannot analyze %s - file not found!" % pth + #except struct.error: + # print "E: bindepend cannot analyze %s - error walking thru pehdr" % pth + return rslt + +def getImports2(path): + """Find the binary dependencies of PTH. + + This implementation walks through the PE header""" + import struct + f = open(path, 'rb') + # skip the MSDOS loader + f.seek(60) + # get offset to PE header + offset = struct.unpack('l', f.read(4))[0] + f.seek(offset) + signature = struct.unpack('l', f.read(4))[0] + coffhdrfmt = 'hhlllhh' + rawcoffhdr = f.read(struct.calcsize(coffhdrfmt)) + coffhdr = struct.unpack(coffhdrfmt, rawcoffhdr) + coffhdr_numsections = coffhdr[1] + + opthdrfmt = 'hbblllllllllhhhhhhllllhhllllll' + rawopthdr = f.read(struct.calcsize(opthdrfmt)) + opthdr = struct.unpack(opthdrfmt, rawopthdr) + opthdr_numrvas = opthdr[-1] + + datadirs = [] + datadirsize = struct.calcsize('ll') # virtual address, size + for i in range(opthdr_numrvas): + rawdatadir = f.read(datadirsize) + datadirs.append(struct.unpack('ll', rawdatadir)) + + sectionfmt = '8s6l2hl' + sectionsize = struct.calcsize(sectionfmt) + sections = [] + for i in range(coffhdr_numsections): + rawsection = f.read(sectionsize) + sections.append(struct.unpack(sectionfmt, rawsection)) + + importva, importsz = datadirs[1] + if importsz == 0: + return [] + # figure out what section it's in + NAME, MISC, VIRTADDRESS, RAWSIZE, POINTERTORAW = range(5) + for j in range(len(sections)-1): + if sections[j][VIRTADDRESS] <= importva < sections[j+1][VIRTADDRESS]: + importsection = sections[j] + break + else: + if importva >= sections[-1][VIRTADDRESS]: + importsection = sections[-1] + else: + print "E: import section is unavailable" + return [] + f.seek(importsection[POINTERTORAW] + importva - importsection[VIRTADDRESS]) + data = f.read(importsz) + iidescrfmt = 'lllll' + CHARACTERISTICS, DATETIME, FWDRCHAIN, NAMERVA, FIRSTTHUNK = range(5) + iidescrsz = struct.calcsize(iidescrfmt) + dlls = [] + while data: + iid = struct.unpack(iidescrfmt, data[:iidescrsz]) + if iid[NAMERVA] == 0: + break + f.seek(importsection[POINTERTORAW] + iid[NAMERVA] - importsection[VIRTADDRESS]) + nm = f.read(256) + nm, jnk = string.split(nm, '\0', 1) + if nm: + dlls.append(nm) + data = data[iidescrsz:] + return dlls + +def Dependencies(lTOC): + """Expand LTOC to include all the closure of binary dependencies. + + LTOC is a logical table of contents, ie, a seq of tuples (name, path). + Return LTOC expanded by all the binary dependencies of the entries + in LTOC, except those listed in the module global EXCLUDES""" + for nm, pth, typ in lTOC: + fullnm = string.upper(os.path.basename(pth)) + if seen.get(string.upper(nm),0): + continue + #print "I: analyzing", pth + seen[string.upper(nm)] = 1 + dlls = getImports(pth) + for lib in dlls: + #print "I: found", lib + if not iswin and not cygwin: + npth = lib + dir, lib = os.path.split(lib) + if excludes.get(dir,0): + continue + if excludes.get(string.upper(lib),0): + continue + if seen.get(string.upper(lib),0): + continue + if iswin or cygwin: + npth = getfullnameof(lib, os.path.dirname(pth)) + if npth: + lTOC.append((lib, npth, 'BINARY')) + else: + print "E: lib not found:", lib, "dependency of", pth + return lTOC + +def getImports3(pth): + """Find the binary dependencies of PTH. + + This implementation is for ldd platforms""" + rslt = [] + for line in os.popen('ldd "%s"' % pth).readlines(): + m = re.search(r"\s+(.*?)\s+=>\s+(.*?)\s+\(.*\)", line) + if m: + name, lib = m.group(1), m.group(2) + if name[:10] == 'linux-gate': + # linux-gate is a fake library which does not exist and + # should be ignored. See also: + # http://www.trilithium.com/johan/2005/08/linux-gate/ + continue + if os.path.exists(lib): + rslt.append(lib) + else: + print 'E: cannot find %s in path %s (needed by %s)' % \ + (name, lib, pth) + return rslt + +def getImports(pth): + """Forwards to either getImports2 or getImports3 + """ + if sys.platform[:3] == 'win' or sys.platform == 'cygwin': + return getImports2(pth) + return getImports3(pth) + +def getWindowsPath(): + """Return the path that Windows will search for dlls.""" + global _bpath + if _bpath is None: + _bpath = [] + if iswin: + try: + import win32api + except ImportError: + print "W: Cannot determine your Windows or System directories" + print "W: Please add them to your PATH if .dlls are not found" + print "W: or install starship.python.net/skippy/win32/Downloads.html" + else: + sysdir = win32api.GetSystemDirectory() + sysdir2 = os.path.normpath(os.path.join(sysdir, '..', 'SYSTEM')) + windir = win32api.GetWindowsDirectory() + _bpath = [sysdir, sysdir2, windir] + _bpath.extend(string.split(os.environ.get('PATH', ''), os.pathsep)) + return _bpath + +if __name__ == "__main__": + if len(sys.argv) < 2: + print "Usage: python %s BINARYFILE" % sys.argv[0] + sys.exit(0) + print getImports(sys.argv[1])