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
                var 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);
            }
        }
Beispiel #2
0
        /// <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(Path.GetFileName(doc.URL), m_file, true, CultureInfo.InvariantCulture) == 0)
                {
                    int lineNo = 0;
                    try
                    {
                        lineNo = doc.FindClosestLine(m_lineNo);
                    }
                    catch (COMException e)
                    {
                        if (e.ErrorCode == (int)CorDebug.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);
        }
Beispiel #3
0
        public MDbgFunction Get(CorDebug.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(CorDebug.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);
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        /// <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)
        {
            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(Path.GetFileName(doc.URL), m_file, true, CultureInfo.InvariantCulture) == 0)
                {
                    int lineNo = 0;
                    try
                    {
                        lineNo = doc.FindClosestLine(m_lineNo);
                    }
                    catch (COMException e)
                    {
                        if (e.ErrorCode == (int) CorDebug.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));
 }
Beispiel #9
0
        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
                var 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);
            }
        }
        private string PrintObject(int indentLevel, CorDebug.CorObjectValue ov, int expandDepth, bool canDoFunceval)
        {
            Debug.Assert(expandDepth >= 0);

            // Print generics-aware type.
            string name = InternalUtil.PrintCorType(m_process, ov.ExactType);

            var 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.
                var 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 (ov.IsValueClass && canDoFunceval)
                // we could display even values for real Objects, but we will just show
                // "description" for valueclasses.
                {
                    CorDebug.CorClass cls      = ov.ExactType.Class;
                    CorMetadataImport importer = m_process.Modules.Lookup(cls.Module).Importer;
                    var 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;

                        CorDebug.CorValue     thisValue;
                        CorDebug.CorHeapValue hv = ov.CastToHeapValue();
                        if (hv != null)
                        {
                            // we need to pass reference value.
                            CorDebug.CorHandleValue handle = hv.CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION);
                            thisValue = handle;
                        }
                        else
                        {
                            thisValue = ov;
                        }

                        try
                        {
                            CorDebug.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);
                            Debug.Assert(toStringFunc != null);
                            // we should be always able to resolve ToString function.

                            eval.CallFunction(toStringFunc.CorFunction, new[] { thisValue });
                            m_process.Go();
                            do
                            {
                                m_process.StopEvent.WaitOne();
                                if (m_process.StopReason is EvalCompleteStopReason)
                                {
                                    CorDebug.CorValue cv = eval.Result;
                                    Debug.Assert(cv != null);
                                    var    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 canot copy a VC class error - Can't copy a VC with object refs in it.
                            if (e.ErrorCode != (int)CorDebug.HResult.CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS)
                            {
                                throw;
                            }
                        }
                        finally
                        {
                            // 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 = -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;
        }
        public ILVirtualDocument(MDbgFunction mdbgFunction)
        {
            CorCode ilCode = mdbgFunction.CorFunction.ILCode;
            Debug.Assert(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;
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
 /// <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)
        {
            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;
        }
 // this is called on the UI thread.
 private bool OpenSourceFile(MDbgFunction function)
 {
     // Update source viewer
     SourceViewerBaseForm f = SourceViewerBaseForm.GetSourceFile(this, function);
     return ShowSourceFile(f);
 }
 /// <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;
 }
Beispiel #18
0
 internal UserEntryBreakpoint(MDbgProcess p, MDbgFunction mfunc)
     : base(null, new BreakpointFunctionToken(mfunc, 0))
 {
     m_process = p;
 }
Beispiel #19
0
 // 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)
 {
     var source = (SourceViewerBaseForm) m_sourceList[function];
     if (source == null)
     {
         source = new VirtualSourceViewerForm(parent, function);
         AddSourceViewer(source);
     }
     m_ActiveSourceFile = source;
     return source;
 }
Beispiel #20
0
 /// <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)));
 }