Created
January 27, 2014 02:05
-
-
Save gimelfarb/8642282 to your computer and use it in GitHub Desktop.
Reading PDB symbol reference info (file, GUID, age) from a loaded Assembly
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static AssemblyDebugInfo ReadAssemblyDebugInfo(Assembly assembly) | |
{ | |
// Parses PE headers structure from the module base address pointer | |
var modulePtr = Marshal.GetHINSTANCE(assembly.ManifestModule); | |
var peHdrs = PeHeaders.FromUnmanagedPtr(modulePtr); | |
// Depending on whether this is 32-bit or 64-bit module, the offsets are | |
// slightly different | |
uint debugOffset, debugSize; | |
if (peHdrs.Is32BitOptionalHeader && peHdrs.OptionalHeader32.NumberOfRvaAndSizes >= 7) | |
{ | |
debugOffset = peHdrs.OptionalHeader32.Debug.VirtualAddress; | |
debugSize = peHdrs.OptionalHeader32.Debug.Size; | |
} | |
else if (!peHdrs.Is32BitOptionalHeader && peHdrs.OptionalHeader64.NumberOfRvaAndSizes >= 7) | |
{ | |
debugOffset = peHdrs.OptionalHeader64.Debug.VirtualAddress; | |
debugSize = peHdrs.OptionalHeader64.Debug.Size; | |
} | |
else | |
{ | |
// In case DEBUG information is not in the module | |
return null; | |
} | |
// Navigating to the DEBUG_DIRECTORY portion, which holds the debug information | |
var debugPtr = new IntPtr(modulePtr.ToInt64() + debugOffset); | |
var debugDirectory = (IMAGE_DEBUG_DIRECTORY)Marshal.PtrToStructure(debugPtr, typeof(IMAGE_DEBUG_DIRECTORY)); | |
// Check that DEBUG information is there and that it is in CODEVIEW/RSDS format, | |
// which is what's used by .NET framework | |
if (debugDirectory.Type != IMAGE_DEBUG_TYPE_CODEVIEW) return null; | |
var rsdsPtr = new IntPtr(modulePtr.ToInt64() + debugDirectory.AddressOfRawData); | |
if (Marshal.ReadInt32(rsdsPtr) != RSDS_SIGNATURE) return null; | |
// Read the RSDS info, which includes the PDB GUID and its Age, together with | |
// PDB filepath | |
var rsdsInfo = (RSDS_DEBUG_FORMAT)Marshal.PtrToStructure(rsdsPtr, typeof(RSDS_DEBUG_FORMAT)); | |
var pathPtr = new IntPtr(rsdsPtr.ToInt64() + Marshal.SizeOf(typeof(RSDS_DEBUG_FORMAT))); | |
var path = Marshal.PtrToStringAnsi(pathPtr); | |
return new AssemblyDebugInfo() | |
{ | |
Guid = new Guid(rsdsInfo.Guid), | |
Age = rsdsInfo.Age, | |
Path = path | |
}; | |
} | |
[StructLayout(LayoutKind.Sequential, Pack = 1)] | |
private struct IMAGE_DEBUG_DIRECTORY | |
{ | |
public UInt32 Characteristics; | |
public UInt32 TimeDateStamp; | |
public UInt16 MajorVersion; | |
public UInt16 MinorVersion; | |
public UInt32 Type; | |
public UInt32 SizeOfData; | |
public UInt32 AddressOfRawData; | |
public UInt32 PointerToRawData; | |
} | |
private const UInt32 IMAGE_DEBUG_TYPE_CODEVIEW = 2; | |
private const UInt32 RSDS_SIGNATURE = 0x53445352; | |
// http://www.godevtool.com/Other/pdb.htm | |
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] | |
private struct RSDS_DEBUG_FORMAT | |
{ | |
public UInt32 Signature; // RSDS | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] | |
public Byte[] Guid; | |
public UInt32 Age; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private void Load(IntPtr memPtr, long index) | |
{ | |
var startIndex = index; | |
dosHeader = FromMemoryPtr<IMAGE_DOS_HEADER>(memPtr, ref index); | |
index = startIndex + dosHeader.e_lfanew + 4; | |
fileHeader = FromMemoryPtr<IMAGE_FILE_HEADER>(memPtr, ref index); | |
// See the optiona header magic to determine 32-bit vs 64-bit | |
var optMagic = Marshal.ReadInt16(new IntPtr(memPtr.ToInt64() + index)); | |
_is32bit = (optMagic != IMAGE_NT_OPTIONAL_HDR64_MAGIC); | |
if (_is32bit) | |
{ | |
optionalHeader32 = FromMemoryPtr<IMAGE_OPTIONAL_HEADER32>(memPtr, ref index); | |
} | |
else | |
{ | |
optionalHeader64 = FromMemoryPtr<IMAGE_OPTIONAL_HEADER64>(memPtr, ref index); | |
} | |
imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; | |
for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo) | |
{ | |
imageSectionHeaders[headerNo] = FromMemoryPtr<IMAGE_SECTION_HEADER>(memPtr, ref index); | |
} | |
} | |
private static T FromMemoryPtr<T>(IntPtr memPtr, ref long index) | |
{ | |
var obj = (T)Marshal.PtrToStructure(new IntPtr(memPtr.ToInt64() + index), typeof(T)); | |
index += Marshal.SizeOf(typeof(T)); | |
return obj; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment