[pygccxml-commit] SF.net SVN: pygccxml:[1491] pygccxml_dev/pygccxml/msvc
Brought to you by:
mbaas,
roman_yakovenko
From: <rom...@us...> - 2008-12-24 08:12:32
|
Revision: 1491 http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1491&view=rev Author: roman_yakovenko Date: 2008-12-24 08:12:27 +0000 (Wed, 24 Dec 2008) Log Message: ----------- integrating "get_exports.py" functionality with pygccxml Modified Paths: -------------- pygccxml_dev/pygccxml/msvc/common_utils.py Added Paths: ----------- pygccxml_dev/pygccxml/msvc/get_dll_exported_symbols.py Modified: pygccxml_dev/pygccxml/msvc/common_utils.py =================================================================== --- pygccxml_dev/pygccxml/msvc/common_utils.py 2008-12-23 20:54:48 UTC (rev 1490) +++ pygccxml_dev/pygccxml/msvc/common_utils.py 2008-12-24 08:12:27 UTC (rev 1491) @@ -185,6 +185,11 @@ undecorate_blob = undname_creator().undecorate_blob undecorate_decl = undname_creator().undecorated_decl +import exceptions +class LicenseWarning( exceptions.UserWarning ): + def __init__( self, *args, **keywd ): + exceptions.UserWarning.__init__( self, *args, **keywd ) + class exported_symbols: map_file_re = re.compile( r' +\d+ (?P<decorated>.+?) \((?P<undecorated>.+)\)$' ) @staticmethod @@ -206,19 +211,17 @@ @staticmethod def load_from_dll_file( fname ): - import get_exports + import warnings + warnings.warn( '\n'*2 + '-' * 30 + '>>LICENSE WARNING<<' + '-'*30 + + '\n"load_from_dll_file" functionality uses code licensed under MIT license.' + + '\npygccxml project uses Boost Software License, Version 1.0. ' + + '\nFor more information about this functionality take a look on get_dll_exported_symbols.py file.' + + '\n' + '='*79 + + '\n' * 2 + , LicenseWarning ) + import get_dll_exported_symbols result = {} - blobs = get_exports.read_export_table( fname ) + blobs = get_dll_exported_symbols.read_export_table( fname ) for blob in blobs: result[ blob ] = undecorate_blob( blob ) return result - -#~ quick & dirty test -#~ symbols = exported_symbols.load_from_map_file( r'D:\dev\language-binding\sources\pygccxml_dev\unittests\data\msvc\Release\mydll.map' ) -#~ for decorated, undecorated in symbols.iteritems(): - #~ print '---------------------------------------------------------------------' - #~ print decorated - #~ print undecorated - #~ print undecorate_blob( decorated ) - #~ print '=====================================================================' - Added: pygccxml_dev/pygccxml/msvc/get_dll_exported_symbols.py =================================================================== --- pygccxml_dev/pygccxml/msvc/get_dll_exported_symbols.py (rev 0) +++ pygccxml_dev/pygccxml/msvc/get_dll_exported_symbols.py 2008-12-24 08:12:27 UTC (rev 1491) @@ -0,0 +1,290 @@ +#The content of this file was contributed by leppton +# (http://mail.python.org/pipermail/patches/2006-November/020942.html) to ctypes +# project, under MIT License. + +# This example shows how to use ctypes module to read all +# function names from dll export directory + +import os +if os.name != "nt": + raise Exception("Wrong OS") + +import ctypes as ctypes +import ctypes.wintypes as wintypes + +def convert_cdef_to_pydef(line): + """\ +convert_cdef_to_pydef(line_from_c_header_file) -> python_tuple_string +'DWORD var_name[LENGTH];' -> '("var_name", DWORD*LENGTH)' + +doesn't work for all valid c/c++ declarations""" + l = line[:line.find(';')].split() + if len(l) != 2: + return None + type_ = l[0] + name = l[1] + i = name.find('[') + if i != -1: + name, brac = name[:i], name[i:][1:-1] + return '("%s", %s*%s)'%(name,type_,brac) + else: + return '("%s", %s)'%(name,type_) + +def convert_cdef_to_structure(cdef, name, data_dict=ctypes.__dict__): + """\ +convert_cdef_to_structure(struct_definition_from_c_header_file) + -> python class derived from ctypes.Structure + +limited support for c/c++ syntax""" + py_str = '[\n' + for line in cdef.split('\n'): + field = convert_cdef_to_pydef(line) + if field != None: + py_str += ' '*4 + field + ',\n' + py_str += ']\n' + + pyarr = eval(py_str, data_dict) + class ret_val(ctypes.Structure): + _fields_ = pyarr + ret_val.__name__ = name + ret_val.__module__ = None + return ret_val + +#struct definitions we need to read dll file export table +winnt = ( + ('IMAGE_DOS_HEADER', """\ + WORD e_magic; + WORD e_cblp; + WORD e_cp; + WORD e_crlc; + WORD e_cparhdr; + WORD e_minalloc; + WORD e_maxalloc; + WORD e_ss; + WORD e_sp; + WORD e_csum; + WORD e_ip; + WORD e_cs; + WORD e_lfarlc; + WORD e_ovno; + WORD e_res[4]; + WORD e_oemid; + WORD e_oeminfo; + WORD e_res2[10]; + LONG e_lfanew; +"""), + + ('IMAGE_FILE_HEADER', """\ + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +"""), + + ('IMAGE_DATA_DIRECTORY', """\ + DWORD VirtualAddress; + DWORD Size; +"""), + + ('IMAGE_OPTIONAL_HEADER32', """\ + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +""", + {'IMAGE_NUMBEROF_DIRECTORY_ENTRIES':16}), + + ('IMAGE_NT_HEADERS', """\ + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +"""), + + ('IMAGE_EXPORT_DIRECTORY', """\ + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; +"""), + ) + +#Construct python ctypes.Structures from above definitions +data_dict = dict(wintypes.__dict__) +for definition in winnt: + name = definition[0] + def_str = definition[1] + if len(definition) == 3: + data_dict.update(definition[2]) + type_ = convert_cdef_to_structure(def_str, name, data_dict) + data_dict[name] = type_ + globals()[name] = type_ + + ptype = ctypes.POINTER(type_) + pname = 'P'+name + data_dict[pname] = ptype + globals()[pname] = ptype + +del data_dict +del winnt + +class DllException(Exception): + pass + +def read_export_table(dll_name, mmap=False, use_kernel=False): + """\ +read_export_table(dll_name [,mmap=False [,use_kernel=False]]]) + -> list of exported names + +default is to load dll into memory: dll sections are aligned to +page boundaries, dll entry points is called, etc... + +with mmap=True dll file image is mapped to memory, Relative Virtual +Addresses (RVAs) must be mapped to real addresses manually + +with use_kernel=True direct kernel32.dll calls are used, +instead of python mmap module + +see http://www.windowsitlibrary.com/Content/356/11/1.html +for details on Portable Executable (PE) file format +""" + if not mmap: + dll = ctypes.cdll.LoadLibrary(dll_name) + if dll == None: + raise DllException("Cant load dll") + base_addr = dll._handle + + else: + if not use_kernel: + fileH = open(dll_name) + if fileH == None: + raise DllException("Cant load dll") + import mmap + m = mmap.mmap(fileH.fileno(), 0, None, mmap.ACCESS_READ) + # id(m)+8 sucks, is there better way? + base_addr = ctypes.cast(id(m)+8, ctypes.POINTER(ctypes.c_int))[0] + else: + kernel32 = ctypes.windll.kernel32 + if kernel32 == None: + raise DllException("cant load kernel") + fileH = kernel32.CreateFileA(dll_name, 0x00120089, 1,0,3,0,0) + if fileH == 0: + raise DllException("Cant open, errcode = %d"%kernel32.GetLastError()) + mapH = kernel32.CreateFileMappingW(fileH,0,0x8000002,0,0,0) + if mapH == 0: + raise DllException("Cant mmap, errocode = %d"%kernel32.GetLastError()) + base_addr = ctypes.windll.kernel32.MapViewOfFile(mapH, 0x4, 0, 0, 0) + if base_addr == 0: + raise DllException("Cant mmap(2), errocode = %d"%kernel32.GetLastError()) + + dbghelp = ctypes.windll.dbghelp + if dbghelp == None: + raise DllException("dbghelp.dll not installed") + pimage_nt_header = dbghelp.ImageNtHeader(base_addr) + if pimage_nt_header == 0: + raise DllException("Cant find IMAGE_NT_HEADER") + + #Functions like dbghelp.ImageNtHeader above have no type information + #let's make one prototype for extra buzz + #PVOID ImageRvaToVa(PIMAGE_NT_HEADERS NtHeaders, PVOID Base, + # ULONG Rva, PIMAGE_SECTION_HEADER* LastRvaSection) + # we use integers instead of pointers, coz integers are better + # for pointer arithmetic + prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, + ctypes.c_int, ctypes.c_int, ctypes.c_int) + paramflags = ((1,"NtHeaders",pimage_nt_header),(1,"Base",base_addr),(1,"Rva"),(1,"LastRvaSection",0)) + ImageRvaToVa = prototype(('ImageRvaToVa', dbghelp), paramflags) + + def cast_rva(rva, type_): + va = base_addr + rva + if mmap and va > pimage_nt_header: + va = ImageRvaToVa(Rva=rva) + if va == 0: + raise DllException("ImageRvaToVa failed") + return ctypes.cast(va, type_) + + if not mmap: + dos_header = cast_rva(0, PIMAGE_DOS_HEADER)[0] + if dos_header.e_magic != 0x5A4D: + raise DllException("IMAGE_DOS_HEADER.e_magic error") + nt_header = cast_rva(dos_header.e_lfanew, PIMAGE_NT_HEADERS)[0] + else: + nt_header = ctypes.cast(pimage_nt_header, PIMAGE_NT_HEADERS)[0] + if nt_header.Signature != 0x00004550: + raise DllException("IMAGE_NT_HEADERS.Signature error") + + opt_header = nt_header.OptionalHeader + if opt_header.Magic != 0x010b: + raise DllException("IMAGE_OPTIONAL_HEADERS32.Magic error") + + ret_val = [] + exports_dd = opt_header.DataDirectory[0] + if opt_header.NumberOfRvaAndSizes > 0 or exports_dd != 0: + export_dir = cast_rva(exports_dd.VirtualAddress, PIMAGE_EXPORT_DIRECTORY)[0] + + nNames = export_dir.NumberOfNames + if nNames > 0: + PNamesType = ctypes.POINTER(ctypes.c_int * nNames) + names = cast_rva(export_dir.AddressOfNames, PNamesType)[0] + for rva in names: + name = cast_rva(rva, ctypes.c_char_p).value + ret_val.append(name) + + if mmap: + if use_kernel: + kernel32.UnmapViewOfFile(base_addr) + kernel32.CloseHandle(mapH) + kernel32.CloseHandle(fileH) + else: + m.close() + fileH.close() + return ret_val + + +if __name__ == '__main__': + import sys + if len(sys.argv) != 2: + print 'usage: %s dll_file_name'%sys.argv[0] + sys.exit() +## names = read_export_table(sys.argv[1], mmap=False, use_kernel=False) + names = read_export_table(sys.argv[1], mmap=False, use_kernel=False) + for name in names: + print name + + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |