diff options
Diffstat (limited to 'parts/valgrind')
-rw-r--r-- | parts/valgrind/Makefile.am | 15 | ||||
-rw-r--r-- | parts/valgrind/README.dox | 45 | ||||
-rw-r--r-- | parts/valgrind/dialog_widget.ui | 360 | ||||
-rw-r--r-- | parts/valgrind/dialog_widget.ui.h | 21 | ||||
-rw-r--r-- | parts/valgrind/kdevpart_valgrind.rc | 9 | ||||
-rw-r--r-- | parts/valgrind/kdevvalgrind.desktop | 74 | ||||
-rw-r--r-- | parts/valgrind/valgrind_dialog.cpp | 206 | ||||
-rw-r--r-- | parts/valgrind/valgrind_dialog.h | 62 | ||||
-rw-r--r-- | parts/valgrind/valgrind_part.cpp | 366 | ||||
-rw-r--r-- | parts/valgrind/valgrind_part.h | 62 | ||||
-rw-r--r-- | parts/valgrind/valgrind_widget.cpp | 205 | ||||
-rw-r--r-- | parts/valgrind/valgrind_widget.h | 44 | ||||
-rw-r--r-- | parts/valgrind/valgrinditem.cpp | 71 | ||||
-rw-r--r-- | parts/valgrind/valgrinditem.h | 50 |
14 files changed, 1590 insertions, 0 deletions
diff --git a/parts/valgrind/Makefile.am b/parts/valgrind/Makefile.am new file mode 100644 index 00000000..07550df6 --- /dev/null +++ b/parts/valgrind/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = -I$(top_srcdir)/lib/interfaces -I$(top_srcdir)/lib/util $(all_includes) + +kde_module_LTLIBRARIES = libkdevvalgrind.la +libkdevvalgrind_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) +libkdevvalgrind_la_LIBADD = $(top_builddir)/lib/libkdevelop.la + +libkdevvalgrind_la_SOURCES = dialog_widget.ui valgrind_part.cpp valgrind_widget.cpp valgrind_dialog.cpp valgrinditem.cpp + +METASOURCES = AUTO + +servicedir = $(kde_servicesdir) +service_DATA = kdevvalgrind.desktop + +rcdir = $(kde_datadir)/kdevvalgrind +rc_DATA = kdevpart_valgrind.rc diff --git a/parts/valgrind/README.dox b/parts/valgrind/README.dox new file mode 100644 index 00000000..d5e79fd4 --- /dev/null +++ b/parts/valgrind/README.dox @@ -0,0 +1,45 @@ +/** \class ValgrindPart +Valgrind is a tool that helps you find memory management problems in programs. http://developer.kde.org/~sewardj/ + +\authors <a href="mailto:$EMAIL$">$AUTHOR$</a> +\authors <a href="mailto:2nd author AT provider.com">2nd author full name</a> +... +\authors <a href="mailto:nth author AT provider.com">nth author full name</a> + +\maintainer <a href="mailto:$EMAIL$">$AUTHOR$</a> +\maintainer <a href="mailto:2nd maintainer AT provider.com">2nd maintainer full name</a> +... +\maintainer <a href="mailto:nth maintainer AT provider.com">nth maintainer full name</a> + +\feature Integrates Valgrind into KDevelop + +\bug Describe a the 1st bug that you know of, but probably hasn't been reported yet. +.. +\bug Describe a the nth bug that you know of, but probably hasn't been reported yet. + +\requirement Describe a the 1st requirement of your part. +\requirement Describe a the 2nd requirement of your part. +... +\requirement Describe a the nth requirement of your part. + +\todo Describe a the 1st TODO of your part. +\todo Describe a the 2nd TODO of your part. +... +\todo Describe a the nth TODO of your part. + +\faq <b>First frequenly asked question about your part ?</b> Answer. +\faq <b>Second frequenly asked question about your part ?</b> Answer. +... +\faq <b>Last frequenly asked question about your part ?</b> Answer. + +\note First note text. +\note Second note text. +... +\note Last note text. + +\warning First warning text. +\warning Second warning text. +... +\warning Last warning text. + +*/ diff --git a/parts/valgrind/dialog_widget.ui b/parts/valgrind/dialog_widget.ui new file mode 100644 index 00000000..35ded9c1 --- /dev/null +++ b/parts/valgrind/dialog_widget.ui @@ -0,0 +1,360 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>DialogWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>DialogWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>322</width> + <height>306</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Application</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KURLRequester" row="0" column="1"> + <property name="name"> + <cstring>executableEdit</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>&Parameters:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>paramEdit</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>&Executable:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>executableEdit</cstring> + </property> + </widget> + <widget class="KLineEdit" row="1" column="1"> + <property name="name"> + <cstring>paramEdit</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QWidgetStack" row="1" column="0"> + <property name="name"> + <cstring>stack</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>0</number> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Valgrind</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>memleakBox</cstring> + </property> + <property name="text"> + <string>Memory &leak check</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QCheckBox"> + <property name="name"> + <cstring>reachableBox</cstring> + </property> + <property name="text"> + <string>&Show still reachable blocks</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>childrenBox</cstring> + </property> + <property name="text"> + <string>&Trace children</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string>Additional p&arameters:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>valParamEdit</cstring> + </property> + </widget> + <widget class="KLineEdit" row="1" column="1"> + <property name="name"> + <cstring>valParamEdit</cstring> + </property> + </widget> + <widget class="KURLRequester" row="0" column="1"> + <property name="name"> + <cstring>valExecutableEdit</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>E&xecutable:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>valExecutableEdit</cstring> + </property> + </widget> + </grid> + </widget> + </vbox> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>1</number> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>Valgrind</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="1" column="0"> + <property name="name"> + <cstring>layout3_2</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel5_2</cstring> + </property> + <property name="text"> + <string>Additional p&arameters:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>valParamEdit</cstring> + </property> + </widget> + <widget class="KLineEdit" row="1" column="1"> + <property name="name"> + <cstring>ctParamEdit</cstring> + </property> + </widget> + <widget class="KURLRequester" row="0" column="1"> + <property name="name"> + <cstring>ctExecutableEdit</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel4_2</cstring> + </property> + <property name="text"> + <string>E&xecutable:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>valExecutableEdit</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>ctChildrenBox</cstring> + </property> + <property name="text"> + <string>&Trace children</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox" row="1" column="0"> + <property name="name"> + <cstring>groupBox4</cstring> + </property> + <property name="title"> + <string>KCachegrind</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KURLRequester" row="0" column="1"> + <property name="name"> + <cstring>kcExecutableEdit</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel4_2_2</cstring> + </property> + <property name="text"> + <string>Exe&cutable:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>valExecutableEdit</cstring> + </property> + </widget> + </grid> + </widget> + </grid> + </widget> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>memleakBox</sender> + <signal>toggled(bool)</signal> + <receiver>DialogWidget</receiver> + <slot>checkBoxToggled()</slot> + </connection> +</connections> +<tabstops> + <tabstop>executableEdit</tabstop> + <tabstop>paramEdit</tabstop> + <tabstop>memleakBox</tabstop> + <tabstop>reachableBox</tabstop> + <tabstop>childrenBox</tabstop> + <tabstop>valExecutableEdit</tabstop> + <tabstop>valParamEdit</tabstop> + <tabstop>ctChildrenBox</tabstop> + <tabstop>ctExecutableEdit</tabstop> + <tabstop>ctParamEdit</tabstop> + <tabstop>kcExecutableEdit</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> +</includes> +<slots> + <slot access="private" specifier="non virtual">checkBoxToggled()</slot> + <slot>init()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/parts/valgrind/dialog_widget.ui.h b/parts/valgrind/dialog_widget.ui.h new file mode 100644 index 00000000..9a2570ae --- /dev/null +++ b/parts/valgrind/dialog_widget.ui.h @@ -0,0 +1,21 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +void DialogWidget::checkBoxToggled() +{ + reachableBox->setEnabled( memleakBox->isChecked() ); +} + + +void DialogWidget::init() +{ + valParamEdit->setMinimumWidth( valParamEdit->fontMetrics().width( "0" ) * 30 ); + checkBoxToggled(); +} diff --git a/parts/valgrind/kdevpart_valgrind.rc b/parts/valgrind/kdevpart_valgrind.rc new file mode 100644 index 00000000..440b62c2 --- /dev/null +++ b/parts/valgrind/kdevpart_valgrind.rc @@ -0,0 +1,9 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="valgrind" library="libvalgrindplugin" version="3"> +<MenuBar> + <Menu name="debug"><Text>&Debug</Text> + <Action name="tools_valgrind" group="profile"/> + <Action name="tools_calltree" group="profile"/> + </Menu> +</MenuBar> +</kpartplugin> diff --git a/parts/valgrind/kdevvalgrind.desktop b/parts/valgrind/kdevvalgrind.desktop new file mode 100644 index 00000000..23b5cf4f --- /dev/null +++ b/parts/valgrind/kdevvalgrind.desktop @@ -0,0 +1,74 @@ +[Desktop Entry] +Type=Service +Exec=blubb +Comment=Valgrind is a tool that helps you find memory management problems in programs. http://valgrind.org/ +Comment[ca]=Valgrind és una eina que us ajuda a trobar problemes en la gestió de la memòria en els programes. http://valgrind.org/ +Comment[da]=Valgrind er et værktøj der hjælper dig med at finde hukommelseshåndteringsproblemer i programmer. http://valgrind.org/ +Comment[de]=Valgrind ist ein Werkzeug zum Auffinden von Speicherverwaltungsproblemen in Anwendungen. http://valgrind.org/ +Comment[el]=Το Valgrind είναι ένα εργαλείο που βοηθά στην εύρεση προβλημάτων διαχείρισης μνήμης στα προγράμματα. http://valgrind.org/ +Comment[es]=Valgrind es una herramienta que le ayuda a encontrar problemas de gestión de memoria en los programas. http://valgrind.org/ +Comment[et]=Valgrind aitab leida programmides mälulekkeid ja muid mäluga seotud asju. http://valgrind.org/ +Comment[fr]=Valgrind est un outil qui vous aide à trouver les problèmes de gestion de la mémoire dans les programmes. http://valgrind.org/ +Comment[hu]=A Valgrind memóriakezelési hibák keresésére alkalmas program - http://valgrind.org +Comment[it]=Valgrind è uno strumento che ti aiuta a trovare problemi di gestione della memoria nei programmi. http://valgrind.org/ +Comment[ja]=Valgrind は、プログラム内のメモリ管理問題を発見することを手助けするツールです。http://valgrind.org/ +Comment[ms]=Valgrind adalah alatan yang membantu anda mencari masalah pengurusan memori dalam program. http://valgrind.org/ +Comment[nds]=Valgrind is en Warktüüch för't Finnen vun t Spiekerpleegproblemen in Programmen. http://valgrind.org/ +Comment[nl]=Valgrind is een hulpprogramma dat u helpt bij het opsporen van geheugenproblemen in programma's. http://valgrind.org/ +Comment[pl]=Valgrind jest narzędziem pomagającym znaleźć w programach problemy z zarządzaniem pamięcią. http://valgrind.org/ +Comment[pt]=O Valgrind é uma ferramenta que o ajuda a descobrir os problemas de gestão de memória nos programas. http://www.valgrind.org/ +Comment[pt_BR]=Valgrind é uma ferramenta ajuda você a encontrar problemas de gerenciamento de memória nos programas. http://www.valgrind.org/ +Comment[ru]=Valgrind - средство нахождения проблем управления памятью в программах. http://valgrind.org/ +Comment[sk]=Valgrind je nástroj, ktorý pomáha nájsť problémy so správou pamäte v programoch. http://valgrind.org/ +Comment[sr]=Valgrind је алат који вам помаже да нађете проблеме са употребом меморије у програмима. http://valgrind.org/ +Comment[sr@Latn]=Valgrind je alat koji vam pomaže da nađete probleme sa upotrebom memorije u programima. http://valgrind.org/ +Comment[sv]=Valgrind är ett verktyg som hjälper dig hitta minneshanteringsproblem i program. Se http://valgrind.org/. +Comment[zh_TW]=Valgrind 能協助您找到程式中記憶體管理上的問題。http://valgrind.org/ +Name=KDevvalgrind +Name[da]=KDevelop Valgrind +Name[de]=Unterstützung für Valgrind (KDevelop) +Name[hi]=के-डेववेलग्रिंड +Name[nds]=Ünnerstütten för Valgrind (KDevelop) +Name[sk]=KDev valgrind +Name[sv]=KDevelop valgrind +Name[zh_TW]=KDevelop Valgrind +GenericName=Valgrind Frontend +GenericName[ca]=Entorn per a Valgrind +GenericName[da]=Valgrind-grænseflade +GenericName[de]=Oberfläche für Valgrind +GenericName[el]=Πρόγραμμα Valgrind +GenericName[es]=Interfaz para Valgrind +GenericName[et]=Valgrindi kasutajaliides +GenericName[eu]=Valgrind interfazea +GenericName[fa]=پایانۀ Valgrind +GenericName[fr]=Interface de Valgrind +GenericName[ga]=Comhéadan Valgrind +GenericName[gl]=Frontal para Valgrind +GenericName[hi]=वेलग्रिन्ड फ्रन्टएण्ड +GenericName[hu]=Valgrind-kezelő +GenericName[it]=Interfaccia a Valgrind +GenericName[ja]=Valgrind フロントエンド +GenericName[ms]=Frontend Valgrind +GenericName[nds]=Valgrind-Böversiet +GenericName[ne]=भलग्रिन्ड फ्रन्टइन्ड +GenericName[nl]=Valgrind-frontend +GenericName[pl]=Interfejs do Valgrinda +GenericName[pt]=Interface para o Valgrind +GenericName[pt_BR]=Frontend do Valgrind +GenericName[ru]=Интерфейс к Valgrind +GenericName[sk]=Valgrind rozhranie +GenericName[sl]=VMesnik za Valgrind +GenericName[sr]=Кориснички интерфејс за Valgrind +GenericName[sr@Latn]=Korisnički interfejs za Valgrind +GenericName[sv]=Valgrind-gränssnitt +GenericName[ta]=Valgrind முன் பகுதி +GenericName[tg]=Интерфейс дар Valgrind +GenericName[tr]=Valgrind Önucu +GenericName[zh_CN]=Valgrind 前端 +GenericName[zh_TW]=Valgrind 前端介面 +Icon=kdevelop +ServiceTypes=KDevelop/Plugin +X-KDevelop-Scope=Global +X-KDE-Library=libkdevvalgrind +X-KDevelop-Version=5 +X-KDevelop-Properties=CompiledDevelopment diff --git a/parts/valgrind/valgrind_dialog.cpp b/parts/valgrind/valgrind_dialog.cpp new file mode 100644 index 00000000..405d78dd --- /dev/null +++ b/parts/valgrind/valgrind_dialog.cpp @@ -0,0 +1,206 @@ +#include <qlayout.h> +#include <qcheckbox.h> +#include <qregexp.h> +#include <qwidgetstack.h> + +#include <kprocess.h> +#include <klocale.h> +#include <kurlrequester.h> +#include <klineedit.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> + +#include "dialog_widget.h" +#include "valgrind_dialog.h" + +#include "valgrind_dialog.moc" + + +ValgrindDialog::ValgrindDialog( Type type, QWidget* parent ) + : KDialogBase( parent, "valgrind dialog", true, i18n("Valgrind Memory Check"), Ok|Cancel ), + m_type(type) +{ + w = new DialogWidget( this ); + w->valExecutableEdit->setURL( "valgrind" ); + w->executableEdit->setFocus(); + w->stack->raiseWidget(m_type); + setMainWidget( w ); + connect( w->executableEdit->lineEdit(), SIGNAL( textChanged( const QString &)), this, SLOT( valgrindTextChanged())); + connect( w->valExecutableEdit->lineEdit(), SIGNAL( textChanged( const QString &)), this, SLOT( valgrindTextChanged())); + connect( w->ctExecutableEdit->lineEdit(), SIGNAL( textChanged( const QString &)), this, SLOT( valgrindTextChanged())); + connect( w->kcExecutableEdit->lineEdit(), SIGNAL( textChanged( const QString &)), this, SLOT( valgrindTextChanged())); + enableButtonOK( false ); +} + + +ValgrindDialog::~ValgrindDialog() +{ +} + +void ValgrindDialog::valgrindTextChanged() +{ + if (m_type == Memcheck) + enableButtonOK( !w->valExecutableEdit->lineEdit()->text().isEmpty() && !w->executableEdit->lineEdit()->text().isEmpty() ); + else if (m_type == Calltree) + enableButtonOK( !w->executableEdit->lineEdit()->text().isEmpty() && !w->ctExecutableEdit->lineEdit()->text().isEmpty() && !w->kcExecutableEdit->lineEdit()->text().isEmpty() ); +} + +QString ValgrindDialog::executableName() const +{ + return w->executableEdit->url(); +} + +void ValgrindDialog::setExecutable( const QString& url ) +{ + w->executableEdit->setURL( url ); +} + +QString ValgrindDialog::valExecutable() const +{ + return w->valExecutableEdit->url(); +} + +QString ValgrindDialog::parameters() const +{ + return w->paramEdit->text(); +} + +void ValgrindDialog::setParameters( const QString& params ) +{ + w->paramEdit->setText( params ); +} + +void ValgrindDialog::setValExecutable( const QString& ve ) +{ + QString vUrl = ve; + if ( vUrl.isEmpty() ) { + vUrl = KStandardDirs::findExe( "valgrind" ); + } + if ( vUrl.isEmpty() ) { + KMessageBox::sorry( this, i18n( "Could not find valgrind in your $PATH. Please make " + "sure it is installed properly." ), + i18n( "Valgrind Not Found" ) ); + w->valExecutableEdit->setURL( "valgrind" ); + } else { + w->valExecutableEdit->setURL( vUrl ); + } +} + +static const QString memCheckParam( "--tool=memcheck" ); +static const QString leakCheckParam( "--leak-check=yes" ); +static const QString reachableParam( "--show-reachable=yes" ); +static const QString childrenParam( "--trace-children=yes" ); + +QString ValgrindDialog::valParams() const +{ + QString params = w->valParamEdit->text(); + if (isNewValgrindVersion()) + params += " " + memCheckParam; + if ( w->memleakBox->isChecked() ) + params += " " + leakCheckParam; + if ( w->reachableBox->isChecked() ) + params += " " + reachableParam; + if ( w->childrenBox->isChecked() ) + params += " " + childrenParam; + + return params; +} + +void ValgrindDialog::setValParams( const QString& params ) +{ + QString myParams = params; + if ( myParams.contains( leakCheckParam ) ) + w->memleakBox->setChecked( true ); + if ( myParams.contains( reachableParam ) ) + w->reachableBox->setChecked( true ); + if ( myParams.contains( childrenParam ) ) + w->childrenBox->setChecked( true ); + w->init(); + + myParams = myParams.replace( QRegExp( memCheckParam ), "" ); + myParams = myParams.replace( QRegExp( leakCheckParam ), "" ); + myParams = myParams.replace( QRegExp( reachableParam ), "" ); + myParams = myParams.replace( QRegExp( childrenParam ), "" ); + myParams = myParams.stripWhiteSpace(); + w->valParamEdit->setText( myParams ); +} + +QString ValgrindDialog::ctExecutable() const +{ + return w->ctExecutableEdit->url(); +} + +void ValgrindDialog::setCtExecutable( const QString& ce ) +{ + QString vUrl = ce; + if ( vUrl.isEmpty() ) { + vUrl = KStandardDirs::findExe( "valgrind" ); + } + if ( vUrl.isEmpty() ) { + KMessageBox::sorry( this, i18n( "Could not find valgrind in your $PATH. Please make " + "sure it is installed properly." ), + i18n( "Valgrind Not Found" ) ); + w->ctExecutableEdit->setURL( "valgrind" ); + } else { + w->ctExecutableEdit->setURL( vUrl ); + } +} + +QString ValgrindDialog::ctParams() const +{ + QString params = w->ctParamEdit->text(); + if ( w->ctChildrenBox->isChecked() ) + params += " " + childrenParam; + + return params; +} + +void ValgrindDialog::setCtParams( const QString& params ) +{ + QString myParams = params; + //force --tool=callgrind if no params are given + if (myParams.isEmpty()) + myParams = "--tool=callgrind"; + if ( myParams.contains( childrenParam ) ) + w->ctChildrenBox->setChecked( true ); + w->init(); + + myParams = myParams.replace( QRegExp( childrenParam ), "" ); + myParams = myParams.stripWhiteSpace(); + w->ctParamEdit->setText( myParams ); +} + +QString ValgrindDialog::kcExecutable( ) const +{ + return w->kcExecutableEdit->url(); +} + +void ValgrindDialog::setKcExecutable( const QString& ke ) +{ + QString vUrl = ke; + if ( vUrl.isEmpty() ) { + vUrl = KStandardDirs::findExe( "kcachegrind" ); + } + if ( vUrl.isEmpty() ) { + KMessageBox::sorry( this, i18n( "Could not find kcachegrind in your $PATH. Please make " + "sure it is installed properly." ), + i18n( "KCachegrind Not Found" ) ); + w->kcExecutableEdit->setURL( "kcachegrind" ); + } else { + w->kcExecutableEdit->setURL( vUrl ); + } +} + +bool ValgrindDialog::isNewValgrindVersion( ) const +{ + KProcess *proc = new KProcess; + proc->setUseShell(true); + *proc << "test \"valgrind-20\" == `valgrind --version | awk -F \\. '{print $1$2}'`"; + proc->start(KProcess::Block); + if (proc->normalExit()) + return proc->exitStatus(); + return true; +} + +// kate: space-indent on; indent-width 2; tab-width 2; show-tabs on; + diff --git a/parts/valgrind/valgrind_dialog.h b/parts/valgrind/valgrind_dialog.h new file mode 100644 index 00000000..41c25afc --- /dev/null +++ b/parts/valgrind/valgrind_dialog.h @@ -0,0 +1,62 @@ + +#ifndef _VALGRIND_DIALOG_H_ +#define _VALGRIND_DIALOG_H_ + +#include <kdialogbase.h> + +class KURLRequester; +class DialogWidget; + +/** + * + * Harald Fernengel + **/ +class ValgrindDialog : public KDialogBase +{ + Q_OBJECT +public: + enum Type { Memcheck = 0, Calltree = 1 }; + + ValgrindDialog( Type type, QWidget* parent = 0 ); + ~ValgrindDialog(); + + // the app to check + QString executableName() const; + void setExecutable( const QString& url ); + + // command line parameters for the app + QString parameters() const; + void setParameters( const QString& params ); + + // name and/or path to the valgrind executable + QString valExecutable() const; + void setValExecutable( const QString& ve ); + + // command line parameters for valgrind + QString valParams() const; + void setValParams( const QString& params ); + + // name and/or path to the calltree executable + QString ctExecutable() const; + void setCtExecutable( const QString& ce ); + + // command line parameters for calltree + QString ctParams() const; + void setCtParams( const QString& params ); + + // name and/or path to the kcachegrind executable + QString kcExecutable() const; + void setKcExecutable( const QString& ke ); + +protected: + bool isNewValgrindVersion() const; + +private: + DialogWidget *w; + Type m_type; + private slots: + void valgrindTextChanged(); + +}; + +#endif diff --git a/parts/valgrind/valgrind_part.cpp b/parts/valgrind/valgrind_part.cpp new file mode 100644 index 00000000..868faf28 --- /dev/null +++ b/parts/valgrind/valgrind_part.cpp @@ -0,0 +1,366 @@ +#include "valgrind_part.h" + +#include <qwhatsthis.h> +#include <qregexp.h> +#include <qfile.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kdevgenericfactory.h> +#include <kaction.h> +#include <kprocess.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <kdebug.h> + +#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<ValgrindPart> ValgrindFactory; +static const KDevPluginInfo data("kdevvalgrind"); +K_EXPORT_COMPONENT_FACTORY( libkdevvalgrind, ValgrindFactory( data ) ) + +ValgrindPart::ValgrindPart( QObject *parent, const char *name, const QStringList& ) + : KDevPlugin( &data, parent, name ? name : "ValgrindPart" ) +{ + setInstance( ValgrindFactory::instance() ); + setXMLFile( "kdevpart_valgrind.rc" ); + + proc = new KShellProcess(); + connect( proc, SIGNAL(receivedStdout( KProcess*, char*, int )), + this, SLOT(receivedStdout( KProcess*, char*, int )) ); + connect( proc, SIGNAL(receivedStderr( KProcess*, char*, int )), + this, SLOT(receivedStderr( KProcess*, char*, int )) ); + connect( proc, SIGNAL(processExited( KProcess* )), + this, SLOT(processExited( KProcess* )) ); + connect( core(), SIGNAL(stopButtonClicked(KDevPlugin*)), + this, SLOT(slotStopButtonClicked(KDevPlugin*)) ); + connect( core(), SIGNAL(projectOpened()), + this, SLOT(projectOpened()) ); + + m_widget = new ValgrindWidget( this ); + m_widget->setIcon( SmallIcon("fork") ); + m_widget->setCaption(i18n("Valgrind Output")); + + QWhatsThis::add( m_widget, i18n( "<b>Valgrind</b><p>Shows the output of the valgrind. Valgrind detects<br>" + "use of uninitialized memory<br>" + "reading/writing memory after it has been free'd<br>" + "reading/writing off the end of malloc'd blocks<br>" + "reading/writing inappropriate areas on the stack<br>" + "memory leaks -- where pointers to malloc'd blocks are lost forever<br>" + "passing of uninitialised and/or unaddressable memory to system calls<br>" + "mismatched use of malloc/new/new [] vs free/delete/delete []<br>" + "some abuses of the POSIX pthread API." ) ); + + KAction* action = new KAction( i18n("&Valgrind Memory Leak Check"), 0, this, + SLOT(slotExecValgrind()), actionCollection(), "tools_valgrind" ); + action->setToolTip(i18n("Valgrind memory leak check")); + action->setWhatsThis(i18n("<b>Valgrind memory leak check</b><p>Runs Valgrind - a tool to help you find memory-management problems in your programs.")); + + action = new KAction( i18n("P&rofile with KCachegrind"), 0, this, + SLOT(slotExecCalltree()), actionCollection(), "tools_calltree" ); + action->setToolTip(i18n("Profile with KCachegrind")); + action->setWhatsThis(i18n("<b>Profile with KCachegrind</b><p>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() +{ + QString fName = KFileDialog::getOpenFileName(QString::null, "*", 0, i18n("Open Valgrind Output")); + if ( fName.isEmpty() ) + return; + + QFile f( fName ); + if ( !f.open( IO_ReadOnly ) ) { + KMessageBox::sorry( 0, i18n("Could not open valgrind output: %1").arg(fName) ); + return; + } + + clear(); + getActiveFiles(); + + QTextStream stream( &f ); + while ( !stream.atEnd() ) { + receivedString( stream.readLine() + "\n" ); + } + f.close(); +} + +void ValgrindPart::getActiveFiles() +{ + activeFiles.clear(); + if ( project() ) { + QStringList projectFiles = project()->allFiles(); + QString projectDirectory = project()->projectDirectory(); + KURL url; + for ( QStringList::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 QStringList 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 ( QStringList::ConstIterator it2 = activeFiles.begin(); it2 != activeFiles.end(); ++it2 ) { + if ( (*it).url() == (*it2) ) { + (*it).setHighlighted( true ); + return; + } + } + } +} + +void ValgrindPart::appendMessage( const QString& 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() == QDialog::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() == QDialog::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 = QString::null; + currentPid = -1; + lastPiece = QString::null; +} + +void ValgrindPart::runValgrind( const QString& exec, const QString& params, const QString& valExec, const QString& 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(); + + QStringList envVarList; + DomUtil::PairList::ConstIterator it; + for (it = run_envvars.begin(); it != run_envvars.end(); ++it) + { + envVarList << QString("%1=\"%2\" ").arg((*it).first).arg((*it).second); + } + + *proc << envVarList.join("") << valExec << valParams << exec << params; + proc->start( KProcess::NotifyOnExit, KProcess::AllOutput ); + mainWindow()->raiseView( m_widget ); + core()->running( this, true ); + + _lastExec = exec; + _lastParams = params; +} + +void ValgrindPart::receivedStdout( KProcess*, char* /* msg */, int /* len */ ) +{ + //kdDebug() << "got StdOut: " <<QString::fromLocal8Bit( msg, len ) << endl; +} + +void ValgrindPart::receivedStderr( KProcess*, char* msg, int len ) +{ + receivedString( QString::fromLocal8Bit( msg, len ) ); +} + +void ValgrindPart::receivedString( const QString& str ) +{ + QString rmsg = lastPiece + str; + QStringList lines = QStringList::split( "\n", rmsg ); + +// kdDebug() << "got: " << QString::fromLocal8Bit( msg, len ) << endl; + + if ( !rmsg.endsWith( "\n" ) ) { + // the last message is trucated, we'll receive + // the rest in the next call + lastPiece = lines.back(); + lines.pop_back(); + } else { + lastPiece = QString::null; + } + appendMessages( lines ); +} + +void ValgrindPart::appendMessages( const QStringList& lines ) +{ + QRegExp valRe( "==(\\d+)== (.*)" ); + + for ( QStringList::ConstIterator it = lines.begin(); it != lines.end(); ++it ) { + if ( valRe.search( *it ) < 0 ) + continue; + + int cPid = valRe.cap( 1 ).toInt(); + + if ( valRe.cap( 2 ).isEmpty() ) { + appendMessage( currentMessage ); + currentMessage = QString::null; + } else if ( cPid != currentPid ) { + appendMessage( currentMessage ); + currentMessage = *it; + currentPid = cPid; + } else { + if ( !currentMessage.isEmpty() ) + currentMessage += "\n"; + currentMessage += *it; + } + } +} + +void ValgrindPart::processExited( KProcess* p ) +{ + if ( p == proc ) { + appendMessage( currentMessage + lastPiece ); + currentMessage = QString::null; + lastPiece = QString::null; + core()->running( this, false ); + + if (kcInfo.runKc) + { + KProcess *kcProc = new KProcess; +// kcProc->setWorkingDirectory(kcInfo.kcWorkDir); + *kcProc << kcInfo.kcPath; + *kcProc << QString("callgrind.out.%1").arg(p->pid()); + kcProc->start(KProcess::DontCare); + } + } +} + +void ValgrindPart::restorePartialProjectSession( const QDomElement* el ) +{ + QDomElement execElem = el->namedItem( "executable" ).toElement(); + _lastExec = execElem.attribute( "path", "" ); + _lastParams = execElem.attribute( "params", "" ); + + QDomElement valElem = el->namedItem( "valgrind" ).toElement(); + _lastValExec = valElem.attribute( "path", "" ); + _lastValParams = valElem.attribute( "params", "" ); + + QDomElement ctElem = el->namedItem( "calltree" ).toElement(); + _lastCtExec = ctElem.attribute( "path", "" ); + _lastCtParams = ctElem.attribute( "params", "" ); + + QDomElement kcElem = el->namedItem( "kcachegrind" ).toElement(); + _lastKcExec = kcElem.attribute( "path", "" ); +} + +void ValgrindPart::savePartialProjectSession( QDomElement* el ) +{ + QDomDocument domDoc = el->ownerDocument(); + if ( domDoc.isNull() ) + return; + + QDomElement execElem = domDoc.createElement( "executable" ); + execElem.setAttribute( "path", _lastExec ); + execElem.setAttribute( "params", _lastParams ); + + QDomElement valElem = domDoc.createElement( "valgrind" ); + valElem.setAttribute( "path", _lastValExec ); + valElem.setAttribute( "params", _lastValParams ); + + QDomElement ctElem = domDoc.createElement( "calltree" ); + ctElem.setAttribute( "path", _lastCtExec ); + ctElem.setAttribute( "params", _lastCtParams ); + + QDomElement kcElem = domDoc.createElement( "kcachegrind" ); + kcElem.setAttribute( "path", _lastKcExec ); + + el->appendChild( execElem ); + el->appendChild( valElem ); + el->appendChild( ctElem ); + el->appendChild( kcElem ); +} + +#include "valgrind_part.moc" diff --git a/parts/valgrind/valgrind_part.h b/parts/valgrind/valgrind_part.h new file mode 100644 index 00000000..097eb8f8 --- /dev/null +++ b/parts/valgrind/valgrind_part.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2002 Harald Fernengel <harry@kdevelop.org> + */ + +#ifndef __KDEVPART_VALGRIND_H__ +#define __KDEVPART_VALGRIND_H__ + +#include <qguardedptr.h> +#include <qstring.h> +#include <qstringlist.h> +#include <kdevplugin.h> + +class ValgrindWidget; +class KProcess; + +class ValgrindPart : public KDevPlugin +{ + Q_OBJECT + +public: + ValgrindPart( QObject *parent, const char *name, const QStringList & ); + ~ValgrindPart(); + + void runValgrind( const QString& exec, const QString& parameters, const QString& valExec, const QString& valParameters ); + + void savePartialProjectSession( QDomElement* el ); + void restorePartialProjectSession( const QDomElement* el ); + +private slots: + void slotExecValgrind(); + void slotExecCalltree(); + void slotKillValgrind(); + void slotStopButtonClicked( KDevPlugin* which ); + void receivedStdout( KProcess*, char*, int ); + void receivedStderr( KProcess*, char*, int ); + void processExited( KProcess* ); + void loadOutput(); + void projectOpened(); + +private: + void getActiveFiles(); + void appendMessage( const QString& message ); + void appendMessages( const QStringList& lines ); + void receivedString( const QString& str ); + void clear(); + QString _lastExec, _lastParams, _lastValExec, _lastValParams, + _lastCtExec, _lastCtParams, _lastKcExec; + KProcess* proc; + QString currentMessage; + QString lastPiece; + QStringList activeFiles; + int currentPid; + QGuardedPtr<ValgrindWidget> m_widget; + struct { + bool runKc; + QString kcPath; +// QString kcWorkDir; + } kcInfo; +}; + + +#endif diff --git a/parts/valgrind/valgrind_widget.cpp b/parts/valgrind/valgrind_widget.cpp new file mode 100644 index 00000000..356d97bf --- /dev/null +++ b/parts/valgrind/valgrind_widget.cpp @@ -0,0 +1,205 @@ +#include <qlayout.h> +#include <qpainter.h> +#include <qpopupmenu.h> + +#include <kparts/part.h> +#include <klibloader.h> +#include <kurl.h> +#include <kdebug.h> +#include <klistview.h> +#include <klocale.h> +#include <kstatusbar.h> + +#include <kdevcore.h> +#include <kdevpartcontroller.h> +#include <kdevmainwindow.h> +#include <kdevproject.h> + +#include "valgrind_part.h" +#include "valgrind_widget.h" + +#define VALLISTVIEWITEMRTTI 130977 + +// helper class to sort the ListView by item number instead of the string representation of the item number +class ValListViewItem: public QListViewItem +{ +public: + ValListViewItem( QListView* parent, int key, int pid, const QString& message ): + QListViewItem( parent, QString::number( key ), QString::number( pid ), message ), + _key( key ), _pid ( pid ), backtrace( false ), _line( -1 ), _active( false ) {} + + ValListViewItem( ValListViewItem* parent, int key, int pid, const QString& message, const QString& filename, int line, bool active ): + QListViewItem( parent, QString::number( key ), QString::null, message ), + _key( key ), _pid( pid ), backtrace( true ), _filename( filename ), _line( line ), _active( active ) + { + if ( parent->_pid != _pid && _pid > 0 ) + setText( 1, QString::number( _pid ) ); + } + + virtual ~ValListViewItem(); + + static int intCompare( int i1, int i2 ) + { + if ( i1 > i2 ) + return 1; + else if ( i1 < i2 ) + return -1; + else + return 0; + } + + int compare( QListViewItem* i, int col, bool ascending ) const + { + if ( !i || i->rtti() != VALLISTVIEWITEMRTTI ) + return QListViewItem::compare( i, col, ascending ); + switch ( col ) { + case 0 : return intCompare( ((ValListViewItem*)i)->_key, _key ); + case 1 : return intCompare( ((ValListViewItem*)i)->_pid, _pid ); + default: return QListViewItem::compare( i, col, ascending ); + } + } + + void paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align ) + { + if ( _active ) { + QFont fnt = p->font(); + fnt.setBold( true ); + p->setFont( fnt ); + } + QListViewItem::paintCell( p, cg, column, width, align ); + } + + int rtti() const { return VALLISTVIEWITEMRTTI; } + + QString fileName() const { return _filename; } + int line() const { return _line; } + QString message() const { return text( 2 ); } + bool isHighlighted() const { return _active; } + +private: + int _key; + int _pid; + bool backtrace; + QString _filename; + int _line; + bool _active; +}; + +ValListViewItem::~ValListViewItem() {} + +ValgrindWidget::ValgrindWidget( ValgrindPart *part ) + : QWidget(0, "valgrind widget"), _part( part ) +{ + QVBoxLayout* vbl = new QVBoxLayout( this ); + lv = new KListView( this ); + lv->addColumn( i18n( "No." ) ); + lv->addColumn( i18n( "Thread" ) ); + lv->addColumn( i18n( "Message" ) ); + lv->setSorting( 0, false ); + lv->setRootIsDecorated( true ); + lv->setAllColumnsShowFocus( true ); + vbl->addWidget( lv ); + + popup = new QPopupMenu( lv, "valPopup" ); + popup->insertItem( i18n( "&Open Valgrind Output..." ), _part, SLOT(loadOutput()), 0, 0 ); + popup->insertSeparator(); + popup->insertItem( i18n( "Expand All Items" ), this, SLOT(expandAll()), 0, 2 ); + popup->insertItem( i18n( "Collapse All Items" ), this, SLOT(collapseAll()), 0, 3 ); + + connect( popup, SIGNAL(aboutToShow()), + this, SLOT(aboutToShowPopup()) ); + connect( lv, SIGNAL(executed(QListViewItem*)), + this, SLOT(executed(QListViewItem*)) ); + connect( lv, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)) ); +} + + +ValgrindWidget::~ValgrindWidget() +{ +} + +void ValgrindWidget::clear() +{ + lv->clear(); + msgNumber = 1; +} + +void ValgrindWidget::addMessage( const ValgrindItem& vi ) +{ + QStringList projectFiles; + QString projectDirectory; + + ValListViewItem* lvi = new ValListViewItem( lv, msgNumber++, vi.pid(), vi.message() ); + lvi->setMultiLinesEnabled( true ); + const ValgrindItem::BacktraceList backtrace = vi.backtrace(); + if ( !backtrace.isEmpty() ) + lvi->setExpandable( true ); + + int i = 0; + for ( ValgrindItem::BacktraceList::ConstIterator it = backtrace.begin(); it != backtrace.end(); ++it ) { + new ValListViewItem( lvi, ++i, (*it).pid(), (*it).message(), (*it).url(), (*it).line(), (*it).isHighlighted() ); + } +} + +void ValgrindWidget::executed( QListViewItem* lvi ) +{ + Q_ASSERT( _part ); + Q_ASSERT( _part->partController() ); + Q_ASSERT( _part->mainWindow() ); + + if ( !lvi || lvi->rtti() != VALLISTVIEWITEMRTTI ) + return; + ValListViewItem* vli = 0; + if ( !((ValListViewItem*)lvi)->fileName().isEmpty() ) { + vli = (ValListViewItem*)lvi; + } else if ( lvi->isExpandable() ) { + // find the memleak position + QListViewItemIterator it( lv ); + while ( vli == 0 && it.current() ) { + if ( it.current()->rtti() == VALLISTVIEWITEMRTTI && ((ValListViewItem*)it.current())->isHighlighted() ) + vli = (ValListViewItem*)it.current(); + ++it; + } + } + if ( vli ) { + // display the file + _part->partController()->editDocument( KURL( vli->fileName() ), vli->line() - 1 ); + _part->mainWindow()->statusBar()->message( vli->message(), 10000 ); + } +} + +void ValgrindWidget::expandAll() +{ + QListViewItem* child = lv->firstChild(); + while ( child ) { + child->setOpen( true ); + child = child->nextSibling(); + } +} + +void ValgrindWidget::collapseAll() +{ + QListViewItem* child = lv->firstChild(); + while ( child ) { + child->setOpen( false ); + child = child->nextSibling(); + } +} + +void ValgrindWidget::aboutToShowPopup() +{ + bool en = (lv->firstChild() != 0); + popup->setItemEnabled( 2, en ); + popup->setItemEnabled( 3, en ); +} + +void ValgrindWidget::slotContextMenu( KListView* l, QListViewItem* /*i*/, const QPoint& p ) +{ + if ( l != lv ) + return; + + popup->exec( p ); +} + +#include "valgrind_widget.moc" diff --git a/parts/valgrind/valgrind_widget.h b/parts/valgrind/valgrind_widget.h new file mode 100644 index 00000000..1777e183 --- /dev/null +++ b/parts/valgrind/valgrind_widget.h @@ -0,0 +1,44 @@ +#ifndef __VALGRIND_WIDGET_H__ +#define __VALGRIND_WIDGET_H__ + +#include <qwidget.h> +#include <qstring.h> +#include <qstringlist.h> + +#include "valgrinditem.h" + +class ValgrindPart; +class KListView; +class QListViewItem; +class QPopupMenu; + +class ValgrindWidget : public QWidget +{ + Q_OBJECT + +public: + ValgrindWidget( ValgrindPart *part ); + ~ValgrindWidget(); + + void addMessage( const ValgrindItem& vi ); + void clear(); + +signals: + void jumpToFile( const QString& url, int line ); + +private slots: + void executed( QListViewItem* item ); + void slotContextMenu( KListView* l, QListViewItem* i, const QPoint& p ); + void expandAll(); + void collapseAll(); + void aboutToShowPopup(); + +private: + KListView* lv; + int msgNumber; + ValgrindPart* _part; + QPopupMenu* popup; +}; + + +#endif diff --git a/parts/valgrind/valgrinditem.cpp b/parts/valgrind/valgrinditem.cpp new file mode 100644 index 00000000..318254d3 --- /dev/null +++ b/parts/valgrind/valgrinditem.cpp @@ -0,0 +1,71 @@ +#include "valgrinditem.h" + +#include <qregexp.h> +#include <qstringlist.h> + +#include <kdebug.h> + +ValgrindBacktraceItem::ValgrindBacktraceItem( const QString& rawOutput ): _rawOutput( rawOutput ), _highlight( false ) +{ + QRegExp re1( "^==(\\d+)==\\s+(by|at) (0x[\\dABCDEF]+): (.*) \\((.*):(\\d+)\\)$" ); + QRegExp re2( "^==(\\d+)==\\s+(by|at) (0x[\\dABCDEF]+): (.*) \\(in (.*)\\)$" ); + QRegExp valRe( "==(\\d+)== (.*)" ); + if ( valRe.search( _rawOutput ) >= 0 ) + _message = valRe.cap( 2 ); + if ( re1.search( _rawOutput ) >= 0 ) { + _type = SourceCode; + _pid = re1.cap( 1 ).toInt(); + _address = re1.cap( 3 ); + _function = re1.cap( 4 ); + _url = re1.cap( 5 ); + _line = re1.cap( 6 ).toInt(); + } else if ( re2.search( _rawOutput ) >= 0 ) { + _type = Library; + _pid = re2.cap( 1 ).toInt(); + _address = re2.cap( 3 ); + _function = re2.cap( 4 ); + _url = re2.cap( 5 ); + _line = -1; + } else { + _type = Unknown; + _line = -1; + _pid = -1; + } +} + +ValgrindBacktraceItem::~ValgrindBacktraceItem() +{ +} + + +ValgrindItem::ValgrindItem( const QString& message ): _pid(-1) +{ + QRegExp valRe( "==(\\d+)== (.*)" ); + QStringList lines = QStringList::split( "\n", message ); + QString curMsg; + + for ( QStringList::ConstIterator it = lines.begin(); it != lines.end(); ++it ) { + if ( valRe.search( *it ) < 0 ) { + kdDebug() << "ValgrindItem: got unrecognizable line '" << *it << "'" << endl; + continue; // not of interest + } + if ( _pid == -1 ) + _pid = valRe.cap( 1 ).toInt(); + curMsg = valRe.cap( 2 ); + + if ( curMsg.startsWith( " " ) ) { + _backtrace.append( ValgrindBacktraceItem( *it ) ); + } else { + if ( !_message.isEmpty() ) + _message += "\n"; + _message += curMsg; + } + } +// static int i = 0; +// kdDebug() << "got: " << ++i << ": " << _message << endl << message << endl; +} + + +ValgrindItem::~ValgrindItem() +{ +} diff --git a/parts/valgrind/valgrinditem.h b/parts/valgrind/valgrinditem.h new file mode 100644 index 00000000..12784c42 --- /dev/null +++ b/parts/valgrind/valgrinditem.h @@ -0,0 +1,50 @@ +#ifndef _VALGRINDITEM_H_ +#define _VALGRINDITEM_H_ + +#include <qvaluelist.h> +#include <qstring.h> + +class ValgrindBacktraceItem +{ +public: + enum Type { Unknown, SourceCode, Library }; + ValgrindBacktraceItem( const QString& rawOutput = QString::null ); + ~ValgrindBacktraceItem(); + + QString message() const { return _message; } + QString address() const { return _address; } + QString url() const { return _url; } + QString function() const { return _function; } + int line() const { return _line; } + int pid() const { return _pid; } + Type type() const { return _type; } + bool isHighlighted() const { return _highlight; } + void setHighlighted( bool h ) { _highlight = h; } + +private: + QString _rawOutput, _address, _url, _function, _message; + int _line; + int _pid; + Type _type; + bool _highlight; +}; + +class ValgrindItem +{ +public: + ValgrindItem( const QString& message ); + ~ValgrindItem(); + + typedef QValueList<ValgrindBacktraceItem> BacktraceList; + BacktraceList& backtrace() { return _backtrace; } + const BacktraceList& backtrace() const { return _backtrace; } + QString message() const { return _message; } + int pid() const { return _pid; } + +private: + BacktraceList _backtrace; + QString _message; + int _pid; +}; + +#endif |