📄 debuggergdb.cpp
字号:
/*
* This file is part of Code::Blocks Studio, an open-source cross-platform IDE
* Copyright (C) 2003 Yiannis An. Mandravellos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact e-mail: Yiannis An. Mandravellos <mandrav@codeblocks.org>
* Program URL : http://www.codeblocks.org
*
* $Id: debuggergdb.cpp,v 1.62.2.1 2005/10/25 07:59:02 mandrav Exp $
* $Date: 2005/10/25 07:59:02 $
*/
#include <sdk.h>
#include <wx/txtstrm.h>
#include <wx/regex.h>
#include <wx/dialog.h>
#include <wx/msgdlg.h>
#include <wx/tokenzr.h>
#include <manager.h>
#include <configmanager.h>
#include <messagemanager.h>
#include <projectmanager.h>
#include <pluginmanager.h>
#include <editormanager.h>
#include <macrosmanager.h>
#include <projectbuildtarget.h>
#include <sdk_events.h>
#include <editarraystringdlg.h>
#include <compilerfactory.h>
#include <licenses.h>
#include <xtra_res.h>
#include <wx/xrc/xmlres.h>
#include <wx/fs_zip.h>
#include "debuggergdb.h"
#include "debuggeroptionsdlg.h"
#ifdef __WXMSW__
#include <winbase.h> //For GetShortPathName()...only for windows systems
#endif
#define implement_debugger_toolbar
// valid debugger command constants
#define CMD_CONTINUE 1
#define CMD_STEP 2
#define CMD_STEPIN 3
#define CMD_STOP 4
#define CMD_BACKTRACE 5
#define CMD_DISASSEMBLE 6
#define GDB_PROMPT _T("(gdb)")
static const wxString g_EscapeChars = wxChar(26);
int idMenuDebug = XRCID("idDebuggerMenuDebug");
int idMenuRunToCursor = XRCID("idDebuggerMenuRunToCursor");
int idMenuNext = XRCID("idDebuggerMenuNext");
int idMenuStep = XRCID("idDebuggerMenuStep");
int idMenuStepOut = XRCID("idDebuggerMenuStepOut");
int idMenuStop = XRCID("idDebuggerMenuStop");
int idMenuContinue = XRCID("idDebuggerMenuContinue");
int idMenuToggleBreakpoint = XRCID("idDebuggerMenuToggleBreakpoint");
int idMenuSendCommandToGDB = XRCID("idDebuggerMenuSendCommandToGDB");
int idMenuAddSymbolFile = XRCID("idDebuggerMenuAddSymbolFile");
int idMenuCPU = XRCID("idDebuggerMenuCPU");
int idMenuBacktrace = XRCID("idDebuggerMenuBacktrace");
int idMenuEditWatches = XRCID("idDebuggerMenuEditWatches");
int idGDBProcess = wxNewId();
int idTimerPollDebugger = wxNewId();
int idMenuDebuggerAddWatch = wxNewId();
CB_IMPLEMENT_PLUGIN(DebuggerGDB);
BEGIN_EVENT_TABLE(DebuggerGDB, cbDebuggerPlugin)
EVT_UPDATE_UI_RANGE(idMenuContinue, idMenuDebuggerAddWatch, DebuggerGDB::OnUpdateUI)
// these are different because they are loaded from the XRC
EVT_UPDATE_UI(XRCID("idDebuggerMenuDebug"), DebuggerGDB::OnUpdateUI)
EVT_UPDATE_UI(XRCID("idDebuggerMenuRunToCursor"), DebuggerGDB::OnUpdateUI)
EVT_UPDATE_UI(XRCID("idDebuggerMenuNext"), DebuggerGDB::OnUpdateUI)
EVT_UPDATE_UI(XRCID("idDebuggerMenuStep"), DebuggerGDB::OnUpdateUI)
EVT_UPDATE_UI(XRCID("idDebuggerMenuStepOut"), DebuggerGDB::OnUpdateUI)
EVT_UPDATE_UI(XRCID("idDebuggerMenuStop"), DebuggerGDB::OnUpdateUI)
EVT_MENU(idMenuDebug, DebuggerGDB::OnDebug)
EVT_MENU(idMenuContinue, DebuggerGDB::OnContinue)
EVT_MENU(idMenuNext, DebuggerGDB::OnNext)
EVT_MENU(idMenuStep, DebuggerGDB::OnStep)
EVT_MENU(idMenuStepOut, DebuggerGDB::OnStepOut)
EVT_MENU(idMenuToggleBreakpoint, DebuggerGDB::OnToggleBreakpoint)
EVT_MENU(idMenuRunToCursor, DebuggerGDB::OnRunToCursor)
EVT_MENU(idMenuStop, DebuggerGDB::OnStop)
EVT_MENU(idMenuSendCommandToGDB, DebuggerGDB::OnSendCommandToGDB)
EVT_MENU(idMenuAddSymbolFile, DebuggerGDB::OnAddSymbolFile)
EVT_MENU(idMenuBacktrace, DebuggerGDB::OnBacktrace)
EVT_MENU(idMenuCPU, DebuggerGDB::OnDisassemble)
EVT_MENU(idMenuEditWatches, DebuggerGDB::OnEditWatches)
EVT_MENU(idMenuDebuggerAddWatch, DebuggerGDB::OnAddWatch)
EVT_EDITOR_BREAKPOINT_ADDED(DebuggerGDB::OnBreakpointAdded)
EVT_EDITOR_BREAKPOINT_DELETED(DebuggerGDB::OnBreakpointDeleted)
EVT_EDITOR_TOOLTIP(DebuggerGDB::OnValueTooltip)
EVT_PIPEDPROCESS_STDOUT(idGDBProcess, DebuggerGDB::OnGDBOutput)
EVT_PIPEDPROCESS_STDERR(idGDBProcess, DebuggerGDB::OnGDBError)
EVT_PIPEDPROCESS_TERMINATED(idGDBProcess, DebuggerGDB::OnGDBTerminated)
EVT_IDLE(DebuggerGDB::OnIdle)
EVT_TIMER(idTimerPollDebugger, DebuggerGDB::OnTimer)
EVT_COMMAND(-1, cbCustom_WATCHES_CHANGED, DebuggerGDB::OnWatchesChanged)
END_EVENT_TABLE()
DebuggerGDB::DebuggerGDB()
: m_pMenu(0L),
m_pLog(0L),
m_pDbgLog(0L),
m_pProcess(0L),
m_pTbar(0L),
m_PageIndex(-1),
m_DbgPageIndex(-1),
m_ProgramIsStopped(true),
m_pCompiler(0L),
m_LastExitCode(0),
m_TargetIndex(-1),
m_Pid(0),
m_EvalWin(0L),
m_pTree(0L),
m_NoDebugInfo(false),
m_BreakOnEntry(false),
m_HaltAtLine(0),
m_HasDebugLog(false),
m_StoppedOnSignal(false),
m_pDisassembly(0),
m_pBacktrace(0)
{
Manager::Get()->Loadxrc(_T("/debugger_gdb.zip#zip:*.xrc"));
m_PluginInfo.name = _T("DebuggerGDB");
m_PluginInfo.title = _("GDB Debugger");
m_PluginInfo.version = _T("0.1");
m_PluginInfo.description = _("Plugin that interfaces the GNU GDB debugger.");
m_PluginInfo.author = _T("Yiannis An. Mandravellos");
m_PluginInfo.authorEmail = _T("info@codeblocks.org");
m_PluginInfo.authorWebsite = _T("www.codeblocks.org");
m_PluginInfo.thanksTo = _T("");
m_PluginInfo.license = LICENSE_GPL;
m_PluginInfo.hasConfigure = true;
m_TimerPollDebugger.SetOwner(this, idTimerPollDebugger);
ConfigManager::AddConfiguration(m_PluginInfo.title, _T("/debugger_gdb"));
}
void DebuggerGDB::OnAttach()
{
MessageManager* msgMan = Manager::Get()->GetMessageManager();
wxFont font(8, wxMODERN, wxNORMAL, wxNORMAL);
m_pLog = new SimpleTextLog(msgMan, _("Debugger"));
m_pLog->GetTextControl()->SetFont(font);
m_PageIndex = msgMan->AddLog(m_pLog);
// set log image
wxBitmap bmp;
wxString prefix = ConfigManager::Get()->Read(_T("data_path")) + _T("/images/");
bmp.LoadFile(prefix + _T("misc_16x16.png"), wxBITMAP_TYPE_PNG);
Manager::Get()->GetMessageManager()->SetLogImage(m_pLog, bmp);
m_HasDebugLog = ConfigManager::Get()->Read(_T("debugger_gdb/debug_log"), (long int)0L);
if (m_HasDebugLog)
{
m_pDbgLog = new SimpleTextLog(msgMan, m_PluginInfo.title + _(" (debug)"));
m_pDbgLog->GetTextControl()->SetFont(font);
m_DbgPageIndex = msgMan->AddLog(m_pDbgLog);
// set log image
bmp.LoadFile(prefix + _T("contents_16x16.png"), wxBITMAP_TYPE_PNG);
Manager::Get()->GetMessageManager()->SetLogImage(m_pDbgLog, bmp);
}
if (!m_pTree)
m_pTree = new DebuggerTree(this, Manager::Get()->GetNotebook());
}
void DebuggerGDB::OnRelease(bool appShutDown)
{
if (m_pDisassembly)
m_pDisassembly->Destroy();
m_pDisassembly = 0;
if (m_pBacktrace)
m_pBacktrace->Destroy();
m_pBacktrace = 0;
if (m_pTree)
{
delete m_pTree;
m_pTree = 0L;
}
//Close debug session when appShutDown
CmdStop();
if (Manager::Get()->GetMessageManager())
{
if (m_HasDebugLog)
Manager::Get()->GetMessageManager()->DeletePage(m_DbgPageIndex);
Manager::Get()->GetMessageManager()->DeletePage(m_PageIndex);
}
}
DebuggerGDB::~DebuggerGDB()
{
}
int DebuggerGDB::Configure()
{
DebuggerOptionsDlg dlg(Manager::Get()->GetAppWindow());
int ret = dlg.ShowModal();
bool needsRestart = ConfigManager::Get()->Read(_T("debugger_gdb/debug_log"), (long int)0L) != m_HasDebugLog;
if (needsRestart)
wxMessageBox(_("Code::Blocks needs to be restarted for the changes to take effect."), _("Information"), wxICON_INFORMATION);
return ret;
}
void DebuggerGDB::BuildMenu(wxMenuBar* menuBar)
{
if (!m_IsAttached)
return;
m_pMenu=Manager::Get()->LoadMenu(_T("debugger_menu"),true);
// ok, now, where do we insert?
// three possibilities here:
// a) locate "Compile" menu and insert after it
// b) locate "Project" menu and insert after it
// c) if not found (?), insert at pos 5
int finalPos = 5;
int projcompMenuPos = menuBar->FindMenu(_("&Build"));
if (projcompMenuPos == wxNOT_FOUND)
projcompMenuPos = menuBar->FindMenu(_("&Compile"));
if (projcompMenuPos != wxNOT_FOUND)
finalPos = projcompMenuPos + 1;
else
{
projcompMenuPos = menuBar->FindMenu(_("&Project"));
if (projcompMenuPos != wxNOT_FOUND)
finalPos = projcompMenuPos + 1;
}
menuBar->Insert(finalPos, m_pMenu, _("&Debug"));
}
void DebuggerGDB::BuildModuleMenu(const ModuleType type, wxMenu* menu, const wxString& arg)
{
cbProject* prj = Manager::Get()->GetProjectManager()->GetActiveProject();
if (!m_IsAttached)
return;
// we 're only interested in editor menus
// we 'll add a "debug watches" entry only when the debugger is running...
if (type != mtEditorManager || !menu) return;
if (!prj) return;
// Insert toggle breakpoint
menu->Insert(0,idMenuToggleBreakpoint, _("Toggle breakpoint"));
// Insert Run to Cursor
menu->Insert(1,idMenuRunToCursor, _("Run to cursor"));
menu->Insert(2,wxID_SEPARATOR, _T("-"));
if (!m_pProcess) return;
// has to have a word under the caret...
wxString w = GetEditorWordAtCaret();
if (w.IsEmpty())
return;
wxString s;
s.Printf(_("Watch '%s'"), w.c_str());
menu->Insert(2, idMenuDebuggerAddWatch, s);
}
bool DebuggerGDB::BuildToolBar(wxToolBar* toolBar)
{
m_pTbar = toolBar;
/* Loads toolbar using new Manager class functions */
#ifdef implement_debugger_toolbar
if (!m_IsAttached || !toolBar)
return false;
wxString my_16x16=Manager::isToolBar16x16(toolBar) ? _T("_16x16") : _T("");
Manager::AddonToolBar(toolBar,wxString(_T("debugger_toolbar"))+my_16x16);
toolBar->Realize();
return true;
#else
return false;
#endif
}
void DebuggerGDB::DoWatches()
{
wxString info;
if (m_pProcess)
{
if (ConfigManager::Get()->Read(_T("debugger_gdb/watch_args"), 1))
info << _T("Function Arguments = {") << GetInfoFor(_T("info args")) << _T("}") << _T('\n');
if (ConfigManager::Get()->Read(_T("debugger_gdb/watch_locals"), 1))
info << _T("Local variables = {") << GetInfoFor(_T("info locals")) << _T("}") << _T('\n');
for (unsigned int i = 0; i < m_pTree->GetWatches().GetCount(); ++i)
{
wxString watch = m_pTree->GetWatches()[i];
info << watch << _T("{") << GetInfoFor(_T("output ") + watch) << _T("}") << _T('\n');
}
}
else
{
// since no debugging session is active, we might as well show
// the not-evaluated user-watches, just for feedback ;)
for (unsigned int i = 0; i < m_pTree->GetWatches().GetCount(); ++i)
{
info << m_pTree->GetWatches()[i] << _T(',');
}
}
//m_pLog->AddLog(info);
m_pTree->BuildTree(info);
}
void DebuggerGDB::SetBreakpoints()
{
SendCommand(_T("delete")); // clear all breakpoints
cbProject* prj = Manager::Get()->GetProjectManager()->GetActiveProject();
if (prj)
{
for (int i = 0; i < prj->GetFilesCount(); ++i)
{
ProjectFile* pf = prj->GetFile(i);
for (unsigned int x = 0; x < pf->breakpoints.GetCount(); ++x)
{
DebuggerBreakpoint* bp = pf->breakpoints[x];
wxString filename = pf->file.GetFullName();
wxString cmd;
if (bp->enabled)
{
if (bp->func.IsEmpty())
{
cmd << _T("break ") << filename << _T(":") << bp->line + 1;
SendCommand(cmd);
}
//GDB workaround
//Use function name if this is C++ constructor/destructor
else
{
cmd << _T("break ") << bp->func;
GetInfoFor(cmd);
}
//end GDB workaround
}
//SendCommand(cmd);
}
}
}
}
int DebuggerGDB::Debug()
{
if (m_pProcess)
return 1;
m_NoDebugInfo = false;
ProjectManager* prjMan = Manager::Get()->GetProjectManager();
cbProject* project = prjMan->GetActiveProject();
if (!project)
return 2;
MessageManager* msgMan = Manager::Get()->GetMessageManager();
msgMan->SwitchTo(m_PageIndex);
m_pLog->GetTextControl()->Clear();
m_TargetIndex = project->GetActiveBuildTarget();
msgMan->SwitchTo(m_PageIndex);
msgMan->AppendLog(m_PageIndex, _("Selecting target: "));
if (m_TargetIndex == -1)
{
m_TargetIndex = project->SelectTarget(m_TargetIndex);
if (m_TargetIndex == -1)
{
msgMan->Log(m_PageIndex, _("canceled"));
return 3;
}
}
ProjectBuildTarget* target = project->GetBuildTarget(m_TargetIndex);
if (target->GetTargetType() == ttCommandsOnly)
{
wxMessageBox(_("The selected target is only running pre/post build step commands\n"
"Can't debug such a target..."), _("Information"), wxICON_INFORMATION);
msgMan->Log(m_PageIndex, _("aborted"));
return 3;
}
msgMan->Log(m_PageIndex, target->GetTitle());
Compiler* actualCompiler = CompilerFactory::Compilers[target ? target->GetCompilerIndex() : project->GetCompilerIndex()];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -