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