public CodeChunkInfo[] GetCodeChunks() { return(debugger.Dispatcher.UI(() => { var chunks = code.GetCodeChunks(); var res = new CodeChunkInfo[chunks.Length]; for (int i = 0; i < chunks.Length; i++) { res[i] = new CodeChunkInfo(chunks[i].StartAddr, chunks[i].Length); } return res; })); }
bool TryGetNativeCodeCore(CorCode code, DmdMethodBase reflectionMethod, out DbgDotNetNativeCode nativeCode) { nativeCode = default; if (code == null) { return(false); } var process = code.Function?.Module?.Process; if (process == null) { return(false); } // The returned chunks are sorted var chunks = code.GetCodeChunks(); if (chunks.Length == 0) { return(false); } int totalLen = 0; foreach (var chunk in chunks) { totalLen += (int)chunk.Length; } var allCodeBytes = new byte[totalLen]; int currentPos = 0; foreach (var chunk in chunks) { int hr = process.ReadMemory(chunk.StartAddr, allCodeBytes, currentPos, (int)chunk.Length, out int sizeRead); if (hr < 0 || sizeRead != (int)chunk.Length) { return(false); } currentPos += (int)chunk.Length; } Debug.Assert(currentPos == totalLen); // We must get IL to native mappings before we get var homes, or the var // homes array will be empty. var map = code.GetILToNativeMapping(); var varHomes = code.GetVariables(); Array.Sort(varHomes, (a, b) => { int c = a.StartOffset.CompareTo(b.StartOffset); if (c != 0) { return(c); } return(a.Length.CompareTo(b.Length)); }); for (int i = 0, chunkIndex = 0, chunkOffset = 0; i < varHomes.Length; i++) { var startOffset = varHomes[i].StartOffset; while (chunkIndex < chunks.Length) { if (startOffset < (uint)chunkOffset + chunks[chunkIndex].Length) { break; } chunkOffset += (int)chunks[chunkIndex].Length; chunkIndex++; } Debug.Assert(chunkIndex < chunks.Length); if (chunkIndex >= chunks.Length) { varHomes = Array.Empty <VariableHome>(); break; } varHomes[i].StartOffset += chunks[chunkIndex].StartAddr - (uint)chunkOffset; } Array.Sort(varHomes, (a, b) => { int c = a.SlotIndex.CompareTo(b.SlotIndex); if (c != 0) { return(c); } c = a.ArgumentIndex.CompareTo(b.ArgumentIndex); if (c != 0) { return(c); } c = a.StartOffset.CompareTo(b.StartOffset); if (c != 0) { return(c); } return(a.Length.CompareTo(b.Length)); }); Array.Sort(map, (a, b) => { int c = a.nativeStartOffset.CompareTo(b.nativeStartOffset); if (c != 0) { return(c); } return(a.nativeEndOffset.CompareTo(b.nativeEndOffset)); }); totalLen = 0; for (int i = 0; i < chunks.Length; i++) { chunks[i].StartAddr -= (uint)totalLen; totalLen += (int)chunks[i].Length; } var blocks = new DbgDotNetNativeCodeBlock[map.Length]; ulong baseAddress = chunks[0].StartAddr; uint chunkByteOffset = 0; for (int i = 0, chunkIndex = 0; i < blocks.Length; i++) { var info = map[i]; bool b = info.nativeEndOffset <= (uint)allCodeBytes.Length && info.nativeStartOffset <= info.nativeEndOffset && chunkIndex < chunks.Length; Debug.Assert(b); if (!b) { return(false); } int codeLen = (int)(info.nativeEndOffset - info.nativeStartOffset); var rawCode = new ArraySegment <byte>(allCodeBytes, (int)info.nativeStartOffset, codeLen); ulong address = baseAddress + info.nativeStartOffset; if ((CorDebugIlToNativeMappingTypes)info.ilOffset == CorDebugIlToNativeMappingTypes.NO_MAPPING) { blocks[i] = new DbgDotNetNativeCodeBlock(NativeCodeBlockKind.Unknown, address, rawCode, -1); } else if ((CorDebugIlToNativeMappingTypes)info.ilOffset == CorDebugIlToNativeMappingTypes.PROLOG) { blocks[i] = new DbgDotNetNativeCodeBlock(NativeCodeBlockKind.Prolog, address, rawCode, -1); } else if ((CorDebugIlToNativeMappingTypes)info.ilOffset == CorDebugIlToNativeMappingTypes.EPILOG) { blocks[i] = new DbgDotNetNativeCodeBlock(NativeCodeBlockKind.Epilog, address, rawCode, -1); } else { blocks[i] = new DbgDotNetNativeCodeBlock(NativeCodeBlockKind.Code, address, rawCode, (int)info.ilOffset); } chunkByteOffset += (uint)codeLen; for (;;) { if (chunkIndex >= chunks.Length) { if (i + 1 == blocks.Length) { break; } Debug.Assert(false); return(false); } if (chunkByteOffset < chunks[chunkIndex].Length) { break; } chunkByteOffset -= chunks[chunkIndex].Length; chunkIndex++; if (chunkIndex < chunks.Length) { baseAddress = chunks[chunkIndex].StartAddr; } } } NativeCodeOptimization optimization; switch (code.CompilerFlags) { case CorDebugJITCompilerFlags.CORDEBUG_JIT_DEFAULT: optimization = NativeCodeOptimization.Optimized; break; case CorDebugJITCompilerFlags.CORDEBUG_JIT_DISABLE_OPTIMIZATION: case CorDebugJITCompilerFlags.CORDEBUG_JIT_ENABLE_ENC: optimization = NativeCodeOptimization.Unoptimized; break; default: Debug.Fail($"Unknown optimization: {code.CompilerFlags}"); optimization = NativeCodeOptimization.Unknown; break; } NativeCodeInfo codeInfo = null; NativeCodeKind codeKind; switch (Runtime.Process.Machine) { case DbgMachine.X64: case DbgMachine.X86: codeKind = Runtime.Process.Machine == DbgMachine.X86 ? NativeCodeKind.X86_32 : NativeCodeKind.X86_64; var x86Variables = CreateVariablesX86(varHomes) ?? Array.Empty <X86Variable>(); if (x86Variables.Length != 0) { codeInfo = new X86NativeCodeInfo(x86Variables); } break; case DbgMachine.Arm: codeKind = NativeCodeKind.Arm; Debug.Fail("Create variables like x86/x64 code above"); break; case DbgMachine.Arm64: codeKind = NativeCodeKind.Arm64; Debug.Fail("Create variables like x86/x64 code above"); break; default: Debug.Fail($"Unsupported machine: {Runtime.Process.Machine}"); return(false); } var methodName = reflectionMethod?.ToString(); nativeCode = new DbgDotNetNativeCode(codeKind, optimization, blocks, codeInfo, methodName); return(true); }