Exemple #1
0
bool BreakptMgr::DelBreakpoint(const int id)
{
    int index = FindBreakpointById(id, m_bps);
    if (index == wxNOT_FOUND) {
        return false;
    }

    //remove it from the debugger if it's running
    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr && dbgr->IsRunning()) {
        if (id > FIRST_INTERNAL_ID) {
            // This shouldn't happen while the debugger is running (debugger_id should be valid)
            // But if it does, assume it was a bp that gdb couldn't create, and just remove from the bp list
        } else {
            bool contIsNeeded = PauseDebuggerIfNeeded();
            if (dbgr->RemoveBreak(id)) {
                // Strangely, -break-delete doesn't output any confirmation except for ^done. So do it here
                wxString msg = ((m_bps.at(index).bp_type == BP_type_watchpt) ? _("Watchpoint ") : _("Breakpoint "));
                ManagerST::Get()->UpdateAddLine(msg + wxString::Format(_("%u deleted"), id));
            }
            if (contIsNeeded) {
                dbgr->Continue();
            }
        }
    }

    // Delete all markers before removing bp from the vector. Otherwise if id was the last in a file...
    DeleteAllBreakpointMarkers();

    m_bps.erase(m_bps.begin()+index);

    RefreshBreakpointMarkers();
    return true;
}
Exemple #2
0
// Add a breakpoint using the 'Properties' dialog
void BreakptMgr::AddBreakpoint()
{
    BreakptPropertiesDlg dlg(NULL);
    dlg.SetTitle(_("Create a breakpoint or watchpoint"));

    LEditor* const editor = clMainFrame::Get()->GetMainBook()->GetActiveEditor();
    BreakpointInfo bp;
    bp.Create(editor ? editor->GetFileName().GetFullPath() : wxString(), editor ? editor->GetCurrentLine() : -1, GetNextID());
    dlg.EnterBPData(bp);

    if (dlg.ShowModal() != wxID_OK) {
        return;
    }

    if (AddBreakpoint(dlg.b)) {
        IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
        if ((!dlg.b.is_enabled) && dbgr && dbgr->IsRunning()) {
            SetBPEnabledState(dlg.b.debugger_id, dlg.b.is_enabled);
        }
        wxString msg;
        if (dlg.b.bp_type == BP_type_watchpt) {
            msg = _("Watchpoint successfully added");
        } else {
            msg = _("Breakpoint successfully added");
        }
        clMainFrame::Get()->SetStatusMessage(msg, 0);
    }
}
void DisplayVariableDlg::OnMouseMove(wxMouseEvent& event)
{
    DebuggerInformation debuggerInfo;
    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr) {
        DebuggerMgr::Get().GetDebuggerInformation(dbgr->GetName(), debuggerInfo);
    }

    if (debuggerInfo.autoExpandTipItems) {
        int flags (0);
        wxTreeItemId item = m_treeCtrl->HitTest(event.GetPosition(), flags);
        if (item.IsOk() && (flags & wxTREE_HITTEST_ONITEMLABEL)) {

            if (item != m_hoveredItem) {
                m_timer2->Stop();
                m_hoveredItem = item;
                m_timer2->Start(500, true);
                return;

            } else
                return;

        }

        m_hoveredItem = wxTreeItemId();
        m_timer2->Stop();
    }
}
Exemple #4
0
bool BreakptMgr::AddBreakpoint(const BreakpointInfo &bp)
{
    if (bp.bp_type != BP_type_watchpt &&
        bp.file.IsEmpty() && bp.function_name.IsEmpty() && bp.memory_address.IsEmpty() && bp.lineno == wxNOT_FOUND) {
        // no function nor file? no memory address?
        // do nothing then
        return true;
    }

    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr && dbgr->IsRunning()) {
        // If the debugger is already running, tell it we want a new bp
        // If not, they'll all be added together when the debugger does start
        bool contIsNeeded = PauseDebuggerIfNeeded();

        dbgr->Break(bp);

        if (contIsNeeded) {
            dbgr->Continue();
        }
    }

    BreakpointInfo newBreakpoint(bp);
    SetBestBPType(newBreakpoint);
    
    BreakpointInfoVec_t::const_iterator iter = std::find(m_bps.begin(), m_bps.end(), newBreakpoint);
    if ( iter == m_bps.end() ) {
        // new breakpoint
        m_bps.push_back( newBreakpoint );
    }
    
    DeleteAllBreakpointMarkers();
    RefreshBreakpointMarkers();
    return true;
}
Exemple #5
0
bool DebuggerMgr::IsNativeDebuggerRunning() const
{
    std::map<wxString, IDebugger*>::const_iterator iter = m_debuggers.find(m_activeDebuggerName);
    if(iter == m_debuggers.end()) { return false; }
    
    IDebugger* d = iter->second;
    return d && d->IsRunning();
}
void DebuggerCallstackView::OnFrameSelected(clCommandEvent& e)
{
    e.Skip();
    IDebugger* dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if(dbgr && dbgr->IsRunning() && ManagerST::Get()->DbgCanInteract()) {
        // set the frame
        dbgr->QueryFileLine();
    }
}
Exemple #7
0
void WatchesTable::DoShowMoreDetails(long item)
{
	if( item != wxNOT_FOUND ) {
		wxString value = GetColumnText(item, 0);
		IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
		if ( dbgr && dbgr->IsRunning() && ManagerST::Get()->DbgCanInteract() ) {
			dbgr->CreateVariableObject( value, DBG_USERR_WATCHTABLE );
		}
	}
}
Exemple #8
0
// If the debugger is running but can't interact, pause it and return true (to flag needs restart)
bool BreakptMgr::PauseDebuggerIfNeeded()
{
    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr && dbgr->IsRunning() && !ManagerST::Get()->DbgCanInteract()) {
        SetExpectingControl(true);
        dbgr->Interrupt();
        return true;
    }
    return false;
}
void DebuggerDisassemblyTab::OnRefreshView(clCommandEvent& e)
{
    e.Skip();
    IDebugger* debugger = DebuggerMgr::Get().GetActiveDebugger();
    if(debugger && debugger->IsRunning() && ManagerST::Get()->DbgCanInteract()) {
        // Only update disass view if the view is visible
        if(ManagerST::Get()->IsDebuggerViewVisible(DebuggerPane::DISASSEMBLY)) {
            debugger->ListRegisters();
            debugger->Disassemble("", -1);
        }
    }
}
Exemple #10
0
void WatchesTable::RefreshValues()
{
	//ask the debugger to update the table
	//to trigger the update for the table we issue a simple
	//file line update request from the debugger
	if (ManagerST::Get()->DbgCanInteract()) {
		IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
		if (dbgr && dbgr->IsRunning()) {
			dbgr->QueryFileLine();
		}
	}
}
Exemple #11
0
bool BreakptMgr::SetBPEnabledState(const int bid, const bool enable)
{
    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr && dbgr->IsRunning()) {
        // If the debugger is already running, tell it about the new 'enable' level
        // If not, it'll happen automatically when the debugger does start
        bool contIsNeeded = PauseDebuggerIfNeeded();
        bool result = dbgr->SetEnabledState(bid, enable);
        if (contIsNeeded) {
            dbgr->Continue();
        }
        return result;
    }
    return true;
}
Exemple #12
0
bool BreakptMgr::SetBPConditon(const BreakpointInfo& bp)
{
    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr && dbgr->IsRunning()) {
        // If the debugger is already running, tell it about the condition
        // If not, it'll happen automatically when the debugger does start
        bool contIsNeeded = PauseDebuggerIfNeeded();
        bool result = dbgr->SetCondition(bp);
        if (contIsNeeded) {
            dbgr->Continue();
        }
        return result;
    }
    return false;
}
Exemple #13
0
bool BreakptMgr::SetBPIgnoreCount(const int bid, const int ignorecount)
{
    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr && dbgr->IsRunning()) {
        // If the debugger is already running, tell it about the new ignore level
        // If not, it'll happen automatically when the debugger does start
        bool contIsNeeded = PauseDebuggerIfNeeded();
        bool result = dbgr->SetIgnoreLevel(bid, ignorecount);
        if (contIsNeeded) {
            dbgr->Continue();
        }
        return result;
    }
    return true;
}
void DebuggerTreeListCtrlBase::UpdateVariableObjects()
{
    IDebugger *debugger = DebuggerMgr::Get().GetActiveDebugger();
    if(!debugger)
        return;

    wxTreeItemId root = m_listTable->GetRootItem();
    wxTreeItemIdValue cookieOne;
    wxTreeItemId item = m_listTable->GetFirstChild(root, cookieOne);
    while( item.IsOk() ) {
        wxString gdbID = DoGetGdbId(item);
        if(gdbID.IsEmpty() == false) {
            debugger->UpdateVariableObject(gdbID, m_DBG_USERR);
        }
        item = m_listTable->GetNextChild(root, cookieOne);
    }
}
Exemple #15
0
void BreakptMgr::DelAllBreakpoints()
{
    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr && dbgr->IsRunning()) {
        bool contIsNeeded = PauseDebuggerIfNeeded();
        dbgr->RemoveAllBreaks();
        if (contIsNeeded) {
            dbgr->Continue();
        }
    }

    // Delete all markers before clearing m_bps, otherwise we won't know which files they were in
    DeleteAllBreakpointMarkers();
    m_bps.clear();
    m_pendingBreakpointsList.clear();	// Delete any pending bps too
    clMainFrame::Get()->GetDebuggerPane()->GetBreakpointView()->Initialize();
}
Exemple #16
0
// When a a breakpoint is hit, see if it's got a command-list that needs faking
void BreakptMgr::BreakpointHit(int id)
{
    int index = FindBreakpointById(id, m_bps);
    if ((index == wxNOT_FOUND) || (index >= FIRST_INTERNAL_ID)) {
        return;
    }

    BreakpointInfo bp = m_bps.at(index);
    if (! bp.commandlist.IsEmpty()) {
        IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
        if (dbgr && dbgr->IsRunning()) {
            // A likely command, presumably at the end of the command-list, is 'continue' or 'cont'
            // Filter this out and do it separately, otherwise Manager::UpdateLostControl isn't called to blank the indicator
            static wxRegEx reContinue(wxT("(([[:space:]]|(^))((cont$)|(continue)))"));
            bool needsCont = false;
            wxString commands = bp.commandlist;
            if (reContinue.IsValid() && reContinue.Matches(commands)) {
                size_t start, len;
                if (reContinue.GetMatch(&start,&len)) {
                    commands = commands.Left(start);
                    needsCont = true;
                }
            }
            if (! commands.IsEmpty()) {	// Just in case someone's _only_ command is 'continue' !
                dbgr->ExecuteCmd(commands);
            }
            if (needsCont) {
                dbgr->Continue();
            }
        }
    }

    if (bp.bp_type == BP_type_tempbreak) {
        // If this is a temporary bp, remove it from m_bps now it's been hit
        // Otherwise it will be treated as a 'Pending' bp, the button will be displayed
        // and, if clicked, the bp will be resurrected.
        int index = FindBreakpointById(id, m_bps);
        if (index != wxNOT_FOUND) {
            m_bps.erase(m_bps.begin()+index);
        }

    }
}
Exemple #17
0
void BreakpointDlg::Initialize()
{
    std::vector<BreakpointInfo> bps;
    ManagerST::Get()->GetBreakpointsMgr()->GetBreakpoints(bps);

    // This does the display stuff
    m_listCtrlBreakpoints->Initialise(bps);

    // Store the internal and external ids
    m_ids.clear();
    std::vector<BreakpointInfo>::iterator iter = bps.begin();
    for(; iter != bps.end(); ++iter) {
        struct bpd_IDs IDs(*iter);
        m_ids.push_back(IDs);
    }

    int count = m_listCtrlBreakpoints->GetItemCount();
    bool hasitems = count > 0;
    if (hasitems) {
        // Select the first item if there's not already a selection
        if (m_selectedItem == wxNOT_FOUND) {
            m_selectedItem = 0;
        }
        if (m_selectedItem >= count) {	// e.g. if the selection was the last item, then one is deleted
            m_selectedItem = count-1;
        }
        // Even if an item was previously selected, refreshing the pane means we need to reselect
        m_listCtrlBreakpoints->SetItemState(m_selectedItem, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
    }

    // Since any change results in Initialize() being rerun, we can do updateUI here
    m_buttonEdit->Enable(hasitems);
    m_buttonDelete->Enable(hasitems);
    // The 'Apply Pending' button is more complicated: it should be hidden,
    // unless there are pending bps to apply,and the debugger is running
    bool pending = ManagerST::Get()->GetBreakpointsMgr()->PendingBreakpointsExist();
    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    m_buttonApplyPending->Show( pending && dbgr && dbgr->IsRunning() );
    Layout();
    // Enable DeleteAll if there are either bps or pending bps
    m_buttonDeleteAll->Enable(hasitems || pending);
}
Exemple #18
0
void BreakptMgr::SetAllBreakpointsEnabledState(bool enabled)
{
    unsigned int successes = 0;
    bool debuggerIsRunning = false;
    bool contIsNeeded = false;

    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr && dbgr->IsRunning()) {
        debuggerIsRunning = true;
        contIsNeeded = PauseDebuggerIfNeeded();
    }

    for (size_t i=0; i<m_bps.size(); ++i) {
        BreakpointInfo &bp = m_bps.at(i);
        if (((bp.debugger_id != -1) || !debuggerIsRunning) // Sanity check for when the debugger's running
            && (bp.is_enabled != enabled)) { // No point setting it to the current status
            if (debuggerIsRunning) {
                if (dbgr->SetEnabledState(bp.debugger_id, enabled)) {
                    bp.is_enabled = enabled;
                    ++successes;
                }
            } else {
                bp.is_enabled = enabled;
                ++successes;
            }
        }
    }

    if (debuggerIsRunning && contIsNeeded) {
        dbgr->Continue();
    }

    if (successes) {
        RefreshBreakpointMarkers();
        clMainFrame::Get()->GetDebuggerPane()->GetBreakpointView()->Initialize();

        wxString msg = wxString::Format(wxT("%u "), successes);
        msg << (enabled ? _("breakpoints enabled") : _("breakpoints disabled"));
        clMainFrame::Get()->SetStatusMessage(msg, 0);
    }
}
Exemple #19
0
void BreakptMgr::ApplyPendingBreakpoints()
{
    if (!PendingBreakpointsExist()) {
        return; // Nothing to do
    }

    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (!(dbgr && dbgr->IsRunning())) {
        return; // If the debugger isn't running, there's no point (and we shouldn't have reached here anyway)
    }
    bool contIsNeeded = PauseDebuggerIfNeeded();

    for (size_t i=m_pendingBreakpointsList.size(); i>0; --i) {
        BreakpointInfo bp = m_pendingBreakpointsList.at(i-1);

        // First check to see if the debugger already accepted this one
        // The answer should be no, as acceptance should have removed it from this list
        int index = FindBreakpointById(bp.internal_id, m_bps);
        if (index != wxNOT_FOUND) {
            // Hmm. See if there's a valid debugger_id. If so, the bp *was* accepted, and shouldn't be on the pending list
            if (m_bps.at(index).debugger_id != -1) {
                m_pendingBreakpointsList.erase(m_pendingBreakpointsList.begin()+i-1);
            }
            continue;	// The bp hasn't been assessed yet; it's probably pointless to try to reapply it atm
        }

        // This bp didn't 'take' the first time; "..try, try again" :p
        dbgr->Break(bp);
        m_bps.push_back(bp);
    }

    if (contIsNeeded) {
        dbgr->Continue();
    }

    RefreshBreakpointMarkers();
}
void DebuggerTreeListCtrlBase::DoDeleteWatch(const wxTreeItemId& item)
{
    IDebugger *dbgr = DoGetDebugger();
    if(!dbgr || !item.IsOk()) {
        return;
    }

    wxString gdbId = DoGetGdbId(item);
    if(gdbId.IsEmpty() == false) {
        dbgr->DeleteVariableObject(gdbId);
    }

#ifdef __WXMAC__

    // Mac's GDB does not delete all the children of the variable object
    // instead we will do it manually

    if(m_listTable->HasChildren(item)) {
        // Delete this item children
        wxTreeItemIdValue cookie;
        wxTreeItemId child = m_listTable->GetFirstChild(item, cookie);
        while(child.IsOk()) {
            gdbId = DoGetGdbId(child);
            if(gdbId.IsEmpty() == false) {
                dbgr->DeleteVariableObject(gdbId);
            }

            if(m_listTable->HasChildren(child)) {
                DoDeleteWatch(child);
            }

            child = m_listTable->GetNextChild(item, cookie);
        }
    }
#endif

}
bool DebuggerMgr::LoadDebuggers(const wxString& strDebuggersDir)
{
	wxString ext;
#if defined (__WXMSW__)
	ext = wxT("dll");
#else
	ext = wxT("so");
#endif
	wxString fileSpec(wxT("*.")+ext);

	//get list of dlls
	wxArrayString files;

  wxString debuggersPath(strDebuggersDir, wxConvUTF8);
	debuggersPath += wxT("/debuggers");

	wxDir::GetAllFiles(debuggersPath, &files, fileSpec, wxDIR_FILES);

	for(size_t i=0; i<files.GetCount(); i++){
		clDynamicLibrary *dl = new clDynamicLibrary();
		wxString fileName(files.Item(i));
		if(!dl->Load(fileName)){
			wxLogMessage(wxT("Failed to load debugger's dll: ") + fileName);
            if (!dl->GetError().IsEmpty())
                wxLogMessage(dl->GetError());
			delete dl;
			continue;
		}

		bool success(false);
		GET_DBG_INFO_FUNC pfn = (GET_DBG_INFO_FUNC)dl->GetSymbol(wxT("GetDebuggerInfo"), &success);
		if(!success){
            wxLogMessage(wxT("Failed to find GetDebuggerInfo() in dll: ") + fileName);
            if (!dl->GetError().IsEmpty())
                wxLogMessage(dl->GetError());
			//dl->Unload();
			delete dl;
			continue;
		}

		DebuggerInfo info = pfn();
		//Call the init method to create an instance of the debugger
		success = false;
		GET_DBG_CREATE_FUNC pfnInitDbg = (GET_DBG_CREATE_FUNC)dl->GetSymbol(info.initFuncName, &success);
		if(!success){
            wxLogMessage(wxT("Failed to find init function in dll: ") + fileName);
            if (!dl->GetError().IsEmpty())
                wxLogMessage(dl->GetError());
			dl->Detach();
			delete dl;
			continue;
		}

		wxLogMessage(wxT("Loaded debugger: ") + info.name + wxT(", Version: ") + info.version);
		IDebugger *dbg = pfnInitDbg();

		//set the environment
		dbg->SetEnvironment(m_env);

		m_debuggers[info.name] = dbg;

		//keep the dynamic load library
		m_dl.push_back(dl);
	}
	return true;
}
bool DebuggerMgr::LoadDebuggers()
{
    wxString ext;

#if defined(__WXMSW__)
    ext = wxT("dll");

#elif defined(__WXMAC__)
    ext = wxT("dylib");

#else
    ext = wxT("so");

#endif

    wxString fileSpec(wxT("*.") + ext);

    // get list of dlls
    wxArrayString files;
#ifdef __WXGTK__
    wxString debuggersPath(PLUGINS_DIR, wxConvUTF8);
    debuggersPath += wxT("/debuggers");
#elif defined(__WXMSW__)
#ifdef USE_POSIX_LAYOUT
    wxString debuggersPath(clStandardPaths::Get().GetPluginsDirectory() + wxT("/debuggers"));
#else
    wxString debuggersPath(m_baseDir + wxT("/debuggers"));
#endif
#else
    // OSX
    wxFileName debuggersFolder(clStandardPaths::Get().GetDataDir(), "");
    debuggersFolder.AppendDir("debuggers");
    wxString debuggersPath(debuggersFolder.GetPath());
#endif

    CL_DEBUG("Loading debuggers from: %s", debuggersPath);
    wxDir::GetAllFiles(debuggersPath, &files, fileSpec, wxDIR_FILES);

    for(size_t i = 0; i < files.GetCount(); i++) {
        clDynamicLibrary* dl = new clDynamicLibrary();
        wxString fileName(files.Item(i));
        CL_DEBUG("Attempting to load debugger: %s", fileName);
#if defined(__WXMSW__) && !defined(NDEBUG)
        // Under MSW loading a release plugin while in debug mode will cause a crash
        if(!fileName.EndsWith("-dbg.dll")) {
            continue;
        }
#elif defined(__WXMSW__)

        // filter debug plugins
        if(fileName.EndsWith("-dbg.dll")) {
            continue;
        }
#endif
        if(!dl->Load(fileName)) {
            CL_WARNING("Failed to load debugger: %s", fileName);
            if(!dl->GetError().IsEmpty()) {
                CL_WARNING("%s", dl->GetError());
            }
            delete dl;
            continue;
        }

        bool success(false);
        GET_DBG_INFO_FUNC pfn = (GET_DBG_INFO_FUNC)dl->GetSymbol(wxT("GetDebuggerInfo"), &success);
        if(!success) {
            wxLogMessage(wxT("Failed to find GetDebuggerInfo() in dll: ") + fileName);
            if(!dl->GetError().IsEmpty()) {
                wxLogMessage(dl->GetError());
            }
            // dl->Unload();
            delete dl;
            continue;
        }

        DebuggerInfo info = pfn();
        // Call the init method to create an instance of the debugger
        success = false;
        GET_DBG_CREATE_FUNC pfnInitDbg = (GET_DBG_CREATE_FUNC)dl->GetSymbol(info.initFuncName, &success);
        if(!success) {
            wxLogMessage(wxT("Failed to find init function in dll: ") + fileName);
            if(!dl->GetError().IsEmpty()) {
                wxLogMessage(dl->GetError());
            }
            dl->Detach();
            delete dl;
            continue;
        }

        wxLogMessage(wxT("Loaded debugger: ") + info.name + wxT(", Version: ") + info.version);
        IDebugger* dbg = pfnInitDbg();

        // set the environment
        dbg->SetEnvironment(m_env);

        m_debuggers[info.name] = dbg;

        // keep the dynamic load library
        m_dl.push_back(dl);
    }

    // Load all debuggers in the form of plugin (i.e. they dont implement the IDebugger interface)
    // and append them to a special list
    clDebugEvent queryPlugins(wxEVT_DBG_IS_PLUGIN_DEBUGGER);
    EventNotifier::Get()->ProcessEvent(queryPlugins);
    m_pluginsDebuggers.swap(queryPlugins.GetStrings());
    return true;
}
Exemple #23
0
void BreakptMgr::EditBreakpoint(int index, bool &bpExist)
{
    // sanity
    bpExist = true;
    if (index < 0 || index >= (int)m_bps.size()) {
        wxLogMessage(wxT("BreakptMgr::EditBreakpoint: Insane index"));
        bpExist = false;
        return;
    }

    BreakpointInfo bp = m_bps.at(index);
    BreakptPropertiesDlg dlg(NULL);
    wxString title;
    if (bp.bp_type == BP_type_watchpt) {
        title = _("Properties for watchpoint ");
    } else {
        title = _("Properties for breakpoint ");
    }
    int id = bp.debugger_id;
    if (id == -1) {
        id = bp.internal_id - FIRST_INTERNAL_ID;
    }
    title << id;
    dlg.SetTitle(title);

    dlg.EnterBPData(bp);
    if (dlg.ShowModal() != wxID_OK) {
        return ;
    }

    SetBestBPType(dlg.b);	// The edited data's available. Use it to determine the best bp_type
    if (bp == dlg.b) {
        // Nothing was altered
        return ;
    }

    // We've got our altered dlg.b If the debugger's running, we can update it now
    // Otherwise, it'll be automatically inserted correctly when the debugger starts
    IDebugger *dbgr = DebuggerMgr::Get().GetActiveDebugger();
    if (dbgr && dbgr->IsRunning()) {
        if (CanThisBreakpointBeUpdated(dlg.b, bp)) {
            if (dlg.b.ignore_number != bp.ignore_number) {
                if (! SetBPIgnoreCount(dlg.b.debugger_id, dlg.b.ignore_number)) {
                    return;	// Harsh, but what else can one do?
                }
            }
            if (dlg.b.is_enabled != bp.is_enabled) {
                if (! SetBPEnabledState(dlg.b.debugger_id, dlg.b.is_enabled)) {
                    return ;
                }
            }
            if (dlg.b.conditions != bp.conditions) {
                if (! SetBPConditon(dlg.b)) {
                    return ;
                }
            }
            if (dlg.b.commandlist != bp.commandlist) {
                if (! SetBPCommands(dlg.b)) {
                    return ;
                }
            }
        } else {
            // If it can't be updated (because gdb wouldn't be able to cope with the change), replace
            bool contIsNeeded = PauseDebuggerIfNeeded();
            dbgr->RemoveBreak(bp.debugger_id);
            dbgr->Break(dlg.b);
            // dbgr->Break(bp) doesn't set the ignore/disabled/etc states
            // but we can't do it now, as we don't yet know the debugger_id
            // However it will happen later, in SetBreakpointDebuggerID
            if (contIsNeeded) {
                dbgr->Continue();
            }
        }
    }

    // Replace the old data with the new, in m_bps
    m_bps.at(index) = dlg.b;
    DeleteAllBreakpointMarkers();
    RefreshBreakpointMarkers();
}