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 )
269
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