public string DumpASM() { TextWriter asmWriter = new StringWriter(); using (DataTarget target = DataTarget.AttachToProcess(Process.GetCurrentProcess().Id, 5000, AttachFlag.Passive)) { foreach (ClrInfo clrInfo in target.ClrVersions) { this.engine.UpdateLog("Found CLR Version:" + clrInfo.Version.ToString()); // This is the data needed to request the dac from the symbol server: ModuleInfo dacInfo = clrInfo.DacInfo; this.engine.UpdateLog($"Filesize: {dacInfo.FileSize:X}"); this.engine.UpdateLog($"Timestamp: {dacInfo.TimeStamp:X}"); this.engine.UpdateLog($"Dac File: {dacInfo.FileName}"); ClrRuntime runtime = target.ClrVersions.Single().CreateRuntime(); var appDomain = runtime.AppDomains[0]; var module = appDomain.Modules.LastOrDefault(m => m.AssemblyName != null && m.AssemblyName.StartsWith(assemblyName)); asmWriter.WriteLine( $"; {clrInfo.ModuleInfo.ToString()} ({clrInfo.Flavor} {clrInfo.Version})"); asmWriter.WriteLine( $"; {clrInfo.DacInfo.FileName} ({clrInfo.DacInfo.TargetArchitecture} {clrInfo.DacInfo.Version})"); asmWriter.WriteLine(); foreach (var typeClr in module.EnumerateTypes()) { asmWriter.WriteLine($"; Type {typeClr.Name}"); ClrHeap heap = runtime.Heap; ClrType @object = heap.GetTypeByMethodTable(typeClr.MethodTable); foreach (ClrMethod method in @object.Methods) { MethodCompilationType compileType = method.CompilationType; ArchitectureMode mode = clrInfo.DacInfo.TargetArchitecture == Architecture.X86 ? ArchitectureMode.x86_32 : ArchitectureMode.x86_64; this.currentMethodAddress = 0; var translator = new IntelTranslator { SymbolResolver = (Instruction instruction, long addr, ref long offset) => ResolveSymbol(runtime, instruction, addr, ref currentMethodAddress) }; // This not work even ClrMd says opposite... //ulong startAddress = method.NativeCode; //ulong endAddress = method.ILOffsetMap.Select(entry => entry.EndAddress).Max(); DisassembleAndWrite(method, mode, translator, ref currentMethodAddress, asmWriter); this.engine.UpdateLog($"Method {method.Name} disassembled to ASM."); asmWriter.WriteLine(); } } break; } } return(asmWriter.ToString()); }
public string DumpASM() { TextWriter asmWriter = new StringWriter(); using (DataTarget target = DataTarget.AttachToProcess(Process.GetCurrentProcess().Id, 5000, AttachFlag.Passive)) { foreach (ClrInfo clrInfo in target.ClrVersions) { this.engine.UpdateLog("Found CLR Version:" + clrInfo.Version.ToString()); // This is the data needed to request the dac from the symbol server: ModuleInfo dacInfo = clrInfo.DacInfo; this.engine.UpdateLog($"Filesize: {dacInfo.FileSize:X}"); this.engine.UpdateLog($"Timestamp: {dacInfo.TimeStamp:X}"); this.engine.UpdateLog($"Dac File: {dacInfo.FileName}"); ClrRuntime runtime = target.ClrVersions.Single().CreateRuntime(); var appDomain = runtime.AppDomains[0]; var module = appDomain.Modules.LastOrDefault(m => m.AssemblyName != null && m.AssemblyName.StartsWith(assemblyName)); asmWriter.WriteLine( $"; {clrInfo.ModuleInfo.ToString()} ({clrInfo.Flavor} {clrInfo.Version})"); asmWriter.WriteLine( $"; {clrInfo.DacInfo.FileName} ({clrInfo.DacInfo.TargetArchitecture} {clrInfo.DacInfo.Version})"); asmWriter.WriteLine(); foreach (var typeClr in module.EnumerateTypes()) { // Note: Accroding to https://github.com/dotnet/coreclr/blob/master/src/vm/methodtable.h: // "(...) for value types GetBaseSize returns the size of instance fields for // a boxed value, and GetNumInstanceFieldsBytes for an unboxed value." // but mentioned method implementation is trivial: // inline DWORD MethodTable::GetNumInstanceFieldBytes() //{ // LIMITED_METHOD_DAC_CONTRACT; // return (GetBaseSize() - GetClass()->GetBaseSizePadding()); //} asmWriter.WriteLine($"; Type {typeClr.Name}"); asmWriter.WriteLine($"; MethodTable: 0x{typeClr.MethodTable:x16}"); asmWriter.WriteLine($"; Size: {typeClr.BaseSize}{(typeClr.IsValueClass ? string.Format(" (when boxed)") : string.Empty)}"); asmWriter.WriteLine($"; IsValueType: {typeClr.IsValueClass}"); asmWriter.WriteLine($"; IsArray: {typeClr.IsArray}"); asmWriter.WriteLine($"; IsEnum: {typeClr.IsEnum}"); asmWriter.WriteLine($"; IsPrimitive: {typeClr.IsPrivate}"); asmWriter.WriteLine("; Fields:"); asmWriter.WriteLine("; {0,6} {1,16} {2,20} {3,4}", "Offset", "Name", "Type", "Size"); var orderedFields = typeClr.Fields.ToList().OrderBy(x => x.Offset); foreach (var field in orderedFields) { asmWriter.WriteLine($"; {field.Offset,6} {field.Name,16} {field.Type.Name,20} {field.Size,4}"); } ClrHeap heap = runtime.Heap; foreach (ClrMethod method in typeClr.Methods) { MethodCompilationType compileType = method.CompilationType; ArchitectureMode mode = clrInfo.DacInfo.TargetArchitecture == Architecture.X86 ? ArchitectureMode.x86_32 : ArchitectureMode.x86_64; this.currentMethodAddress = 0; var translator = new IntelTranslator { SymbolResolver = (Instruction instruction, long addr, ref long offset) => ResolveSymbol(runtime, instruction, addr, ref currentMethodAddress) }; // This not work even ClrMd says opposite... //ulong startAddress = method.NativeCode; //ulong endAddress = method.ILOffsetMap.Select(entry => entry.EndAddress).Max(); DisassembleAndWrite(method, mode, translator, ref currentMethodAddress, asmWriter); this.engine.UpdateLog($"Method {method.Name} disassembled to ASM."); asmWriter.WriteLine(); } } break; } } return(asmWriter.ToString()); }