[pygccxml-commit] SF.net SVN: pygccxml:[1551] pygccxml_dev
Brought to you by:
mbaas,
roman_yakovenko
|
From: <rom...@us...> - 2009-01-08 12:32:03
|
Revision: 1551
http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1551&view=rev
Author: roman_yakovenko
Date: 2009-01-08 12:31:59 +0000 (Thu, 08 Jan 2009)
Log Message:
-----------
improving support of .so binary file parser
Modified Paths:
--------------
pygccxml_dev/pygccxml/binary_parsers/__init__.py
pygccxml_dev/pygccxml/binary_parsers/parsers.py
pygccxml_dev/pygccxml/binary_parsers/undname.py
pygccxml_dev/unittests/undname_creator_tester.py
Modified: pygccxml_dev/pygccxml/binary_parsers/__init__.py
===================================================================
--- pygccxml_dev/pygccxml/binary_parsers/__init__.py 2009-01-07 22:25:48 UTC (rev 1550)
+++ pygccxml_dev/pygccxml/binary_parsers/__init__.py 2009-01-08 12:31:59 UTC (rev 1551)
@@ -14,3 +14,7 @@
def undecorate_blob( blob ):
"""returns undecorated\unmangled string, created from blob"""
return undname.undname_creator_t().undecorate_blob( blob )
+
+def format_decl( decl, hint=None ):
+ """returns string, that represents formatted decl, according to some rules"""
+ return undname.undname_creator_t().format_decl( decl, hint=hint )
Modified: pygccxml_dev/pygccxml/binary_parsers/parsers.py
===================================================================
--- pygccxml_dev/pygccxml/binary_parsers/parsers.py 2009-01-07 22:25:48 UTC (rev 1550)
+++ pygccxml_dev/pygccxml/binary_parsers/parsers.py 2009-01-08 12:31:59 UTC (rev 1551)
@@ -102,30 +102,32 @@
CCTS = declarations.CALLING_CONVENTION_TYPES
-class msvc_libparser_t( libparser_t ):
+class formated_mapping_parser_t( libparser_t ):
"""base parser class for few MSVC binary files"""
- def __init__( self, global_ns, binary_file ):
+ def __init__( self, global_ns, binary_file, hint ):
libparser_t.__init__( self, global_ns, binary_file )
self.__formated_decls = {}
self.undname_creator = undname.undname_creator_t()
+ formatter = lambda decl: self.undname_creator.format_decl( f, hint )
+
for f in self.global_ns.calldefs( allow_empty=True, recursive=True ):
- self.__formated_decls[ self.undname_creator.undecorated_decl( f ) ] = f
+ self.__formated_decls[ formatter( f ) ] = f
for v in self.global_ns.variables( allow_empty=True, recursive=True ):
- self.__formated_decls[ self.undname_creator.undecorated_decl( v ) ] = v
+ self.__formated_decls[ formatter( v ) ] = v
@property
def formated_decls( self ):
return self.__formated_decls
-class map_file_parser_t( msvc_libparser_t ):
+class map_file_parser_t( formated_mapping_parser_t ):
"""parser for MSVC .map file"""
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 )
+ formated_mapping_parser_t.__init__( self, global_ns, map_file_path, 'msvc' )
def load_symbols( self ):
"""returns dictionary { decorated symbol : orignal declaration name }"""
@@ -176,12 +178,12 @@
return decorated, decl
-class dll_file_parser_t( msvc_libparser_t ):
+class dll_file_parser_t( formated_mapping_parser_t ):
"""parser for Windows .dll file"""
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 )
+ formated_mapping_parser_t.__init__( self, global_ns, map_file_path, 'msvc' )
def load_symbols( self ):
import get_dll_exported_symbols
@@ -207,18 +209,23 @@
class so_file_parser_t( libparser_t ):
+ nm_executable = 'nm'
+ #numeric-sort used for mapping between mangled and unmangled name
+ cmd_mangled = '%(nm)s --extern-only --dynamic --defined-only --numeric-sort %(lib)s'
+ cmd_demangled = '%(nm)s --extern-only --dynamic --defined-only --demangle --numeric-sort %(lib)s'
+ entry = re.compile( r'^(?P<address>(?:\w|\d)+)\s\w\s(?P<symbol>.+)$' )
+
def __init__( self, global_ns, binary_file ):
libparser_t.__init__( self, global_ns, binary_file )
self.__mangled2decls = {}
-
+
for f in self.global_ns.calldefs( allow_empty=True, recursive=True ):
self.__mangled2decls[ f.mangled ] = f
-
+
for v in self.global_ns.variables( allow_empty=True, recursive=True ):
self.__mangled2decls[ v.mangled ] = v
-
- def load_symbols( self ):
- cmd = 'nm --extern-only --dynamic --defined-only %s' % self.binary_file
+
+ def __execute_nm( self, cmd ):
process = subprocess.Popen( args=cmd
, shell=True
, stdin=subprocess.PIPE
@@ -231,26 +238,39 @@
while process.poll() is None:
output.append( process.stdout.readline() )
#the process already finished, read th rest of the output
- for line in process.stdout.readlines():
- output.append( line )
+ output.extend( process.stdout.readlines() )
if process.returncode:
msg = ["Unable to extract public\\exported symbols from '%s' file." % self.binary_file ]
msg.append( 'The command line, which was used to extract symbols, is "%s"' % cmd )
raise RuntimeError( os.linesep.join(msg) )
-
- result = []
+ return output
+
+ def __extract_symbols( self, cmd ):
+ output = self.__execute_nm( cmd )
+ result = {}
for line in output:
- line = line.strip()
- if line:
- result.append( line.split( ' ' )[-1] )
+ found = self.entry.match( line )
+ if found:
+ result[ found.group( 'address' ) ] = found.group( 'symbol' )
return result
-
+
+ def load_symbols( self ):
+ tmpl_args = dict( nm=self.nm_executable, lib=self.binary_file )
+ mangled_smbls = self.__extract_symbols( self.cmd_mangled % tmpl_args )
+ demangled_smbls = self.__extract_symbols( self.cmd_demangled % tmpl_args )
+ result = []
+ for address, blob in mangled_smbls.iteritems():
+ if address in demangled_smbls:
+ result.append( blob, demangled_smbls[address] )
+ return result
+
def merge( self, smbl ):
- if smbl in self.__mangled2decls:
- return smbl, self.__mangled2decls[smbl]
- else:
- return (None, None)
-
+ decorated, undecorated = smbl
+ if undecorated not in self.formated_decls:
+ return None, None
+ decl = self.formated_decls[ undecorated ]
+ return decorated, decl
+
def merge_information( global_ns, fname, runs_under_unittest=False ):
"""high level function - select the appropriate binary file parser and integrates
the information from the file to the declarations tree. """
Modified: pygccxml_dev/pygccxml/binary_parsers/undname.py
===================================================================
--- pygccxml_dev/pygccxml/binary_parsers/undname.py 2009-01-07 22:25:48 UTC (rev 1550)
+++ pygccxml_dev/pygccxml/binary_parsers/undname.py 2009-01-08 12:31:59 UTC (rev 1551)
@@ -128,7 +128,7 @@
else:
return s
- def __format_type_as_undecorated( self, type_, is_argument ):
+ def __format_type_as_undecorated( self, type_, is_argument, hint ):
result = []
type_ = declarations.remove_alias( type_ )
if declarations.is_array( type_ ):
@@ -138,32 +138,42 @@
result.append( 'const' )
else:
result.append( self.__remove_leading_scope( type_.decl_string ) )
- return ' '.join( result )
+ result = ' '.join( result )
+ if hint == 'nm':
+ for x in ( '*', '&' ):
+ result = result.replace( ' ' + x, x )
+ return 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 ):
+ def format_argtypes( self, argtypes, hint ):
if not argtypes:
- return 'void'
+ if hint == 'msvc':
+ return 'void'
+ else:
+ return ''
else:
- formater = lambda type_: self.__format_type_as_undecorated( type_, True )
+ formater = lambda type_: self.__format_type_as_undecorated( type_, True, hint )
return ','.join( map( formater, argtypes ) )
- def __undecorated_calldef( self, calldef ):
+ def format_calldef( self, calldef, hint ):
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:
+ if is_mem_fun and hint == 'msvc' and calldef.virtuality != declarations.VIRTUALITY_TYPES.NOT_VIRTUAL:
result.append( 'virtual ' )
- if is_mem_fun and calldef.has_static:
+ if is_mem_fun and hint == 'msvc'and calldef.has_static:
result.append( 'static ' )
- if calldef_type.return_type:
- result.append( self.__format_type_as_undecorated( calldef.return_type, False ) )
+ if hint == 'msvc' and calldef_type.return_type:
+ #nm doesn't dump return type information
+ result.append( self.__format_type_as_undecorated( calldef.return_type, False, hint ) )
result.append( ' ' )
if is_mem_fun:
result.append( self.__remove_leading_scope( calldef.parent.decl_string ) + '::')
@@ -171,35 +181,50 @@
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 ) ) )
+ if hint == 'msvc':
+ result.append( '<%s>' % ','.join( declarations.templates.args( calldef.parent.name ) ) )
- result.append( '(%s)' % self.undecorate_argtypes( calldef_type.arguments_types ) )
+ result.append( '(%s)' % self.format_argtypes( calldef_type.arguments_types, hint ) )
if is_mem_fun and calldef.has_const:
- result.append( 'const' )
+ if hint == 'msvc':
+ result.append( 'const' )
+ else:
+ result.append( ' const' )
return ''.join( result )
- def __undecorated_variable( self, decl ):
+ def format_var( self, decl, hint ):
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 hint == 'msvc':
+ result.append( self.__format_type_as_undecorated( decl.type, False, hint ) )
+ 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):
+ def format_decl(self, decl, hint=None):
"""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.
+
+ Different compilers\utilities undecorate/demangle magled string ( unique names ) in a different way.
+ hint argument will tell pygccxml how to format declarations, so it couls be mapped later to the blob.
+ The valid options are" msvc, nm
"""
name = None
+ if hint is None:
+ if 'win32' in sys.platform:
+ hint = 'msvc'
+ else:
+ hint = 'nm'
+
if isinstance( decl, declarations.calldef_t ):
- name = self.__undecorated_calldef( decl )
+ name = self.format_calldef( decl, hint )
elif isinstance( decl, declarations.variable_t ):
- name = self.__undecorated_variable( decl )
+ name = self.format_var( decl, hint )
else:
raise NotImplementedError()
return self.__normalize( name )
Modified: pygccxml_dev/unittests/undname_creator_tester.py
===================================================================
--- pygccxml_dev/unittests/undname_creator_tester.py 2009-01-07 22:25:48 UTC (rev 1550)
+++ pygccxml_dev/unittests/undname_creator_tester.py 2009-01-08 12:31:59 UTC (rev 1551)
@@ -45,8 +45,6 @@
tester_t.global_ns = declarations.get_global_namespace( decls )
tester_t.global_ns.init_optimizer()
- declarations.print_declarations( tester_t.global_ns )
-
process = subprocess.Popen( args='scons msvc_compiler=%s' % autoconfig.compiler
, shell=True
, stdin=subprocess.PIPE
@@ -117,7 +115,7 @@
def test_z_compare_parsers( self ):
if 'win32' not in sys.platform:
- return
+ return
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 )
@@ -127,7 +125,7 @@
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 )
+ print '\n%s could not be found in .map file' % binary_parsers.undecorate_blob( blob )
#~ self.failUnless( blob in msymbols, binary_parsers.undecorate_blob( blob ) )
else:
mdecl = msymbols[ blob ]
@@ -138,6 +136,12 @@
if 'linux2' in sys.platform:
self.__tester_impl( self.so_file )
+ def test_print( self ):
+ symbols, parser = binary_parsers.merge_information( self.global_ns, self.map_file, runs_under_unittest=True )
+ for d in symbols.itervalues():
+ print binary_parsers.format_decl( d, 'nm' )
+
+
def create_suite():
suite = unittest.TestSuite()
suite.addTest( unittest.makeSuite(tester_t))
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|