[pygccxml-commit] SF.net SVN: pygccxml:[1538] pygccxml_dev
Brought to you by:
mbaas,
roman_yakovenko
From: <rom...@us...> - 2009-01-06 08:38:34
|
Revision: 1538 http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1538&view=rev Author: roman_yakovenko Date: 2009-01-06 08:38:32 +0000 (Tue, 06 Jan 2009) Log Message: ----------- small refactoring, which allows to merge information from binary files to the declarations tree Modified Paths: -------------- pygccxml_dev/pygccxml/binary_parsers/__init__.py pygccxml_dev/pygccxml/declarations/decl_printer.py pygccxml_dev/pygccxml/declarations/declaration.py pygccxml_dev/unittests/data/core_cache.hpp pygccxml_dev/unittests/undname_creator_tester.py Added Paths: ----------- pygccxml_dev/pygccxml/binary_parsers/parsers.py pygccxml_dev/pygccxml/binary_parsers/undname.py Removed Paths: ------------- pygccxml_dev/pygccxml/binary_parsers/common_utils.py Modified: pygccxml_dev/pygccxml/binary_parsers/__init__.py =================================================================== --- pygccxml_dev/pygccxml/binary_parsers/__init__.py 2009-01-05 22:58:43 UTC (rev 1537) +++ pygccxml_dev/pygccxml/binary_parsers/__init__.py 2009-01-06 08:38:32 UTC (rev 1538) @@ -3,7 +3,9 @@ # accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -from common_utils import undecorate_blob -from common_utils import undecorate_decl -from common_utils import exported_symbols -from common_utils import UNDECORATE_NAME_OPTIONS +import sys +import undname +from parsers import merge_information + +def undecorate_blob( blob ): + return undname.undname_creator_t().undecorate_blob( blob ) Deleted: pygccxml_dev/pygccxml/binary_parsers/common_utils.py =================================================================== --- pygccxml_dev/pygccxml/binary_parsers/common_utils.py 2009-01-05 22:58:43 UTC (rev 1537) +++ pygccxml_dev/pygccxml/binary_parsers/common_utils.py 2009-01-06 08:38:32 UTC (rev 1538) @@ -1,285 +0,0 @@ -# Copyright 2004-2008 Roman Yakovenko. -# Distributed under the Boost Software License, Version 1.0. (See -# accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -import os -import re -import sys -import ctypes -from .. import declarations - -class UNDECORATE_NAME_OPTIONS: - UNDNAME_COMPLETE = 0x0000 #Enables full undecoration. - UNDNAME_NO_LEADING_UNDERSCORES = 0x0001 #Removes leading underscores from Microsoft extended keywords. - UNDNAME_NO_MS_KEYWORDS = 0x0002 #Disables expansion of Microsoft extended keywords. - UNDNAME_NO_FUNCTION_RETURNS = 0x0004 #Disables expansion of return type for primary declaration. - UNDNAME_NO_ALLOCATION_MODEL = 0x0008 #Disables expansion of the declaration model. - UNDNAME_NO_ALLOCATION_LANGUAGE = 0x0010 #Disables expansion of the declaration language specifier. - UNDNAME_RESERVED1 = 0x0020 #RESERVED. - UNDNAME_RESERVED2 = 0x0040 #RESERVED. - UNDNAME_NO_THISTYPE = 0x0060 #Disables all modifiers on the this type. - UNDNAME_NO_ACCESS_SPECIFIERS = 0x0080 #Disables expansion of access specifiers for members. - UNDNAME_NO_THROW_SIGNATURES = 0x0100 #Disables expansion of "throw-signatures" for functions and pointers to functions. - UNDNAME_NO_MEMBER_TYPE = 0x0200 #Disables expansion of static or virtual members. - UNDNAME_NO_RETURN_UDT_MODEL = 0x0400 #Disables expansion of the Microsoft model for UDT returns. - UNDNAME_32_BIT_DECODE = 0x0800 #Undecorates 32-bit decorated names. - UNDNAME_NAME_ONLY = 0x1000 #Gets only the name for primary declaration; returns just [scope::]name. Expands template params. - UNDNAME_TYPE_ONLY = 0x2000 #Input is just a type encoding; composes an abstract declarator. - UNDNAME_HAVE_PARAMETERS = 0x4000 #The real template parameters are available. - UNDNAME_NO_ECSU = 0x8000 #Suppresses enum/class/struct/union. - UNDNAME_NO_IDENT_CHAR_CHECK = 0x10000 #Suppresses check for valid identifier characters. - UNDNAME_NO_PTR64 = 0x20000 #Does not include ptr64 in output. - - UNDNAME_SCOPES_ONLY = UNDNAME_NO_LEADING_UNDERSCORES \ - | UNDNAME_NO_MS_KEYWORDS \ - | UNDNAME_NO_FUNCTION_RETURNS \ - | UNDNAME_NO_ALLOCATION_MODEL \ - | UNDNAME_NO_ALLOCATION_LANGUAGE \ - | UNDNAME_NO_ACCESS_SPECIFIERS \ - | UNDNAME_NO_THROW_SIGNATURES \ - | UNDNAME_NO_MEMBER_TYPE \ - | UNDNAME_NO_ECSU \ - | UNDNAME_NO_IDENT_CHAR_CHECK - - SHORT_UNIQUE_NAME = UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_ECSU - -#~ The following code doesn't work - access violation - -#~__unDName definition was taken from: -#~http://www.tech-archive.net/Archive/VC/microsoft.public.vc.language/2006-02/msg00754.html - -#~ msvcrxx = ctypes.windll.msvcr90 -#~ free_type = ctypes.CFUNCTYPE( None, ctypes.c_void_p ) #free type -#~ malloc_type = ctypes.CFUNCTYPE( ctypes.c_void_p, ctypes.c_uint ) #malloc type -#~ __unDName = msvcrxx.__unDName -#~ __unDName.argtypes = [ ctypes.c_char_p #undecorated name - #~ , ctypes.c_char_p #decorated name - #~ , ctypes.c_int #sizeof undecorated name - #~ , malloc_type - #~ , free_type - #~ , ctypes.c_ushort #flags - #~ ] -#~ __unDName.restype = ctypes.c_char_p -#~ def undecorate_name( name, options=None ): - #~ if not name: - #~ return '' - #~ if options is None: - #~ options = UNDECORATE_NAME_OPTIONS.SHORT_UNIQUE_NAME - #~ buffer_size = 1024 * 32 - #~ undecorated_name = ctypes.create_string_buffer('\0' * buffer_size) #should be enouph for any symbol - #~ __unDName( undecorated_name - #~ , str(name) - #~ , buffer_size - #~ , malloc_type( msvcrxx.malloc ) - #~ , free_type( msvcrxx.free ) - #~ , options ) - #~ return undecorated_name.value - -class undname_creator: - def __init__( self ): - import ctypes.wintypes - self.__undname = ctypes.windll.dbghelp.UnDecorateSymbolName - self.__undname.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint, ctypes.c_uint] - self.__clean_ecsu = re.compile( r'(?:(^|\W))(?:(class|enum|struct|union))' ) - self.__fundamental_types = ( - ( 'short unsigned int', 'unsigned short') - , ( 'short int', 'short' ) - , ( 'long int', 'long' ) - , ( 'long unsigned int', 'unsigned long' ) - ) - self.__calling_conventions = re.compile( r'(?:(^|\s))(?:__(cdecl|clrcall|stdcall|fastcall|thiscall)\s)' ) - - def normalize_undecorated( self, undname, options=None ): - if options is None: - options = UNDECORATE_NAME_OPTIONS.SHORT_UNIQUE_NAME - if UNDECORATE_NAME_OPTIONS.UNDNAME_NO_ECSU & options: - undname = self.__clean_ecsu.sub( '', undname ) - if UNDECORATE_NAME_OPTIONS.UNDNAME_NO_ACCESS_SPECIFIERS & options: - for prefix in ( 'public: ', 'private: ', 'protected: ' ): - if undname.startswith( prefix ): - undname = undname[ len(prefix): ] - break - if UNDECORATE_NAME_OPTIONS.UNDNAME_NO_MS_KEYWORDS & options: - undname = self.__calling_conventions.sub( ' ', undname) - return undname.strip() - - def undecorate_blob( self, name, options=None ): - if options is None: - options = UNDECORATE_NAME_OPTIONS.SHORT_UNIQUE_NAME - buffer = ctypes.create_string_buffer(1024*16) - res = self.__undname( str(name), buffer, ctypes.sizeof(buffer), options) - if res: - return self.normalize_undecorated( str(buffer[:res]) ) - else: - return name - - def __remove_leading_scope( self, s ): - if s and s.startswith( '::' ): - return s[2:] - else: - return s - - def __format_type_as_undecorated( self, type_, is_argument ): - result = [] - type_ = declarations.remove_alias( type_ ) - if declarations.is_array( type_ ): - result.append( declarations.array_item_type( type_ ).decl_string ) - result.append( '*' ) - if is_argument: - result.append( 'const' ) - else: - result.append( self.__remove_leading_scope( type_.decl_string ) ) - return ' '.join( result ) - - def __normalize( self, name ): - for what, with_ in self.__fundamental_types: - name = name.replace( what, with_ ) - name = name.replace( ', ', ',' ) - return name - - def undecorate_argtypes( self, argtypes ): - if not argtypes: - return 'void' - else: - formater = lambda type_: self.__format_type_as_undecorated( type_, True ) - return ','.join( map( formater, argtypes ) ) - - def __undecorated_calldef( self, calldef ): - calldef_type = calldef.function_type() - - result = [] - is_mem_fun = isinstance( calldef, declarations.member_calldef_t ) - if is_mem_fun and calldef.virtuality != declarations.VIRTUALITY_TYPES.NOT_VIRTUAL: - result.append( 'virtual ' ) - if is_mem_fun and calldef.has_static: - result.append( 'static ' ) - if calldef_type.return_type: - result.append( self.__format_type_as_undecorated( calldef.return_type, False ) ) - result.append( ' ' ) - if is_mem_fun: - result.append( self.__remove_leading_scope( calldef.parent.decl_string ) + '::') - - result.append( calldef.name ) - if isinstance( calldef, ( declarations.constructor_t, declarations.destructor_t) ) \ - and declarations.templates.is_instantiation( calldef.parent.name ): - result.append( '<%s>' % ','.join( declarations.templates.args( calldef.parent.name ) ) ) - - result.append( '(%s)' % self.undecorate_argtypes( calldef_type.arguments_types ) ) - if is_mem_fun and calldef.has_const: - result.append( 'const' ) - return ''.join( result ) - - def __undecorated_variable( self, decl ): - result = [] - is_mem_var = isinstance( decl.parent, declarations.class_t ) - if is_mem_var and decl.type_qualifiers.has_static: - result.append( 'static ' ) - result.append( self.__format_type_as_undecorated( decl.type, False ) ) - result.append( ' ' ) - if is_mem_var: - result.append( self.__remove_leading_scope( decl.parent.decl_string ) + '::' ) - result.append( decl.name ) - return ''.join( result ) - - def undecorated_decl(self, decl): - """returns string, which contains full function name formatted exactly as - result of dbghelp.UnDecorateSymbolName, with UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_ECSU - options. - """ - name = None - if isinstance( decl, declarations.calldef_t ): - name = self.__undecorated_calldef( decl ) - elif isinstance( decl, declarations.variable_t ): - name = self.__undecorated_variable( decl ) - else: - raise NotImplementedError() - return self.__normalize( name ) - -if 'win' in sys.platform: - undecorate_blob = undname_creator().undecorate_blob - undecorate_decl = undname_creator().undecorated_decl - undecorate_argtypes = undname_creator().undecorate_argtypes - normalize_undecorated = undname_creator().normalize_undecorated -else: - def undecorate_blob( x ): - raise NotImplementedError() - def undecorate_decl( x ): - raise NotImplementedError() - def undecorate_argtypes( x ): - raise NotImplementedError() - def normalize_undecorated( *args ): - raise NotImplementedError() - -import exceptions -class LicenseWarning( exceptions.UserWarning ): - def __init__( self, *args, **keywd ): - exceptions.UserWarning.__init__( self, *args, **keywd ) - -class exported_symbols: - map_file_re_c = re.compile( r' +\d+ (?P<internall>.+?)(?:\s+exported name\:\s(?P<name>.*)$)') - map_file_re_cpp = re.compile( r' +\d+ (?P<decorated>.+?) \((?P<undecorated>.+)\)$' ) - - @staticmethod - def load_from_map_file( fname ): - """returns dictionary { decorated symbol : orignal declaration name }""" - result = {} - f = open( fname ) - lines = [] - was_exports = False - for line in f: - if was_exports: - lines.append( line ) - elif 'Exports' == line.strip(): - was_exports = True - else: - pass - index = 0 - - while index < len( lines ): - line = lines[index].rstrip() - found = exported_symbols.map_file_re_cpp.match( line ) - if found: - result[ found.group( 'decorated' ) ] = normalize_undecorated( found.group( 'undecorated' ) ) - elif index + 1 < len( lines ): - two_lines = line + lines[index+1].rstrip() - found = exported_symbols.map_file_re_c.match( two_lines ) - if found: - result[ found.group( 'name' ) ] = found.group( 'name' ) - index += 1 - else: - pass - index += 1 - return result - - @staticmethod - def load_from_dll_file( fname ): - 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_dll_exported_symbols.read_export_table( fname ) - for blob in blobs: - result[ blob ] = undecorate_blob( blob ) - return result - - @staticmethod - def load_from_file( fname ): - ext = os.path.splitext( fname )[1] - if '.dll' == ext: - return exported_symbols.load_from_dll_file( fname ) - elif '.map' == ext: - return exported_symbols.load_from_map_file( fname ) - else: - raise RuntimeError( "Don't know how to read exported symbols from file '%s'" - % fname ) - - @staticmethod - def is_c_function( decl, blob ): - return decl.name == blob Copied: pygccxml_dev/pygccxml/binary_parsers/parsers.py (from rev 1537, pygccxml_dev/pygccxml/binary_parsers/common_utils.py) =================================================================== --- pygccxml_dev/pygccxml/binary_parsers/parsers.py (rev 0) +++ pygccxml_dev/pygccxml/binary_parsers/parsers.py 2009-01-06 08:38:32 UTC (rev 1538) @@ -0,0 +1,193 @@ +# Copyright 2004-2008 Roman Yakovenko. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os +import re +import sys +import ctypes +import undname +import warnings +import exceptions +from .. import declarations + +class LicenseWarning( exceptions.UserWarning ): + def __init__( self, *args, **keywd ): + exceptions.UserWarning.__init__( self, *args, **keywd ) + + +dll_file_parser_warning = \ +""" + +----------------------------->> LICENSE WARNING <<----------------------------- +"dll_file_parser_t" functionality uses code licensed under MIT license. +pygccxml project uses Boost Software License, Version 1.0. +For more information about this functionality take a look on +get_dll_exported_symbols.py file. +================================================================================ + + +""" + +class libparser_t( object ): + def __init__( self, global_ns, binary_file ): + self.__global_ns = global_ns + self.__binary_file = binary_file + self.__loaded_symbols = None + + @property + def global_ns( self ): + """reference to global namespace""" + return self.__global_ns + + @property + def binary_file( self ): + """binary file path""" + return self.__binary_file + + @property + def loaded_symbols( self ): + """list of symbols, which were loaded from the binary file""" + return self.__loaded_symbols + + def load_symbols( self ): + raise NotImplementedError() + + def merge( self ): + raise NotImplementedError() + + def parse( self ): + self.__loaded_symbols = self.load_symbols() + result = {} + for smbl in self.__loaded_symbols: + decorated, decl = self.merge( smbl ) + if decl: + decl.decorated_name = decorated + result[ decorated ] = decl + return result + +CCTS = declarations.CALLING_CONVENTION_TYPES + + +CCTS = declarations.CALLING_CONVENTION_TYPES + +class msvc_libparser_t( libparser_t ): + def __init__( self, global_ns, binary_file ): + libparser_t.__init__( self, global_ns, binary_file ) + self.__formated_decls = {} + self.undname_creator = undname.undname_creator_t() + + for f in self.global_ns.calldefs( allow_empty=True, recursive=True ): + self.__formated_decls[ self.undname_creator.undecorated_decl( f ) ] = f + + for v in self.global_ns.variables( allow_empty=True, recursive=True ): + self.__formated_decls[ self.undname_creator.undecorated_decl( v ) ] = v + + @property + def formated_decls( self ): + return self.__formated_decls + +class map_file_parser_t( msvc_libparser_t ): + c_entry = re.compile( r' +\d+ (?P<internall>.+?)(?:\s+exported name\:\s(?P<name>.*)$)') + cpp_entry = re.compile( r' +\d+ (?P<decorated>.+?) \((?P<undecorated>.+)\)$' ) + + def __init__( self, global_ns, map_file_path ): + msvc_libparser_t.__init__( self, global_ns, map_file_path ) + + def load_symbols( self ): + """returns dictionary { decorated symbol : orignal declaration name }""" + f = file( self.binary_file ) + lines = [] + was_exports = False + for line in f: + if was_exports: + lines.append( line ) + elif 'Exports' == line.strip(): + was_exports = True + else: + pass + + index = 0 + result = [] + while index < len( lines ): + line = lines[index].rstrip() + found = self.cpp_entry.match( line ) + if found: + result.append( ( found.group( 'decorated' ), found.group( 'undecorated' ) ) ) + elif index + 1 < len( lines ): + two_lines = line + lines[index+1].rstrip() + found = self.c_entry.match( two_lines ) + if found: + result.append( ( found.group( 'name' ), found.group( 'name' ) ) ) + index += 1 + else: + pass + index += 1 + return result + + def merge( self, smbl ): + decorated, undecorated = smbl + if decorated == undecorated: + #we deal with C function ( or may be we deal with variable?, I have to check the latest + f = self.global_ns.free_fun( decorated ) + #TODO create usecase, where C function uses different calling convention + f.calling_convention = CCTS.CDECL + return decorated, f + else: + undecorated_normalized = self.undname_creator.normalize_undecorated( undecorated ) + if undecorated_normalized not in self.formated_decls: + return None, None + decl = self.formated_decls[ undecorated_normalized ] + if isinstance( decl, declarations.calldef_t ): + decl.calling_convention = CCTS.extract( undecorated, CCTS.CDECL ) + return decorated, decl + + +class dll_file_parser_t( msvc_libparser_t ): + def __init__( self, global_ns, map_file_path ): + global dll_file_parser_warning + warnings.warn( dll_file_parser_warning, LicenseWarning ) + msvc_libparser_t.__init__( self, global_ns, map_file_path ) + + def load_symbols( self ): + import get_dll_exported_symbols + return get_dll_exported_symbols.read_export_table( self.binary_file ) + + def merge( self, smbl ): + blob = smbl + blob_undecorated = self.undname_creator.undecorate_blob( blob, undname.UNDECORATE_NAME_OPTIONS.UNDNAME_COMPLETE ) + blob_undecorated_normalized = self.undname_creator.undecorate_blob( blob ) + if blob == blob_undecorated == blob_undecorated_normalized: + #we deal with C function ( or may be we deal with variable?, I have to check the latest + f = self.global_ns.free_fun( blob ) + #TODO create usecase, where C function uses different calling convention + f.calling_convention = CCTS.CDECL + return blob, f + else: + if blob_undecorated_normalized not in self.formated_decls: + return None, None + decl = self.formated_decls[ blob_undecorated_normalized ] + if isinstance( decl, declarations.calldef_t ): + decl.calling_convention = CCTS.extract( blob_undecorated, CCTS.CDECL ) + return blob, decl + + +def merge_information( global_ns, fname, runs_under_unittest=False ): + ext = os.path.splitext( fname )[1] + parser = None + if '.dll' == ext: + parser = dll_file_parser_t( global_ns, fname ) + elif '.map' == ext: + parser = map_file_parser_t( global_ns, fname ) + else: + raise RuntimeError( "Don't know how to read exported symbols from file '%s'" + % fname ) + symbols = parser.parse() + if runs_under_unittest: + return symbols, parser + else: + return symbols + + + Added: pygccxml_dev/pygccxml/binary_parsers/undname.py =================================================================== --- pygccxml_dev/pygccxml/binary_parsers/undname.py (rev 0) +++ pygccxml_dev/pygccxml/binary_parsers/undname.py 2009-01-06 08:38:32 UTC (rev 1538) @@ -0,0 +1,201 @@ +# Copyright 2004-2008 Roman Yakovenko. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os +import re +import sys +import ctypes +from pygccxml import declarations + +class UNDECORATE_NAME_OPTIONS: + UNDNAME_COMPLETE = 0x0000 #Enables full undecoration. + UNDNAME_NO_LEADING_UNDERSCORES = 0x0001 #Removes leading underscores from Microsoft extended keywords. + UNDNAME_NO_MS_KEYWORDS = 0x0002 #Disables expansion of Microsoft extended keywords. + UNDNAME_NO_FUNCTION_RETURNS = 0x0004 #Disables expansion of return type for primary declaration. + UNDNAME_NO_ALLOCATION_MODEL = 0x0008 #Disables expansion of the declaration model. + UNDNAME_NO_ALLOCATION_LANGUAGE = 0x0010 #Disables expansion of the declaration language specifier. + UNDNAME_RESERVED1 = 0x0020 #RESERVED. + UNDNAME_RESERVED2 = 0x0040 #RESERVED. + UNDNAME_NO_THISTYPE = 0x0060 #Disables all modifiers on the this type. + UNDNAME_NO_ACCESS_SPECIFIERS = 0x0080 #Disables expansion of access specifiers for members. + UNDNAME_NO_THROW_SIGNATURES = 0x0100 #Disables expansion of "throw-signatures" for functions and pointers to functions. + UNDNAME_NO_MEMBER_TYPE = 0x0200 #Disables expansion of static or virtual members. + UNDNAME_NO_RETURN_UDT_MODEL = 0x0400 #Disables expansion of the Microsoft model for UDT returns. + UNDNAME_32_BIT_DECODE = 0x0800 #Undecorates 32-bit decorated names. + UNDNAME_NAME_ONLY = 0x1000 #Gets only the name for primary declaration; returns just [scope::]name. Expands template params. + UNDNAME_TYPE_ONLY = 0x2000 #Input is just a type encoding; composes an abstract declarator. + UNDNAME_HAVE_PARAMETERS = 0x4000 #The real template parameters are available. + UNDNAME_NO_ECSU = 0x8000 #Suppresses enum/class/struct/union. + UNDNAME_NO_IDENT_CHAR_CHECK = 0x10000 #Suppresses check for valid identifier characters. + UNDNAME_NO_PTR64 = 0x20000 #Does not include ptr64 in output. + + UNDNAME_SCOPES_ONLY = UNDNAME_NO_LEADING_UNDERSCORES \ + | UNDNAME_NO_MS_KEYWORDS \ + | UNDNAME_NO_FUNCTION_RETURNS \ + | UNDNAME_NO_ALLOCATION_MODEL \ + | UNDNAME_NO_ALLOCATION_LANGUAGE \ + | UNDNAME_NO_ACCESS_SPECIFIERS \ + | UNDNAME_NO_THROW_SIGNATURES \ + | UNDNAME_NO_MEMBER_TYPE \ + | UNDNAME_NO_ECSU \ + | UNDNAME_NO_IDENT_CHAR_CHECK + + SHORT_UNIQUE_NAME = UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_ECSU + +#~ The following code doesn't work - access violation + +#~__unDName definition was taken from: +#~http://www.tech-archive.net/Archive/VC/microsoft.public.vc.language/2006-02/msg00754.html + +#~ msvcrxx = ctypes.windll.msvcr90 +#~ free_type = ctypes.CFUNCTYPE( None, ctypes.c_void_p ) #free type +#~ malloc_type = ctypes.CFUNCTYPE( ctypes.c_void_p, ctypes.c_uint ) #malloc type +#~ __unDName = msvcrxx.__unDName +#~ __unDName.argtypes = [ ctypes.c_char_p #undecorated name + #~ , ctypes.c_char_p #decorated name + #~ , ctypes.c_int #sizeof undecorated name + #~ , malloc_type + #~ , free_type + #~ , ctypes.c_ushort #flags + #~ ] +#~ __unDName.restype = ctypes.c_char_p +#~ def undecorate_name( name, options=None ): + #~ if not name: + #~ return '' + #~ if options is None: + #~ options = UNDECORATE_NAME_OPTIONS.SHORT_UNIQUE_NAME + #~ buffer_size = 1024 * 32 + #~ undecorated_name = ctypes.create_string_buffer('\0' * buffer_size) #should be enouph for any symbol + #~ __unDName( undecorated_name + #~ , str(name) + #~ , buffer_size + #~ , malloc_type( msvcrxx.malloc ) + #~ , free_type( msvcrxx.free ) + #~ , options ) + #~ return undecorated_name.value + +class undname_creator_t: + def __init__( self ): + import ctypes.wintypes + self.__undname = ctypes.windll.dbghelp.UnDecorateSymbolName + self.__undname.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint, ctypes.c_uint] + self.__clean_ecsu = ( re.compile( r'(?P<startswith>^|\W)(?:(class|enum|struct|union)\s)' ) + , '%(startswith)s' ) + self.__fundamental_types = ( + ( 'short unsigned int', 'unsigned short') + , ( 'short int', 'short' ) + , ( 'long int', 'long' ) + , ( 'long unsigned int', 'unsigned long' ) + ) + self.__calling_conventions = ( re.compile( r'(?P<startswith>^|\s)(?:__(cdecl|clrcall|stdcall|fastcall|thiscall)\s)' ) + , '%(startswith)s' ) + + def normalize_undecorated( self, undname, options=None ): + if options is None: + options = UNDECORATE_NAME_OPTIONS.SHORT_UNIQUE_NAME + if UNDECORATE_NAME_OPTIONS.UNDNAME_NO_ECSU & options: + expr, substitute = self.__clean_ecsu + undname = expr.sub( lambda m: substitute % m.groupdict(), undname ) + if UNDECORATE_NAME_OPTIONS.UNDNAME_NO_ACCESS_SPECIFIERS & options: + for prefix in ( 'public: ', 'private: ', 'protected: ' ): + if undname.startswith( prefix ): + undname = undname[ len(prefix): ] + break + if UNDECORATE_NAME_OPTIONS.UNDNAME_NO_MS_KEYWORDS & options: + expr, substitute = self.__calling_conventions + undname = expr.sub( lambda m: substitute % m.groupdict(), undname ) + return undname.strip() + + def undecorate_blob( self, name, options=None ): + if options is None: + options = UNDECORATE_NAME_OPTIONS.SHORT_UNIQUE_NAME + buffer = ctypes.create_string_buffer(1024*16) + res = self.__undname( str(name), buffer, ctypes.sizeof(buffer), options) + if res: + return self.normalize_undecorated( str(buffer[:res]) ) + else: + return name + + def __remove_leading_scope( self, s ): + if s and s.startswith( '::' ): + return s[2:] + else: + return s + + def __format_type_as_undecorated( self, type_, is_argument ): + result = [] + type_ = declarations.remove_alias( type_ ) + if declarations.is_array( type_ ): + result.append( declarations.array_item_type( type_ ).decl_string ) + result.append( '*' ) + if is_argument: + result.append( 'const' ) + else: + result.append( self.__remove_leading_scope( type_.decl_string ) ) + return ' '.join( result ) + + def __normalize( self, name ): + for what, with_ in self.__fundamental_types: + name = name.replace( what, with_ ) + name = name.replace( ', ', ',' ) + return name + + def undecorate_argtypes( self, argtypes ): + if not argtypes: + return 'void' + else: + formater = lambda type_: self.__format_type_as_undecorated( type_, True ) + return ','.join( map( formater, argtypes ) ) + + def __undecorated_calldef( self, calldef ): + calldef_type = calldef.function_type() + + result = [] + is_mem_fun = isinstance( calldef, declarations.member_calldef_t ) + if is_mem_fun and calldef.virtuality != declarations.VIRTUALITY_TYPES.NOT_VIRTUAL: + result.append( 'virtual ' ) + if is_mem_fun and calldef.has_static: + result.append( 'static ' ) + if calldef_type.return_type: + result.append( self.__format_type_as_undecorated( calldef.return_type, False ) ) + result.append( ' ' ) + if is_mem_fun: + result.append( self.__remove_leading_scope( calldef.parent.decl_string ) + '::') + + result.append( calldef.name ) + if isinstance( calldef, ( declarations.constructor_t, declarations.destructor_t) ) \ + and declarations.templates.is_instantiation( calldef.parent.name ): + result.append( '<%s>' % ','.join( declarations.templates.args( calldef.parent.name ) ) ) + + result.append( '(%s)' % self.undecorate_argtypes( calldef_type.arguments_types ) ) + if is_mem_fun and calldef.has_const: + result.append( 'const' ) + return ''.join( result ) + + def __undecorated_variable( self, decl ): + result = [] + is_mem_var = isinstance( decl.parent, declarations.class_t ) + if is_mem_var and decl.type_qualifiers.has_static: + result.append( 'static ' ) + result.append( self.__format_type_as_undecorated( decl.type, False ) ) + result.append( ' ' ) + if is_mem_var: + result.append( self.__remove_leading_scope( decl.parent.decl_string ) + '::' ) + result.append( decl.name ) + return ''.join( result ) + + def undecorated_decl(self, decl): + """returns string, which contains full function name formatted exactly as + result of dbghelp.UnDecorateSymbolName, with UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_ECSU + options. + """ + name = None + if isinstance( decl, declarations.calldef_t ): + name = self.__undecorated_calldef( decl ) + elif isinstance( decl, declarations.variable_t ): + name = self.__undecorated_variable( decl ) + else: + raise NotImplementedError() + return self.__normalize( name ) Modified: pygccxml_dev/pygccxml/declarations/decl_printer.py =================================================================== --- pygccxml_dev/pygccxml/declarations/decl_printer.py 2009-01-05 22:58:43 UTC (rev 1537) +++ pygccxml_dev/pygccxml/declarations/decl_printer.py 2009-01-06 08:38:32 UTC (rev 1538) @@ -123,9 +123,6 @@ if self.verbose and self.__inst.decorated_name: decorated_name = 'decorated name: %s'%(self.__inst.decorated_name) self.writer( ' ' * curr_level * self.INDENT_SIZE + decorated_name + os.linesep) - if self.verbose and self.__inst.undecorated_name: - undecorated_name = 'undecorated name: %s' % (self.__inst.undecorated_name) - self.writer( ' ' * curr_level * self.INDENT_SIZE + undecorated_name + os.linesep) def print_calldef_info(self, decl=None): """ Returns function signature: [retval, [arg1, ..., argN]]. """ Modified: pygccxml_dev/pygccxml/declarations/declaration.py =================================================================== --- pygccxml_dev/pygccxml/declarations/declaration.py 2009-01-05 22:58:43 UTC (rev 1537) +++ pygccxml_dev/pygccxml/declarations/declaration.py 2009-01-06 08:38:32 UTC (rev 1538) @@ -69,7 +69,6 @@ self._compiler = None self._partial_name = None self._decorated_name = None - self._undecorated_name = None def __str__(self): """Default __str__ method. @@ -244,15 +243,6 @@ @type: str """ ) - def _get_undecorated_name( self ): - return self._undecorated_name - def _set_undecorated_name( self, undecorated_name ): - self._undecorated_name = undecorated_name - undecorated_name = property( _get_undecorated_name, _set_undecorated_name - , doc="""declaration name, which was created by pygccxml, for matching ( source code <==> binary ) purpose - @type: str - """ ) - def _get_attributes( self ): return self._attributes def _set_attributes( self, attributes ): Modified: pygccxml_dev/unittests/data/core_cache.hpp =================================================================== --- pygccxml_dev/unittests/data/core_cache.hpp 2009-01-05 22:58:43 UTC (rev 1537) +++ pygccxml_dev/unittests/data/core_cache.hpp 2009-01-06 08:38:32 UTC (rev 1538) @@ -22,4 +22,4 @@ #endif//__core_cache_hpp__ -//touch//touch//touch//touch//touch \ No newline at end of file +//touch//touch//touch//touch//touch//touch//touch//touch \ No newline at end of file Modified: pygccxml_dev/unittests/undname_creator_tester.py =================================================================== --- pygccxml_dev/unittests/undname_creator_tester.py 2009-01-05 22:58:43 UTC (rev 1537) +++ pygccxml_dev/unittests/undname_creator_tester.py 2009-01-06 08:38:32 UTC (rev 1538) @@ -20,19 +20,24 @@ global_ns = None known_issues = set([ - #pointer to functions - 'void (** myclass_t::get_do_smth(void))(std::auto_ptr<number_t> &)' - , 'void myclass_t::set_do_smth(void (**)(std::auto_ptr<number_t> &))' - # array as function argument - , 'int FA10_i_i(int * const)' + # array as function argument: 'int FA10_i_i(int * const)' + '?FA10_i_i@@YAHQAH@Z' + #pointer to function: 'void myclass_t::set_do_smth(void (**)(std::auto_ptr<number_t> &))' + , '?set_do_smth@myclass_t@@QAEXPAP6AXAAV?$auto_ptr@Vnumber_t@@@std@@@Z@Z' + #pointer to functions: 'void (** myclass_t::get_do_smth(void))(std::auto_ptr<number_t> &)' + , '?get_do_smth@myclass_t@@QAEPAP6AXAAV?$auto_ptr@Vnumber_t@@@std@@@ZXZ' ]) if 'msvc71' == utils.native_compiler.get_gccxml_compiler(): - known_issues.add( 'std::auto_ptr<number_t> & std::auto_ptr<number_t>::operator=(std::auto_ptr_ref<number_t>)' ) + #missing reference in argument - compiler issue 'std::auto_ptr<number_t> & std::auto_ptr<number_t>::operator=(std::auto_ptr_ref<number_t>)' + known_issues.add( '??4?$auto_ptr@Vnumber_t@@@std@@QAEAAV01@U?$auto_ptr_ref@Vnumber_t@@@1@@Z' ) def __init__(self, *args ): parser_test_case.parser_test_case_t.__init__( self, *args ) self.header = r'msvc\mydll.h' + self.map_file = os.path.join( autoconfig.data_directory, 'msvc', 'release', 'mydll.map' ) + self.dll_file = os.path.join( autoconfig.data_directory, 'msvc', 'release', 'mydll.dll' ) + def setUp(self): if not tester_t.global_ns: decls = parser.parse( [self.header], self.config ) @@ -49,46 +54,61 @@ return False def __tester_impl( self, fname ): - symbols = binary_parsers.exported_symbols.load_from_file( fname ) + symbols, parser = binary_parsers.merge_information( self.global_ns, fname, runs_under_unittest=True ) self.failUnless( 'identity' in symbols ) - undecorated_blob_names = set() - for blob in symbols.iterkeys(): + blob_names = set() + for blob in parser.loaded_symbols: + if isinstance( blob, tuple ): + blob = blob[0] undname = binary_parsers.undecorate_blob( blob ) if "`" in undname: continue - undecorated_blob_names.add( undname ) + blob_names.add( blob ) - undecorated_decl_names = set() - for f in self.global_ns.decls(self.is_included): - undecorated_decl_names.add( binary_parsers.undecorate_decl( f ) ) + decl_blob_names = set( symbols.keys() ) - issuperset = undecorated_decl_names.issuperset( undecorated_blob_names ) + issuperset = decl_blob_names.issuperset( blob_names ) if not issuperset: - common = undecorated_decl_names.intersection( undecorated_blob_names ) + common = decl_blob_names.intersection( blob_names ) - undecorated_decl_names.difference_update(common) - undecorated_blob_names.difference_update(common) - if not self.known_issues.issubset( undecorated_blob_names ): - undecorated_blob_names.difference_update( self.known_issues ) + decl_blob_names.difference_update(common) + blob_names.difference_update(common) + if not self.known_issues.issubset( blob_names ): + blob_names.difference_update( self.known_issues ) msg = [ "undecorate_decl - failed" ] - msg.append( "undecorated_decl_names :" ) - for i in undecorated_decl_names: + msg.append( "decl_blob_names :" ) + for i in decl_blob_names: msg.append( '\t==>%s<==' % i ) - msg.append( "undecorated_blob_names :" ) - for i in undecorated_blob_names: + msg.append( "blob_names :" ) + for i in blob_names: msg.append( '\t==>%s<==' % i ) self.fail( os.linesep.join(msg) ) def test_map_file( self ): - map_file = os.path.join( autoconfig.data_directory, 'msvc', 'release', 'mydll.map' ) - self.__tester_impl( map_file ) + self.__tester_impl( self.map_file ) def test_dll_file( self ): - dll_file = os.path.join( autoconfig.data_directory, 'msvc', 'release', 'mydll.dll' ) - self.__tester_impl( dll_file ) + self.__tester_impl( self.dll_file ) + def test_compare_parsers( self ): + dsymbols, dparser = binary_parsers.merge_information( self.global_ns, self.dll_file, runs_under_unittest=True ) + msymbols, mparser = binary_parsers.merge_information( self.global_ns, self.map_file, runs_under_unittest=True ) + + self.failUnless( len( dparser.loaded_symbols ) == len( mparser.loaded_symbols ) ) + + was_error = False + for blob, decl in dsymbols.iteritems(): + if blob not in msymbols: + was_error = True + print '\n%s could not be found in map file loaded symbols' % binary_parsers.undecorate_blob( blob ) + #~ self.failUnless( blob in msymbols, binary_parsers.undecorate_blob( blob ) ) + else: + mdecl = msymbols[ blob ] + self.failUnless( mdecl is decl ) + self.failUnless( was_error == False ) + def create_suite(): suite = unittest.TestSuite() if 'win' in sys.platform: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |