#include "valgrind_part.h" #include #include #include #include #include #include #include #include #include #include #include #include "kdevcore.h" #include "kdevmainwindow.h" #include "kdevproject.h" #include "kdevplugininfo.h" #include "valgrind_widget.h" #include "valgrind_dialog.h" #include "valgrinditem.h" typedef KDevGenericFactory ValgrindFactory; static const KDevPluginInfo data("kdevvalgrind"); K_EXPORT_COMPONENT_FACTORY( libkdevvalgrind, ValgrindFactory( data ) ) ValgrindPart::ValgrindPart( TQObject *parent, const char *name, const TQStringList& ) : KDevPlugin( &data, parent, name ? name : "ValgrindPart" ) { setInstance( ValgrindFactory::instance() ); setXMLFile( "kdevpart_valgrind.rc" ); proc = new KShellProcess(); connect( proc, TQT_SIGNAL(receivedStdout( TDEProcess*, char*, int )), this, TQT_SLOT(receivedStdout( TDEProcess*, char*, int )) ); connect( proc, TQT_SIGNAL(receivedStderr( TDEProcess*, char*, int )), this, TQT_SLOT(receivedStderr( TDEProcess*, char*, int )) ); connect( proc, TQT_SIGNAL(processExited( TDEProcess* )), this, TQT_SLOT(processExited( TDEProcess* )) ); connect( core(), TQT_SIGNAL(stopButtonClicked(KDevPlugin*)), this, TQT_SLOT(slotStopButtonClicked(KDevPlugin*)) ); connect( core(), TQT_SIGNAL(projectOpened()), this, TQT_SLOT(projectOpened()) ); m_widget = new ValgrindWidget( this ); m_widget->setIcon( SmallIcon("fork") ); m_widget->setCaption(i18n("Valgrind Output")); TQWhatsThis::add( m_widget, i18n( "Valgrind

Shows the output of the valgrind. Valgrind detects
" "use of uninitialized memory
" "reading/writing memory after it has been free'd
" "reading/writing off the end of malloc'd blocks
" "reading/writing inappropriate areas on the stack
" "memory leaks -- where pointers to malloc'd blocks are lost forever
" "passing of uninitialised and/or unaddressable memory to system calls
" "mismatched use of malloc/new/new [] vs free/delete/delete []
" "some abuses of the POSIX pthread API." ) ); TDEAction* action = new TDEAction( i18n("&Valgrind Memory Leak Check"), 0, this, TQT_SLOT(slotExecValgrind()), actionCollection(), "tools_valgrind" ); action->setToolTip(i18n("Valgrind memory leak check")); action->setWhatsThis(i18n("Valgrind memory leak check

Runs Valgrind - a tool to help you find memory-management problems in your programs.")); action = new TDEAction( i18n("P&rofile with KCachegrind"), 0, this, TQT_SLOT(slotExecCalltree()), actionCollection(), "tools_calltree" ); action->setToolTip(i18n("Profile with KCachegrind")); action->setWhatsThis(i18n("Profile with KCachegrind

Runs your program in calltree and then displays profiler information in KCachegrind.")); mainWindow()->embedOutputView( m_widget, "Valgrind", i18n("Valgrind memory leak check") ); } ValgrindPart::~ValgrindPart() { if ( m_widget ) mainWindow()->removeView( m_widget ); delete m_widget; delete proc; } void ValgrindPart::projectOpened() { _lastExec.truncate( 0 ); } void ValgrindPart::loadOutput() { TQString fName = KFileDialog::getOpenFileName(TQString(), "*", 0, i18n("Open Valgrind Output")); if ( fName.isEmpty() ) return; TQFile f( fName ); if ( !f.open( IO_ReadOnly ) ) { KMessageBox::sorry( 0, i18n("Could not open valgrind output: %1").arg(fName) ); return; } clear(); getActiveFiles(); TQTextStream stream( &f ); while ( !stream.atEnd() ) { receivedString( stream.readLine() + "\n" ); } f.close(); } void ValgrindPart::getActiveFiles() { activeFiles.clear(); if ( project() ) { TQStringList projectFiles = project()->allFiles(); TQString projectDirectory = project()->projectDirectory(); KURL url; for ( TQStringList::Iterator it = projectFiles.begin(); it != projectFiles.end(); ++it ) { KURL url( projectDirectory + "/" + (*it) ); url.cleanPath( true ); activeFiles += url.path(); kdDebug() << "set project file: " << url.path().latin1() << endl; } } } static void guessActiveItem( ValgrindItem& item, const TQStringList activeFiles ) { if ( activeFiles.isEmpty() && item.backtrace().isEmpty() ) return; for ( ValgrindItem::BacktraceList::Iterator it = item.backtrace().begin(); it != item.backtrace().end(); ++it ) { // active: first line of backtrace that lies in project source file for ( TQStringList::ConstIterator it2 = activeFiles.begin(); it2 != activeFiles.end(); ++it2 ) { if ( (*it).url() == (*it2) ) { (*it).setHighlighted( true ); return; } } } } void ValgrindPart::appendMessage( const TQString& message ) { if ( message.isEmpty() ) return; ValgrindItem item( message ); guessActiveItem( item, activeFiles ); m_widget->addMessage( item ); } void ValgrindPart::slotExecValgrind() { ValgrindDialog* dlg = new ValgrindDialog(ValgrindDialog::Memcheck); if ( project() && _lastExec.isEmpty() ) { dlg->setExecutable( project()->mainProgram() ); } else { dlg->setExecutable( _lastExec ); } dlg->setParameters( _lastParams ); dlg->setValExecutable( _lastValExec ); dlg->setValParams( _lastValParams ); kcInfo.runKc = false; _lastValExec = dlg->valExecutable(); _lastValParams = dlg->valParams(); if ( dlg->exec() == TQDialog::Accepted ) { runValgrind( dlg->executableName(), dlg->parameters(), dlg->valExecutable(), dlg->valParams() ); } } void ValgrindPart::slotExecCalltree() { ValgrindDialog* dlg = new ValgrindDialog(ValgrindDialog::Calltree); if ( project() && _lastExec.isEmpty() ) { dlg->setExecutable( project()->mainProgram() ); } else { dlg->setExecutable( _lastExec ); } dlg->setParameters( _lastParams ); dlg->setCtExecutable( _lastCtExec ); dlg->setKcExecutable( _lastKcExec ); dlg->setCtParams( _lastCtParams ); kcInfo.runKc = true; kcInfo.kcPath = dlg->kcExecutable(); // kcInfo.kcWorkDir = KURL(dlg->executableName()).directory(); if ( dlg->exec() == TQDialog::Accepted ) { runValgrind( dlg->executableName(), dlg->parameters(), dlg->ctExecutable(), dlg->ctParams() ); } _lastKcExec = dlg->kcExecutable(); _lastCtExec = dlg->ctExecutable(); _lastCtParams = dlg->ctParams(); } void ValgrindPart::slotKillValgrind() { if ( proc ) proc->kill(); } void ValgrindPart::slotStopButtonClicked( KDevPlugin* which ) { if ( which != 0 && which != this ) return; slotKillValgrind(); } void ValgrindPart::clear() { m_widget->clear(); currentMessage = TQString(); currentPid = -1; lastPiece = TQString(); } void ValgrindPart::runValgrind( const TQString& exec, const TQString& params, const TQString& valExec, const TQString& valParams ) { if ( proc->isRunning() ) { KMessageBox::sorry( 0, i18n( "There is already an instance of valgrind running." ) ); return; /// @todo - ask for forced kill } clear(); getActiveFiles(); // proc->setWorkingDirectory(KURL(exec).directory()); proc->clearArguments(); DomUtil::PairList run_envvars; if (project()) run_envvars = project()->runEnvironmentVars(); TQStringList envVarList; DomUtil::PairList::ConstIterator it; for (it = run_envvars.begin(); it != run_envvars.end(); ++it) { envVarList << TQString("%1=\"%2\" ").arg((*it).first).arg((*it).second); } *proc << envVarList.join("") << valExec << valParams << exec << params; proc->start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); mainWindow()->raiseView( m_widget ); core()->running( this, true ); _lastExec = exec; _lastParams = params; } void ValgrindPart::receivedStdout( TDEProcess*, char* /* msg */, int /* len */ ) { //kdDebug() << "got StdOut: " <running( this, false ); if (kcInfo.runKc) { TDEProcess *kcProc = new TDEProcess; // kcProc->setWorkingDirectory(kcInfo.kcWorkDir); *kcProc << kcInfo.kcPath; *kcProc << TQString("callgrind.out.%1").arg(p->pid()); kcProc->start(TDEProcess::DontCare); } } } void ValgrindPart::restorePartialProjectSession( const TQDomElement* el ) { TQDomElement execElem = el->namedItem( "executable" ).toElement(); _lastExec = execElem.attribute( "path", "" ); _lastParams = execElem.attribute( "params", "" ); TQDomElement valElem = el->namedItem( "valgrind" ).toElement(); _lastValExec = valElem.attribute( "path", "" ); _lastValParams = valElem.attribute( "params", "" ); TQDomElement ctElem = el->namedItem( "calltree" ).toElement(); _lastCtExec = ctElem.attribute( "path", "" ); _lastCtParams = ctElem.attribute( "params", "" ); TQDomElement kcElem = el->namedItem( "tdecachegrind" ).toElement(); _lastKcExec = kcElem.attribute( "path", "" ); } void ValgrindPart::savePartialProjectSession( TQDomElement* el ) { TQDomDocument domDoc = el->ownerDocument(); if ( domDoc.isNull() ) return; TQDomElement execElem = domDoc.createElement( "executable" ); execElem.setAttribute( "path", _lastExec ); execElem.setAttribute( "params", _lastParams ); TQDomElement valElem = domDoc.createElement( "valgrind" ); valElem.setAttribute( "path", _lastValExec ); valElem.setAttribute( "params", _lastValParams ); TQDomElement ctElem = domDoc.createElement( "calltree" ); ctElem.setAttribute( "path", _lastCtExec ); ctElem.setAttribute( "params", _lastCtParams ); TQDomElement kcElem = domDoc.createElement( "tdecachegrind" ); kcElem.setAttribute( "path", _lastKcExec ); el->appendChild( execElem ); el->appendChild( valElem ); el->appendChild( ctElem ); el->appendChild( kcElem ); } #include "valgrind_part.moc"