private void AddToCache(int functionToken, int version, MDbgFunction mdbgFunction) { Debug.Assert(mdbgFunction != null); Debug.Assert(functionToken == mdbgFunction.CorFunction.Token); Debug.Assert(version == mdbgFunction.CorFunction.Version); if (m_functions.Contains(functionToken)) { // we already have some versions need to convert to array ArrayList al = new ArrayList(); Object data = m_functions[functionToken]; if (data is MDbgFunction) { al.Add(data); } else { // data is array foreach (MDbgFunction f in (data as Array)) { al.Add(f); } } // now we add at the end newly added function al.Add(mdbgFunction); m_functions.Remove(functionToken); m_functions.Add(functionToken, al.ToArray(typeof(MDbgFunction))); } else { m_functions.Add(functionToken, mdbgFunction); } }
/// <summary> /// Creates a default 'source level step' on process with current active frame and active thread. /// </summary> /// <param name="process">non-null process </param> /// <param name="type">type of step (in, out, over)</param> /// <param name="singleStepInstructions">false to step source level, true to step single instructions</param> /// <returns></returns> public static StepperDescriptor CreateSourceLevelStep(MDbgProcess process, StepperType type, bool singleStepInstructions) { StepperDescriptor s = new StepperDescriptor(process); s.StepperType = type; // // Handle Step-out case. // if (type == StepperType.Out) { return(s); } // // Handle step-over / step-in case // bool stepInto = (type == StepperType.In); // Cache current s.Thread = process.Threads.Active.CorThread; s.Frame = s.Thread.ActiveFrame; CorDebugMappingResult mappingResult; uint ip; if (!singleStepInstructions) { // For source-level stepping, skip some interceptors. These are random, and cause // random differences in stepping across different runtimes; and user generally don't care // about interceptors. // It's actually a debatable policy about which interceptors to skip and stop on. s.InterceptMask = CorDebugIntercept.INTERCEPT_ALL & ~(CorDebugIntercept.INTERCEPT_SECURITY | CorDebugIntercept.INTERCEPT_CLASS_INIT); } s.Frame.GetIP(out ip, out mappingResult); if (singleStepInstructions || (mappingResult != CorDebugMappingResult.MAPPING_EXACT && mappingResult != CorDebugMappingResult.MAPPING_APPROXIMATE)) { // Leave step ranges null } else { // Getting the step ranges is what really makes this a source-level step. MDbgFunction f = process.Modules.LookupFunction(s.Frame.Function); COR_DEBUG_STEP_RANGE[] sr = f.GetStepRangesFromIP((int)ip); if (sr != null) { s.SetStepRanges(sr, true); } else { // Leave step ranges null. } } return(s); }
public MDbgFunction Get(CorFunction managedFunction) { int funcVersion; funcVersion = managedFunction.Version; // now get version from our cache. MDbgFunction mdbgFunction = RetrieveFromCache(managedFunction.Token, funcVersion); if (mdbgFunction == null) { mdbgFunction = new MDbgFunction(m_module, managedFunction); AddToCache(managedFunction.Token, funcVersion, mdbgFunction); } return mdbgFunction; }
public MDbgFunction Get(CorFunction managedFunction) { int funcVersion; funcVersion = managedFunction.Version; // now get version from our cache. MDbgFunction mdbgFunction = RetrieveFromCache(managedFunction.Token, funcVersion); if (mdbgFunction == null) { mdbgFunction = new MDbgFunction(m_module, managedFunction); AddToCache(managedFunction.Token, funcVersion, mdbgFunction); } return(mdbgFunction); }
// Dispose all functions in our collection and then empty the collection. public void Dispose() { foreach (object o in m_functions.Values) { // items may be either a function, or an array of functions. MDbgFunction f1 = o as MDbgFunction; if (f1 != null) { f1.Dispose(); } else { MDbgFunction[] a = (MDbgFunction[])o; foreach (MDbgFunction f in a) { f.Dispose(); } } } Clear(); }
private void AddToCache(int functionToken, int version, MDbgFunction mdbgFunction) { Debug.Assert(mdbgFunction != null); Debug.Assert(functionToken == mdbgFunction.CorFunction.Token); Debug.Assert(version == mdbgFunction.CorFunction.Version); if (m_functions.Contains(functionToken)) { // we already have some versions need to convert to array ArrayList al = new ArrayList(); Object data = m_functions[functionToken]; if (data is MDbgFunction) { al.Add(data); } else { // data is array foreach (MDbgFunction f in (data as Array)) al.Add(f); } // now we add at the end newly added function al.Add(mdbgFunction); m_functions.Remove(functionToken); m_functions.Add(functionToken, al.ToArray(typeof(MDbgFunction))); } else { m_functions.Add(functionToken, mdbgFunction); } }
// this is called on the UI thread. bool OpenSourceFile(MDbgFunction function) { // Update source viewer SourceViewerBaseForm f = SourceViewerBaseForm.GetSourceFile(this, function); return ShowSourceFile(f); }
// There's one SourceViewerForm instance for each source-file // Get the instance for the new source file. // Called on UI thread. public static SourceViewerBaseForm GetSourceFile(MainForm parent, MDbgFunction function) { SourceViewerBaseForm source = (SourceViewerBaseForm)m_sourceList[function]; if (source == null) { source = new VirtualSourceViewerForm(parent, function); AddSourceViewer(source); } m_ActiveSourceFile = source; return source; }
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; }
/// <summary> /// Creates a breakpoint in the debugged program based on managed Function /// and IL offset within the method. /// </summary> /// <param name="managedFunction">object representing loaded managed function.</param> /// <param name="offset">IL offset from the beginning of the function. /// Offset 0 menas start of the function.</param> /// <returns>created breakpoint.</returns> /// <remarks> /// Since this method takes MDbgFunction object, breakpoints can be only created on code that has /// been loaded into the debugged application. /// </remarks> public MDbgBreakpoint CreateBreakpoint(MDbgFunction managedFunction, int offset) { return new MDbgFunctionBreakpoint(this, new BreakpointFunctionToken(managedFunction, offset)); }
/// <summary> /// Function tries to resolve the breakpoint from breakpoint description. /// </summary> /// <param name="functionBreakpoint">A breakpoint object.</param> /// <param name="managedModule">A module that the breakpoint should be resolved at.</param> /// <param name="managedFunction">A function that is resolved from the breakpoint description.</param> /// <param name="ilOffset">An il offset within a function resolved from the breakpoint description.</param> /// <returns>true if breakpoint was successfully resolved</returns> /// <remarks> /// Resolved is usually called for every loaded module. /// </remarks> public bool ResolveLocation(MDbgFunctionBreakpoint functionBreakpoint, MDbgModule managedModule, out MDbgFunction managedFunction, out int ilOffset) { managedFunction = null; ilOffset = -1; // check if the function is from the module we specified. if (m_function.Module != managedModule) return false; managedFunction = m_function; ilOffset = m_ILoffset; return true; }
/// <summary> /// Function tries to resolve the breakpoint from breakpoint description. /// </summary> /// <param name="functionBreakpoint">A breakpoint object.</param> /// <param name="managedModule">A module that the breakpoint should be resolved at.</param> /// <param name="managedFunction">A function that is resolved from the breakpoint description.</param> /// <param name="ILoffset">An il offset within a function resolved from the breakpoint description.</param> /// <returns>true if breakpoint was successfully resolved</returns> /// <remarks> /// Resolved is usually called for every loaded module. /// </remarks> public bool ResolveLocation(MDbgFunctionBreakpoint functionBreakpoint, MDbgModule managedModule, out MDbgFunction managedFunction, out int ILoffset) { Debug.Assert(m_lineNo > 0 && m_file.Length > 0); managedFunction = null; ILoffset = 0; if (managedModule.SymReader == null) { // no symbols for current module, skip it. return(false); } foreach (ISymbolDocument doc in managedModule.SymReader.GetDocuments()) { if (String.Compare(doc.URL, m_file, true, CultureInfo.InvariantCulture) == 0 || String.Compare(System.IO.Path.GetFileName(doc.URL), m_file, true, CultureInfo.InvariantCulture) == 0) { int lineNo = 0; try { lineNo = doc.FindClosestLine(m_lineNo); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode == (int)HResult.E_FAIL) { // we continue, because this location is not in this file, let's // keep trying to search for next file. continue; } } ISymbolMethod symMethod = managedModule.SymReader.GetMethodFromDocumentPosition(doc, lineNo, 0); managedFunction = managedModule.GetFunction(symMethod.Token.GetToken()); ILoffset = managedFunction.GetIPFromPosition(doc, lineNo); // If this IL if (ILoffset == -1) { return(false); } Debug.Assert(ILoffset != -1); return(true); } } managedFunction = null; ILoffset = -1; return(false); }
/// <summary> /// Creates a breakpoint in the debugged program based on managed Function /// and IL offset within the method. /// </summary> /// <param name="managedFunction">object representing loaded managed function.</param> /// <param name="offset">IL offset from the beginning of the function. /// Offset 0 menas start of the function.</param> /// <returns>created breakpoint.</returns> /// <remarks> /// Since this method takes MDbgFunction object, breakpoints can be only created on code that has /// been loaded into the debugged application. /// </remarks> public MDbgBreakpoint CreateBreakpoint(MDbgFunction managedFunction, int offset) { return(new MDbgFunctionBreakpoint(this, new BreakpointFunctionToken(managedFunction, offset))); }
private string PrintObject(int indentLevel, CorObjectValue ov, int expandDepth, bool canDoFunceval) { Debug.Assert(expandDepth >= 0); bool fNeedToResumeThreads = true; // Print generics-aware type. string name = InternalUtil.PrintCorType(this.m_process, ov.ExactType); StringBuilder txt = new StringBuilder(); txt.Append(name); if (expandDepth > 0) { // we gather the field info of the class before we do // funceval since funceval requires running the debugger process // and this in turn can cause GC and invalidate our references. StringBuilder expandedDescription = new StringBuilder(); if (IsComplexType) { foreach (MDbgValue v in GetFields()) { expandedDescription.Append("\n").Append(IndentedString(indentLevel + 1, v.Name)). Append("=").Append(IndentedBlock(indentLevel + 2, v.GetStringValue(expandDepth - 1, false))); } } // if the value we're printing is a nullable type that has no value (is null), we can't do a func eval // to get its value, since it will be boxed as a null pointer. We already have the information we need, so // we'll just take care of it now. Note that ToString() for null-valued nullable types just prints the // empty string. // bool hasValue = (bool)(GetField("hasValue").CorValue.CastToGenericValue().GetValue()); if (IsNullableType(ov.ExactType) && !(bool)(GetField("hasValue").CorValue.CastToGenericValue().GetValue())) { txt.Append(" < >"); } else if (ov.IsValueClass && canDoFunceval) // we could display even values for real Objects, but we will just show // "description" for valueclasses. { CorClass cls = ov.ExactType.Class; CorMetadataImport importer = m_process.Modules.Lookup(cls.Module).Importer; MetadataType mdType = importer.GetType(cls.Token) as MetadataType; if (mdType.ReallyIsEnum) { txt.AppendFormat(" <{0}>", InternalGetEnumString(ov, mdType)); } else if (m_process.IsRunning) { txt.Append(" <N/A during run>"); } else { MDbgThread activeThread = m_process.Threads.Active; CorValue thisValue; CorHeapValue hv = ov.CastToHeapValue(); if (hv != null) { // we need to pass reference value. CorHandleValue handle = hv.CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION); thisValue = handle; } else { thisValue = ov; } try { CorEval eval = m_process.Threads.Active.CorThread.CreateEval(); m_process.CorProcess.SetAllThreadsDebugState(CorDebugThreadState.THREAD_SUSPEND, activeThread.CorThread); MDbgFunction toStringFunc = m_process.ResolveFunctionName(null, "System.Object", "ToString", thisValue.ExactType.Class.Module.Assembly.AppDomain)[0]; Debug.Assert(toStringFunc != null); // we should be always able to resolve ToString function. eval.CallFunction(toStringFunc.CorFunction, new CorValue[] { thisValue }); m_process.Go(); do { m_process.StopEvent.WaitOne(); if (m_process.StopReason is EvalCompleteStopReason) { CorValue cv = eval.Result; Debug.Assert(cv != null); MDbgValue mv = new MDbgValue(m_process, cv); string valName = mv.GetStringValue(0); // just purely for esthetical reasons we 'discard' " if (valName.StartsWith("\"") && valName.EndsWith("\"")) { valName = valName.Substring(1, valName.Length - 2); } txt.Append(" <").Append(valName).Append(">"); break; } if ((m_process.StopReason is ProcessExitedStopReason) || (m_process.StopReason is EvalExceptionStopReason)) { txt.Append(" <N/A cannot evaluate>"); break; } // hitting bp or whatever should not matter -- we need to ignore it m_process.Go(); }while (true); } catch (COMException e) { // Ignore cannot copy a VC class error - Can't copy a VC with object refs in it. if (e.ErrorCode != (int)HResult.CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS) { throw; } } catch (System.NotImplementedException) { fNeedToResumeThreads = false; } finally { if (fNeedToResumeThreads) { // we need to resume all the threads that we have suspended no matter what. m_process.CorProcess.SetAllThreadsDebugState(CorDebugThreadState.THREAD_RUN, activeThread.CorThread); } } } } txt.Append(expandedDescription.ToString()); } return(txt.ToString()); }
/// <summary> /// Function tries to resolve the breakpoint from breakpoint description. /// </summary> /// <param name="functionBreakpoint">A breakpoint object.</param> /// <param name="managedModule">A module that the breakpoint should be resolved at.</param> /// <param name="managedFunction">A function that is resolved from the breakpoint description.</param> /// <param name="ilOffset">An il offset within a function resolved from the breakpoint description.</param> /// <returns>true if breakpoint was successfully resolved</returns> /// <remarks> /// Resolved is usually called for every loaded module. /// </remarks> public bool ResolveLocation(MDbgFunctionBreakpoint functionBreakpoint, MDbgModule managedModule, out MDbgFunction managedFunction, out int ilOffset) { managedFunction = null; ilOffset = m_ILoffset; if (m_moduleName != null && m_moduleName.Length > 0) { if (!managedModule.MatchesModuleName(m_moduleName)) return false; } managedFunction = functionBreakpoint.m_breakpointCollection.m_process.ResolveFunctionName(managedModule, m_className, m_methodName); return managedFunction != null; }
/// <summary> /// Function tries to resolve the breakpoint from breakpoint description. /// </summary> /// <param name="functionBreakpoint">A breakpoint object.</param> /// <param name="managedModule">A module that the breakpoint should be resolved at.</param> /// <param name="managedFunction">A function that is resolved from the breakpoint description.</param> /// <param name="ilOffset">An il offset within a function resolved from the breakpoint description.</param> /// <returns>true if breakpoint was successfully resolved</returns> /// <remarks> /// Resolved is usually called for every loaded module. /// </remarks> public bool ResolveLocation(MDbgFunctionBreakpoint functionBreakpoint, MDbgModule managedModule, out MDbgFunction managedFunction, out int ilOffset) { managedFunction = null; ilOffset = m_ILoffset; if (m_moduleName != null && m_moduleName.Length > 0) { if (!managedModule.MatchesModuleName(m_moduleName)) { return(false); } } managedFunction = functionBreakpoint.m_breakpointCollection.m_process.ResolveFunctionName(managedModule, m_className, m_methodName); return(managedFunction != null); }
/// <summary> /// Constructs new BreakpointFunctionToken object. /// </summary> /// <param name="managedFunction">A function breakpoint is created at.</param> /// <param name="ilOffset">An il offset within a method description.</param> public BreakpointFunctionToken(MDbgFunction managedFunction, int ilOffset) { Debug.Assert(managedFunction != null); m_function = managedFunction; m_ILoffset = ilOffset; }
/// <summary> /// Function tries to resolve the breakpoint from breakpoint description. /// </summary> /// <param name="functionBreakpoint">A breakpoint object.</param> /// <param name="managedModule">A module that the breakpoint should be resolved at.</param> /// <param name="managedFunction">A function that is resolved from the breakpoint description.</param> /// <param name="ILoffset">An il offset within a function resolved from the breakpoint description.</param> /// <returns>true if breakpoint was successfully resolved</returns> /// <remarks> /// Resolved is usually called for every loaded module. /// </remarks> public bool ResolveLocation(MDbgFunctionBreakpoint functionBreakpoint, MDbgModule managedModule, out MDbgFunction managedFunction, out int ILoffset) { Debug.Assert(m_lineNo > 0 && m_file.Length > 0); managedFunction = null; ILoffset = 0; if (managedModule.SymReader == null) // no symbols for current module, skip it. return false; foreach (ISymbolDocument doc in managedModule.SymReader.GetDocuments()) { if (String.Compare(doc.URL, m_file, true, CultureInfo.InvariantCulture) == 0 || String.Compare(System.IO.Path.GetFileName(doc.URL), m_file, true, CultureInfo.InvariantCulture) == 0) { int lineNo = 0; try { lineNo = doc.FindClosestLine(m_lineNo); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode == (int)HResult.E_FAIL) // we continue, because this location is not in this file, let's // keep trying to search for next file. continue; } ISymbolMethod symMethod = managedModule.SymReader.GetMethodFromDocumentPosition(doc, lineNo, 0); managedFunction = managedModule.GetFunction(symMethod.Token.GetToken()); ILoffset = managedFunction.GetIPFromPosition(doc, lineNo); // If this IL if (ILoffset == -1) { return false; } Debug.Assert(ILoffset != -1); return true; } } managedFunction = null; ILoffset = -1; return false; }
/// <summary> /// Function tries to resolve the breakpoint from breakpoint description. /// </summary> /// <param name="functionBreakpoint">A breakpoint object.</param> /// <param name="managedModule">A module that the breakpoint should be resolved at.</param> /// <param name="managedFunction">A function that is resolved from the breakpoint description.</param> /// <param name="ilOffset">An il offset within a function resolved from the breakpoint description.</param> /// <returns>true if breakpoint was successfully resolved</returns> /// <remarks> /// Resolved is usually called for every loaded module. /// </remarks> public bool ResolveLocation(MDbgFunctionBreakpoint functionBreakpoint, MDbgModule managedModule, out MDbgFunction managedFunction, out int ilOffset) { managedFunction = null; ilOffset = -1; // check if the function is from the module we specified. if (m_function.Module != managedModule) { return(false); } managedFunction = m_function; ilOffset = m_ILoffset; return(true); }
// parent - main containing window that this source window lives inside of. // function - function for which we're building virtual source around. // Get the IL from the given frame. // Called on UI thread. 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 = this.richText.Font; Font emphasis = new Font( fontCurrent.FontFamily, fontCurrent.Size, FontStyle.Bold ); cache = new FontCache(emphasis); } // Underlying writer to the window. RawWriter 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(true == 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]; ISymbolDocument[] 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); }
internal UserEntryBreakpoint(MDbgProcess p, MDbgFunction mfunc) : base(null, new BreakpointFunctionToken(mfunc, 0)) { m_process = p; }