KDevelop API Documentation

languages/cpp/debugger/debuggerpart.cpp

Go to the documentation of this file.
00001 /*************************************************************************** 00002 * Copyright (C) 1999-2001 by John Birch * 00003 * jbb@kdevelop.org * 00004 * Copyright (C) 2001 by Bernd Gehrmann * 00005 * bernd@kdevelop.org * 00006 * * 00007 * This program is free software; you can redistribute it and/or modify * 00008 * it under the terms of the GNU General Public License as published by * 00009 * the Free Software Foundation; either version 2 of the License, or * 00010 * (at your option) any later version. * 00011 * * 00012 ***************************************************************************/ 00013 00014 #include <qdir.h> 00015 #include <qvbox.h> 00016 #include <qwhatsthis.h> 00017 #include <qpopupmenu.h> 00018 00019 #include <kaction.h> 00020 #include <kdebug.h> 00021 #include <kfiledialog.h> 00022 #include <kdevgenericfactory.h> 00023 #include <kiconloader.h> 00024 #include <klocale.h> 00025 #include <kmainwindow.h> 00026 #include <kstatusbar.h> 00027 #include <kparts/part.h> 00028 #include <ktexteditor/viewcursorinterface.h> 00029 #include <kmessagebox.h> 00030 #include <kapplication.h> 00031 #include <dcopclient.h> 00032 #include <qtimer.h> 00033 00034 #include "kdevcore.h" 00035 #include "kdevproject.h" 00036 #include "kdevmainwindow.h" 00037 #include "kdevappfrontend.h" 00038 #include "kdevpartcontroller.h" 00039 #include "kdevdebugger.h" 00040 #include "domutil.h" 00041 #include "variablewidget.h" 00042 #include "gdbbreakpointwidget.h" 00043 #include "framestackwidget.h" 00044 #include "disassemblewidget.h" 00045 #include "processwidget.h" 00046 #include "gdbcontroller.h" 00047 #include "breakpoint.h" 00048 #include "dbgpsdlg.h" 00049 #include "dbgtoolbar.h" 00050 #include "memviewdlg.h" 00051 #include "gdbparser.h" 00052 #include "gdboutputwidget.h" 00053 #include "debuggerconfigwidget.h" 00054 #include "processlinemaker.h" 00055 00056 #include <iostream> 00057 00058 #include "debuggerpart.h" 00059 00060 namespace GDBDebugger 00061 { 00062 00063 static const KAboutData data("kdevdebugger", I18N_NOOP("Debugger"), "1.0"); 00064 00065 typedef KDevGenericFactory<DebuggerPart> DebuggerFactory; 00066 K_EXPORT_COMPONENT_FACTORY( libkdevdebugger, DebuggerFactory( &data ) ) 00067 00068 DebuggerPart::DebuggerPart( QObject *parent, const char *name, const QStringList & ) : 00069 KDevPlugin( "CppDebugger", "debugger", parent, name ? name : "DebuggerPart" ), 00070 controller(0) 00071 { 00072 setObjId("DebuggerInterface"); 00073 setInstance(DebuggerFactory::instance()); 00074 00075 setXMLFile("kdevdebugger.rc"); 00076 00077 statusBarIndicator = new QLabel(" ", mainWindow()->statusBar()); 00078 statusBarIndicator->setFixedWidth(15); 00079 mainWindow()->statusBar()->addWidget(statusBarIndicator, 0, true); 00080 statusBarIndicator->show(); 00081 00082 // Setup widgets and dbgcontroller 00083 variableWidget = new VariableWidget(); 00084 variableWidget->setEnabled(false); 00085 variableWidget->setIcon(SmallIcon("math_brace")); 00086 variableWidget->setCaption(i18n("Variable Tree")); 00087 QWhatsThis::add 00088 (variableWidget, i18n("<b>Variable tree</b><p>" 00089 "The variable tree allows you to see " 00090 "the variable values as you step " 00091 "through your program using the internal " 00092 "debugger. Click the RMB on items in " 00093 "this view to get a popup menu.\n" 00094 "To speed up stepping through your code " 00095 "leave the tree items closed and add the " 00096 "variable(s) to the watch section.\n" 00097 "To change a variable value in your " 00098 "running app use a watch variable (eg a=5).")); 00099 mainWindow()->embedSelectView(variableWidget, i18n("Variables / Watch"), i18n("Debugger variable-view")); 00100 mainWindow()->setViewAvailable(variableWidget, false); 00101 00102 gdbBreakpointWidget = new GDBBreakpointWidget(); 00103 gdbBreakpointWidget->setCaption(i18n("Breakpoint List")); 00104 QWhatsThis::add 00105 (gdbBreakpointWidget, i18n("<b>Breakpoint list</b><p>" 00106 "Displays a list of breakpoints with " 00107 "their current status. Clicking on a " 00108 "breakpoint item allows you to change " 00109 "the breakpoint and will take you " 00110 "to the source in the editor window.")); 00111 gdbBreakpointWidget->setIcon( SmallIcon("stop") ); 00112 mainWindow()->embedOutputView(gdbBreakpointWidget, i18n("Breakpoints"), i18n("Debugger breakpoints")); 00113 00114 framestackWidget = new FramestackWidget(); 00115 framestackWidget->setEnabled(false); 00116 framestackWidget->setCaption(i18n("Frame Stack")); 00117 QWhatsThis::add 00118 (framestackWidget, i18n("<b>Frame stack</b><p>" 00119 "Often referred to as the \"call stack\", " 00120 "this is a list showing what function is " 00121 "currently active and who called each " 00122 "function to get to this point in your " 00123 "program. By clicking on an item you " 00124 "can see the values in any of the " 00125 "previous calling functions.")); 00126 framestackWidget->setIcon( SmallIcon("table") ); 00127 mainWindow()->embedOutputView(framestackWidget, i18n("Frame Stack"), i18n("Debugger function call stack")); 00128 mainWindow()->setViewAvailable(framestackWidget, false); 00129 00130 disassembleWidget = new DisassembleWidget(); 00131 disassembleWidget->setEnabled(false); 00132 disassembleWidget->setCaption(i18n("Machine Code Display")); 00133 QWhatsThis::add 00134 (disassembleWidget, i18n("<b>Machine code display</b><p>" 00135 "A machine code view into your running " 00136 "executable with the current instruction " 00137 "highlighted. You can step instruction by " 00138 "instruction using the debuggers toolbar " 00139 "buttons of \"step over\" instruction and " 00140 "\"step into\" instruction.")); 00141 disassembleWidget->setIcon( SmallIcon("gear") ); 00142 mainWindow()->embedOutputView(disassembleWidget, i18n("Disassemble"), 00143 i18n("Debugger disassemble view")); 00144 mainWindow()->setViewAvailable(disassembleWidget, false); 00145 00146 gdbOutputWidget = new GDBOutputWidget; 00147 gdbOutputWidget->setEnabled(false); 00148 gdbOutputWidget->setIcon( SmallIcon("inline_image") ); 00149 QWhatsThis::add 00150 (gdbOutputWidget, i18n("<b>GDB output</b><p>" 00151 "Shows all gdb commands being executed. " 00152 "You can also issue any other gdb command while debugging.")); 00153 mainWindow()->embedOutputView(gdbOutputWidget, i18n("GDB"), 00154 i18n("GDB output")); 00155 mainWindow()->setViewAvailable(gdbOutputWidget, false); 00156 00157 VariableTree *variableTree = variableWidget->varTree(); 00158 00159 // variableTree -> framestackWidget 00160 connect( variableTree, SIGNAL(selectFrame(int, int)), 00161 framestackWidget, SLOT(slotSelectFrame(int, int))); 00162 00163 // gdbBreakpointWidget -> this 00164 connect( gdbBreakpointWidget, SIGNAL(refreshBPState(const Breakpoint&)), 00165 this, SLOT(slotRefreshBPState(const Breakpoint&))); 00166 connect( gdbBreakpointWidget, SIGNAL(publishBPState(const Breakpoint&)), 00167 this, SLOT(slotRefreshBPState(const Breakpoint&))); 00168 connect( gdbBreakpointWidget, SIGNAL(gotoSourcePosition(const QString&, int)), 00169 this, SLOT(slotGotoSource(const QString&, int)) ); 00170 00171 // Now setup the actions 00172 KAction *action; 00173 00174 action = new KAction(i18n("&Start"), "1rightarrow", CTRL+SHIFT+Key_F9, 00175 this, SLOT(slotRun()), 00176 actionCollection(), "debug_run"); 00177 action->setToolTip( i18n("Start in debugger") ); 00178 action->setWhatsThis( i18n("<b>Start in debugger</b><p>" 00179 "Starts the debugger with the project's main " 00180 "executable. You may set some breakpoints " 00181 "before this, or you can interrupt the program " 00182 "while it is running, in order to get information " 00183 "about variables, frame stack, and so on.") ); 00184 00185 action = new KAction(i18n("Sto&p"), "stop", 0, 00186 this, SLOT(slotStop()), 00187 actionCollection(), "debug_stop"); 00188 action->setToolTip( i18n("Stop debugger") ); 00189 action->setWhatsThis(i18n("<b>Stop debugger</b><p>Kills the executable and exits the debugger.")); 00190 00191 action = new KAction(i18n("Interrupt"), "player_pause", 0, 00192 this, SLOT(slotPause()), 00193 actionCollection(), "debug_pause"); 00194 action->setToolTip( i18n("Interrupt application") ); 00195 action->setWhatsThis(i18n("<b>Interrupt application</b><p>Interrupts the debugged process or current GDB command.")); 00196 00197 action = new KAction(i18n("Run to &Cursor"), "dbgrunto", 0, 00198 this, SLOT(slotRunToCursor()), 00199 actionCollection(), "debug_runtocursor"); 00200 action->setToolTip( i18n("Run to cursor") ); 00201 action->setWhatsThis(i18n("<b>Run to cursor</b><p>Continues execution until the cursor position is reached.")); 00202 00203 00204 action = new KAction(i18n("Step &Over"), "dbgnext", 0, 00205 this, SLOT(slotStepOver()), 00206 actionCollection(), "debug_stepover"); 00207 action->setToolTip( i18n("Step over the next line") ); 00208 action->setWhatsThis( i18n("<b>Step over</b><p>" 00209 "Executes one line of source in the current source file. " 00210 "If the source line is a call to a function the whole " 00211 "function is executed and the app will stop at the line " 00212 "following the function call.") ); 00213 00214 00215 action = new KAction(i18n("Step over Ins&truction"), "dbgnextinst", 0, 00216 this, SLOT(slotStepOverInstruction()), 00217 actionCollection(), "debug_stepoverinst"); 00218 action->setToolTip( i18n("Step over instruction") ); 00219 action->setWhatsThis(i18n("<b>Step over instruction</b><p>Steps over the next assembly instruction.")); 00220 00221 00222 action = new KAction(i18n("Step &Into"), "dbgstep", 0, 00223 this, SLOT(slotStepInto()), 00224 actionCollection(), "debug_stepinto"); 00225 action->setToolTip( i18n("Step into the next statement") ); 00226 action->setWhatsThis( i18n("<b>Step into</b><p>" 00227 "Executes exactly one line of source. If the source line " 00228 "is a call to a function then execution will stop after " 00229 "the function has been entered.") ); 00230 00231 00232 action = new KAction(i18n("Step into I&nstruction"), "dbgstepinst", 0, 00233 this, SLOT(slotStepIntoInstruction()), 00234 actionCollection(), "debug_stepintoinst"); 00235 action->setToolTip( i18n("Step into instruction") ); 00236 action->setWhatsThis(i18n("<b>Step into instruction</b><p>Steps into the next assembly instruction.")); 00237 00238 00239 action = new KAction(i18n("Step O&ut"), "dbgstepout", 0, 00240 this, SLOT(slotStepOut()), 00241 actionCollection(), "debug_stepout"); 00242 action->setToolTip( i18n("Steps out of the current function") ); 00243 action->setWhatsThis( i18n("<b>Step out</b><p>" 00244 "Executes the application until the currently executing " 00245 "function is completed. The debugger will then display " 00246 "the line after the original call to that function. If " 00247 "program execution is in the outermost frame (i.e. in " 00248 "main()) then this operation has no effect.") ); 00249 00250 00251 action = new KAction(i18n("Viewers"), "dbgmemview", 0, 00252 this, SLOT(slotMemoryView()), 00253 actionCollection(), "debug_memview"); 00254 action->setToolTip( i18n("Debugger viewers") ); 00255 action->setWhatsThis(i18n("<b>Debugger viewers</b><p>Various information about application being executed. There are 4 views available:<br>" 00256 "<b>Memory</b><br>" 00257 "<b>Disassemble</b><br>" 00258 "<b>Registers</b><br>" 00259 "<b>Libraries</b>")); 00260 00261 00262 action = new KAction(i18n("Examine Core File"), "core", 0, 00263 this, SLOT(slotExamineCore()), 00264 actionCollection(), "debug_core"); 00265 action->setToolTip( i18n("Examine core file") ); 00266 action->setWhatsThis( i18n("<b>Examine core file</b><p>" 00267 "This loads a core file, which is typically created " 00268 "after the application has crashed, e.g. with a " 00269 "segmentation fault. The core file contains an " 00270 "image of the program memory at the time it crashed, " 00271 "allowing you to do a post-mortem analysis.") ); 00272 00273 00274 action = new KAction(i18n("Attach to Process"), "connect_creating", 0, 00275 this, SLOT(slotAttachProcess()), 00276 actionCollection(), "debug_attach"); 00277 action->setToolTip( i18n("Attach to process") ); 00278 action->setWhatsThis(i18n("<b>Attach to process</b><p>Attaches the debugger to a running process.")); 00279 00280 action = new KAction(i18n("Toggle Breakpoint"), 0, 0, 00281 this, SLOT(toggleBreakpoint()), 00282 actionCollection(), "debug_toggle_breakpoint"); 00283 action->setToolTip(i18n("Toggle breakpoint")); 00284 action->setWhatsThis(i18n("<b>Toggle breakpoint</b><p>Toggles the breakpoint at the current line in editor.")); 00285 00286 connect( mainWindow()->main()->guiFactory(), SIGNAL(clientAdded(KXMLGUIClient*)), 00287 this, SLOT(guiClientAdded(KXMLGUIClient*)) ); 00288 00289 connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)), 00290 this, SLOT(projectConfigWidget(KDialogBase*)) ); 00291 00292 connect( partController(), SIGNAL(loadedFile(const QString &)), 00293 gdbBreakpointWidget, SLOT(slotRefreshBP(const QString &)) ); 00294 connect( debugger(), SIGNAL(toggledBreakpoint(const QString &, int)), 00295 gdbBreakpointWidget, SLOT(slotToggleBreakpoint(const QString &, int)) ); 00296 connect( debugger(), SIGNAL(editedBreakpoint(const QString &, int)), 00297 gdbBreakpointWidget, SLOT(slotEditBreakpoint(const QString &, int)) ); 00298 connect( debugger(), SIGNAL(toggledBreakpointEnabled(const QString &, int)), 00299 gdbBreakpointWidget, SLOT(slotToggleBreakpointEnabled(const QString &, int)) ); 00300 00301 connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)), 00302 this, SLOT(contextMenu(QPopupMenu *, const Context *)) ); 00303 00304 connect( core(), SIGNAL(stopButtonClicked(KDevPlugin*)), 00305 this, SLOT(slotStop(KDevPlugin*)) ); 00306 connect( core(), SIGNAL(projectClosed()), 00307 this, SLOT(projectClosed()) ); 00308 00309 connect( partController(), SIGNAL(activePartChanged(KParts::Part*)), 00310 this, SLOT(slotActivePartChanged(KParts::Part*)) ); 00311 00312 procLineMaker = new ProcessLineMaker(); 00313 00314 connect( procLineMaker, SIGNAL(receivedStdoutLine(const QString&)), 00315 appFrontend(), SLOT(insertStdoutLine(const QString&)) ); 00316 connect( procLineMaker, SIGNAL(receivedStderrLine(const QString&)), 00317 appFrontend(), SLOT(insertStderrLine(const QString&)) ); 00318 00319 setupController(); 00320 00321 QCStringList objects = kapp->dcopClient()->registeredApplications(); 00322 for (QCStringList::Iterator it = objects.begin(); it != objects.end(); ++it) 00323 if ((*it).find("drkonqi-") == 0) 00324 slotDCOPApplicationRegistered(*it); 00325 00326 connect(kapp->dcopClient(), SIGNAL(applicationRegistered(const QCString&)), SLOT(slotDCOPApplicationRegistered(const QCString&))); 00327 kapp->dcopClient()->setNotifications(true); 00328 } 00329 00330 void DebuggerPart::slotDCOPApplicationRegistered(const QCString& appId) 00331 { 00332 if (appId.find("drkonqi-") == 0) { 00333 QByteArray answer; 00334 QCString replyType; 00335 00336 #if defined(KDE_MAKE_VERSION) 00337 # if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90) 00338 kapp->dcopClient()->call(appId, "krashinfo", "appName()", QByteArray(), replyType, answer, true, 5000); 00339 # else 00340 kapp->dcopClient()->call(appId, "krashinfo", "appName()", QByteArray(), replyType, answer, true); 00341 # endif 00342 #else 00343 kapp->dcopClient()->call(appId, "krashinfo", "appName()", QByteArray(), replyType, answer, true); 00344 #endif 00345 00346 QDataStream d(answer, IO_ReadOnly); 00347 QCString appName; 00348 d >> appName; 00349 00350 if (appName.length() && project() && project()->mainProgram().endsWith(appName)) { 00351 kapp->dcopClient()->send(appId, "krashinfo", "registerDebuggingApplication(QString)", i18n("Debug in &KDevelop")); 00352 connectDCOPSignal(appId, "krashinfo", "acceptDebuggingApplication()", "slotDebugExternalProcess()", true); 00353 } 00354 } 00355 } 00356 00357 ASYNC DebuggerPart::slotDebugExternalProcess() 00358 { 00359 QByteArray answer; 00360 QCString replyType; 00361 00362 #if defined(KDE_MAKE_VERSION) 00363 # if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90) 00364 kapp->dcopClient()->call(kapp->dcopClient()->senderId(), "krashinfo", "pid()", QByteArray(), replyType, answer, true, 5000); 00365 # else 00366 kapp->dcopClient()->call(kapp->dcopClient()->senderId(), "krashinfo", "pid()", QByteArray(), replyType, answer, true); 00367 # endif 00368 #else 00369 kapp->dcopClient()->call(kapp->dcopClient()->senderId(), "krashinfo", "pid()", QByteArray(), replyType, answer, true); 00370 #endif 00371 00372 QDataStream d(answer, IO_ReadOnly); 00373 int pid; 00374 d >> pid; 00375 00376 if (attachProcess(pid) && m_drkonqi.isEmpty()) { 00377 m_drkonqi = kapp->dcopClient()->senderId(); 00378 QTimer::singleShot(15000, this, SLOT(slotCloseDrKonqi())); 00379 mainWindow()->raiseView(framestackWidget); 00380 } 00381 00382 mainWindow()->main()->raise(); 00383 } 00384 00385 void DebuggerPart::slotCloseDrKonqi() 00386 { 00387 kapp->dcopClient()->send(m_drkonqi, "MainApplication-Interface", "quit()", QByteArray()); 00388 m_drkonqi = ""; 00389 } 00390 00391 DebuggerPart::~DebuggerPart() 00392 { 00393 kapp->dcopClient()->setNotifications(false); 00394 00395 if (variableWidget) 00396 mainWindow()->removeView(variableWidget); 00397 if (gdbBreakpointWidget) 00398 mainWindow()->removeView(gdbBreakpointWidget); 00399 if (framestackWidget) 00400 mainWindow()->removeView(framestackWidget); 00401 if (disassembleWidget) 00402 mainWindow()->removeView(disassembleWidget); 00403 if(gdbOutputWidget) 00404 mainWindow()->removeView(gdbOutputWidget); 00405 00406 delete variableWidget; 00407 delete gdbBreakpointWidget; 00408 delete framestackWidget; 00409 delete disassembleWidget; 00410 delete gdbOutputWidget; 00411 delete controller; 00412 delete floatingToolBar; 00413 delete statusBarIndicator; 00414 delete procLineMaker; 00415 00416 GDBParser::destroy(); 00417 } 00418 00419 00420 void DebuggerPart::guiClientAdded( KXMLGUIClient* client ) 00421 { 00422 // Can't change state until after XMLGUI has been loaded... 00423 // Anyone know of a better way of doing this? 00424 if( client == this ) 00425 stateChanged( QString("stopped") ); 00426 } 00427 00428 void DebuggerPart::contextMenu(QPopupMenu *popup, const Context *context) 00429 { 00430 if (!context->hasType( Context::EditorContext )) 00431 return; 00432 00433 const EditorContext *econtext = static_cast<const EditorContext*>(context); 00434 m_contextIdent = econtext->currentWord(); 00435 00436 popup->insertSeparator(); 00437 if (econtext->url().isLocalFile()) 00438 { 00439 int id = popup->insertItem( i18n("Toggle Breakpoint"), this, SLOT(toggleBreakpoint()) ); 00440 popup->setWhatsThis(id, i18n("<b>Toggle breakpoint</b><p>Toggles breakpoint at the current line.")); 00441 } 00442 if (!m_contextIdent.isEmpty()) 00443 { 00444 int id = popup->insertItem( i18n("Watch: %1").arg(m_contextIdent), this, SLOT(contextWatch()) ); 00445 popup->setWhatsThis(id, i18n("<b>Toggle breakpoint</b><p>Adds an expression under the cursor to the Variables/Watch list.")); 00446 } 00447 } 00448 00449 00450 void DebuggerPart::toggleBreakpoint() 00451 { 00452 KParts::ReadWritePart *rwpart 00453 = dynamic_cast<KParts::ReadWritePart*>(partController()->activePart()); 00454 KTextEditor::ViewCursorInterface *cursorIface 00455 = dynamic_cast<KTextEditor::ViewCursorInterface*>(partController()->activeWidget()); 00456 00457 if (!rwpart || !cursorIface) 00458 return; 00459 00460 uint line, col; 00461 cursorIface->cursorPositionReal(&line, &col); 00462 00463 gdbBreakpointWidget->slotToggleBreakpoint(rwpart->url().path(), line); 00464 } 00465 00466 00467 void DebuggerPart::contextWatch() 00468 { 00469 variableWidget->slotAddWatchVariable(m_contextIdent); 00470 } 00471 00472 00473 void DebuggerPart::projectConfigWidget(KDialogBase *dlg) 00474 { 00475 QVBox *vbox = dlg->addVBoxPage(i18n("Debugger")); 00476 DebuggerConfigWidget *w = new DebuggerConfigWidget(this, vbox, "debugger config widget"); 00477 connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) ); 00478 connect( dlg, SIGNAL(finished()), controller, SLOT(configure()) ); 00479 } 00480 00481 00482 void DebuggerPart::setupController() 00483 { 00484 VariableTree *variableTree = variableWidget->varTree(); 00485 00486 controller = new GDBController(variableTree, framestackWidget, *projectDom()); 00487 00488 // variableTree -> controller 00489 connect( variableTree, SIGNAL(expandItem(TrimmableItem*)), 00490 controller, SLOT(slotExpandItem(TrimmableItem*))); 00491 connect( variableTree, SIGNAL(expandUserItem(VarItem*, const QCString&)), 00492 controller, SLOT(slotExpandUserItem(VarItem*, const QCString&))); 00493 connect( variableTree, SIGNAL(setLocalViewState(bool)), 00494 controller, SLOT(slotSetLocalViewState(bool))); 00495 connect( variableTree, SIGNAL(varItemConstructed(VarItem*)), 00496 controller, SLOT(slotVarItemConstructed(VarItem*))); // jw 00497 00498 // variableTree -> gdbBreakpointWidget 00499 connect( variableTree, SIGNAL(toggleWatchpoint(const QString &)), 00500 gdbBreakpointWidget, SLOT(slotToggleWatchpoint(const QString &))); 00501 00502 // framestackWidget -> controller 00503 connect( framestackWidget, SIGNAL(selectFrame(int,int,bool)), 00504 controller, SLOT(slotSelectFrame(int,int,bool))); 00505 00506 // gdbBreakpointWidget -> controller 00507 connect( gdbBreakpointWidget, SIGNAL(clearAllBreakpoints()), 00508 controller, SLOT(slotClearAllBreakpoints())); 00509 connect( gdbBreakpointWidget, SIGNAL(publishBPState(const Breakpoint&)), 00510 controller, SLOT(slotBPState(const Breakpoint &))); 00511 00512 // disassembleWidget -> controller 00513 connect( disassembleWidget, SIGNAL(disassemble(const QString&, const QString&)), 00514 controller, SLOT(slotDisassemble(const QString&, const QString&))); 00515 00516 // gdbOutputWidget -> controller 00517 connect( gdbOutputWidget, SIGNAL(userGDBCmd(const QString &)), 00518 controller, SLOT(slotUserGDBCmd(const QString&))); 00519 connect( gdbOutputWidget, SIGNAL(breakInto()), 00520 controller, SLOT(slotBreakInto())); 00521 00522 // controller -> gdbBreakpointWidget 00523 connect( controller, SIGNAL(acceptPendingBPs()), 00524 gdbBreakpointWidget, SLOT(slotSetPendingBPs())); 00525 connect( controller, SIGNAL(unableToSetBPNow(int)), 00526 gdbBreakpointWidget, SLOT(slotUnableToSetBPNow(int))); 00527 connect( controller, SIGNAL(rawGDBBreakpointList (char*)), 00528 gdbBreakpointWidget, SLOT(slotParseGDBBrkptList(char*))); 00529 connect( controller, SIGNAL(rawGDBBreakpointSet(char*, int)), 00530 gdbBreakpointWidget, SLOT(slotParseGDBBreakpointSet(char*, int))); 00531 00532 // controller -> disassembleWidget 00533 connect( controller, SIGNAL(showStepInSource(const QString&, int, const QString&)), 00534 disassembleWidget, SLOT(slotShowStepInSource(const QString&, int, const QString&))); 00535 connect( controller, SIGNAL(rawGDBDisassemble(char*)), 00536 disassembleWidget, SLOT(slotDisassemble(char*))); 00537 00538 // controller -> this 00539 connect( controller, SIGNAL(dbgStatus(const QString&, int)), 00540 this, SLOT(slotStatus(const QString&, int))); 00541 connect( controller, SIGNAL(showStepInSource(const QString&, int, const QString&)), 00542 this, SLOT(slotShowStep(const QString&, int))); 00543 00544 // controller -> procLineMaker 00545 connect( controller, SIGNAL(ttyStdout(const char*)), 00546 procLineMaker, SLOT(slotReceivedStdout(const char*))); 00547 connect( controller, SIGNAL(ttyStderr(const char*)), 00548 procLineMaker, SLOT(slotReceivedStderr(const char*))); 00549 00550 // controller -> gdbOutputWidget 00551 connect( controller, SIGNAL(gdbStdout(const char*)), 00552 gdbOutputWidget, SLOT(slotReceivedStdout(const char*)) ); 00553 connect( controller, SIGNAL(gdbStderr(const char*)), 00554 gdbOutputWidget, SLOT(slotReceivedStderr(const char*)) ); 00555 connect( controller, SIGNAL(dbgStatus(const QString&, int)), 00556 gdbOutputWidget, SLOT(slotDbgStatus(const QString&, int))); 00557 00558 // gdbBreakpointWidget -> disassembleWidget 00559 connect( gdbBreakpointWidget, SIGNAL(publishBPState(const Breakpoint&)), 00560 disassembleWidget, SLOT(slotBPState(const Breakpoint &))); 00561 } 00562 00563 00564 bool DebuggerPart::startDebugger() 00565 { 00566 QString build_dir; // Currently selected build directory 00567 DomUtil::PairList run_envvars; // List with the environment variables 00568 QString run_directory; // Directory from where the program should be run 00569 QString program; // Absolute path to application 00570 QString run_arguments; // Command line arguments to be passed to the application 00571 00572 if (project()) { 00573 build_dir = project()->buildDirectory(); 00574 run_envvars = project()->runEnvironmentVars(); 00575 run_directory = project()->runDirectory(); 00576 program = project()->mainProgram(); 00577 run_arguments = project()->runArguments(); 00578 } 00579 00580 QString shell = DomUtil::readEntry(*projectDom(), "/kdevdebugger/general/dbgshell"); 00581 if( !shell.isEmpty() ) 00582 { 00583 QFileInfo info( shell ); 00584 if( info.isRelative() ) 00585 { 00586 shell = build_dir + "/" + shell; 00587 info.setFile( shell ); 00588 } 00589 if( !info.exists() ) 00590 { 00591 KMessageBox::error( 00592 mainWindow()->main(), 00593 i18n("Could not locate the debugging shell '%1'.").arg( shell ), 00594 i18n("Debugging shell not found.") ); 00595 return false; 00596 } 00597 } 00598 00599 core()->running(this, true); 00600 00601 stateChanged( QString("active") ); 00602 00603 KActionCollection *ac = actionCollection(); 00604 ac->action("debug_run")->setText( i18n("&Continue") ); 00605 ac->action("debug_run")->setIcon( "dbgrun" ); 00606 ac->action("debug_run")->setStatusText( i18n("Continues the application execution") ); 00607 ac->action("debug_run")->setWhatsThis( i18n("Continue application execution\n\n" 00608 "Continues the execution of your application in the " 00609 "debugger. This only takes effect when the application " 00610 "has been halted by the debugger (i.e. a breakpoint has " 00611 "been activated or the interrupt was pressed).") ); 00612 00613 00614 mainWindow()->setViewAvailable(variableWidget, true); 00615 mainWindow()->setViewAvailable(framestackWidget, true); 00616 mainWindow()->setViewAvailable(disassembleWidget, true); 00617 mainWindow()->setViewAvailable(gdbOutputWidget, true); 00618 00619 variableWidget->setEnabled(true); 00620 framestackWidget->setEnabled(true); 00621 disassembleWidget->setEnabled(true); 00622 00623 gdbOutputWidget->clear(); 00624 gdbOutputWidget->setEnabled(true); 00625 00626 if (DomUtil::readBoolEntry(*projectDom(), "/kdevdebugger/general/floatingtoolbar", true)) 00627 { 00628 floatingToolBar = new DbgToolBar(this, mainWindow()->main()); 00629 floatingToolBar->show(); 00630 } 00631 00632 controller->slotStart(shell, run_envvars, run_directory, program, run_arguments); 00633 return true; 00634 } 00635 00636 void DebuggerPart::slotStopDebugger() 00637 { 00638 controller->slotStopDebugger(); 00639 debugger()->clearExecutionPoint(); 00640 00641 delete floatingToolBar; 00642 floatingToolBar = 0; 00643 00644 gdbBreakpointWidget->reset(); 00645 framestackWidget->clear(); 00646 variableWidget->clear(); 00647 disassembleWidget->clear(); 00648 disassembleWidget->slotActivate(false); 00649 00650 variableWidget->setEnabled(false); 00651 framestackWidget->setEnabled(false); 00652 disassembleWidget->setEnabled(false); 00653 gdbOutputWidget->setEnabled(false); 00654 00655 mainWindow()->setViewAvailable(variableWidget, false); 00656 mainWindow()->setViewAvailable(framestackWidget, false); 00657 mainWindow()->setViewAvailable(disassembleWidget, false); 00658 mainWindow()->setViewAvailable(gdbOutputWidget, false); 00659 00660 KActionCollection *ac = actionCollection(); 00661 ac->action("debug_run")->setText( i18n("&Start") ); 00662 ac->action("debug_run")->setIcon( "1rightarrow" ); 00663 ac->action("debug_run")->setStatusText( i18n("Runs the program in the debugger") ); 00664 ac->action("debug_run")->setWhatsThis( i18n("Start in debugger\n\n" 00665 "Starts the debugger with the project's main " 00666 "executable. You may set some breakpoints " 00667 "before this, or you can interrupt the program " 00668 "while it is running, in order to get information " 00669 "about variables, frame stack, and so on.") ); 00670 00671 stateChanged( QString("stopped") ); 00672 00673 core()->running(this, false); 00674 } 00675 00676 void DebuggerPart::projectClosed() 00677 { 00678 slotStopDebugger(); 00679 } 00680 00681 void DebuggerPart::slotRun() 00682 { 00683 if( controller->stateIsOn( s_dbgNotStarted ) ) 00684 { 00685 mainWindow()->statusBar()->message(i18n("Debugging program"), 1000); 00686 mainWindow()->raiseView(gdbOutputWidget); 00687 appFrontend()->clearView(); 00688 startDebugger(); 00689 } 00690 else 00691 { 00692 mainWindow()->statusBar()->message(i18n("Continuing program"), 1000); 00693 } 00694 controller->slotRun(); 00695 } 00696 00697 00698 void DebuggerPart::slotExamineCore() 00699 { 00700 mainWindow()->statusBar()->message(i18n("Choose a core file to examine..."), 1000); 00701 00702 QString dirName = project()? project()->projectDirectory() : QDir::homeDirPath(); 00703 QString coreFile = KFileDialog::getOpenFileName(dirName); 00704 if (coreFile.isNull()) 00705 return; 00706 00707 mainWindow()->statusBar()->message(i18n("Examining core file %1").arg(coreFile), 1000); 00708 00709 startDebugger(); 00710 controller->slotCoreFile(coreFile); 00711 } 00712 00713 00714 void DebuggerPart::slotAttachProcess() 00715 { 00716 mainWindow()->statusBar()->message(i18n("Choose a process to attach to..."), 1000); 00717 00718 Dbg_PS_Dialog dlg; 00719 if (!dlg.exec() || !dlg.pidSelected()) 00720 return; 00721 00722 int pid = dlg.pidSelected(); 00723 attachProcess(pid); 00724 } 00725 00726 bool DebuggerPart::attachProcess(int pid) 00727 { 00728 mainWindow()->statusBar()->message(i18n("Attaching to process %1").arg(pid), 1000); 00729 00730 bool ret = startDebugger(); 00731 controller->slotAttachTo(pid); 00732 return ret; 00733 } 00734 00735 00736 void DebuggerPart::slotStop(KDevPlugin* which) 00737 { 00738 if( which != 0 && which != this ) 00739 return; 00740 00741 // if( !controller->stateIsOn( s_dbgNotStarted ) && !controller->stateIsOn( s_shuttingDown ) ) 00742 slotStopDebugger(); 00743 } 00744 00745 00746 void DebuggerPart::slotPause() 00747 { 00748 controller->slotBreakInto(); 00749 } 00750 00751 00752 void DebuggerPart::slotRunToCursor() 00753 { 00754 KParts::ReadWritePart *rwpart 00755 = dynamic_cast<KParts::ReadWritePart*>(partController()->activePart()); 00756 KTextEditor::ViewCursorInterface *cursorIface 00757 = dynamic_cast<KTextEditor::ViewCursorInterface*>(partController()->activeWidget()); 00758 00759 if (!rwpart || !rwpart->url().isLocalFile() || !cursorIface) 00760 return; 00761 00762 uint line, col; 00763 cursorIface->cursorPosition(&line, &col); 00764 00765 controller->slotRunUntil(rwpart->url().path(), line); 00766 } 00767 00768 void DebuggerPart::slotStepOver() 00769 { 00770 controller->slotStepOver(); 00771 } 00772 00773 00774 void DebuggerPart::slotStepOverInstruction() 00775 { 00776 controller->slotStepOver(); 00777 } 00778 00779 00780 void DebuggerPart::slotStepIntoInstruction() 00781 { 00782 controller->slotStepIntoIns(); 00783 } 00784 00785 00786 void DebuggerPart::slotStepInto() 00787 { 00788 controller->slotStepInto(); 00789 } 00790 00791 00792 void DebuggerPart::slotStepOut() 00793 { 00794 controller->slotStepOutOff(); 00795 } 00796 00797 00798 void DebuggerPart::slotMemoryView() 00799 { 00800 // Hmm, couldn't this be made non-modal? 00801 00802 MemoryViewDialog *dlg = new MemoryViewDialog(); 00803 connect( dlg, SIGNAL(disassemble(const QString&, const QString&)), 00804 controller, SLOT(slotDisassemble(const QString&, const QString&))); 00805 connect( dlg, SIGNAL(memoryDump(const QString&, const QString&)), 00806 controller, SLOT(slotMemoryDump(const QString&, const QString&))); 00807 connect( dlg, SIGNAL(registers()), 00808 controller, SLOT(slotRegisters())); 00809 connect( dlg, SIGNAL(libraries()), 00810 controller, SLOT(slotLibraries())); 00811 00812 connect( controller, SIGNAL(rawGDBMemoryDump(char*)), 00813 dlg, SLOT(slotRawGDBMemoryView(char*))); 00814 connect( controller, SIGNAL(rawGDBDisassemble(char*)), 00815 dlg, SLOT(slotRawGDBMemoryView(char*))); 00816 connect( controller, SIGNAL(rawGDBRegisters(char*)), 00817 dlg, SLOT(slotRawGDBMemoryView(char*))); 00818 connect( controller, SIGNAL(rawGDBLibraries(char*)), 00819 dlg, SLOT(slotRawGDBMemoryView(char*))); 00820 00821 dlg->exec(); 00822 delete dlg; 00823 } 00824 00825 00826 void DebuggerPart::slotRefreshBPState( const Breakpoint& BP) 00827 { 00828 if (BP.type() == BP_TYPE_FilePos) 00829 { 00830 const FilePosBreakpoint& bp = dynamic_cast<const FilePosBreakpoint&>(BP); 00831 if (bp.isActionDie()) 00832 debugger()->setBreakpoint(bp.fileName(), bp.lineNum()-1, -1, true, false); 00833 else 00834 debugger()->setBreakpoint(bp.fileName(), bp.lineNum()-1, 00835 1/*bp->id()*/, bp.isEnabled(), bp.isPending() ); 00836 } 00837 } 00838 00839 00840 void DebuggerPart::slotStatus(const QString &msg, int state) 00841 { 00842 QString stateIndicator; 00843 00844 if (state & s_dbgNotStarted) 00845 { 00846 stateIndicator = " "; 00847 } 00848 else if (state & s_appBusy) 00849 { 00850 stateIndicator = "A"; 00851 debugger()->clearExecutionPoint(); 00852 stateChanged( QString("active") ); 00853 } 00854 else if (state & s_programExited) 00855 { 00856 stateIndicator = "E"; 00857 stateChanged( QString("stopped") ); 00858 KActionCollection *ac = actionCollection(); 00859 ac->action("debug_run")->setText( i18n("Restart") ); 00860 ac->action("debug_run")->setIcon( "1rightarrow" ); 00861 ac->action("debug_run")->setStatusText( i18n("Restart the program in the debugger") ); 00862 ac->action("debug_run")->setWhatsThis( i18n("Restart in debugger\n\n" 00863 "Restarts the program in the debugger") ); 00864 // slotStop(); 00865 } 00866 else 00867 { 00868 stateIndicator = "P"; 00869 stateChanged( QString("paused") ); 00870 } 00871 00872 // And now? :-) 00873 kdDebug(9012) << "Debugger state: " << stateIndicator << ": " << endl; 00874 kdDebug(9012) << " " << msg << endl; 00875 00876 statusBarIndicator->setText(stateIndicator); 00877 if (!msg.isEmpty()) 00878 mainWindow()->statusBar()->message(msg, 3000); 00879 } 00880 00881 00882 void DebuggerPart::slotShowStep(const QString &fileName, int lineNum) 00883 { 00884 if ( ! fileName.isEmpty() ) 00885 { 00886 // Debugger counts lines from 1 00887 debugger()->gotoExecutionPoint(fileName, lineNum-1); 00888 } 00889 } 00890 00891 00892 void DebuggerPart::slotGotoSource(const QString &fileName, int lineNum) 00893 { 00894 if ( ! fileName.isEmpty() ) 00895 partController()->editDocument(fileName, lineNum); 00896 } 00897 00898 00899 void DebuggerPart::slotActivePartChanged( KParts::Part* part ) 00900 { 00901 KAction* action = actionCollection()->action("debug_toggle_breakpoint"); 00902 if(!action) 00903 return; 00904 00905 if(!part) 00906 { 00907 action->setEnabled(false); 00908 return; 00909 } 00910 KTextEditor::ViewCursorInterface *iface 00911 = dynamic_cast<KTextEditor::ViewCursorInterface*>(part->widget()); 00912 action->setEnabled( iface != 0 ); 00913 } 00914 00915 void DebuggerPart::restorePartialProjectSession(const QDomElement* el) 00916 { 00917 gdbBreakpointWidget->restorePartialProjectSession(el); 00918 } 00919 00920 void DebuggerPart::savePartialProjectSession(QDomElement* el) 00921 { 00922 gdbBreakpointWidget->savePartialProjectSession(el); 00923 } 00924 00925 } 00926 00927 #include "debuggerpart.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Oct 19 08:01:42 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003