• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

kmobiletools

crashhandler.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002 *   Copyright (C) 2007 Sérgio Gomes <sergiomdgomes@gmail.com>             *
00003 *   Original work by Max Howell <max.howell@methylblue.com> in Amarok     *
00004 *                                                                         *
00005 *   This program is free software; you can redistribute it and/or modify  *
00006 *   it under the terms of the GNU General Public License as published by  *
00007 *   the Free Software Foundation; either version 2 of the License, or     *
00008 *   (at your option) any later version.                                   *
00009 *                                                                         *
00010 ***************************************************************************/
00011 
00012 #include "crashhandler.h"
00013 #include "aboutdata.h"
00014 
00015 #include <kdebug.h>       //kBacktrace()
00016 #include <kdeversion.h>
00017 #include <klocale.h>
00018 #include <ktemporaryfile.h>
00019 
00020 #include <qfile.h>
00021 #include <qregexp.h>
00022 #include <q3textstream.h>
00023 #include <qglobal.h> //qVersion()
00024 //Added by qt3to4:
00025 #include <Q3CString>
00026 #include <kglobal.h>
00027 #include <kstandarddirs.h>
00028 
00029 #include <cstdio>         //popen, fread
00030 #include <iostream>
00031 #include <sys/types.h>    //pid_t
00032 #include <sys/wait.h>     //waitpid
00033 #include <unistd.h>       //write, getpid
00034 #include <ktoolinvocation.h>
00035 
00036 namespace KMobileTools
00037 {
00038     static QString runCommand( const Q3CString &command )
00039     {
00040         static const uint SIZE = 40960; //40 KiB
00041         static char stdoutBuf[ SIZE ] = {0};
00042 
00043         std::cout << "Running: " << command.constData() << std::endl;
00044 
00045         FILE *process = ::popen( command, "r" );
00046         if ( process )
00047         {
00048             stdoutBuf[ std::fread( static_cast<void*>( stdoutBuf ), sizeof(char), SIZE-1, process ) ] = '\0';
00049                 ::pclose( process );
00050         }
00051         return QString::fromLocal8Bit( stdoutBuf );
00052     }
00053 
00054     void Crash::crashHandler( int /*signal*/ )
00055     {
00056         // we need to fork to be able to get a
00057         // semi-decent bt - I dunno why
00058         const pid_t pid = ::fork();
00059 
00060         if( pid < 0 )
00061         {
00062             std::cout << "forking crash reporter failed\n";
00063             // continuing now can't do no good
00064             _exit( 1 );
00065     }
00066     else if ( pid == 0 )
00067     {
00068             // we are the child process (the result of the fork)
00069         std::cout << "KMobileTools is crashing...\n";
00070 
00071         QString subject = KMOBILETOOLS_VERSION " ";
00072         QString body = i18n(
00073                 "KMobileTools has crashed! We are terribly sorry about this :(\n\n"
00074                 "But, all is not lost! You could potentially help us fix the crash. "
00075                 "Information describing the crash is below, so just click send, "
00076                 "or if you have time, write a brief description of how the crash happened first.\n\n"
00077                 "If you want, you can also add as attachment KMobileTools log files. You can find them in %1\n\n"
00078                 "Many thanks.\n\n", KGlobal::dirs()->saveLocation("tmp", "kmobiletools", true) );
00079         body += i18n( "\n\n\n\n\n\n"
00080                 "The information below is to help the developers identify the problem, "
00081                 "please do not modify it.\n\n\n\n" );
00082 
00083 
00084         body += "======== DEBUG INFORMATION  =======\n"
00085                 "Version:    " KMOBILETOOLS_VERSION "\n"
00086                 "Build date: " __DATE__ "\n"
00087                 "CC version: " __VERSION__ "\n" //assuming we're using GCC
00088                 "KDElibs:    " KDE_VERSION_STRING "\n"
00089                 "Qt:         %1\n"
00090                 "CPU count:  %2\n";
00091 
00092         QString cpucount = "unknown";
00093 #ifdef __linux__
00094             QString line;
00095             uint cpuCount = 0;
00096             QFile cpuinfo( "/proc/cpuinfo" );
00097             if ( cpuinfo.open( QIODevice::ReadOnly ) ) {
00098                 while ( cpuinfo.readLine( line, 20000 ) != -1 ) {
00099                     if ( line.startsWith( "processor" ) ) {
00100                         ++cpuCount;
00101                     }
00102                 }
00103             }
00104             cpucount = QString::number( cpuCount );
00105 #endif
00106 
00107 
00108             body = body.arg( qVersion() )
00109                     .arg( cpucount );
00110 
00111 #ifdef NDEBUG
00112             body += "NDEBUG:     true";
00113 #endif
00114             body += '\n';
00115 
00117 
00118             KTemporaryFile temp;
00119             temp.setAutoRemove( true );
00120 
00121             const int handle = temp.handle();
00122 
00123 //             QCString gdb_command_string =
00124 //                     "file amarokapp\n"
00125 //                     "attach " + QCString().setNum( ::getppid() ) + "\n"
00126 //                     "bt\n" "echo \\n\n"
00127 //                     "thread apply all bt\n";
00128 
00129             const Q3CString gdb_batch =
00130                     "bt\n"
00131                     "echo \\n\\n\n"
00132                     "bt full\n"
00133                     "echo \\n\\n\n"
00134                     "echo ==== (gdb) thread apply all bt ====\\n\n"
00135                     "thread apply all bt\n";
00136 
00137             ::write( handle, gdb_batch, gdb_batch.length() );
00138             ::fsync( handle );
00139 
00140             // so we can read stderr too
00141             ::dup2( fileno( stdout ), fileno( stderr ) );
00142 
00143 
00144             Q3CString gdb;
00145             gdb  = "gdb --nw -n --batch -x ";
00146             gdb += temp.name().latin1();
00147             gdb += " kmobiletools ";
00148             gdb += Q3CString().setNum( ::getppid() );
00149 
00150             QString bt = runCommand( gdb );
00151 
00153             bt.remove( "(no debugging symbols found)..." );
00154             bt.remove( "(no debugging symbols found)\n" );
00155             bt.replace( QRegExp("\n{2,}"), "\n" ); //clean up multiple \n characters
00156             bt.trimmed();
00157 
00159             bool useful = true;
00160             const QString fileCommandOutput = runCommand( "file `which kmobiletools`" );
00161 
00162             if( fileCommandOutput.find( "not stripped", false ) == -1 )
00163                 subject += "[___stripped]"; //same length as below
00164             else
00165                 subject += "[NOTstripped]";
00166 
00167             if( !bt.isEmpty() ) {
00168                 const int invalidFrames = bt.count( QRegExp("\n#[0-9]+\\s+0x[0-9A-Fa-f]+ in \\?\\?") );
00169                 const int validFrames = bt.count( QRegExp("\n#[0-9]+\\s+0x[0-9A-Fa-f]+ in [^?]") );
00170                 const int totalFrames = invalidFrames + validFrames;
00171         const int sourceFrames = bt.count( QRegExp("at[\\s]+[\\w]+\\.(cpp|h):[\\d]+") );
00172         
00173             body += QString("Total frames: %1, invalid: %2, valid: %3, with source: %4\n\n")
00174         .arg(totalFrames).arg(invalidFrames).arg(validFrames).arg(sourceFrames);
00175 
00176                 if( totalFrames > 0 ) {
00177                     const double validity = (double(validFrames) / totalFrames) * sourceFrames;
00178                     subject += QString("[validity: %1]").arg( validity, 0, 'f', 2 );
00179                     if( validity <= 0.5 || sourceFrames==0 ) useful = false;
00180                 }
00181                 subject += QString("[frames: %1]").arg( totalFrames, 3 /*padding*/ );
00182 
00183                 if( bt.find( QRegExp(" at \\w*\\.cpp:\\d+\n") ) >= 0 )
00184                     subject += "[line numbers]";
00185             }
00186             else
00187                 useful = false;
00188 
00189             std::cout << subject.latin1() << std::endl;
00190 
00191 
00192             //TODO -fomit-frame-pointer buggers up the backtrace, so detect it
00193             //TODO -O optimization can rearrange execution and stuff so show a warning for the developer
00194             //TODO pass the CXXFLAGS used with the email
00195 
00196             if( useful ) {
00197                 body += "==== file `which kmobiletools` =======\n";
00198                 body += fileCommandOutput + "\n\n";
00199                 body += "==== (gdb) bt =====================\n";
00200                 body += bt + "\n\n";
00201                 body += "==== kBacktrace() ================\n";
00202                 body += kBacktrace();
00203 
00204                 //TODO startup notification
00205                 KToolInvocation::invokeMailer(
00206                         /*to*/          "bugs@kmobiletools.org",
00207                         /*cc*/          QString(),
00208                         /*bcc*/         QString(),
00209                         /*subject*/     subject,
00210                         /*body*/        body,
00211                         /*messageFile*/ QString(),
00212                         /*attachURLs*/  QStringList(),
00213                         /*startup_id*/  "" );
00214             }
00215             else {
00216                 std::cout << qPrintable( i18n( "\nKMobileTools has crashed! We are terribly sorry about this :(\n\n"
00217                         "But, all is not lost! Perhaps an upgrade is already available "
00218                         "which fixes the problem. Please check your distribution's software repository.\n" ) );
00219             }
00220 
00221             //_exit() exits immediately, otherwise this
00222             //function is called repeatedly ad finitum
00223             ::_exit( 255 );
00224     }
00225 
00226     else {
00227             // we are the process that crashed
00228 
00229             ::alarm( 0 );
00230 
00231             // wait for child to exit
00232             ::waitpid( pid, NULL, 0 );
00233             ::_exit( 253 );
00234     }
00235     }
00236 }
00237 

kmobiletools

Skip menu "kmobiletools"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal