@@ -21,11 +21,20 @@ namespace Microsoft.Diagnostics.Symbols
2121 /// support other formats (e.g. Dwarf).
2222 ///
2323 /// To implmente support for Windows PDBs we use the Debug Interface Access (DIA). See
24- /// http://msdn.microsoft.com/en-us/ library/x93ctkx8.aspx for more. I have only exposed what
24+ /// http://msdn.microsoft.com/library/x93ctkx8.aspx for more. I have only exposed what
2525 /// I need, and the interface is quite large (and not super pretty).
2626 /// </summary>
2727 public unsafe class NativeSymbolModule : ManagedSymbolModule
2828 {
29+ /// <summary>
30+ /// Returns the name of the type allocated for a given relative virtual address.
31+ /// Returns null if the given rva does not match a known heap allocation site.
32+ /// </summary>
33+ public string GetTypeForHeapAllocationSite ( uint rva )
34+ {
35+ return m_heapAllocationSites . Value . TryGetValue ( rva , out var name ) ? name : null ;
36+ }
37+
2938 /// <summary>
3039 /// Finds a (method) symbolic name for a given relative virtual address of some code.
3140 /// Returns an empty string if a name could not be found.
@@ -922,27 +931,46 @@ private string SourceServerEvaluate(string result, Dictionary<string, string> va
922931 #endregion
923932 }
924933
925- private void Initialize ( SymbolReader reader , string pdbFilePath , Action loadData )
934+ private NativeSymbolModule ( SymbolReader reader , string pdbFilePath , Action < IDiaDataSource3 > loadData ) : base ( reader , pdbFilePath )
926935 {
927936 m_reader = reader;
928937
929938 m_source = DiaLoader. GetDiaSourceObject ( ) ;
930- loadData( ) ;
939+ loadData( m_source ) ;
931940 m_source. openSession ( out m_session ) ;
932941 m_session. getSymbolsByAddr ( out m_symbolsByAddr ) ;
933942
943+ m_heapAllocationSites = new Lazy< IReadOnlyDictionary < uint , string > > ( ( ) =>
944+ {
945+ // Retrieves the S_HEAPALLOCSITE information from the pdb as described here:
946+ // https://docs.microsoft.com/visualstudio/profiling/custom-native-etw-heap-events
947+ Dictionary < uint , string > result = null ;
948+ m_session . getHeapAllocationSites ( out var diaEnumSymbols ) ;
949+ for ( ; ; )
950+ {
951+ diaEnumSymbols . Next ( 1 , out var sym , out var fetchCount ) ;
952+ if ( fetchCount == 0 )
953+ {
954+ return ( IReadOnlyDictionary < uint , string > ) result ?? System . Collections . Immutable . ImmutableDictionary < uint , string > . Empty ;
955+ }
956+
957+ result = result ?? new Dictionary < uint , string > ( ) ;
958+ m_session . symbolById ( sym . typeId , out var typeSym ) ;
959+ result [ sym . relativeVirtualAddress + ( uint ) sym . length ] = HeapAllocationTypeInfo . GetTypeName ( typeSym ) ;
960+ }
961+ } ) ;
962+
934963 m_reader. m_log . WriteLine ( "Opening PDB {0} with signature GUID {1} Age {2}" , pdbFilePath , PdbGuid , PdbAge ) ;
935964 }
936965
937- internal NativeSymbolModule( SymbolReader reader , string pdbFilePath ) : base ( reader , pdbFilePath )
966+ internal NativeSymbolModule( SymbolReader reader , string pdbFilePath )
967+ : this ( reader , pdbFilePath , s => s . loadDataFromPdb ( pdbFilePath ) )
938968 {
939- Initialize( reader , pdbFilePath , ( ) => m_source . loadDataFromPdb ( pdbFilePath ) ) ;
940969 }
941970
942- internal NativeSymbolModule( SymbolReader reader , string pdbFilePath , Stream pdbStream ) : base ( reader , pdbFilePath )
971+ internal NativeSymbolModule( SymbolReader reader , string pdbFilePath , Stream pdbStream )
972+ : this ( reader , pdbFilePath , s => s . loadDataFromIStream ( new ComStreamWrapper ( pdbStream ) ) )
943973 {
944- IStream comStream = new ComStreamWrapper( pdbStream ) ;
945- Initialize( reader , pdbFilePath , ( ) => m_source . loadDataFromIStream ( comStream ) ) ;
946974 }
947975
948976 internal void LogManagedInfo( string pdbName , Guid pdbGuid , int pdbAge )
@@ -1166,6 +1194,166 @@ public byte[] GetTypeMDTokenMap()
11661194 return buf;
11671195 }
11681196
1197+ /// <summary>
1198+ /// This static class contains the GetTypeName method for retrieving the type name of
1199+ /// a heap allocation site.
1200+ ///
1201+ /// See https://github.com/KirillOsenkov/Dia2Dump/blob/master/PrintSymbol.cpp for more details
1202+ /// </summary>
1203+ private static class HeapAllocationTypeInfo
1204+ {
1205+ internal static string GetTypeName( IDiaSymbol symbol )
1206+ {
1207+ var name = symbol. name ?? "<unknown>" ;
1208+
1209+ switch ( ( SymTagEnum ) symbol . symTag )
1210+ {
1211+ case SymTagEnum. UDT:
1212+ case SymTagEnum. Enum:
1213+ case SymTagEnum. Typedef:
1214+ return name;
1215+ case SymTagEnum. FunctionType:
1216+ return "function";
1217+ case SymTagEnum. PointerType:
1218+ return $"{GetTypeName(symbol.type)} {(symbol.reference != 0 ? " & " : " * ") }" ;
1219+ case SymTagEnum. ArrayType :
1220+ return "array";
1221+ case SymTagEnum . BaseType :
1222+ var sb = new StringBuilder ( ) ;
1223+ switch ( ( BasicType ) symbol . baseType )
1224+ {
1225+ case BasicType . btUInt:
1226+ sb. Append( "unsigned ") ;
1227+ goto case BasicType. btInt;
1228+ case BasicType. btInt:
1229+ switch ( symbol . length )
1230+ {
1231+ case 1 :
1232+ sb . Append ( "char ") ;
1233+ break ;
1234+ case 2 :
1235+ sb . Append ( "short ") ;
1236+ break ;
1237+ case 4 :
1238+ sb . Append ( "int ") ;
1239+ break ;
1240+ case 8 :
1241+ sb . Append ( "long ") ;
1242+ break ;
1243+ }
1244+ return sb . ToString ( ) ;
1245+ case BasicType. btFloat:
1246+ return symbol. length == 4 ? "float " : "double ";
1247+ default :
1248+ return BaseTypes[ symbol. baseType] ;
1249+ }
1250+ }
1251+
1252+ return $"unhandled symbol tag { symbol. symTag} ";
1253+ }
1254+
1255+ private enum SymTagEnum
1256+ {
1257+ Null ,
1258+ Exe ,
1259+ Compiland ,
1260+ CompilandDetails ,
1261+ CompilandEnv ,
1262+ Function ,
1263+ Block ,
1264+ Data ,
1265+ Annotation ,
1266+ Label ,
1267+ PublicSymbol ,
1268+ UDT ,
1269+ Enum ,
1270+ FunctionType ,
1271+ PointerType ,
1272+ ArrayType ,
1273+ BaseType ,
1274+ Typedef ,
1275+ BaseClass ,
1276+ Friend ,
1277+ FunctionArgType ,
1278+ FuncDebugStart ,
1279+ FuncDebugEnd ,
1280+ UsingNamespace ,
1281+ VTableShape ,
1282+ VTable ,
1283+ Custom ,
1284+ Thunk ,
1285+ CustomType ,
1286+ ManagedType ,
1287+ Dimension ,
1288+ CallSite ,
1289+ InlineSite ,
1290+ BaseInterface ,
1291+ VectorType ,
1292+ MatrixType ,
1293+ HLSLType
1294+ } ;
1295+
1296+ private enum BasicType
1297+ {
1298+ btNoType = 0 ,
1299+ btVoid = 1 ,
1300+ btChar = 2 ,
1301+ btWChar = 3 ,
1302+ btInt = 6 ,
1303+ btUInt = 7 ,
1304+ btFloat = 8 ,
1305+ btBCD = 9 ,
1306+ btBool = 10 ,
1307+ btLong = 13 ,
1308+ btULong = 14 ,
1309+ btCurrency = 25 ,
1310+ btDate = 26 ,
1311+ btVariant = 27 ,
1312+ btComplex = 28 ,
1313+ btBit = 29 ,
1314+ btBSTR = 30 ,
1315+ btHresult = 31 ,
1316+ btChar16 = 32 , // char16_t
1317+ btChar32 = 33 , // char32_t
1318+ } ;
1319+
1320+ private static readonly string [ ] BaseTypes = new [ ]
1321+ {
1322+ "<NoType>" , // btNoType = 0,
1323+ "void" , // btVoid = 1,
1324+ "char" , // btChar = 2,
1325+ "wchar_t" , // btWChar = 3,
1326+ "signed char" ,
1327+ "unsigned char" ,
1328+ "int" , // btInt = 6,
1329+ "unsigned int" , // btUInt = 7,
1330+ "float" , // btFloat = 8,
1331+ "<BCD>" , // btBCD = 9,
1332+ "bool" , // btBool = 10,
1333+ "short" ,
1334+ "unsigned short" ,
1335+ "long" , // btLong = 13,
1336+ "unsigned long" , // btULong = 14,
1337+ "__int8" ,
1338+ "__int16" ,
1339+ "__int32" ,
1340+ "__int64" ,
1341+ "__int128" ,
1342+ "unsigned __int8" ,
1343+ "unsigned __int16" ,
1344+ "unsigned __int32" ,
1345+ "unsigned __int64" ,
1346+ "unsigned __int128" ,
1347+ "<currency>" , // btCurrency = 25,
1348+ "<date>" , // btDate = 26,
1349+ "VARIANT" , // btVariant = 27,
1350+ "<complex>" , // btComplex = 28,
1351+ "<bit>" , // btBit = 29,
1352+ "BSTR" , // btBSTR = 30,
1353+ "HRESULT" // btHresult = 31
1354+ } ;
1355+ }
1356+
11691357 private bool m_checkedForMergedAssemblies;
11701358 private Dictionary< int , string > m_mergedAssemblies ;
11711359
@@ -1175,10 +1363,11 @@ public byte[] GetTypeMDTokenMap()
11751363 private ManagedSymbolModule m_managedPdb;
11761364 private bool m_managedPdbAttempted ;
11771365
1178- internal SymbolReader m_reader;
1179- internal IDiaSession m_session;
1180- private IDiaDataSource3 m_source;
1181- private IDiaEnumSymbolsByAddr m_symbolsByAddr;
1366+ internal readonly IDiaSession m_session;
1367+ private readonly SymbolReader m_reader;
1368+ private readonly IDiaDataSource3 m_source;
1369+ private readonly IDiaEnumSymbolsByAddr m_symbolsByAddr;
1370+ private readonly Lazy < IReadOnlyDictionary < uint , string > > m_heapAllocationSites ; // rva => typename
11821371
11831372 #endregion
11841373 }
0 commit comments