1  import os 
  2  import re 
  3  import pdb 
  4  import sys 
  5  import ctypes 
  6  import pprint 
  7  import logging 
  8  import comtypes 
  9  import itertools 
 10  import comtypes.client 
 11   
 12  from . import enums 
 13  from . import impl_details 
 14   
 15  from ... import utils 
 16  from ... import declarations 
 17  from .. import config as msvc_cfg 
 18  from .. import common_utils as msvc_utils 
 19   
 20  msdia = comtypes.client.GetModule( msvc_cfg.msdia_path ) 
 21   
 22  SymTagEnum = 12 
 23  msdia.SymTagEnum = 12 
 24   
 25 -def iif( condition, true_value, false_value ): 
  26      if condition: 
 27          return true_value 
 28      else: 
 29          return false_value 
  30   
 32      return ctypes.cast( x, ctypes.POINTER( msdia.IDiaSymbol ) ) 
  33   
 35      return ctypes.cast( x, ctypes.POINTER( msdia.IDiaTable ) ) 
  36   
 38      return ctypes.cast( x, ctypes.POINTER( msdia.IDiaEnumSymbols ) ) 
  39   
 41      return ctypes.cast( x, ctypes.POINTER( comtypes.automation.IEnumVARIANT ) ) 
  42   
 44      files = iter( session.findFile( None, '', 0 ) ) 
 45      for f in files: 
 46          f = ctypes.cast( f, ctypes.POINTER(msdia.IDiaSourceFile) ) 
 47          print 'File: ', f.fileName 
  48   
 50      COMPILER = declarations.compilers.MSVC_PDB_9 
 52          self.logger = utils.loggers.pdb_reader 
 53          self.logger.setLevel(logging.INFO) 
 54          self.logger.debug( 'creating DiaSource object' ) 
 55          self.__dia_source = comtypes.client.CreateObject( msdia.DiaSource ) 
 56          self.logger.debug( 'loading pdb file: %s' % pdb_file_path ) 
 57          self.__dia_source.loadDataFromPdb(pdb_file_path) 
 58          self.logger.debug( 'opening session' ) 
 59          self.__dia_session = self.__dia_source.openSession() 
 60          self.logger.debug( 'opening session - done' ) 
 61          self.__global_ns = declarations.namespace_t( '::' ) 
 62          self.__global_ns.compiler = self.COMPILER 
 63          self.__id2decl = {}  
 64          self.__types_cache = {}  
  65   
 67          valid_names = ( 'Symbols', 'SourceFiles', 'Sections' 
 68                          , 'SegmentMap', 'InjectedSource', 'FrameData' ) 
 69          tables = self.__dia_session.getEnumTables() 
 70          for table in itertools.imap(as_table, tables): 
 71              if name == table.name: 
 72                  return table 
 73          else: 
 74              return None 
  75   
 76      @utils.cached 
 78          return self.__find_table( "Symbols" ) 
  79   
 80      @utils.cached 
 88              smbl.undecorate_name = smbl_undecorate_name 
 89              smbls[ smbl.symIndexId ] = smbl 
 90          self.logger.info( 'loading symbols(%d) from the file - done', len( smbls ) ) 
 91          return smbls 
  92   
 94          def ns_filter( smbl ): 
 95              self.logger.debug( '__load_ns.ns_filter, %s', smbl.uname ) 
 96              tags = ( msdia.SymTagFunction 
 97                       , msdia.SymTagBlock 
 98                       , msdia.SymTagData 
 99                        
100                        
101                       , msdia.SymTagUDT 
102                       , msdia.SymTagEnum 
103                        
104                        
105                       , msdia.SymTagArrayType 
106                       , msdia.SymTagBaseType 
107                       , msdia.SymTagTypedef 
108                       , msdia.SymTagBaseClass 
109                       , msdia.SymTagFriend 
110                        
111                        
112                      ) 
113              if smbl.symTag not in tags: 
114                  self.logger.debug( 'smbl.symTag not in tags, %s', smbl.uname ) 
115                  return False 
116              elif smbl.symTag == msdia.SymTagData and not self.__is_my_var( smbl ): 
117                  return False 
118              elif not smbl.name: 
119                  self.logger.debug( 'not smbl.name, %s', smbl.uname ) 
120                  return False 
121               
122                   
123                   
124              elif smbl.classParent: 
125                  parent_smbl = self.symbols[ smbl.classParentId ] 
126                  while parent_smbl: 
127                      if parent_smbl.symTag == msdia.SymTagUDT: 
128                          if parent_smbl.uname in smbl.uname: 
129                               
130                               
131                              self.logger.debug( 'parent_smbl.symTag == msdia.SymTagUDT, %s', parent_smbl.uname ) 
132                              return False 
133                          else: 
134                              return True 
135                      else: 
136                          parent_smbl = self.symbols[ parent_smbl.classParentId ] 
137              else: 
138                  return True 
 139   
140          self.logger.debug( 'scanning symbols table' ) 
141   
142          self.logger.debug( 'looking for scopes' ) 
143          names = set() 
144          for index, smbl in enumerate( itertools.ifilter( ns_filter, self.symbols.itervalues() ) ): 
145              if index and ( index % 10000 == 0 ): 
146                  self.logger.debug( '%d symbols scanned', index ) 
147              name_splitter = impl_details.get_name_splitter( smbl.uname ) 
148              for sn in name_splitter.scope_names: 
149                  if '<' in sn: 
150                      break 
151                  else: 
152                      names.add( sn ) 
153          names = list( names ) 
154          names.sort() 
155          self.logger.debug( 'looking for scopes - done' ) 
156   
157          nss = {'': self.__global_ns} 
158   
159          self.logger.debug( 'building namespace objects' ) 
160          for ns_name in itertools.ifilterfalse( self.__find_udt, names ): 
161              self.logger.debug( 'inserting ns "%s" into declarations tree', ns_name ) 
162              name_splitter = impl_details.get_name_splitter( ns_name ) 
163              if not name_splitter.scope_names: 
164                  parent_ns = self.global_ns 
165              else: 
166                  parent_ns = nss.get( name_splitter.scope_names[-1], None ) 
167                  if not parent_ns: 
168                      continue  
169              ns_decl = declarations.namespace_t( name_splitter.name ) 
170              ns_decl.compiler = self.COMPILER 
171              ns_decl.mangled = ns_decl.name 
172              ns_decl.demangled = ns_decl.name 
173              parent_ns.adopt_declaration( ns_decl ) 
174              nss[ ns_name ] = ns_decl 
175              self.logger.debug( 'inserting ns "%s" into declarations tree - done', ns_name ) 
176          self.logger.debug( 'building namespace objects - done' ) 
177   
178          self.logger.debug( 'scanning symbols table - done' ) 
179   
201   
223   
237   
239 -        def __init__( self, global_ns, classes, id2decl ): 
 244   
246              smbl = decl.dia_symbols[0] 
247              if smbl.classParent: 
248                  if smbl.classParentId in self.id2decl: 
249                      return True 
250                  else: 
251                      return False 
252              if self.classes.has_key( smbl.classParentId ): 
253                  return False 
254              name_splitter = impl_details.get_name_splitter( smbl.uname ) 
255              if not name_splitter.scope_names: 
256                  return True  
257              else: 
258                   
259                  parent_name = '::' + name_splitter.scope_names[-1] 
260                  if parent_name in self.__parent_exist: 
261                      return True 
262                  found = self.global_ns.decls( parent_name 
263                                                , decl_type=declarations.scopedef_t 
264                                                , allow_empty=True 
265                                                , recursive=True ) 
266                  if found: 
267                      self.__parent_exist.add( parent_name ) 
268                  return bool( found ) 
 271          self.logger.info( 'clearing symbols' ) 
272          to_be_deleted = [] 
273          useless_tags = ( 
274              msdia.SymTagAnnotation 
275              , msdia.SymTagPublicSymbol 
276              , msdia.SymTagBlock 
277              , msdia.SymTagFuncDebugStart 
278              , msdia.SymTagFuncDebugEnd 
279          ) 
280          for smbl_id, smbl in self.symbols.iteritems(): 
281              if smbl.symTag in useless_tags \ 
282                 or ( smbl.symTag == msdia.SymTagData and not self.__is_my_var( smbl ) ): 
283                  to_be_deleted.append( smbl_id ) 
284   
285          map( lambda smbl_id: self.symbols.pop( smbl_id ), to_be_deleted ) 
286          self.logger.info( 'clearing symbols(%d) - done', len( to_be_deleted ) ) 
 287   
288   
298   
311   
312   
314          self.__clear_symbols() 
315          self.__load_nss() 
316          self.__load_classes() 
317          self.__load_base_classes() 
318          self.__load_enums() 
319          self.__load_vars() 
320          self.__load_typedefs() 
321          self.__load_calldefs() 
322          map( self.__normalize_name, self.global_ns.decls(recursive=True) ) 
323          self.__join_unnamed_nss( self.global_ns ) 
 324           
325   
326      @property 
328          return self.__dia_session.globalScope 
 329   
330      @property 
332          return self.__global_ns 
 333   
335          if not( decl1.__class__ is decl2.__class__ ): 
336              return False 
337          if decl1.name == decl2.name: 
338              if isinstance( decl1, declarations.calldef_t ): 
339                   
340                  return False 
341              else: 
342                  return True 
343          else: 
344              return False 
 345               
346   
348          self.logger.debug( 'testing whether name( "%s" ) is UDT symbol' % name ) 
349          flags = enums.NameSearchOptions.nsfCaseSensitive 
350          found = self.dia_global_scope.findChildren( msdia.SymTagUDT, name, flags ) 
351          if found.Count == 1: 
352              self.logger.debug( 'name( "%s" ) is UDT symbol' % name ) 
353              return as_symbol( found.Item(0) ) 
354          elif 1 < found.Count: 
355              raise RuntimeError( "duplicated UDTs with name '%s', were found" % name ) 
356               
357               
358               
359                   
360                   
361                   
362          else: 
363              self.logger.debug( 'name( "%s" ) is **NOT** UDT symbol' % name ) 
364              return None 
 365   
376   
377   
379          classes = {} 
380          is_udt = lambda smbl: smbl.symTag == msdia.SymTagUDT 
381          self.logger.info( 'building udt objects' ) 
382          for udt_smbl in itertools.ifilter( is_udt, self.symbols.itervalues() ): 
383              classes[udt_smbl.symIndexId] = self.__create_class(udt_smbl) 
384          self.logger.info( 'building udt objects(%d) - done', len(classes) ) 
385   
386          self.logger.info( 'integrating udt objects with namespaces' ) 
387          does_parent_exists = self.parent_exists_t( self.global_ns, classes, self.__id2decl ) 
388          while classes: 
389              to_be_integrated = len( classes ) 
390              self.logger.info( 'there are %d classes to go', len( classes ) ) 
391              to_be_deleted = filter( does_parent_exists, classes.itervalues() ) 
392              map( self.__update_decls_tree, to_be_deleted ) 
393              map( lambda decl: classes.pop( decl.dia_symbols[0].symIndexId ) 
394                   , to_be_deleted ) 
395              if not ( to_be_integrated - len( classes ) ): 
396                  for cls in classes.itervalues(): 
397                      self.logger.warning( 'unable to integrate class "%s" into declarations tree', cls.dia_symbols[0].uname ) 
398                  break 
399          self.logger.info( 'integrating udt objects with namespaces - done' ) 
 400   
402          make_hi = declarations.hierarchy_info_t 
403          is_base_class = lambda smbl: smbl.symTag == msdia.SymTagBaseClass \ 
404                                       and False == smbl.indirectVirtualBaseClass 
405          self.logger.info( 'building class hierarchies' ) 
406          for count, smbl in enumerate( itertools.ifilter( is_base_class, self.symbols.itervalues() ) ): 
407              base_id = smbl.type.symIndexId 
408              derived_id = smbl.classParentId 
409   
410              hi_base = make_hi( self.__id2decl[base_id] 
411                                 , self.__guess_access_type( smbl ) 
412                                 , bool( smbl.virtualBaseClass ) ) 
413              self.__id2decl[ derived_id ].bases.append( hi_base ) 
414   
415              hi_derived = make_hi( self.__id2decl[derived_id] 
416                                    , self.__guess_access_type( smbl ) 
417                                    , bool( smbl.virtualBaseClass ) ) 
418              self.__id2decl[ base_id ].derived.append( hi_derived ) 
419   
420          self.logger.info( 'building class hierarchies(%d) - done', count ) 
 421   
423          is_enum = lambda smbl: smbl.symTag == msdia.SymTagEnum 
424          self.logger.info( 'building enum objects' ) 
425          for enums_count, enum_smbl in enumerate( itertools.ifilter( is_enum, self.symbols.itervalues() ) ): 
426              enum_decl = self.__create_enum(enum_smbl) 
427              if not enum_decl: 
428                  continue 
429              self.__update_decls_tree( enum_decl ) 
430          self.logger.info( 'building enum objects(%d) - done', enums_count ) 
 431   
433          name_splitter = impl_details.get_name_splitter( enum_smbl.uname ) 
434          self.logger.debug( 'working on enum %s', enum_smbl.uname ) 
435          enum_decl = declarations.enumeration_t( name_splitter.name ) 
436          self.__update_decl( enum_decl, enum_smbl ) 
437   
438          values = enum_smbl.findChildren( msdia.SymTagData, None, 0 ) 
439          for v in itertools.imap(as_symbol, values): 
440              if v.classParent.symIndexId != enum_smbl.symIndexId: 
441                  continue 
442              enum_decl.append_value( v.name, v.value ) 
443          if enum_decl.values: 
444              return enum_decl 
445          else: 
446               
447               
448               
449              return None 
 450   
457   
459           
460          if smbl.symTag != msdia.SymTagData: 
461              return False 
462          if not smbl.uname: 
463              return False 
464          if smbl.classParentId not in self.symbols: 
465              return True  
466          parent_smbl = self.symbols[ smbl.classParentId ] 
467          return bool( parent_smbl.symTag == msdia.SymTagUDT ) 
 468   
470          self.logger.info( 'building variable objects' ) 
471   
472          for vars_count, var_smbl in enumerate( itertools.ifilter( self.__is_my_var, self.symbols.itervalues() ) ): 
473              var_decl = self.__create_var(var_smbl) 
474              if var_decl: 
475                  self.__update_decls_tree( var_decl ) 
476          self.logger.info( 'building variable objects(%d) - done', vars_count ) 
 477   
487   
489          self.logger.info( 'building typedef objects' ) 
490          is_typedef = lambda smbl: smbl.symTag == msdia.SymTagTypedef 
491          for typedefs_count, typedef_smbl in enumerate( itertools.ifilter( is_typedef, self.symbols.itervalues() ) ): 
492              typedef_decl = self.__create_typedef(typedef_smbl) 
493              self.__update_decls_tree( typedef_decl ) 
494          self.logger.info( 'building typedef objects(%d) - done', typedefs_count ) 
 495   
504   
506          self.logger.info( 'building function objects' ) 
507          is_function = lambda smbl: smbl.symTag == msdia.SymTagFunction 
508          for functions_count, function_smbl in enumerate( itertools.ifilter( is_function, self.symbols.itervalues() ) ): 
509              function_decl = self.__create_calldef(function_smbl) 
510              if function_decl: 
511                  self.__update_decls_tree( function_decl ) 
512          self.logger.info( 'building function objects(%d) - done', functions_count ) 
 513   
515           
516          if not smbl.uname.startswith( 'operator' ) or smbl.uname == 'operator': 
517              return None 
518          oper_smbls = ('!', ' ', '*', '%', '&', '(', '+', '-', ',', '/', '|', '~', '[', '^', '=', '<') 
519          if smbl.uname[ len( 'operator' ) ] not in oper_smbls: 
520              return None 
521          if smbl.uname[ len( 'operator' ) ] == ' ' \ 
522             and smbl.uname not in ['operator new', 'operator delete']: 
523               
524              return declarations.casting_operator_t() 
525          if isinstance( operator_type, declarations.member_function_type_t ): 
526              return declarations.member_operator_t() 
527          else: 
528              return declarations.free_operator_t() 
 529   
538   
540          self.logger.debug( 'creating calldef "%s"', smbl.uname ) 
541           
542               
543          name_splitter = impl_details.get_name_splitter( smbl.uname ) 
544          calldef_type = self.create_type( smbl.type )  
545          decl = None 
546          if isinstance( calldef_type, declarations.member_function_type_t ): 
547              could_be_static = False 
548              could_be_const = False 
549              if smbl.uname.startswith( '~' ): 
550                  decl = declarations.destructor_t() 
551              if not decl:  
552                  decl = self.__guess_operator_type(smbl, calldef_type) 
553                  could_be_static = True 
554                  could_be_const = True 
555              if not decl:  
556                  decl = self.__guess_constructor( smbl, calldef_type ) 
557              if not decl: 
558                  decl = declarations.member_function_t() 
559                  could_be_static = True 
560                  could_be_const = True 
561              if smbl.virtual: 
562                  decl.virtuality = iif( smbl.pure 
563                                         , declarations.VIRTUALITY_TYPES.PURE_VIRTUAL 
564                                         , declarations.VIRTUALITY_TYPES.VIRTUAL ) 
565              decl.has_const = bool( could_be_const and smbl.constType ) 
566              decl.has_static = bool( could_be_static and smbl.isStatic ) 
567          else: 
568              decl = self.__guess_operator_type(smbl, calldef_type) 
569              if not decl: 
570                  if 'instantiate::`dynamic initializer for' in smbl.uname: 
571                      return  
572                  decl = declarations.free_function_t() 
573          decl.name = smbl.uname 
574          decl.arguments = map( lambda t: declarations.argument_t( type=t ) 
575                                , calldef_type.arguments_types ) 
576   
577          args_smbls = map( as_symbol, smbl.findChildren( msdia.SymTagData, None, 0 ) ) 
578          args_smbls = filter( lambda smbl: smbl.dataKind == enums.DataKind.DataIsParam, args_smbls ) 
579   
580          for index, arg_smbl in enumerate( args_smbls ): 
581              arg_decl = decl.arguments[index] 
582              arg_decl.name = arg_smbl.name 
583              arg_decl.default_value = arg_smbl.value 
584          decl.return_type = calldef_type.return_type 
585   
586          self.__update_decl( decl, smbl ) 
587          self.logger.debug( 'creating calldef "%s" - done', smbl.uname ) 
588          return decl 
 589   
605   
704