public DebuggerCode(Debugger debugger, CorCode code) { debugger.Dispatcher.VerifyAccess(); this.debugger = debugger; CorCode = code; hashCode = code.GetHashCode(); address = code.Address; size = code.Size; isIL = code.IsIL; }
internal DnCodeBreakpoint(CorCode code, uint offset) { Module = GetModule(code); var func = code.Function; Token = func?.Token ?? 0; Offset = offset; this.code = code; }
internal DnCodeBreakpoint(SerializedDnModule module, uint token, uint offset) { this.module = module; this.token = token; this.offset = offset; this.code = null; }
internal DnCodeBreakpoint(CorCode code, uint offset) { this.module = GetModule(code); var func = code.Function; this.token = func == null ? 0 : func.Token; this.offset = offset; this.code = code; }
/// <summary> /// Function tries to bind a breakpoint to the specified module. /// </summary> /// <param name="managedModule">A module the breakpoint should be bound to.</param> /// <returns>true if breakpoint was successfully bound or false if it failed or was already bound.</returns> /// <remarks> /// This function is called by breakpoint manager for every brekapoint whenever a new module /// gets loaded into the debugged process or whenever a dynamic module loads a new class /// or new symbols. This adds any missing bindings, but will not duplicate any that already exist. /// </remarks> public sealed override bool BindToModule(MDbgModule managedModule) { List <MDbgFunction> funcs; int ILoffset; // If we already bound a breakpoint in this module then nothing to do if (m_breakpoints != null && m_breakpoints.ContainsKey(managedModule)) { return(false); } // If we can't resolve the location in this module then there is nothing to do if (!m_location.ResolveLocation(this, managedModule, out funcs, out ILoffset)) { return(false); } // Use the resolved information to get a raw CorBreakpoint object. CorFunctionBreakpoint breakpoint = null; try { if (ILoffset == 0) { foreach (var func in funcs) { breakpoint = func.CorFunction.CreateBreakpoint(); SetupBreakpoint(breakpoint, managedModule); } } else { foreach (var func in funcs) { // we need to set a breakpoint on code rather than directly on function CorCode code = func.CorFunction.ILCode; if (code == null) { throw new MDbgException(String.Format(CultureInfo.InvariantCulture, "IL Code for function {0} is null", new Object[] { func.FullName })); } breakpoint = code.CreateBreakpoint(ILoffset); SetupBreakpoint(breakpoint, managedModule); } } } catch (NotImplementedException) { return(false); } catch (COMException) { return(false); } return(true); }
public DebuggerCode(Debugger debugger, CorCode code) { debugger.Dispatcher.VerifyAccess(); this.debugger = debugger; this.code = code; this.hashCode = code.GetHashCode(); this.address = code.Address; this.size = code.Size; this.isIL = code.IsIL; }
public ILVirtualDocument(MDbgFunction mdbgFunction) { CorCode ilCode = mdbgFunction.CorFunction.ILCode; Debug.Assert(true == ilCode.IsIL); byte[] code = ilCode.GetCode(); ILDisassembler.Disassemble(code, mdbgFunction.Module.Importer, out m_lines, out ip2lineMapping); Debug.Assert(m_lines != null && ip2lineMapping != null); m_functionName = mdbgFunction.FullName; }
static void ProcessCommand(CorProcess process) { Task.Run(() => { while (true) { Console.Write("> "); String command = Console.ReadLine(); if (command.StartsWith("set-break", StringComparison.Ordinal)) { // setting breakpoint command = command.Remove(0, "set-break".Length).Trim(); // try module!type.method location (simple regex used) Match match = methodBreakpointRegex.Match(command); if (match.Groups["method"].Length > 0) { Console.Write("Setting method breakpoint... "); CorFunction func = process.ResolveFunctionName(match.Groups["module"].Value, match.Groups["class"].Value, match.Groups["method"].Value); func.CreateBreakpoint().Activate(true); Console.WriteLine("done."); continue; } // try file code:line location match = codeBreakpointRegex.Match(command); if (match.Groups["filepath"].Length > 0) { Console.Write("Setting code breakpoint..."); int offset; CorCode code = process.ResolveCodeLocation(match.Groups["filepath"].Value, Int32.Parse(match.Groups["linenum"].Value), out offset); code.CreateBreakpoint(offset).Activate(true); Console.WriteLine("done."); continue; } } else if (command.StartsWith("go", StringComparison.Ordinal)) { process.Continue(false); ProcessCommand(process); break; } } }); }
/// <summary> /// Creates a native instruction breakpoint /// </summary> /// <param name="code">Native code</param> /// <param name="offset">Offset</param> /// <param name="cond">Condition</param> /// <returns></returns> public DnNativeCodeBreakpoint CreateNativeBreakpoint(CorCode code, uint offset, Func<NativeCodeBreakpointConditionContext, bool> cond) { DebugVerifyThread(); var bp = new DnNativeCodeBreakpoint(code, offset, cond); var module = code.Function?.Module?.DnModuleId ?? new DnModuleId(); nativeCodeBreakpointList.Add(module, bp); foreach (var dnMod in GetLoadedDnModules(module)) bp.AddBreakpoint(dnMod); return bp; }
/// <summary> /// Function tries to bind a breakpoint to the specified module. /// </summary> /// <param name="managedModule">A module the breakpoint should be bound to.</param> /// <returns>true if breakpoint was successfully bound or false if it failed or was already bound.</returns> /// <remarks> /// This function is called by breakpoint manager for every brekapoint whenever a new module /// gets loaded into the debugged process or whenever a dynamic module loads a new class /// or new symbols. This adds any missing bindings, but will not duplicate any that already exist. /// </remarks> public sealed override bool BindToModule(MDbgModule managedModule) { MDbgFunction func; int ILoffset; // If we already bound a breakpoint in this module then nothing to do if (m_breakpoints != null && m_breakpoints.ContainsKey(managedModule)) { return(false); } // If we can't resolve the location in this module then there is nothing to do if (!m_location.ResolveLocation(this, managedModule, out func, out ILoffset)) { return(false); } // Use the resolved information to get a raw CorBreakpoint object. CorFunctionBreakpoint breakpoint = null; try { if (ILoffset == 0) { breakpoint = func.CorFunction.CreateBreakpoint(); } else { // we need to set a breakpoint on code rather than directly on function CorCode code = func.CorFunction.ILCode; if (code == null) { throw new MDbgException(String.Format(CultureInfo.InvariantCulture, "IL Code for function {0} is null", new Object[] { func.FullName })); } breakpoint = code.CreateBreakpoint(ILoffset); } } catch (NotImplementedException) { return(false); } catch (COMException) { return(false); } // Add the new CorBreakpoint object to our internal list and register a handler for it. Debug.Assert(breakpoint != null); breakpoint.Activate(true); if (m_breakpoints == null) { m_breakpoints = new Dictionary <MDbgModule, CorFunctionBreakpoint>(); } m_breakpoints.Add(managedModule, breakpoint); MDbgProcess p = managedModule.Process; CustomBreakpointEventHandler handler = new CustomBreakpointEventHandler(this.InternalOnHitHandler); p.RegisterCustomBreakpoint(breakpoint, handler); return(true); }
public override DbgCodeLocation Clone() => owner.Create(DbgModule, Module, Token, Offset, ILOffsetMapping, NativeAddress.Address, NativeAddress.Offset, CorCode.AddRef());
internal DnCodeBreakpoint(DnModuleId module, uint token, uint offset) { Module = module; Token = token; Offset = offset; code = null; }
internal DnNativeCodeBreakpoint CreateNativeBreakpointForGetReturnValue(CorCode code, uint offset, Action <CorThread> callback) { debuggerThread.VerifyAccess(); return(dnDebugger.CreateNativeBreakpoint(code, offset, ctx => { callback(ctx.E.CorThread); return false; })); }
/// <summary> /// Function tries to bind a breakpoint to the specified module. /// </summary> /// <param name="managedModule">A module the breakpoint should be bound to.</param> /// <returns>true if breakpoint was successfully bound or false if it failed or was already bound.</returns> /// <remarks> /// This function is called by breakpoint manager for every brekapoint whenever a new module /// gets loaded into the debugged process or whenever a dynamic module loads a new class /// or new symbols. This adds any missing bindings, but will not duplicate any that already exist. /// </remarks> public sealed override bool BindToModule(MDbgModule managedModule) { MDbgFunction func; int ILoffset; // Note that in some cases (eg. source/line breakpoints) we may actually // want to bind to multiple locations in this module instead of just one. if (!m_location.ResolveLocation(this, managedModule, out func, out ILoffset)) { return(false); } if (m_breakpoints != null) { // Assume all breakpoints are CorFunctionBreakpoints. // If this ever becomes invalid, we'll need a new check here to avoid // duplicating that type of breakpoint. foreach (CorFunctionBreakpoint cb in m_breakpoints) { // If we find a CorBreakpoint that already matches this location // don't add a new one, or the debugger will stop twice when it's hit. // Note that CorFunction instances are 1:1 with a specific function in a // specific module and AppDomain (but represents all generic instantiations). if (cb.Function == func.CorFunction && cb.Offset == ILoffset) { return(false); } } } // Use the resolved information to get a raw CorBreakpoint object. CorBreakpoint breakpoint = null; try { if (ILoffset == 0) { breakpoint = func.CorFunction.CreateBreakpoint(); } else { // we need to set a breakpoint on code rather than directly on function CorCode code = func.CorFunction.ILCode; if (code == null) { throw new MDbgException(String.Format(CultureInfo.InvariantCulture, "IL Code for function {0} is null", new Object[] { func.FullName })); } breakpoint = code.CreateBreakpoint(ILoffset); } } catch (COMException) { return(false); } // Add the new CorBreakpoint object to our internal list and register a handler for it. Debug.Assert(breakpoint != null); breakpoint.Activate(true); if (m_breakpoints == null) { m_breakpoints = new ArrayList(); } m_breakpoints.Add(breakpoint); MDbgProcess p = managedModule.Process; CustomBreakpointEventHandler handler = new CustomBreakpointEventHandler(this.InternalOnHitHandler); p.RegisterCustomBreakpoint(breakpoint, handler); return(true); }
public static void ILDasmCmd(string args) { // Provides disassembly of IL opcodes. ArgParser ap = new ArgParser(args); if (ap.Count > 1) { WriteError("Wrong # of arguments."); return; } MDbgFrame functionFrame = null; MDbgFunction function = null; if (ap.Exists(0)) { function = Debugger.Processes.Active.ResolveFunctionNameFromScope(ap.AsString(0)); if (function == null) { throw new MDbgShellException("no such function."); } } else { functionFrame = Debugger.Processes.Active.Threads.Active.CurrentFrame; function = functionFrame.Function; } CorCode ilCode = function.CorFunction.ILCode; //CorMetadataImport importer = functionFrame.Function.Module.Importer; Debug.Assert(true == ilCode.IsIL); WriteOutput("code size: " + ilCode.Size); ILVirtualDocument doc = new ILVirtualDocument(function); int currentLine; if (functionFrame != null) { // we have frame and therefore we should show current location uint ip; CorDebugMappingResult mappingResult; functionFrame.CorFrame.GetIP(out ip, out mappingResult); WriteOutput("current IL-IP: " + ip); WriteOutput("mapping: " + mappingResult.ToString()); WriteOutput("URL: " + doc.Path); currentLine = doc.Ip2LineNo((int)ip); } else { // no current IP. currentLine = -1; } for (int i = 0; i < doc.Count; i++) { if (i == currentLine) { WriteOutput("* " + doc[i]); } else { WriteOutput(" " + doc[i]); } } }
internal DnNativeCodeBreakpoint(CorCode code, uint offset, Func<NativeCodeBreakpointConditionContext, bool> cond) : base(code, offset) { Condition = cond ?? defaultCond; }
static DnModuleId GetModule(CorCode code) => code.Function?.Module?.DnModuleId ?? new DnModuleId();
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); }
internal VirtualSourceViewerForm(MainForm parent, MDbgFunction function) { m_function = function; Debug.Assert(function != null); // Now actually right in text. do this first so that we can get the current font. BeginInit(parent); // Get fonts FontCache cache; { Font fontCurrent = richText.Font; var emphasis = new Font( fontCurrent.FontFamily, fontCurrent.Size, FontStyle.Bold ); cache = new FontCache(emphasis); } // Underlying writer to the window. var rawWriter = new RawWriter(cache); // Il2Native mapping can be used to find out what IL offsets we can actually stop on. Il2NativeIterator il2nativeIterator = null; // Actual IL disassembly in string form. ILDasmIterator ilDasm = null; // Iterator through sequence points and source files. SequencePointIterator seqIterator = null; string fullName = "?"; int token = 0; ulong nativeStartAddress = 0; CorDebugJITCompilerFlags codeFlags = CorDebugJITCompilerFlags.CORDEBUG_JIT_DEFAULT; // Make cross-thread call to worker thread to collect raw information. // This needs to access MDbg and so can't be done on our UI thread. parent.ExecuteOnWorkerThreadIfStoppedAndBlock(delegate(MDbgProcess proc) { Debug.Assert(proc != null); Debug.Assert(!proc.IsRunning); Debug.Assert(function.Module.Process == proc); // Get some properties about this function to display. token = function.CorFunction.Token; nativeStartAddress = function.CorFunction.NativeCode.Address; codeFlags = function.CorFunction.NativeCode.CompilerFlags; CorCode ilCode = function.CorFunction.ILCode; Debug.Assert(ilCode.IsIL); byte[] code = ilCode.GetCode(); fullName = function.FullName; // This does the real disassembly work. string[] lines = null; // strings of IL. ILDisassembler.Disassemble(code, function.Module.Importer, out lines, out m_il2RowMapping); ilDasm = new ILDasmIterator(rawWriter, m_il2RowMapping, lines); IL2NativeMap[] il2nativeMapping = function.CorFunction.NativeCode. GetILToNativeMapping(); il2nativeIterator = new Il2NativeIterator(rawWriter, il2nativeMapping, code); // Get sequence points ISymbolMethod symMethod = function.SymMethod; // Sequence point information int[] seqIlOffsets = null; string[] seqPaths = null; int[] seqStartLines = null, seqEndLines = null, seqStartColumns = null, seqEndColumns = null; int seqCount = 0; if (symMethod != null) { seqCount = symMethod.SequencePointCount; seqIlOffsets = new int[seqCount]; var seqDocuments = new ISymbolDocument[seqCount]; seqPaths = new string[seqCount]; seqStartLines = new int[seqCount]; seqEndLines = new int[seqCount]; seqStartColumns = new int[seqCount]; seqEndColumns = new int[seqCount]; symMethod.GetSequencePoints(seqIlOffsets, seqDocuments, seqStartLines, seqStartColumns, seqEndLines, seqEndColumns); for (int i = 0; i < seqCount; i++) { seqPaths[i] = seqDocuments[i].URL; } } seqIterator = new SequencePointIterator(rawWriter, parent, seqIlOffsets, seqPaths, seqStartLines, seqStartColumns, seqEndLines, seqEndColumns); } ); // end worker call // We assume sequence points are sorted by IL offset. We assert that in the iterators below. // Now we need to go through and stitch the IL + Source together. // This also works even if we have no source (since that's just the degenerate case of 0 sequence points) // Print out header information Debug.Assert(token != 0); rawWriter.WriteLine(String.Format(CultureInfo.InvariantCulture, "> Function name:{0} (token={1:x})", fullName, token)); rawWriter.WriteLine(String.Format(CultureInfo.InvariantCulture, "> Native Code Address =0x{0:x}, flags={1}", nativeStartAddress, codeFlags)); // Walk through the IL in order and write out interleaved IL and Sequence Points. while (!seqIterator.IsDone) { // Add IL snippets that occur before this sequence point. WriteIlAndNative(ilDasm, il2nativeIterator, seqIterator.IlOffset); seqIterator.WriteSource(); seqIterator.Next(); } // Write the IL that's after the last sequence point WriteIlAndNative(ilDasm, il2nativeIterator, ilDasm.IlLength); // Set the text. InitLines(null, rawWriter.Lines, rawWriter.FormatList); EndInit(fullName); }
protected override void CloseCore(DbgDispatcher dispatcher) => CorCode.Close();
static SerializedDnModule GetModule(CorCode code) { var func = code.Function; uint token = func == null ? 0 : func.Token; var mod = func == null ? null : func.Module; return mod == null ? new SerializedDnModule() : mod.SerializedDnModule; }