KDevelop API Documentation

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 #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     // Setup widgets and dbgcontroller
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 (&eg; a=5)."));
00100     mainWindow()->embedSelectView(variableWidget, i18n("Variables / Watch"), i18n("Debugger variable-view"));
00101 //    mainWindow()->setViewAvailable(variableWidget, false);
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     // variableTree -> framestackWidget
00162     connect( variableTree,     SIGNAL(selectFrame(int, int)),
00163              framestackWidget, SLOT(slotSelectFrame(int, int)));
00164 
00165     // gdbBreakpointWidget -> this
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     // Now setup the actions
00174     KAction *action;
00175 
00176 //    action = new KAction(i18n("&Start"), "1rightarrow", CTRL+SHIFT+Key_F9,
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     // Can't change state until after XMLGUI has been loaded...
00426     // Anyone know of a better way of doing this?
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     // variableTree -> controller
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*)));     // jw
00501 
00502     // variableTree -> gdbBreakpointWidget
00503     connect( variableTree,          SIGNAL(toggleWatchpoint(const QString &)),
00504              gdbBreakpointWidget,   SLOT(slotToggleWatchpoint(const QString &)));
00505 
00506     // framestackWidget -> controller
00507     connect( framestackWidget,      SIGNAL(selectFrame(int,int,bool)),
00508              controller,            SLOT(slotSelectFrame(int,int,bool)));
00509 
00510     // gdbBreakpointWidget -> controller
00511     connect( gdbBreakpointWidget,   SIGNAL(clearAllBreakpoints()),
00512              controller,            SLOT(slotClearAllBreakpoints()));
00513     connect( gdbBreakpointWidget,   SIGNAL(publishBPState(const Breakpoint&)),
00514              controller,            SLOT(slotBPState(const Breakpoint &)));
00515 
00516     // disassembleWidget -> controller
00517     connect( disassembleWidget,     SIGNAL(disassemble(const QString&, const QString&)),
00518              controller,            SLOT(slotDisassemble(const QString&, const QString&)));
00519 
00520     // gdbOutputWidget -> controller
00521     connect( gdbOutputWidget,       SIGNAL(userGDBCmd(const QString &)),
00522              controller,            SLOT(slotUserGDBCmd(const QString&)));
00523     connect( gdbOutputWidget,       SIGNAL(breakInto()),
00524              controller,            SLOT(slotBreakInto()));
00525 
00526     // controller -> gdbBreakpointWidget
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     // controller -> disassembleWidget
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     // controller -> this
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     // controller -> procLineMaker
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     // controller -> gdbOutputWidget
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     // gdbBreakpointWidget -> disassembleWidget
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;              // Currently selected build directory
00571     DomUtil::PairList run_envvars;  // List with the environment variables
00572     QString run_directory;          // Directory from where the program should be run
00573     QString program;                // Absolute path to application
00574     QString run_arguments;          // Command line arguments to be passed to the application
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 //    ac->action("debug_run")->setIcon( "dbgrun" );
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 //    mainWindow()->setViewAvailable(variableWidget, true);
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 //    mainWindow()->setViewAvailable(variableWidget, false);
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 //    ac->action("debug_run")->setIcon( "1rightarrow" );
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 //    if( !controller->stateIsOn( s_dbgNotStarted ) && !controller->stateIsOn( s_shuttingDown ) )
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     // Hmm, couldn't this be made non-modal?
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->id()*/, 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 //        ac->action("debug_run")->setIcon( "1rightarrow" );
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 //        slotStop();
00878     }
00879     else
00880     {
00881         stateIndicator = "P";
00882         stateChanged( QString("paused") );
00883     }
00884 
00885     // And now? :-)
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         // Debugger counts lines from 1
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"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:29 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003