/// <summary> /// Initializes a new instance of the <see cref="ClrMethodAdapter" /> class. /// </summary> /// <param name="method">The method.</param> /// <exception cref="ArgumentNullException">method</exception> /// <inheritdoc /> public ClrMethodAdapter(IConverter converter, ClrMd.ClrMethod method) : base(converter) { Method = method ?? throw new ArgumentNullException(nameof(method)); GCInfo = Method.GCInfo; IsAbstract = Method.IsAbstract; IsClassConstructor = Method.IsClassConstructor; IsConstructor = Method.IsConstructor; IsFinal = Method.IsFinal; IsInternal = Method.IsInternal; IsPInvoke = Method.IsPInvoke; IsPrivate = Method.IsPrivate; IsProtected = Method.IsProtected; IsPublic = Method.IsPublic; IsRTSpecialName = Method.IsRTSpecialName; IsSpecialName = Method.IsSpecialName; IsStatic = Method.IsStatic; IsVirtual = Method.IsVirtual; MetadataToken = Method.MetadataToken; try { MethodDesc = Method.MethodDesc; } catch (Exception) { ; // CLRMd bug } Name = Method.Name; NativeCode = Method.NativeCode; }
public LoneTargetInformation(ClrDump clrDump, ClrObject target, ClrMethod methInfo, ClrObject owner) { this.clrDump = clrDump; this.target = target; this.methInfo = methInfo; this.owner = owner; }
/// <summary> /// Converts the specified method. /// </summary> /// <param name="method">The method.</param> /// <returns>IClrMethod.</returns> public IClrMethod Convert(ClrMd.ClrMethod method) { if (method == null) { return(null); } var item = new ClrMethodAdapter(this, method); return(Cache.GetOrAdd <IClrMethod>(method, () => item, () => item.Setup())); }
/// <summary> /// Finds the IL offset for the specified frame. /// </summary> /// <param name="method">The method.</param> /// <param name="instructionPointer">The instruction pointer.</param> internal static uint FindIlOffset(Microsoft.Diagnostics.Runtime.ClrMethod method, ulong instructionPointer) { ulong ip = instructionPointer; uint last = uint.MaxValue; foreach (var item in method.ILOffsetMap) { if (item.StartAddress > ip) { return(last); } if (ip <= item.EndAddress) { return((uint)item.ILOffset); } last = (uint)item.ILOffset; } return(last); }
private void DecompileMethods(ClrMethod[] methods) { string moduleFileName = methods[0].Type.Module.FileName; string typeName = methods[0].Type.Name; var assemblyDef = AssemblyDefinition.ReadAssembly(moduleFileName); var typeDef = TypeDefFromAssemblyDef(typeName, assemblyDef); AstBuilder decompiler = new AstBuilder( new DecompilerContext(typeDef.Module) { CurrentType = typeDef }); foreach (var method in methods) { var methodDef = typeDef.Methods.Single( m => m.MetadataToken.ToUInt32() == method.MetadataToken); decompiler.AddMethod(methodDef); } GenerateCode(decompiler); }
public ClrMethodDecorator(ClrMethod clrMethod, ThreadDispatcher threadDispatcher) { _clrMethod = clrMethod; _threadDispatcher = threadDispatcher; }
/// <summary> /// See https://github.com/goldshtn/msos/commit/705d3758d15835d2520b31fcf3028353bdbca73b#commitcomment-12499813 /// and https://github.com/Microsoft/dotnetsamples/blob/master/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Debugger/IDebugControl.cs#L126-L156 /// </summary> private void PrintAssemblyCode(ClrMethod method, IList<ILToNativeMap> ilMaps, ClrRuntime runtime, IDebugControl debugControl) { // This is the first instruction of the JIT'ed (or NGEN'ed) machine code. ulong startAddress = ilMaps.Select(entry => entry.StartAddress).Min(); // Unfortunately there's not a great way to get the size of the code, or the end address. // You are supposed to do code flow analysis like "uf" in windbg to find the size, but // in practice you can use the IL to native mapping: ulong endAddress = ilMaps.Select(entry => entry.EndAddress).Max(); var bufferSize = 500; // per-line var lineOfAssembly = new StringBuilder(bufferSize); ulong startOffset = startAddress, endOffset; uint disassemblySize; do { var flags = DEBUG_DISASM.EFFECTIVE_ADDRESS; var result = debugControl.Disassemble(startOffset, flags, lineOfAssembly, bufferSize, out disassemblySize, out endOffset); startOffset = endOffset; logger?.Write(lineOfAssembly.ToString()); if (lineOfAssembly.ToString().Contains(" call ") == false) continue; var methodCallInfo = GetCalledMethodFromAssemblyOutput(runtime, lineOfAssembly.ToString()); if (string.IsNullOrWhiteSpace(methodCallInfo) == false) logger?.WriteLine(LogKind.Info, $" {methodCallInfo}"); } while (disassemblySize > 0 && endOffset <= endAddress); logger?.WriteLine(); }
private void PrintLocationAndILMapInfo(ClrMethod method, ILOffsetSourceLocation location, IList<ILToNativeMap> ilMaps) { try { var ilMapsInfo = ilMaps.Select(ilMap => string.Format("IL_{0:X4} [{1:X8}-{2:X8} ({3:X8}-{4:X8})] ", ilMap.ILOffset, ilMap.StartAddress, ilMap.EndAddress, ilMap.StartAddress - @method.NativeCode, ilMap.EndAddress - @method.NativeCode)); logger?.WriteLine(LogKind.Statistic, string.Join("\n ", ilMapsInfo)); } catch (Exception ex) { logger?.WriteLine(LogKind.Error, ex.ToString()); } }
private static PdbReader GetReaderForMethod(ClrMethod method) { ClrModule module = method?.Type?.Module; PdbInfo info = module?.Pdb; PdbReader reader = null; if (info != null) { if (!s_pdbReaders.TryGetValue(info, out reader)) { SymbolLocator locator = GetSymbolLocator(module); string pdbPath = locator.FindPdb(info); if (pdbPath != null) { try { reader = new PdbReader(pdbPath); } catch (IOException) { // This will typically happen when trying to load information // from public symbols, or symbol files generated by some weird // compiler. We can ignore this, but there's no need to load // this PDB anymore, so we will put null in the dictionary and // be done with it. reader = null; } } s_pdbReaders[info] = reader; } } return reader; }
private void DisassembleMethod(ClrMethod method) { var module = method.Type.Module; string fileName = module.FileName; AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(fileName); TypeDefinition type = assembly.MainModule.GetType(method.Type.Name); MethodDefinition methodDef = type.Methods.Single( m => m.MetadataToken.ToUInt32() == method.MetadataToken); _context.WriteLine("{0}", method.GetFullSignature()); if (method.ILOffsetMap == null) return; var mapByOffset = (from map in method.ILOffsetMap where map.ILOffset != -2 where map.StartAddress <= map.EndAddress orderby map.ILOffset select map).ToArray(); if (mapByOffset.Length == 0) { // The method doesn't have an offset map. Just print the whole thing. PrintInstructions(methodDef.Body.Instructions); } // This is the prologue, looks like it's always there, but it could // also be the only thing that's in the method DisassembleNative(method.ILOffsetMap.Single(e => e.ILOffset == -2)); for (int i = 0; i < mapByOffset.Length; ++i) { var map = mapByOffset[i]; IEnumerable<Instruction> instructions; if (i == mapByOffset.Length - 1) { instructions = methodDef.Body.Instructions.Where( instr => instr.Offset >= map.ILOffset); } else { instructions = methodDef.Body.Instructions.Where( instr => instr.Offset >= map.ILOffset && instr.Offset < mapByOffset[i + 1].ILOffset); } var sourceLocation = method.GetSourceLocation(map.ILOffset); if (sourceLocation != null) { _context.WriteLine("{0} {1}-{2}:{3}-{4}", sourceLocation.FilePath, sourceLocation.LineNumber, sourceLocation.LineNumberEnd, sourceLocation.ColStart, sourceLocation.ColEnd); for (int line = sourceLocation.LineNumber; line <= sourceLocation.LineNumberEnd; ++line) { _context.WriteLine(ReadSourceLine(sourceLocation.FilePath, line)); _context.WriteLine(new string(' ', sourceLocation.ColStart - 1) + new string('^', sourceLocation.ColEnd - sourceLocation.ColStart)); } } PrintInstructions(instructions); DisassembleNative(map); } // TODO We are still not printing the epilogue while sosex does }
/// <summary> /// Reads the CLR source file name, line number and displacement. /// </summary> /// <param name="pdbName">The name of pdb.</param> /// <param name="method">The method.</param> /// <param name="address">The address.</param> internal static Tuple <string, uint, ulong> ReadClrSourceFileNameAndLine(String pdbName, Microsoft.Diagnostics.Runtime.ClrMethod method, ulong address) { Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbReader pdbReader = new Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbReader(pdbName); Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbFunction function = pdbReader.GetFunctionFromToken(method.MetadataToken); uint ilOffset = FindIlOffset(method, address); ulong distance = ulong.MaxValue; string sourceFileName = ""; uint sourceFileLine = uint.MaxValue; if (function != null && function.SequencePoints != null) { foreach (Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbSequencePointCollection sequenceCollection in function.SequencePoints) { foreach (Microsoft.Diagnostics.Runtime.Utilities.Pdb.PdbSequencePoint point in sequenceCollection.Lines) { if (point.Offset <= ilOffset) { ulong dist = ilOffset - point.Offset; if (dist < distance) { sourceFileName = sequenceCollection.File.Name; sourceFileLine = point.LineBegin; distance = dist; } } } } return(Tuple.Create(sourceFileName, sourceFileLine, distance)); } else { return(Tuple.Create("", (uint)0, (ulong)0)); } }
/// <summary> /// Gets the source location of a given metadata token for a function and offset. /// </summary> /// <param name="method">The method to look up the source information.</param> /// <param name="ilOffset">The il offset to look up the source information.</param> /// <returns>The SourceLocation for the given IL offset, or null if no mapping exists.</returns> public abstract SourceLocation GetSourceInformation(ClrMethod method, int ilOffset);
public virtual SourceLocation GetSourceInformation(ClrMethod method, int ilOffset) { return null; }
public MethodInformation(ClrDumpType dumpType, ClrMethod clrMethod) { this.dumpType = dumpType; this.clrMethod = clrMethod; }
public DelegateTargetInformation(ulong address, ClrDumpType clrDumpType, ClrMethod methInfo) : this(address, clrDumpType) { this.methInfo = methInfo; }