kmobiletools
crashhandler.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "crashhandler.h"
00013 #include "aboutdata.h"
00014
00015 #include <kdebug.h>
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>
00024
00025 #include <Q3CString>
00026 #include <kglobal.h>
00027 #include <kstandarddirs.h>
00028
00029 #include <cstdio>
00030 #include <iostream>
00031 #include <sys/types.h>
00032 #include <sys/wait.h>
00033 #include <unistd.h>
00034 #include <ktoolinvocation.h>
00035
00036 namespace KMobileTools
00037 {
00038 static QString runCommand( const Q3CString &command )
00039 {
00040 static const uint SIZE = 40960;
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 )
00055 {
00056
00057
00058 const pid_t pid = ::fork();
00059
00060 if( pid < 0 )
00061 {
00062 std::cout << "forking crash reporter failed\n";
00063
00064 _exit( 1 );
00065 }
00066 else if ( pid == 0 )
00067 {
00068
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"
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
00124
00125
00126
00127
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
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" );
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]";
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 );
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
00193
00194
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
00205 KToolInvocation::invokeMailer(
00206 "bugs@kmobiletools.org",
00207 QString(),
00208 QString(),
00209 subject,
00210 body,
00211 QString(),
00212 QStringList(),
00213 "" );
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
00222
00223 ::_exit( 255 );
00224 }
00225
00226 else {
00227
00228
00229 ::alarm( 0 );
00230
00231
00232 ::waitpid( pid, NULL, 0 );
00233 ::_exit( 253 );
00234 }
00235 }
00236 }
00237