////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeBreakpointError (CLangDebugger debugger, DebugBreakpointManager breakpointManager, DebuggeeBreakpointPending pendingBreakpoint, DebuggeeCodeContext codeContext, MiBreakpoint gdbBreakpoint, string error)
      : base (breakpointManager, pendingBreakpoint, codeContext, error)
    {
      m_debugger = debugger;

      GdbBreakpoint = gdbBreakpoint;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeBreakpointBound (CLangDebugger debugger, DebugBreakpointManager breakpointManager, DebuggeeBreakpointPending pendingBreakpoint, DebuggeeCodeContext codeContext, MiBreakpoint gdbBreakpoint)
      : base (breakpointManager, pendingBreakpoint, codeContext)
    {
      m_debugger = debugger;

      GdbBreakpoint = gdbBreakpoint;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    private void OnClientAsyncRecord (MiAsyncRecord asyncRecord)
    {
      LoggingUtils.PrintFunction ();

      switch (asyncRecord.Type)
      {
        case MiAsyncRecord.AsyncType.Exec: 
        {
          // 
          // Records prefixed '*'.
          // 

          switch (asyncRecord.Class)
          {
            case "running":
            {
              // 
              // The target is now running. The thread field tells which specific thread is now running, can be 'all' if every thread is running.
              // 

              lock (NativeProgram)
              {
                NativeProgram.SetRunning (true);

                string threadId = asyncRecord ["thread-id"] [0].GetString ();

                if (threadId.Equals ("all"))
                {
                  Dictionary<uint, DebuggeeThread> programThreads = NativeProgram.GetThreads ();

                  lock (programThreads)
                  {
                    foreach (DebuggeeThread thread in programThreads.Values)
                    {
                      thread.SetRunning (true);
                    }
                  }
                }
                else
                {
                  uint numericThreadId = uint.Parse (threadId);

                  NativeProgram.CurrentThreadId = numericThreadId;

                  CLangDebuggeeThread thread = NativeProgram.GetThread (numericThreadId);

                  if (thread != null)
                  {
                    thread.SetRunning (true);
                  }
                }
              }

              break;
            }

            case "stopped":
            {
              // 
              // The target has stopped.
              // 

              CLangDebuggeeThread stoppedThread = null;

              lock (NativeProgram)
              {
                NativeProgram.SetRunning (false);

                if (asyncRecord.HasField ("thread-id"))
                {
                  uint threadId = asyncRecord ["thread-id"] [0].GetUnsignedInt ();

                  NativeProgram.CurrentThreadId = threadId;
                }

                if (stoppedThread == null)
                {
                  stoppedThread = NativeProgram.GetThread (NativeProgram.CurrentThreadId);
                }

                if (stoppedThread != null)
                {
                  stoppedThread.SetRunning (false);
                }
                else
                {
                  throw new InvalidOperationException ("Could not evaluate a thread on which we stopped");
                }

                // 
                // Flag some or all of the program's threads as stopped, directed by 'stopped-threads' field.
                // 

                bool hasStoppedThreads = asyncRecord.HasField ("stopped-threads");

                if (hasStoppedThreads)
                {
                  // 
                  // If all threads are stopped, the stopped field will have the value of "all". 
                  // Otherwise, the value of the stopped field will be a list of thread identifiers.
                  // 

                  MiResultValue stoppedThreadsRecord = asyncRecord ["stopped-threads"] [0];

                  if (stoppedThreadsRecord is MiResultValueList)
                  {
                    MiResultValueList stoppedThreads = stoppedThreadsRecord as MiResultValueList;

                    foreach (MiResultValue stoppedThreadValue in stoppedThreads.List)
                    {
                      uint stoppedThreadId = stoppedThreadValue.GetUnsignedInt ();

                      CLangDebuggeeThread thread = NativeProgram.GetThread (stoppedThreadId);

                      if (thread != null)
                      {
                        thread.SetRunning (false);
                      }
                    }
                  }
                  else
                  {
                    Dictionary<uint, DebuggeeThread> programThreads = NativeProgram.GetThreads ();

                    lock (programThreads)
                    {
                      foreach (DebuggeeThread thread in programThreads.Values)
                      {
                        thread.SetRunning (false);
                      }
                    }
                  }
                }
              }

              // 
              // Unblocks waiting for 'stopped' to be processed. Skipping event handling during interrupt requests as it confuses VS debugger flow.
              // 

              bool ignoreInterruptSignal = false;

              if (m_interruptOperationCompleted != null)
              {
                m_interruptOperationCompleted.Set ();

                ignoreInterruptSignal = true;
              }

              // 
              // Process any pending requests to refresh registered breakpoints.
              // 

#if false
              RefreshSharedLibraries ();
#endif


#if false
              NativeProgram.RefreshAllThreads ();
#endif

              if (!GdbClient.GetClientFeatureSupported ("breakpoint-notifications"))
              {
                Engine.BreakpointManager.RefreshBreakpoints ();
              }

              // 
              // This behaviour seems at odds with the GDB/MI spec, but a *stopped event can contain
              // multiple 'reason' fields. This seems to occur mainly when signals have been ignored prior 
              // to a non-ignored triggering, i.e:
              // 
              //   Signal        Stop\tPrint\tPass to program\tDescription\n
              //   SIGSEGV       No\tYes\tYes\t\tSegmentation fault\n
              // 
              // *stopped,reason="signal-received",signal-name="SIGSEGV",signal-meaning="Segmentation fault",reason="signal-received",signal-name="SIGSEGV",signal-meaning="Segmentation fault",reason="exited-signalled",signal-name="SIGSEGV",signal-meaning="Segmentation fault"
              // 

              if (asyncRecord.HasField ("reason"))
              {
                // 
                // Here we pick the most recent (unhandled) signal.
                // 

                int stoppedIndex = asyncRecord ["reason"].Count - 1;

                MiResultValue stoppedReason = asyncRecord ["reason"] [stoppedIndex];

                // 
                // The reason field can have one of the following values:
                // 

                switch (stoppedReason.GetString ())
                {
                  case "breakpoint-hit":
                  case "watchpoint-trigger":
                  {
                    bool canContinue = true;

                    uint breakpointId = asyncRecord ["bkptno"] [0].GetUnsignedInt ();

                    string breakpointMode = asyncRecord ["disp"] [0].GetString ();

                    if (breakpointMode.Equals ("del"))
                    {
                      // 
                      // For temporary breakpoints, we won't have a valid managed object - so will just enforce a break event.
                      // 

                      //Engine.Broadcast (new DebugEngineEvent.Break (), NativeProgram.DebugProgram, stoppedThread);

                      Engine.Broadcast (new DebugEngineEvent.BreakpointHit (null), NativeProgram.DebugProgram, stoppedThread);
                    }
                    else
                    {
                      DebuggeeBreakpointBound boundBreakpoint = Engine.BreakpointManager.FindBoundBreakpoint (breakpointId);

                      if (boundBreakpoint == null)
                      {
                        // 
                        // Could not find the breakpoint we're looking for. Refresh everything and try again.
                        // 

                        Engine.BreakpointManager.SetDirty (true);

                        Engine.BreakpointManager.RefreshBreakpoints ();

                        boundBreakpoint = Engine.BreakpointManager.FindBoundBreakpoint (breakpointId);
                      }

                      if (boundBreakpoint == null)
                      {
                        // 
                        // Could not locate a registered breakpoint with matching id.
                        // 

                        DebugEngineEvent.Exception exception = new DebugEngineEvent.Exception (NativeProgram.DebugProgram, stoppedReason.GetString (), "Breakpoint #" + breakpointId + "hit", 0x00000000, canContinue);

                        Engine.Broadcast (exception, NativeProgram.DebugProgram, stoppedThread);
                      }
                      else
                      {
                        enum_BP_STATE [] breakpointState = new enum_BP_STATE [1];

                        LoggingUtils.RequireOk (boundBreakpoint.GetState (breakpointState));

                        if (breakpointState [0] == enum_BP_STATE.BPS_DELETED)
                        {
                          // 
                          // Hit a breakpoint which internally is flagged as deleted. Oh noes!
                          // 

                          DebugEngineEvent.Exception exception = new DebugEngineEvent.Exception (NativeProgram.DebugProgram, stoppedReason.GetString (), "Breakpoint #" + breakpointId + " hit [deleted]", 0x00000000, canContinue);

                          Engine.Broadcast (exception, NativeProgram.DebugProgram, stoppedThread);
                        }
                        else
                        {
                          // 
                          // Hit a breakpoint which is known about. Issue break event.
                          // 

                          IDebugBoundBreakpoint2 [] boundBreakpoints = new IDebugBoundBreakpoint2 [] { boundBreakpoint };

                          IEnumDebugBoundBreakpoints2 enumeratedBoundBreakpoint = new DebuggeeBreakpointBound.Enumerator (boundBreakpoints);

                          Engine.Broadcast (new DebugEngineEvent.BreakpointHit (enumeratedBoundBreakpoint), NativeProgram.DebugProgram, stoppedThread);
                        }
                      }
                    }

                    break;
                  }

                  case "end-stepping-range":
                  case "function-finished":
                  {
                    Engine.Broadcast (new DebugEngineEvent.StepComplete (), NativeProgram.DebugProgram, stoppedThread);

                    break;
                  }

                  case "signal-received":
                  {
                    string signalName = asyncRecord ["signal-name"] [stoppedIndex].GetString ();

                    string signalMeaning = asyncRecord ["signal-meaning"] [stoppedIndex].GetString ();

                    switch (signalName)
                    {
                      case null:
                      case "SIGINT":
                      {
                        if (!ignoreInterruptSignal)
                        {
                          Engine.Broadcast (new DebugEngineEvent.Break (), NativeProgram.DebugProgram, stoppedThread);
                        }

                        break;
                      }

                      default:
                      {
                        StringBuilder signalDescription = new StringBuilder ();

                        signalDescription.AppendFormat ("{0} ({1})", signalName, signalMeaning);

                        if (asyncRecord.HasField ("frame"))
                        {
                          MiResultValueTuple frameTuple = asyncRecord ["frame"] [0] as MiResultValueTuple;

                          if (frameTuple.HasField ("addr"))
                          {
                            string address = frameTuple ["addr"] [0].GetString ();

                            signalDescription.AppendFormat (" at {0}", address);
                          }

                          if (frameTuple.HasField ("func"))
                          {
                            string function = frameTuple ["func"] [0].GetString ();

                            signalDescription.AppendFormat (" ({0})", function);
                          }
                        }

                        bool canContinue = true;

                        DebugEngineEvent.Exception exception = new DebugEngineEvent.Exception (NativeProgram.DebugProgram, signalName, signalDescription.ToString (), 0x80000000, canContinue);

                        Engine.Broadcast (exception, NativeProgram.DebugProgram, stoppedThread);

                        break;
                      }
                    }

                    break;
                  }

                  case "read-watchpoint-trigger":
                  case "access-watchpoint-trigger":
                  case "location-reached":
                  case "watchpoint-scope":
                  case "solib-event":
                  case "fork":
                  case "vfork":
                  case "syscall-entry":
                  case "exec":
                  {
                    Engine.Broadcast (new DebugEngineEvent.Break (), NativeProgram.DebugProgram, stoppedThread);

                    break;
                  }

                  case "exited":
                  case "exited-normally":
                  case "exited-signalled":
                  {
                    // 
                    // React to program termination, but defer this so it doesn't consume the async output thread.
                    // 

                    ThreadPool.QueueUserWorkItem (delegate (object state)
                    {
                      try
                      {
                        LoggingUtils.RequireOk (Engine.Detach (NativeProgram.DebugProgram));
                      }
                      catch (Exception e)
                      {
                        LoggingUtils.HandleException (e);
                      }
                    });

                    break;
                  }
                }
              }

              break;
            }
          }

          break;
        }

        case MiAsyncRecord.AsyncType.Status:
        {
          // 
          // Records prefixed '+'.
          // 

          break;
        }


        case MiAsyncRecord.AsyncType.Notify:
        {
          // 
          // Records prefixed '='.
          // 

          switch (asyncRecord.Class)
          {
            case "thread-group-added":
            case "thread-group-started":
            {
              // 
              // A thread group became associated with a running program, either because the program was just started or the thread group was attached to a program.
              // 

              try
              {
                string threadGroupId = asyncRecord ["id"] [0].GetString ();

                m_threadGroupStatus [threadGroupId] = 0;
              }
              catch (Exception e)
              {
                LoggingUtils.HandleException (e);
              }

              break;
            }

            case "thread-group-removed":
            case "thread-group-exited":
            {
              // 
              // A thread group is no longer associated with a running program, either because the program has exited, or because it was detached from.
              // 

              try
              {
                string threadGroupId = asyncRecord ["id"] [0].GetString ();

                if (asyncRecord.HasField ("exit-code"))
                {
                  m_threadGroupStatus [threadGroupId] = asyncRecord ["exit-code"] [0].GetUnsignedInt ();
                }
              }
              catch (Exception e)
              {
                LoggingUtils.HandleException (e);
              }

              break;
            }

            case "thread-created":
            {
              // 
              // A thread either was created. The id field contains the gdb identifier of the thread. The gid field identifies the thread group this thread belongs to. 
              // 

              try
              {
                uint threadId = asyncRecord ["id"] [0].GetUnsignedInt ();

                string threadGroupId = asyncRecord ["group-id"] [0].GetString ();

                CLangDebuggeeThread thread = NativeProgram.GetThread (threadId);

                if (thread == null)
                {
                  NativeProgram.AddThread (threadId);
                }
              }
              catch (Exception e)
              {
                LoggingUtils.HandleException (e);
              }

              break;
            }

            case "thread-exited":
            {
              // 
              // A thread has exited. The 'id' field contains the GDB identifier of the thread. The 'group-id' field identifies the thread group this thread belongs to. 
              // 

              try
              {
                uint threadId = asyncRecord ["id"] [0].GetUnsignedInt ();

                string threadGroupId = asyncRecord ["group-id"] [0].GetString ();

                uint exitCode = m_threadGroupStatus [threadGroupId];

                NativeProgram.RemoveThread (threadId, exitCode);
              }
              catch (Exception e)
              {
                LoggingUtils.HandleException (e);
              }

              break;
            }

            case "thread-selected":
            {
              // 
              // Informs that the selected thread was changed as result of the last command.
              // 

              try
              {
                uint threadId = asyncRecord ["id"] [0].GetUnsignedInt ();

                NativeProgram.CurrentThreadId = threadId;
              }
              catch (Exception e)
              {
                LoggingUtils.HandleException (e);
              }

              break;
            }

            case "library-loaded":
            {
              // 
              // Reports that a new library file was loaded by the program.
              // 

              try
              {
                string moduleName = asyncRecord ["id"] [0].GetString ();

                CLangDebuggeeModule module = NativeProgram.GetModule (moduleName);

                if (module == null)
                {
                  module = NativeProgram.AddModule (moduleName, asyncRecord);
                }

                if (!GdbClient.GetClientFeatureSupported ("breakpoint-notifications"))
                {
                  Engine.BreakpointManager.SetDirty (true);
                }
              }
              catch (Exception e)
              {
                LoggingUtils.HandleException (e);
              }

              break;
            }

            case "library-unloaded":
            {
              // 
              // Reports that a library was unloaded by the program.
              // 

              try
              {
                string moduleName = asyncRecord ["id"] [0].GetString ();

                NativeProgram.RemoveModule (moduleName);

                if (!GdbClient.GetClientFeatureSupported ("breakpoint-notifications"))
                {
                  Engine.BreakpointManager.SetDirty (true);
                }
              }
              catch (Exception e)
              {
                LoggingUtils.HandleException (e);
              }

              break;
            }

            case "breakpoint-created":
            case "breakpoint-modified":
            case "breakpoint-deleted":
            {
              try
              {
                IDebugPendingBreakpoint2 pendingBreakpoint = null;

                if (asyncRecord.HasField ("bkpt"))
                {
                  MiResultValue breakpointData = asyncRecord ["bkpt"] [0];

                  MiBreakpoint currentGdbBreakpoint = new MiBreakpoint (breakpointData.Values);

                  pendingBreakpoint = Engine.BreakpointManager.FindPendingBreakpoint (currentGdbBreakpoint.ID);

                  // If the breakpoint is unknown, this usually means it was bound externally to the IDE.
                  /*if (pendingBreakpoint == null)
                  {
                    // 
                    // CreatePendingBreakpoint always sets the dirty flag, so we need to reset this if it's handled immediately.
                    // 

                    DebugBreakpointRequest breakpointRequest = new DebugBreakpointRequest (currentGdbBreakpoint.Address);

                    LoggingUtils.RequireOk (Engine.BreakpointManager.CreatePendingBreakpoint (breakpointRequest, out pendingBreakpoint));
                  }*/
                }
                else if (asyncRecord.HasField ("id"))
                {
                  pendingBreakpoint = Engine.BreakpointManager.FindPendingBreakpoint (asyncRecord ["id"] [0].GetUnsignedInt ());
                }

                bool wasDirty = Engine.BreakpointManager.IsDirty ();

                if (pendingBreakpoint != null)
                {
                  DebuggeeBreakpointPending thisBreakpoint = pendingBreakpoint as DebuggeeBreakpointPending;

                  thisBreakpoint.RefreshBoundBreakpoints ();

                  thisBreakpoint.RefreshErrorBreakpoints ();
                }

                if (wasDirty)
                {
                  Engine.BreakpointManager.SetDirty (true);
                }
              }
              catch (Exception e)
              {
                LoggingUtils.HandleException (e);
              }

              break;
            }
          }

          break;
        }
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    private void RefreshBreakpoint (object breakpoint)
    {
      // 
      // Validate breakpoint input type. This function can be used for 'bound' and 'error' objects, so we need to handle this appropriately.
      // 

      LoggingUtils.PrintFunction ();

      CLangDebuggeeBreakpointBound boundBreakpoint = null;

      CLangDebuggeeBreakpointError errorBreakpoint = null;

      MiBreakpoint gdbBreakpoint;

      DebuggeeBreakpointResolution resolution;

      if (breakpoint == null)
      {
        throw new ArgumentNullException ("breakpoint");
      }
      else if (breakpoint is CLangDebuggeeBreakpointBound)
      {
        boundBreakpoint = breakpoint as CLangDebuggeeBreakpointBound;

        gdbBreakpoint = boundBreakpoint.GdbBreakpoint;

        IDebugBreakpointResolution2 boundBreakpointResolution;

        int handle = boundBreakpoint.GetBreakpointResolution (out boundBreakpointResolution);

        if (handle == Constants.E_BP_DELETED)
        {
          return;
        }

        LoggingUtils.RequireOk (handle);

        resolution = (DebuggeeBreakpointResolution) boundBreakpointResolution;
      }
      else if (breakpoint is CLangDebuggeeBreakpointError)
      {
        errorBreakpoint = breakpoint as CLangDebuggeeBreakpointError;

        gdbBreakpoint = errorBreakpoint.GdbBreakpoint;

        IDebugErrorBreakpointResolution2 errorBreakpointResolution;

        int handle = errorBreakpoint.GetBreakpointResolution (out errorBreakpointResolution);

        if (handle == Constants.E_BP_DELETED)
        {
          return;
        }

        resolution = (DebuggeeBreakpointResolution) errorBreakpointResolution;

        lock (m_errorBreakpoints)
        {
          m_errorBreakpoints.Remove (errorBreakpoint);
        }
      }
      else
      {
        throw new ArgumentException ("breakpoint");
      }

      // 
      // Query breakpoint info/status directly from GDB/MI.
      // 

      try
      {
        string command = string.Format ("-break-info {0}", gdbBreakpoint.ID);

        m_debugger.GdbClient.SendCommand (command, delegate (MiResultRecord resultRecord)
        {
          if (resultRecord == null)
          {
            throw new InvalidOperationException ();
          }
          else if (resultRecord.IsError ())
          {
            // 
            // GDB/MI breakpoint info request failed.
            // 

            gdbBreakpoint.Address = MiBreakpoint.Pending;

            (resolution as DebuggeeBreakpointResolution).CodeContext.Address = new DebuggeeAddress (gdbBreakpoint.Address);

            errorBreakpoint = new CLangDebuggeeBreakpointError (m_debugger, m_breakpointManager, this, (resolution as DebuggeeBreakpointResolution).CodeContext, gdbBreakpoint, resultRecord.Records [1].Stream);

            lock (m_errorBreakpoints)
            {
              m_errorBreakpoints.Add (errorBreakpoint);
            }

            m_debugger.Engine.Broadcast (new DebugEngineEvent.BreakpointError (errorBreakpoint), m_debugger.NativeProgram.DebugProgram, m_debugger.NativeProgram.GetThread (m_debugger.NativeProgram.CurrentThreadId));
          }
          else
          {
            // 
            // We've probably got sane breakpoint information back. Update current breakpoint values and re-process.
            // 

            MiResultValue breakpointData = resultRecord ["BreakpointTable"] [0] ["body"] [0] ["bkpt"] [0];

            MiBreakpoint currentGdbBreakpoint = new MiBreakpoint (breakpointData.Values);

            DebuggeeCodeContext codeContext = (resolution as DebuggeeBreakpointResolution).CodeContext;

            DebuggeeDocumentContext documentContext = codeContext.DocumentContext;

            LoggingUtils.RequireOk (CreateBoundBreakpoint (currentGdbBreakpoint, documentContext, codeContext));
          }
        });
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public int CreateBoundBreakpoint (MiBreakpoint breakpoint, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext)
    {
      LoggingUtils.PrintFunction ();

      try
      {
        if (breakpoint == null)
        {
          throw new ArgumentNullException ("breakpoint");
        }

        if (breakpoint.IsPending ())
        {
          // 
          // Address can't be satisfied. Unsatisfied likely indicates the modules or symbols associated with the context aren't loaded, yet.
          // 

          DebuggeeAddress pendingAddress = new DebuggeeAddress (MiBreakpoint.Pending);

          DebuggeeCodeContext pendingContext = new CLangDebuggeeCodeContext (m_debugger, pendingAddress, documentContext);

          LoggingUtils.RequireOk (CreateErrorBreakpoint ("Additional library symbols required.", breakpoint, documentContext, pendingContext));
        }
        else if (breakpoint.IsMultiple ())
        {
          // 
          // Breakpoint satisfied to multiple locations, no single memory address available.
          // 

          CLangDebuggeeBreakpointBound boundBreakpoint = new CLangDebuggeeBreakpointBound (m_debugger, m_breakpointManager, this, codeContext, breakpoint);

          lock (m_boundBreakpoints)
          {
            m_boundBreakpoints.Clear ();

            m_boundBreakpoints.Add (boundBreakpoint);
          }

          m_debugger.Engine.Broadcast (new DebugEngineEvent.BreakpointBound (this, boundBreakpoint), m_debugger.NativeProgram.DebugProgram, m_debugger.NativeProgram.GetThread (m_debugger.NativeProgram.CurrentThreadId));
        }
        else
        {
          // 
          // Address satisfied, and the breakpoint is legitimately bound.
          // 

          DebuggeeAddress boundAddress = new DebuggeeAddress (breakpoint.Address);

          DebuggeeCodeContext addressContext = new CLangDebuggeeCodeContext (m_debugger, boundAddress, documentContext);

          CLangDebuggeeBreakpointBound boundBreakpoint = new CLangDebuggeeBreakpointBound (m_debugger, m_breakpointManager, this, addressContext, breakpoint);

          lock (m_boundBreakpoints)
          {
            m_boundBreakpoints.Clear ();

            m_boundBreakpoints.Add (boundBreakpoint);
          }

          m_debugger.Engine.Broadcast (new DebugEngineEvent.BreakpointBound (this, boundBreakpoint), m_debugger.NativeProgram.DebugProgram, m_debugger.NativeProgram.GetThread (m_debugger.NativeProgram.CurrentThreadId));
        }

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        return Constants.E_FAIL;
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public int CreateErrorBreakpoint (string errorReason, MiBreakpoint gdbBreakpoint, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext)
    {
      // 
      // Create a C-language breakpoint. This is tied to a GDB/MI breakpoint object.
      // 

      LoggingUtils.PrintFunction ();

      try
      {
        CLangDebuggeeBreakpointError errorBreakpoint = new CLangDebuggeeBreakpointError (m_debugger, m_breakpointManager, this, codeContext, gdbBreakpoint, errorReason);

        lock (m_errorBreakpoints)
        {
          m_errorBreakpoints.Clear ();

          m_errorBreakpoints.Add (errorBreakpoint);
        }

        uint numDebugPrograms = 1;

        IEnumDebugPrograms2 debugPrograms;

        IDebugProgram2 [] debugProgramsArray = new IDebugProgram2 [numDebugPrograms];

        LoggingUtils.RequireOk (m_breakpointManager.Engine.EnumPrograms (out debugPrograms));

        LoggingUtils.RequireOk (debugPrograms.Next (numDebugPrograms, debugProgramsArray, ref numDebugPrograms));

        m_breakpointManager.Engine.Broadcast (new DebugEngineEvent.BreakpointError (errorBreakpoint), debugProgramsArray [0], null);

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        return Constants.E_FAIL;
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public override int CreateBoundBreakpoint (string location, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext)
    {
      // 
      // Register a new GDB breakpoint.
      // 

      LoggingUtils.PrintFunction ();

      try
      {
        if (m_breakpointRequestInfo.bpLocation.bpLocationType == (uint)enum_BP_TYPE.BPT_DATA)
        {
          throw new NotImplementedException ();
        }

        m_debugger.RunInterruptOperation (delegate (CLangDebugger debugger)
        {
          string command = string.Format ("-break-insert -f {0} {1}", ((m_breakpointEnabled) ? "" : "-d"), PathUtils.SantiseWindowsPath (location));

          debugger.GdbClient.SendCommand (command, delegate (MiResultRecord resultRecord)
          {
            if (resultRecord != null)
            {
              if (resultRecord.IsError ())
              {
                string errorReason = "<unknown error>";

                if (resultRecord.HasField ("msg"))
                {
                  errorReason = resultRecord ["msg"] [0].GetString ();
                }

                LoggingUtils.RequireOk (CreateErrorBreakpoint (errorReason, documentContext, codeContext));
              }
              else
              {
                MiResultValue breakpointData = resultRecord ["bkpt"] [0];

                MiBreakpoint breakpoint = new MiBreakpoint (breakpointData.Values);

                LoggingUtils.RequireOk (CreateBoundBreakpoint (breakpoint, documentContext, codeContext));
              }
            }
          });
        });

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        return Constants.E_FAIL;
      }
    }