/// <summary> /// Checks availability of debugging information for given assembly. /// </summary> /// <param name="assemblyPath"> /// File path of the assembly or null /// </param> /// <param name="isFileLayout">type of in-memory PE layout, if true, file based layout otherwise, loaded layout</param> /// <param name="loadedPeAddress"> /// Loaded PE image address or zero if the module is dynamic (generated by Reflection.Emit). /// Dynamic modules have their PDBs (if any) generated to an in-memory stream /// (pointed to by <paramref name="inMemoryPdbAddress"/> and <paramref name="inMemoryPdbSize"/>). /// </param> /// <param name="loadedPeSize">loaded PE image size</param> /// <param name="inMemoryPdbAddress">in memory PDB address or zero</param> /// <param name="inMemoryPdbSize">in memory PDB size</param> /// <returns>Symbol reader handle or zero if error</returns> private IntPtr LoadSymbolsForModule( IntPtr self, string assemblyPath, bool isFileLayout, ulong loadedPeAddress, uint loadedPeSize, ulong inMemoryPdbAddress, uint inMemoryPdbSize) { try { Stream peStream = null; if (loadedPeAddress != 0) { peStream = MemoryService.CreateMemoryStream(loadedPeAddress, loadedPeSize); } Stream pdbStream = null; if (inMemoryPdbAddress != 0) { pdbStream = MemoryService.CreateMemoryStream(inMemoryPdbAddress, inMemoryPdbSize); } OpenedReader openedReader = GetReader(assemblyPath, isFileLayout, peStream, pdbStream); if (openedReader != null) { GCHandle gch = GCHandle.Alloc(openedReader); return(GCHandle.ToIntPtr(gch)); } } catch (Exception ex) { Trace.TraceError($"LoadSymbolsForModule: {ex.Message}"); } return(IntPtr.Zero); }
private OpenedReader TryOpenReaderFromEmbeddedPdb(PEReader peReader, DebugDirectoryEntry embeddedPdbEntry) { OpenedReader result = null; MetadataReaderProvider provider = null; try { // TODO: We might want to cache this provider globally (across stack traces), // since decompressing embedded PDB takes some time. provider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedPdbEntry); result = new OpenedReader(provider, provider.GetMetadataReader()); } catch (Exception e) when(e is BadImageFormatException || e is IOException) { return(null); } finally { if (result == null) { provider?.Dispose(); } } return(result); }
/// <summary> /// Checks availability of debugging information for given assembly. /// </summary> /// <param name="assemblyPath"> /// File path of the assembly or null if the module is in-memory or dynamic (generated by Reflection.Emit) /// </param> /// <param name="isFileLayout">type of in-memory PE layout, if true, file based layout otherwise, loaded layout</param> /// <param name="loadedPeAddress"> /// Loaded PE image address or zero if the module is dynamic (generated by Reflection.Emit). /// Dynamic modules have their PDBs (if any) generated to an in-memory stream /// (pointed to by <paramref name="inMemoryPdbAddress"/> and <paramref name="inMemoryPdbSize"/>). /// </param> /// <param name="loadedPeSize">loaded PE image size</param> /// <param name="inMemoryPdbAddress">in memory PDB address or zero</param> /// <param name="inMemoryPdbSize">in memory PDB size</param> /// <returns>Symbol reader handle or zero if error</returns> internal static IntPtr LoadSymbolsForModule(string assemblyPath, bool isFileLayout, ulong loadedPeAddress, int loadedPeSize, ulong inMemoryPdbAddress, int inMemoryPdbSize, ReadMemoryDelegate readMemory) { try { TargetStream peStream = null; if (assemblyPath == null && loadedPeAddress != 0) { peStream = new TargetStream(loadedPeAddress, loadedPeSize, readMemory); } TargetStream pdbStream = null; if (inMemoryPdbAddress != 0) { pdbStream = new TargetStream(inMemoryPdbAddress, inMemoryPdbSize, readMemory); } OpenedReader openedReader = GetReader(assemblyPath, isFileLayout, peStream, pdbStream); if (openedReader != null) { GCHandle gch = GCHandle.Alloc(openedReader); return(GCHandle.ToIntPtr(gch)); } } catch { } return(IntPtr.Zero); }
private unsafe static OpenedReader TryOpenReaderForInMemoryPdb(IntPtr inMemoryPdbAddress, int inMemoryPdbSize) { Debug.Assert(inMemoryPdbAddress != IntPtr.Zero); // quick check to avoid throwing exceptions below in common cases: const uint ManagedMetadataSignature = 0x424A5342; if (inMemoryPdbSize < sizeof(uint) || *(uint *)inMemoryPdbAddress != ManagedMetadataSignature) { // not a Portable PDB return(null); } OpenedReader result = null; MetadataReaderProvider provider = null; try { provider = MetadataReaderProvider.FromMetadataImage((byte *)inMemoryPdbAddress, inMemoryPdbSize); result = new OpenedReader(provider, provider.GetMetadataReader()); } catch (BadImageFormatException) { return(null); } finally { if (result == null) { provider?.Dispose(); } } return(result); }
private static OpenedReader TryOpenReaderFromCodeView(PEReader peReader, DebugDirectoryEntry codeViewEntry, string assemblyPath) { OpenedReader result = null; MetadataReaderProvider provider = null; try { CodeViewDebugDirectoryData data = peReader.ReadCodeViewDebugDirectoryData(codeViewEntry); string pdbPath = data.Path; Stream pdbStream = null; if (assemblyPath != null) { try { pdbPath = Path.Combine(Path.GetDirectoryName(assemblyPath), GetFileName(pdbPath)); } catch { // invalid characters in CodeView path return(null); } pdbStream = TryOpenFile(pdbPath); } if (pdbStream == null) { if (s_symbolStore == null) { return(null); } Debug.Assert(codeViewEntry.MinorVersion == ImageDebugDirectory.PortablePDBMinorVersion); SymbolStoreKey key = PortablePDBFileKeyGenerator.GetKey(pdbPath, data.Guid); pdbStream = GetSymbolStoreFile(key)?.Stream; } provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); MetadataReader reader = provider.GetMetadataReader(); // Validate that the PDB matches the assembly version if (data.Age == 1 && new BlobContentId(reader.DebugMetadataHeader.Id) == new BlobContentId(data.Guid, codeViewEntry.Stamp)) { result = new OpenedReader(provider, reader); } } catch (Exception e) when(e is BadImageFormatException || e is IOException) { return(null); } finally { if (result == null) { provider?.Dispose(); } } return(result); }
/// <summary> /// Helper method to return source line number and source file name for given IL offset and method token. /// </summary> /// <param name="openedReader">symbol reader returned by LoadSymbolsForModule</param> /// <param name="methodToken">method token</param> /// <param name="ilOffset">IL offset</param> /// <param name="lineNumber">source line number return</param> /// <param name="fileName">source file name return</param> /// <returns> true if information is available</returns> private bool GetSourceLineByILOffset( OpenedReader openedReader, int methodToken, long ilOffset, out int lineNumber, out string fileName) { lineNumber = 0; fileName = null; MetadataReader reader = openedReader.Reader; try { Handle handle = MetadataTokens.Handle(methodToken); if (handle.Kind != HandleKind.MethodDefinition) { return(false); } MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle(); if (methodDebugHandle.IsNil) { return(false); } MethodDebugInformation methodDebugInfo = reader.GetMethodDebugInformation(methodDebugHandle); SequencePointCollection sequencePoints = methodDebugInfo.GetSequencePoints(); SequencePoint?nearestPoint = null; foreach (SequencePoint point in sequencePoints) { if (point.Offset > ilOffset) { break; } if (point.StartLine != 0 && !point.IsHidden) { nearestPoint = point; } } if (nearestPoint.HasValue) { lineNumber = nearestPoint.Value.StartLine; fileName = reader.GetString(reader.GetDocument(nearestPoint.Value.Document).Name); return(true); } } catch (Exception ex) { Trace.TraceError($"GetSourceLineByILOffset: {ex.Message}"); } return(false); }
private static bool GetLocalsInfoForMethod(string assemblyPath, int methodToken, out List <LocalVarInfo> locals) { locals = null; OpenedReader openedReader = GetReader(assemblyPath, isFileLayout: true, peStream: null, pdbStream: null); if (openedReader == null) { return(false); } using (openedReader) { try { Handle handle = MetadataTokens.Handle(methodToken); if (handle.Kind != HandleKind.MethodDefinition) { return(false); } locals = new List <LocalVarInfo>(); MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle(); LocalScopeHandleCollection localScopes = openedReader.Reader.GetLocalScopes(methodDebugHandle); foreach (LocalScopeHandle scopeHandle in localScopes) { LocalScope scope = openedReader.Reader.GetLocalScope(scopeHandle); LocalVariableHandleCollection localVars = scope.GetLocalVariables(); foreach (LocalVariableHandle varHandle in localVars) { LocalVariable localVar = openedReader.Reader.GetLocalVariable(varHandle); if (localVar.Attributes == LocalVariableAttributes.DebuggerHidden) { continue; } LocalVarInfo info = new LocalVarInfo(); info.startOffset = scope.StartOffset; info.endOffset = scope.EndOffset; info.name = openedReader.Reader.GetString(localVar.Name); locals.Add(info); } } } catch { return(false); } } return(true); }
private static OpenedReader TryOpenReaderFromCodeView(PEReader peReader, DebugDirectoryEntry codeViewEntry, string assemblyPath) { OpenedReader result = null; MetadataReaderProvider provider = null; try { var data = peReader.ReadCodeViewDebugDirectoryData(codeViewEntry); string pdbPath = data.Path; if (assemblyPath != null) { try { pdbPath = Path.Combine(Path.GetDirectoryName(assemblyPath), Path.GetFileName(pdbPath)); } catch { // invalid characters in CodeView path return(null); } } var pdbStream = TryOpenFile(pdbPath); if (pdbStream == null) { return(null); } provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); var reader = provider.GetMetadataReader(); // Validate that the PDB matches the assembly version if (data.Age == 1 && new BlobContentId(reader.DebugMetadataHeader.Id) == new BlobContentId(data.Guid, codeViewEntry.Stamp)) { result = new OpenedReader(provider, reader); } } catch (Exception e) when(e is BadImageFormatException || e is IOException) { return(null); } finally { if (result == null) { provider?.Dispose(); } } return(result); }
/// <summary> /// Helper method to return source name, line numbers and IL offsets for given method token. /// </summary> /// <param name="assemblyPath">file path of the assembly</param> /// <param name="methodToken">method token</param> /// <param name="points">list of debug information for each sequence point return</param> /// <returns>true if information is available</returns> /// <remarks>used by the gdb JIT support (not SOS). Does not support in-memory PEs or PDBs</remarks> private static bool GetDebugInfoForMethod(string assemblyPath, int methodToken, out List <DebugInfo> points) { points = null; OpenedReader openedReader = GetReader(assemblyPath, isFileLayout: true, peStream: null, pdbStream: null); if (openedReader == null) { return(false); } using (openedReader) { try { Handle handle = MetadataTokens.Handle(methodToken); if (handle.Kind != HandleKind.MethodDefinition) { return(false); } points = new List <DebugInfo>(); MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle(); MethodDebugInformation methodDebugInfo = openedReader.Reader.GetMethodDebugInformation(methodDebugHandle); SequencePointCollection sequencePoints = methodDebugInfo.GetSequencePoints(); foreach (SequencePoint point in sequencePoints) { if (point.StartLine == 0 || point.StartLine == SequencePoint.HiddenLine) { continue; } DebugInfo debugInfo = new DebugInfo(); debugInfo.lineNumber = point.StartLine; debugInfo.fileName = openedReader.Reader.GetString(openedReader.Reader.GetDocument(point.Document).Name); debugInfo.ilOffset = point.Offset; points.Add(debugInfo); } } catch { return(false); } } return(true); }
/// <summary> /// Helper method to return local variable name for given local index and IL offset. /// </summary> /// <param name="openedReader">symbol reader returned by LoadSymbolsForModule</param> /// <param name="methodToken">method token</param> /// <param name="localIndex">local variable index</param> /// <param name="localVarName">local variable name return</param> /// <returns>true if name has been found</returns> private bool GetLocalVariableByIndex( OpenedReader openedReader, int methodToken, int localIndex, out string localVarName) { localVarName = null; MetadataReader reader = openedReader.Reader; try { Handle handle = MetadataTokens.Handle(methodToken); if (handle.Kind != HandleKind.MethodDefinition) { return(false); } MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle(); LocalScopeHandleCollection localScopes = reader.GetLocalScopes(methodDebugHandle); foreach (LocalScopeHandle scopeHandle in localScopes) { LocalScope scope = reader.GetLocalScope(scopeHandle); LocalVariableHandleCollection localVars = scope.GetLocalVariables(); foreach (LocalVariableHandle varHandle in localVars) { LocalVariable localVar = reader.GetLocalVariable(varHandle); if (localVar.Index == localIndex) { if (localVar.Attributes == LocalVariableAttributes.DebuggerHidden) { return(false); } localVarName = reader.GetString(localVar.Name); return(true); } } } } catch (Exception ex) { Trace.TraceError($"GetLocalVariableByIndex: {ex.Message}"); } return(false); }
private static OpenedReader TryOpenReaderForInMemoryPdb(Stream pdbStream) { Debug.Assert(pdbStream != null); byte[] buffer = new byte[sizeof(uint)]; if (pdbStream.Read(buffer, 0, sizeof(uint)) != sizeof(uint)) { return(null); } uint signature = BitConverter.ToUInt32(buffer, 0); // quick check to avoid throwing exceptions below in common cases: const uint ManagedMetadataSignature = 0x424A5342; if (signature != ManagedMetadataSignature) { // not a Portable PDB return(null); } OpenedReader result = null; MetadataReaderProvider provider = null; try { pdbStream.Position = 0; provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); result = new OpenedReader(provider, provider.GetMetadataReader()); } catch (Exception e) when(e is BadImageFormatException || e is IOException) { return(null); } finally { if (result == null) { provider?.Dispose(); } } return(result); }
/// <summary> /// Returns local variable name for given local index and IL offset. /// </summary> /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param> /// <param name="methodToken">method token</param> /// <param name="localIndex">local variable index</param> /// <param name="localVarName">local variable name return</param> /// <returns>true if name has been found</returns> private bool GetLocalVariableName( IntPtr self, IntPtr symbolReaderHandle, int methodToken, int localIndex, out IntPtr localVarName) { Debug.Assert(symbolReaderHandle != IntPtr.Zero); localVarName = IntPtr.Zero; GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle); OpenedReader openedReader = (OpenedReader)gch.Target; if (!GetLocalVariableByIndex(openedReader, methodToken, localIndex, out string localVar)) { return(false); } localVarName = Marshal.StringToBSTR(localVar); return(true); }
/// <summary> /// Returns source line number and source file name for given IL offset and method token. /// </summary> /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param> /// <param name="methodToken">method token</param> /// <param name="ilOffset">IL offset</param> /// <param name="lineNumber">source line number return</param> /// <param name="fileName">source file name return</param> /// <returns> true if information is available</returns> private bool GetLineByILOffset( IntPtr self, IntPtr symbolReaderHandle, int methodToken, long ilOffset, out int lineNumber, out IntPtr fileName) { Debug.Assert(symbolReaderHandle != IntPtr.Zero); fileName = IntPtr.Zero; GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle); OpenedReader openedReader = (OpenedReader)gch.Target; if (!GetSourceLineByILOffset(openedReader, methodToken, ilOffset, out lineNumber, out string sourceFileName)) { return(false); } fileName = Marshal.StringToBSTR(sourceFileName); return(true); }
private static OpenedReader TryOpenReaderFromCodeView(PEReader peReader, DebugDirectoryEntry codeViewEntry, string assemblyPath) { OpenedReader result = null; MetadataReaderProvider provider = null; try { var data = peReader.ReadCodeViewDebugDirectoryData(codeViewEntry); string pdbPath = data.Path; if (assemblyPath != null) { try { pdbPath = Path.Combine(Path.GetDirectoryName(assemblyPath), GetFileName(pdbPath)); } catch { // invalid characters in CodeView path return(null); } } var pdbStream = TryOpenFile(pdbPath); if (pdbStream == null) { // workaround, since NI file could be generated in `.native_image` subdirectory // NOTE this is temporary solution until we add option for specifying pdb path try { int tmpLastIndex = assemblyPath.LastIndexOf(".native_image"); if (tmpLastIndex == -1) { return(null); } string tmpPath = assemblyPath.Substring(0, tmpLastIndex); pdbPath = Path.Combine(Path.GetDirectoryName(tmpPath), GetFileName(pdbPath)); } catch { // invalid characters in CodeView path return(null); } pdbStream = TryOpenFile(pdbPath); if (pdbStream == null) { return(null); } } provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); var reader = provider.GetMetadataReader(); // Validate that the PDB matches the assembly version if (data.Age == 1 && new BlobContentId(reader.DebugMetadataHeader.Id) == new BlobContentId(data.Guid, codeViewEntry.Stamp)) { result = new OpenedReader(provider, reader); } } catch (Exception e) when(e is BadImageFormatException || e is IOException) { return(null); } finally { if (result == null) { provider?.Dispose(); } } return(result); }
private unsafe static OpenedReader TryOpenReaderForInMemoryPdb(IntPtr inMemoryPdbAddress, int inMemoryPdbSize) { Debug.Assert(inMemoryPdbAddress != IntPtr.Zero); // quick check to avoid throwing exceptions below in common cases: const uint ManagedMetadataSignature = 0x424A5342; if (inMemoryPdbSize < sizeof(uint) || *(uint*)inMemoryPdbAddress != ManagedMetadataSignature) { // not a Portable PDB return null; } OpenedReader result = null; MetadataReaderProvider provider = null; try { provider = MetadataReaderProvider.FromMetadataImage((byte*)inMemoryPdbAddress, inMemoryPdbSize); result = new OpenedReader(provider, provider.GetMetadataReader()); } catch (BadImageFormatException) { return null; } finally { if (result == null) { provider?.Dispose(); } } return result; }
private static OpenedReader TryOpenReaderForInMemoryPdb(Stream pdbStream) { Debug.Assert(pdbStream != null); byte[] buffer = new byte[sizeof(uint)]; if (pdbStream.Read(buffer, 0, sizeof(uint)) != sizeof(uint)) { return null; } uint signature = BitConverter.ToUInt32(buffer, 0); // quick check to avoid throwing exceptions below in common cases: const uint ManagedMetadataSignature = 0x424A5342; if (signature != ManagedMetadataSignature) { // not a Portable PDB return null; } OpenedReader result = null; MetadataReaderProvider provider = null; try { pdbStream.Position = 0; provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); result = new OpenedReader(provider, provider.GetMetadataReader()); } catch (Exception e) when (e is BadImageFormatException || e is IOException) { return null; } finally { if (result == null) { provider?.Dispose(); } } return result; }
private static OpenedReader TryOpenReaderFromEmbeddedPdb(PEReader peReader, DebugDirectoryEntry embeddedPdbEntry) { OpenedReader result = null; MetadataReaderProvider provider = null; try { // TODO: We might want to cache this provider globally (across stack traces), // since decompressing embedded PDB takes some time. provider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedPdbEntry); result = new OpenedReader(provider, provider.GetMetadataReader()); } catch (Exception e) when (e is BadImageFormatException || e is IOException) { return null; } finally { if (result == null) { provider?.Dispose(); } } return result; }
private static OpenedReader TryOpenReaderFromCodeView(PEReader peReader, DebugDirectoryEntry codeViewEntry, string assemblyPath) { OpenedReader result = null; MetadataReaderProvider provider = null; try { var data = peReader.ReadCodeViewDebugDirectoryData(codeViewEntry); string pdbPath = data.Path; if (assemblyPath != null) { try { pdbPath = Path.Combine(Path.GetDirectoryName(assemblyPath), Path.GetFileName(pdbPath)); } catch { // invalid characters in CodeView path return null; } } var pdbStream = TryOpenFile(pdbPath); if (pdbStream == null) { return null; } provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); var reader = provider.GetMetadataReader(); // Validate that the PDB matches the assembly version if (data.Age == 1 && new BlobContentId(reader.DebugMetadataHeader.Id) == new BlobContentId(data.Guid, codeViewEntry.Stamp)) { result = new OpenedReader(provider, reader); } } catch (Exception e) when (e is BadImageFormatException || e is IOException) { return null; } finally { if (result == null) { provider?.Dispose(); } } return result; }