private static Dictionary <string, IntPtr> ParseSymbols(string pdbPath, IntPtr moduleAddress) { var symbols = new Dictionary <string, IntPtr>(); // Initialise a symbol handler for the local process using var localProcess = Process.GetCurrentProcess(); if (!Dbghelp.SymInitialize(localProcess.SafeHandle, IntPtr.Zero, false)) { throw new Win32Exception($"Failed to call SymInitialize with error code {Marshal.GetLastWin32Error()}"); } // Load the symbol table for the PDB var pdbPathBuffer = Encoding.Default.GetBytes(pdbPath); var symbolTableBaseAddress = Dbghelp.SymLoadModuleEx(localProcess.SafeHandle, IntPtr.Zero, ref pdbPathBuffer[0], IntPtr.Zero, moduleAddress, (int)new FileInfo(pdbPath).Length, IntPtr.Zero, 0); if (symbolTableBaseAddress == IntPtr.Zero) { throw new Win32Exception($"Failed to call SymLoadModuleEx with error code {Marshal.GetLastWin32Error()}"); } // Initialise the callback used during the SymEnumSymbols call bool Callback(ref SymbolInfo symbolInfo, int symbolSize, IntPtr userContext) { var symbolNameBuffer = new byte[symbolInfo.NameLen]; Unsafe.CopyBlockUnaligned(ref symbolNameBuffer[0], ref symbolInfo.Name, (uint)symbolNameBuffer.Length); symbols.TryAdd(Encoding.Default.GetString(symbolNameBuffer), (IntPtr)symbolInfo.Address); return(true); } var callbackDelegate = new Prototypes.EnumerateSymbolsCallback(Callback); // Enumerate the PDB symbols if (!Dbghelp.SymEnumSymbols(localProcess.SafeHandle, symbolTableBaseAddress, IntPtr.Zero, callbackDelegate, IntPtr.Zero)) { throw new Win32Exception($"Failed to call SymEnumSymbols with error code {Marshal.GetLastWin32Error()}"); } if (!Dbghelp.SymUnloadModule(localProcess.SafeHandle, symbolTableBaseAddress)) { throw new Win32Exception($"Failed to call SymUnloadModule with error code {Marshal.GetLastWin32Error()}"); } return(symbols); }
internal int GetSymbolAddress(string symbolName) { // Initialise a symbol handler Dbghelp.SymSetOptions(SymbolOptions.UndecorateName); using var currentProcessHandle = Process.GetCurrentProcess().SafeHandle; if (!Dbghelp.SymInitialize(currentProcessHandle, null, false)) { throw new Win32Exception(); } try { const int pseudoDllAddress = 0x1000; // Load the symbol table for the PDB into the symbol handler var pdbSize = new FileInfo(_pdbFilePath).Length; var symbolTableAddress = Dbghelp.SymLoadModule(currentProcessHandle, IntPtr.Zero, _pdbFilePath, null, pseudoDllAddress, (int)pdbSize); if (symbolTableAddress == 0) { throw new Win32Exception(); } // Initialise an array to receive the symbol information var symbolInformationSize = (Unsafe.SizeOf <SymbolInfo>() + sizeof(char) * Constants.MaxSymbolNameLength + sizeof(long) - 1) / sizeof(long); Span <byte> symbolInformationBytes = stackalloc byte[symbolInformationSize]; MemoryMarshal.Write(symbolInformationBytes, ref Unsafe.AsRef(new SymbolInfo(Constants.MaxSymbolNameLength))); try { // Retrieve the symbol information if (!Dbghelp.SymFromName(currentProcessHandle, symbolName, out symbolInformationBytes[0])) { throw new Win32Exception(); } } catch { Dbghelp.SymUnloadModule(currentProcessHandle, pseudoDllAddress); throw; } if (!Dbghelp.SymUnloadModule(currentProcessHandle, pseudoDllAddress)) { throw new Win32Exception(); } // Calculate the address of the symbol var symbolInformation = MemoryMarshal.Read <SymbolInfo>(symbolInformationBytes); return((int)symbolInformation.Address - pseudoDllAddress); } finally { Dbghelp.SymCleanup(currentProcessHandle); } }