[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    drkonqi and backtrace analysis
From:       Lubos Lunak <l.lunak () suse ! cz>
Date:       2008-08-04 10:54:27
Message-ID: 200808041254.27768.l.lunak () suse ! cz
[Download RAW message or body]

Hello,

 I'm not sure if anybody has noticed, but bugs.kde.org currently has loads of 
reports with completely useless backtraces (and so there has to step in the 
human factor in the form of the bug squad and do the 
useless-please-install-debuginfo-heres-techbase-link routine). I've already 
fixed that and rewrote the code a bit so hopefully next time it'll be simpler 
also for somebody else to save the day, however with the usage of hidden 
symbol visibility and so on useless backtraces have become quite common, so 
these days it's not very nice to just shrug off all of those.

 Therefore I'd like to commit the attached patch which should try harder when 
analysing the backtrace and should also collect information about which 
binaries are missing debuginfo. The idea is that distributions will also ship 
$KDEDIR/lib/kde4/libexec/installdebuginfo [1], and if it is available then 
drkonqi will offer installing the necessary debugging packages and try again.

 I would like to also backport this to 4.1, together with the fixes which 
already are in trunk, but a) this adds new i18n, and b) I think it needs some 
testing, as there are still some issues I'm unsure about, such as:
- the dialog offering to install debugging packages hides the backtrace, so 
one cannot actually tell if it's really necessary - any ideas for a better UI 
solution?
- it currently lists even things like libc in the list of libraries needing 
debuginfo if it's present in the backtrace, which may not be usually 
necessary - should it restrict the list just to KDE/Qt libs or any better 
ideas?
- it is a question whether the detection whether a backtrace is or is not 
useless is not too strict - e.g. the backtrace from [2] is currently flagged 
[3] as useless (with the copy and save buttons disabled), but it looks like 
it could be actually good enough - is it ok to still complain, or any ideas?

[1] see Debuginfo::installDebuginfo() for invocation
[2] http://lists.kde.org/?l=kde-devel&m=121784325621415&w=2
[3] for debugging it is possible to make it process any backtrace, see 
beginning of BackTraceGdb::processDebuggerOutput()

-- 
Lubos Lunak
KDE developer
--------------------------------------------------------------
SUSE LINUX, s.r.o.   e-mail: l.lunak@suse.cz , l.lunak@kde.org
Lihovarska 1060/12   tel: +420 284 028 972
190 00 Prague 9      fax: +420 284 028 951
Czech Republic       http://www.suse.cz

["drkonqi.patch" (text/x-diff)]

--- drkonqi/debugger.cpp.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/debugger.cpp	2008-08-04 12:32:27.000000000 +0200
@@ -45,6 +45,7 @@
 
 #include "backtracegdb.h"
 #include "krashconf.h"
+#include "debuginfo.h"
 #include "debugger.moc"
 
 KrashDebugger :: KrashDebugger (const KrashConfig *krashconf, QWidget *parent)
@@ -91,12 +92,39 @@ KrashDebugger :: ~KrashDebugger()
   //  delete m_proctrace;
 }
 
-void KrashDebugger :: slotDone(const QString& str)
+void KrashDebugger::slotDone()
 {
   m_status->setText(i18nc("debugging finished", "Backtrace loaded."));
-  m_copyButton->setEnabled( true );
-  m_saveButton->setEnabled( true );
-  m_backtrace->setPlainText( m_prependText + str ); // replace with possibly \
post-processed backtrace +  // replace with possibly post-processed backtrace
+  m_backtrace->setPlainText( m_prependText + m_proctrace->processedInfo());
+  Debuginfo db;
+  db.check( m_proctrace, this );
+  if( db.shouldRestart()) {
+      // try again
+      m_backtrace->clear();
+      m_prependText.clear();
+      m_proctrace->deleteLater();
+      m_proctrace = NULL;
+      startDebugger();
+      return;
+  }
+  if( db.allowSending()) {
+      m_copyButton->setEnabled( true );
+      m_saveButton->setEnabled( true );
+  } else {
+      m_prependText.prepend( i18n( "Unable to create a valid backtrace." ) + "\n\n" \
); +      m_backtrace->setPlainText( m_prependText + m_proctrace->debuggerOutput());
+  }
+}
+
+void KrashDebugger::slotSomeError()
+{
+  QString str = i18n( "Failed to create a valid backtrace. This is probably "
+      "because you do not have the necessary debugging tools installed." );
+  KMessageBox::sorry(this, i18n("Unable to create a backtrace.") + "\n\n" 
+      + str + "\n\n" );
+  m_status->setText(i18n("Unable to create a valid backtrace."));
+  m_backtrace->setPlainText( str + "\n\n" + m_backtrace->toPlainText());
 }
 
 void KrashDebugger :: slotCopy()
@@ -159,21 +187,6 @@ void KrashDebugger :: slotSave()
   }
 }
 
-void KrashDebugger :: slotSomeError()
-{
-  KMessageBox::sorry(this, i18n("Unable to create a valid backtrace.") + "\n\n" 
-      + 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_status->setText(i18n("Unable to create a valid backtrace."));
-  m_backtrace->setPlainText(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->toPlainText());
-}
-
 void KrashDebugger :: slotAppend(const QString &str)
 {
   m_status->setText(i18n("Loading backtrace..."));
@@ -221,7 +234,7 @@ void KrashDebugger :: startDebugger()
 
   connect(m_proctrace, SIGNAL(append(const QString &)),
           SLOT(slotAppend(const QString &)));
-  connect(m_proctrace, SIGNAL(done(const QString&)), SLOT(slotDone(const \
QString&))); +  connect(m_proctrace, SIGNAL(done()), SLOT(slotDone()));
   connect(m_proctrace, SIGNAL(someError()), SLOT(slotSomeError()));
 
   m_proctrace->start();
--- drkonqi/backtracegdb.cpp.sav	2008-08-01 16:45:35.000000000 +0200
+++ drkonqi/backtracegdb.cpp	2008-08-04 12:33:24.000000000 +0200
@@ -46,6 +46,7 @@
 BackTraceGdb::BackTraceGdb(const KrashConfig *krashconf, QObject *parent)
   : BackTrace(krashconf,parent)
   , backtraceWithCrash( 0 )
+  , useful( Useless )
 {
 }
 
@@ -55,6 +56,14 @@ BackTraceGdb::~BackTraceGdb()
 
 QString BackTraceGdb::processDebuggerOutput( QString bt )
 {
+#if 0
+    // for debugging
+    QFile test( "bt.txt" );
+    if( !test.open( QFile::ReadOnly ))
+        abort();
+    bt = QString::fromUtf8( test.readAll());
+    test.close();
+#endif
     QStringList lines = bt.split( '\n' );
     // read the common part until backtraces are found (either line starting with
     // something like 'Thread 1 (Thread 0xb5d3f8e0 (LWP 25088)):' or directly the \
first @@ -84,7 +93,7 @@ QString BackTraceGdb::processDebuggerOut
     }
     // remove some not very useful lines like '(no debugging symbols)', etc.
     common = removeLines( common, QRegExp( ".*\\(no debugging symbols found\\).*" \
                ));
-    common = removeLines( common, QRegExp( "\\[Thread debugging using libthread_db \
enabled\\]" )); +    common = removeLines( common, QRegExp( ".*\\[Thread debugging \
                using libthread_db enabled\\]" ));
     common = removeLines( common, QRegExp( "\\[New Thread 0x[0-9a-f]+\\s+\\(LWP \
                [0-9]+\\)\\]" ));
     // remove the line that shows where the process is at the moment '0xffffe430 in \
                __kernel_vsyscall ()',
     // gdb prints that automatically, but it will be later visible again in the \
backtrace @@ -97,9 +106,16 @@ QString BackTraceGdb::processDebuggerOut
          ++i )
         processBacktrace( i );
 
+    checkUseful();
+
     QString ret = common.join( "\n" );
-    foreach( const QStringList& bt, backtraces )
-        ret += '\n' + bt.join( "\n" );
+    // put the backtrace with the crash always first
+    ret += "\n" + backtraces[ backtraceWithCrash ].join( "\n" );
+    for( int i = 0;
+         i < backtraces.count();
+         ++i )
+        if( i != backtraceWithCrash )
+            ret += "\n" + backtraces[ i ].join( "\n" );
     ret += '\n';  
     return ret;
 }
@@ -124,27 +140,63 @@ void BackTraceGdb::processBacktrace( int
     }
 }
 
-bool BackTraceGdb::usefulDebuggerOutput( QString /*bt - use already done parsing*/ )
+void BackTraceGdb::checkUseful()
 {
+    useful = Complete;
     if( common.isEmpty() || backtraces.isEmpty())
-        return false;
-    if( !usefulBacktrace( backtraceWithCrash ))
-        return false;
-    // ignore other backtraces from other threads as hopefully irrelevant
-    return true;
+    {
+        useful = Useless;
+        return;
+    }
+    for( int i = 0;
+         i < backtraces.count();
+         ++i )
+        checkUsefulBacktrace( i, i == backtraceWithCrash );
+    if( !binariesMissingDebug.isEmpty())
+        useful = qMin( useful, Incomplete );
 }
-
-bool BackTraceGdb::usefulBacktrace( int index )
+  
+void BackTraceGdb::checkUsefulBacktrace( int index, bool primary )
 {
     QStringList& bt = backtraces[ index ];
     QRegExp backtracestart( "#[0-9]+ .*" ); // not #0, probably replaces by \
[KCrash...]  int start = bt.indexOf( backtracestart );
     if( start < 0 )
-        return false;
-    int end = bt.count() - 1;
-    while( end >= 0 && bt[ end ].isEmpty())
+    {
+        useful = primary ? Useless : qMin( useful, PartiallyBroken );
+        return;
+    }
+    int end = bt.count(); // points after end
+    while( end > 0 && bt[ end - 1 ].isEmpty())
         --end;
-    int frames = end - start + 1;
+    int frames = end - start;
+    // read involved libraries without debug info
+    QRegExp backtracenodebug( \
"#[0-9]+\\s+0x[0-9a-f]+\\s+in\\s+\\S+\\s+\\(?\\)?\\s+from\\s+(\\S+)\\s*" ); +    for( \
int i = start; +         i < end;
+         ++i )
+    {
+        if( backtracenodebug.exactMatch( bt[ i ] ))
+        {
+            QString lib = backtracenodebug.cap( 1 );
+            if( !binariesMissingDebug.contains( lib ))
+                binariesMissingDebug.append( lib );
+        }
+    }
+    // add the binary to the list of missing debuginfo if there is any frame without \
specifying any location +    // (i.e. '#12 0x08048b95 in ?? ()' )
+    QRegExp backtracenodebugbinary( \
"#[0-9]+\\s+0x[0-9a-f]+\\s+in\\s+[\\S\\?]+\\s+\\(?\\)?\\s*" ); +    for( int i = \
start; +         i < end;
+         ++i )
+    {
+        if( backtracenodebugbinary.exactMatch( bt[ i ] )) {
+            QString binary = KStandardDirs::findExe( m_krashconf->programName());
+            if( !binary.isEmpty())
+                binariesMissingDebug.append( binary );
+            break;
+        }
+    }
     // topmost items must mean something, otherwise the backtrace is not very \
usable,  // which means ok is:
     // - no ?? at all in first 3 items (or all of them, if there are less than 3 \
frames) @@ -168,8 +220,10 @@ bool BackTraceGdb::usefulBacktrace( int
         ok = true;
     }
     if( !ok )
-        return false;
-    return true;
+    {
+        useful = primary ? Useless : qMin( useful, PartiallyBroken );
+        return;
+    }
 }
 
 QStringList BackTraceGdb::removeLines( QStringList list, const QRegExp& regexp )
@@ -217,3 +271,13 @@ bool BackTraceGdb::prettyKcrashHandler(
     }
     return false;
 }
+
+QStringList BackTraceGdb::missingDebuginfo() const
+{
+    return binariesMissingDebug;
+}
+
+BackTrace::Usefulness BackTraceGdb::usefulness() const
+{
+    return useful;
+}
--- drkonqi/backtrace.cpp.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/backtrace.cpp	2008-08-01 17:45:37.000000000 +0200
@@ -122,6 +122,7 @@ void BackTrace::slotReadInput()
         m_output.remove(0, pos + 1);
 
         m_strBt.append(line);
+        m_debuggerOutput.append(line);
         emit append(line);
     }
 }
@@ -137,8 +138,15 @@ void BackTrace::slotProcessExited(int ex
     return;
   }
   m_strBt = processDebuggerOutput( m_strBt );
-  if( m_krashconf->disableChecks() || usefulDebuggerOutput( m_strBt ))
-    emit done(m_strBt);
-  else
-    emit someError();
+  emit done();
+}
+
+QString BackTrace::processedInfo() const
+{
+  return m_strBt;
+}
+
+QString BackTrace::debuggerOutput() const
+{
+  return m_debuggerOutput;
 }
--- drkonqi/debugger.h.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/debugger.h	2008-08-01 16:48:26.000000000 +0200
@@ -46,7 +46,7 @@ public:
 
 public Q_SLOTS:
   void slotAppend(const QString &);
-  void slotDone(const QString&);
+  void slotDone();
   void slotSomeError();
 
 protected:
--- drkonqi/backtrace.h.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/backtrace.h	2008-08-01 17:44:43.000000000 +0200
@@ -33,6 +33,9 @@ class KTemporaryFile;
 
 #include <KProcess>
 
+/**
+ A class that creates and analyzes the backtrace and other information related to \
the crash. + */
 class BackTrace : public QObject
 {
   Q_OBJECT
@@ -41,28 +44,86 @@ public:
   static BackTrace* create(const KrashConfig* krashconf, QObject* parent);
   ~BackTrace();
 
+  /**
+   Starts retrieving and analyzing the crash information.
+   Signal append() will be emitted with new data and either someError()
+   or done() will be emitted after finished.
+   */
   void start();
+  /**
+   After done() is emitted, this function provides a list of libraries that
+   are involved in the backtrace and do not have debug information available.
+   They are sorted starting with the most important (topmost) stack frame,
+   the last item is the binary of the application itself.
+   */
+  virtual QStringList missingDebuginfo() const = 0;
+  /**
+   After done() is emitted, this provides the processed crash information \
(backtrace). +   */
+  virtual QString processedInfo() const;
+  /**
+   This functions gives the unmodified debugger output used for processedInfo().
+   */
+  QString debuggerOutput() const;
+  
+  /**
+   Enum describing how useful the resulting crash information is. It can be either \
complete +   (full information is available, including debug information), incomplete \
(useful, but +   debug information is not full, user should be suggested to install \
debug packages +   to improve it), partially broken (still probably useful, but some \
stack frames may be +   missing, user should be encourages to install debug packages \
to fix it) and useless +   (completely unusable).
+   */
+  enum Usefulness
+  { // ordering is important, code uses qMin()
+      Useless,
+      PartiallyBroken,
+      Incomplete,
+      Complete
+  };
+
+  /**
+   Gives how useful was the crash information found after processing it.
+   */
+  virtual Usefulness usefulness() const = 0;
 
 Q_SIGNALS:
+  /**
+   Provides parts of the crash information (new data should be appended to the \
previous data). +   This is provided while the information is still read and is not \
processed in any way. +   */
   void append(const QString &str); // Just the new text
-
+  /**
+   Reading the crash information was finished. Use the usefulness() call to see how \
useful it was +   found by the analysis. When the usefulness is low, the user should \
be encouraged to install +   debug packages for libraries given by missingDebuginfo() \
and restarting reading the crash +   information. The actual resulting crash \
information is available from processedInfo(). +   */
+  void done();
+  /**
+   There was an unknown error while trying to gather crash information, such as no \
debugger +   being available.
+   */
   void someError();
-  void done(const QString &); // replaces whole text
-
-protected Q_SLOTS:
-  void slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus);
-  void slotReadInput();
 
 protected:
   BackTrace(const KrashConfig *krashconf, QObject *parent);
+  /**
+   Processes the output from the debugger and returns it, or returns just unmodified \
output +   if there were problems with analysing it.
+   */
   virtual QString processDebuggerOutput( QString bt ) = 0;
-  virtual bool usefulDebuggerOutput( QString bt ) = 0;
   const KrashConfig * const m_krashconf;
 
+protected Q_SLOTS:
+  void slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus);
+  void slotReadInput();
+
 private:
   KProcess *m_proc;
   KTemporaryFile *m_temp;
   QString m_strBt;
+  QString m_debuggerOutput;
   QByteArray m_output;
 };
 #endif
--- drkonqi/debuginfo.h.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/debuginfo.h	2008-08-01 16:48:26.000000000 +0200
@@ -0,0 +1,53 @@
+/*****************************************************************
+ * drkonqi - The KDE Crash Handler
+ *
+ * Copyright (C) 2008 Lubos Lunak <l.lunak@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.
+ *****************************************************************/
+
+#ifndef DEBUGINFO_H
+#define DEBUGINFO_H
+
+#include <qobject.h>
+
+class BackTrace;
+
+/**
+ * Check how useful the backtrace is, offer installing debuginfo packages.
+ */
+class Debuginfo : public QObject
+{
+  Q_OBJECT
+
+public:
+  Debuginfo();
+  void check( BackTrace* bt, QWidget* w );
+  bool shouldRestart() const;
+  bool allowSending() const;
+private:
+  bool installDebuginfo( BackTrace* bt, QWidget* w );
+  bool restart;
+  bool allow;
+  QString installtool;
+};
+#endif
--- drkonqi/CMakeLists.txt.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/CMakeLists.txt	2008-08-01 16:48:26.000000000 +0200
@@ -11,6 +11,7 @@ set(drkonqi_SRCS
    drbugreport.cpp 
    backtrace.cpp 
    backtracegdb.cpp
+   debuginfo.cpp
    toplevel.cpp )
 
 kde4_add_executable(drkonqi ${drkonqi_SRCS})
--- drkonqi/toplevel.cpp.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/toplevel.cpp	2008-08-01 16:48:26.000000000 +0200
@@ -40,6 +40,7 @@
 #include "drbugreport.h"
 #include "debugger.h"
 #include "krashconf.h"
+#include "debuginfo.h"
 
 #include "toplevel.moc"
 
@@ -178,16 +179,7 @@ void Toplevel :: slotUser1()
   m_bugreport = new DrKBugReport(this, true, m_krashconf->aboutData());
 
   if (i == KMessageBox::Yes) {
-    QApplication::setOverrideCursor ( Qt::WaitCursor );
-
-    // generate the backtrace
-    BackTrace *backtrace = BackTrace::create( m_krashconf, this );
-    connect(backtrace, SIGNAL(someError()), SLOT(slotBacktraceSomeError()));
-    connect(backtrace, SIGNAL(done(const QString &)),
-            SLOT(slotBacktraceDone(const QString &)));
-
-    backtrace->start();
-
+    generateBacktrace();
     return;
   }
 
@@ -198,6 +190,19 @@ void Toplevel :: slotUser1()
      close();
 }
 
+void Toplevel::generateBacktrace()
+{
+    QApplication::setOverrideCursor ( Qt::WaitCursor );
+
+    // generate the backtrace
+    BackTrace *backtrace = BackTrace::create( m_krashconf, this );
+    connect(backtrace, SIGNAL(someError()), SLOT(slotBacktraceSomeError()));
+    connect(backtrace, SIGNAL(done()),
+            SLOT(slotBacktraceDone()));
+
+    backtrace->start();
+}
+
 void Toplevel :: slotUser2()
 {
   QString str = m_krashconf->debuggerCommand();
@@ -219,16 +224,31 @@ void Toplevel :: slotUser3()
   m_krashconf->acceptDebuggingApp();
 }
 
-void Toplevel :: slotBacktraceDone(const QString &str)
+void Toplevel :: slotBacktraceDone()
 {
+  QApplication::restoreOverrideCursor();
+
+  BackTrace* bt = static_cast< BackTrace* >( sender());
+  Debuginfo db;
+  db.check( bt, this );
+  if( db.shouldRestart()) {
+      // try again
+      bt->deleteLater();
+      generateBacktrace();
+      return;
+  }
+  if( !db.allowSending()) {
+      delete m_bugreport;
+      m_bugreport = 0;
+      return;
+  }
+
   // Do not translate.. This will be included in the _MAIL_.
   QString buf = QLatin1String
-    ("\n\n\nHere is a backtrace generated by DrKonqi:\n") + str;
+    ("\n\n\nHere is a backtrace generated by DrKonqi:\n") + bt->processedInfo();
 
   m_bugreport->setText(buf);
 
-  QApplication::restoreOverrideCursor();
-
   m_bugreport->exec();
   delete m_bugreport;
   m_bugreport = 0;
--- drkonqi/debuginfo.cpp.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/debuginfo.cpp	2008-08-01 19:15:28.000000000 +0200
@@ -0,0 +1,142 @@
+/*****************************************************************
+ * drkonqi - The KDE Crash Handler
+ *
+ * Copyright (C) 2008 Lubos Lunak <l.lunak@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 "debuginfo.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+
+#include "backtrace.h"
+
+#include "debuginfo.moc"
+
+Debuginfo::Debuginfo()
+  : restart( false )
+  , allow( true )
+  , installtool( KStandardDirs::findExe( "installdebuginfo" ))
+{
+    
+}
+
+void Debuginfo::check( BackTrace* bt, QWidget* w )
+{
+    switch( bt->usefulness()) {
+        case BackTrace::Complete:
+            return; // all ok
+        case BackTrace::Incomplete:
+            if( installtool.isEmpty())
+                return; // missing debuginfo but can't install, consider to be ok
+            if( KMessageBox::questionYesNo( w, i18n( "This backtrace could be \
improved.") + "\n\n"  +                    + i18n("This backtrace appears to be \
useful, but it could be improved " +                    "by installing debugging \
packages, thus providing the developers " +                    "with more \
information." ) + "\n\n" +                    + i18n("Do you want to try to install \
debugging packages and regenerate " +                    "the backtrace?"),
+                    QString(), KStandardGuiItem::yes(), KStandardGuiItem::no(),
+                    "regenerateincomplete" )
+                    == KMessageBox::Yes ) {
+                if( installDebuginfo( bt, w )) {
+                    restart = true;
+                }
+            }
+            return;
+        case BackTrace::PartiallyBroken:
+            if( installtool.isEmpty()) // backtrace broken a bit but still partially \
useful,  +                return;  // missing debuginfo but can't install, let's say \
this is still ok +            if( KMessageBox::questionYesNo( w,
+                    i18n( "This backtrace appears to be partially broken.") + "\n\n" \
 +                    + i18n("This backtrace appears to be at least partially useful, \
" +                    "but it could be improved by installing debugging packages, "
+                    "thus providing the developers with more information." ) + \
"\n\n" +                    + i18n("Do you want to try to install debugging packages \
and regenerate " +                    "the backtrace?"),
+                    QString(), KStandardGuiItem::yes(), KStandardGuiItem::no(),
+                    "regeneratepartiallybroken" )
+                    == KMessageBox::Yes ) {
+                if( installDebuginfo( bt, w )) {
+                    restart = true;
+                }
+            }
+            return;
+        case BackTrace::Useless: {
+            allow = false;
+            if( installtool.isEmpty() || bt->missingDebuginfo().isEmpty()) {
+                KMessageBox::sorry( w, i18n("Unable to create a backtrace.") + \
"\n\n"  +                    + 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."));
+                return;
+            }
+            if( KMessageBox::questionYesNo( w, i18n( "Unable to create a \
backtrace.") + "\n\n"  +                    + 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"
+                    + i18n("Do you want to try to install debugging packages and \
regenerate " +                    "the backtrace?"),
+                    QString(), KStandardGuiItem::yes(), KStandardGuiItem::no(),
+                    "regenerateuseless" )
+                    == KMessageBox::Yes ) {
+                if( installDebuginfo( bt, w )) {
+                    restart = true;
+                }
+            }
+            return;
+        }
+    }
+}
+
+/*
+ Launch the tool as 'installdebuginfo --winid <parent window> <list of binaries>'.
+ Note that in the future there may be more options.
+*/
+bool Debuginfo::installDebuginfo( BackTrace* bt, QWidget* w )
+{
+    KProcess proc;
+    proc << installtool;
+    proc << "--winid" << QString::number( w->winId());
+    proc << bt->missingDebuginfo();
+    if( proc.execute() != 0 ) {
+        KMessageBox::sorry( w, i18n( "Installing debugging packages failed." ));
+        return false;
+    }
+    return true;
+}
+
+bool Debuginfo::shouldRestart() const
+{
+    return restart;
+}
+
+bool Debuginfo::allowSending() const
+{
+    return allow;
+}
--- drkonqi/backtracegdb.h.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/backtracegdb.h	2008-08-01 17:22:30.000000000 +0200
@@ -38,19 +38,23 @@ class BackTraceGdb : public BackTrace
 public:
   BackTraceGdb(const KrashConfig *krashconf, QObject *parent);
   ~BackTraceGdb();
+  virtual QStringList missingDebuginfo() const;
 
 protected:
   virtual QString processDebuggerOutput( QString bt );
-  virtual bool usefulDebuggerOutput( QString bt );
+  virtual Usefulness usefulness() const;
 private:
   void processBacktrace( int index );
-  bool usefulBacktrace( int index );
+  void checkUseful();
+  void checkUsefulBacktrace( int index, bool primary );
   QStringList removeLines( QStringList list, const QRegExp& regexp );
   QStringList removeFirstLine( QStringList list, const QRegExp& regexp );
   bool prettyKcrashHandler( int index );
   QStringList common; // the first part gdb output, before any backtraces
   QList< QStringList > backtraces; // backtraces, more if there are more threads
   int backtraceWithCrash; // index of the thread in which the crash happened
+  QStringList binariesMissingDebug; // list of binaries/libraries in the backtrace \
without debug info +  Usefulness useful;
 };
 
 #endif
--- drkonqi/toplevel.h.sav	2008-08-01 16:14:46.000000000 +0200
+++ drkonqi/toplevel.h	2008-08-01 16:48:26.000000000 +0200
@@ -57,10 +57,11 @@ protected Q_SLOTS:
 
 protected Q_SLOTS:
   void slotBacktraceSomeError();
-  void slotBacktraceDone(const QString &);
+  void slotBacktraceDone();
   void expandDetails(bool expand);
 
 private:
+  void generateBacktrace();
   KrashConfig *m_krashconf;
   DrKBugReport *m_bugreport;
   KrashDebugger *m_debugger;



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic