/***************************************************************** * drkonqi - The KDE Crash Handler * * Copyright (C) 2000-2003 Hans Petter Bieker <bieker@kde.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************/ #include <tqlayout.h> #include <tqhbox.h> #include <tqlabel.h> #include <kdialog.h> #include <klocale.h> #include <kglobal.h> #include <kglobalsettings.h> #include <kfiledialog.h> #include <kmessagebox.h> #include <kpushbutton.h> #include <kstdguiitem.h> #include <ktextbrowser.h> #include <ktempfile.h> #include "backtrace.h" #include "krashconf.h" #include "debugger.h" #include "debugger.moc" KrashDebugger :: KrashDebugger (const KrashConfig *krashconf, TQWidget *parent, const char *name) : TQWidget( parent, name ), m_krashconf(krashconf), m_proctrace(0) { TQVBoxLayout *vbox = new TQVBoxLayout( this, 0, KDialog::marginHint() ); vbox->setAutoAdd(TRUE); m_backtrace = new KTextBrowser(this); m_backtrace->setTextFormat(TQt::PlainText); m_backtrace->setFont(KGlobalSettings::fixedFont()); TQWidget *w = new TQWidget( this ); ( new TQHBoxLayout( w, 0, KDialog::marginHint() ) )->setAutoAdd( true ); m_status = new TQLabel( w ); m_status->tqsetSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Preferred ) ); //m_copyButton = new KPushButton( KStdGuiItem::copy(), w ); KGuiItem item( i18n( "C&opy" ), TQString::tqfromLatin1( "editcopy" ) ); m_copyButton = new KPushButton( item, w ); connect( m_copyButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotCopy() ) ); m_copyButton->setEnabled( false ); m_saveButton = new KPushButton( m_krashconf->safeMode() ? KStdGuiItem::save() : KStdGuiItem::saveAs(), w ); connect( m_saveButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotSave() ) ); m_saveButton->setEnabled( false ); } KrashDebugger :: ~KrashDebugger() { // This will SIGKILL gdb and SIGCONT program which crashed. // delete m_proctrace; } void KrashDebugger :: slotDone(const TQString& str) { m_status->setText(i18n("Done.")); m_copyButton->setEnabled( true ); m_saveButton->setEnabled( true ); m_backtrace->setText( m_prependText + str ); // replace with possibly post-processed backtrace } void KrashDebugger :: slotCopy() { m_backtrace->selectAll(); m_backtrace->copy(); } void KrashDebugger :: slotSave() { if (m_krashconf->safeMode()) { KTempFile tf(TQString::fromAscii("/tmp/"), TQString::fromAscii(".kcrash"), 0600); if (!tf.status()) { *tf.textStream() << m_backtrace->text(); tf.close(); KMessageBox::information(this, i18n("Backtrace saved to %1").arg(tf.name())); } else { KMessageBox::sorry(this, i18n("Cannot create a file in which to save the backtrace")); } } else { TQString defname = m_krashconf->execName() + TQString::tqfromLatin1( ".kcrash" ); if( defname.contains( '/' )) defname = defname.mid( defname.findRev( '/' ) + 1 ); TQString filename = KFileDialog::getSaveFileName(defname, TQString::null, this, i18n("Select Filename")); if (!filename.isEmpty()) { TQFile f(filename); if (f.exists()) { if (KMessageBox::Cancel == KMessageBox::warningContinueCancel( 0, i18n( "A file named \"%1\" already exists. " "Are you sure you want to overwrite it?" ).arg( filename ), i18n( "Overwrite File?" ), i18n( "&Overwrite" ) )) return; } if (f.open(IO_WriteOnly)) { TQTextStream ts(&f); ts << m_backtrace->text(); f.close(); } else { KMessageBox::sorry(this, i18n("Cannot open file %1 for writing").arg(filename)); } } } } void KrashDebugger :: slotSomeError() { m_status->setText(i18n("Unable to create a valid backtrace.")); m_backtrace->setText(i18n("This backtrace appears to be of no use.\n" "This is probably because your packages are built in a way " "which prevents creation of proper backtraces, or the stack frame " "was seriously corrupted in the crash.\n\n" ) + m_backtrace->text()); } void KrashDebugger :: slotAppend(const TQString &str) { m_status->setText(i18n("Loading backtrace...")); // append doesn't work here because it will add a newline as well m_backtrace->setText(m_backtrace->text() + str); } void KrashDebugger :: showEvent(TQShowEvent *e) { TQWidget::showEvent(e); startDebugger(); } void KrashDebugger :: startDebugger() { // Only start one copy if (m_proctrace || !m_backtrace->text().isEmpty()) return; TQString msg; bool checks = performChecks( &msg ); if( !checks && !m_krashconf->disableChecks()) { m_backtrace->setText( m_prependText + i18n( "The following options are enabled:\n\n" ) + msg + i18n( "\nAs the usage of these options is not recommended -" " because they can, in rare cases, be responsible for KDE problems - a backtrace" " will not be generated.\n" "You need to turn these options off and reproduce" " the problem again in order to get a backtrace.\n" )); m_status->setText( i18n( "Backtrace will not be created.")); return; } if( !msg.isEmpty()) { m_prependText += msg + '\n'; m_backtrace->setText( m_prependText ); } m_status->setText(i18n("Loading symbols...")); m_proctrace = new BackTrace(m_krashconf, TQT_TQOBJECT(this)); connect(m_proctrace, TQT_SIGNAL(append(const TQString &)), TQT_SLOT(slotAppend(const TQString &))); connect(m_proctrace, TQT_SIGNAL(done(const TQString&)), TQT_SLOT(slotDone(const TQString&))); connect(m_proctrace, TQT_SIGNAL(someError()), TQT_SLOT(slotSomeError())); m_proctrace->start(); } // this function check for "dangerous" settings, returns false // and message in case some of them are activated bool KrashDebugger::performChecks( TQString* msg ) { bool ret = true; KConfig kdedcfg( TQString::tqfromLatin1( "kdedrc" ), true ); kdedcfg.setGroup( "General" ); if( kdedcfg.readBoolEntry( "DelayedCheck", false )) { // ret = false; it's not that dangerous *msg += i18n( "System configuration startup check disabled.\n" ); } return ret; }