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; }
// 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(); } }
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; }
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(); } }
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 ); } } }
// 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); } } }
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(); } } }
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; }
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; }
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); } }
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(); }
// 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); } } }
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); }
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); } }
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; }
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(); }