Ran qt3to4
[basket4.git] / src / crashhandler.cpp
blobb6498aada29f1bbe438ba1448193b209b7e1657d
1 // Code from Amarok.
3 /***************************************************************************
4 * Copyright (C) 2005 Max Howell <max.howell@methylblue.com> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 ***************************************************************************/
13 //#include "amarok.h"
14 //#include "amarokconfig.h"
15 #include "crashhandler.h"
16 //#include "debug.h"
17 #include "config.h"
19 #include <kapplication.h> //invokeMailer()
20 #include <kaboutdata.h>
21 #include <kdeversion.h>
22 #include <klocale.h>
23 #include <ktempfile.h>
25 #include <qfile.h>
26 #include <qregexp.h>
27 #include <q3textstream.h>
28 //Added by qt3to4:
29 #include <Q3CString>
31 #include <cstdio> //popen, fread
32 #include <iostream>
33 #include <sys/types.h> //pid_t
34 #include <sys/wait.h> //waitpid
35 //#include <taglib/taglib.h>
36 #include <unistd.h> //write, getpid
40 //#ifndef TAGLIB_PATCH_VERSION
41 //// seems to be wheel's style
42 //#define TAGLIB_PATCH_VERSION 0
43 //#endif
46 #if 0
47 class CrashHandlerWidget : public KDialog {
48 public:
49 CrashHandlerWidget();
51 #endif
53 static QString
54 runCommand( const Q3CString &command )
56 static const uint SIZE = 40960; //40 KiB
57 static char stdoutBuf[ SIZE ];
59 // debug() << "Running: " << command << endl;
61 FILE *process = ::popen( command, "r" );
62 stdoutBuf[ std::fread( static_cast<void*>( stdoutBuf ), sizeof(char), SIZE-1, process ) ] = '\0';
63 ::pclose( process );
65 return QString::fromLocal8Bit( stdoutBuf );
68 void
69 Crash::crashHandler( int /*signal*/ )
71 // we need to fork to be able to get a
72 // semi-decent bt - I dunno why
73 const pid_t pid = ::fork();
75 if( pid <= 0 )
77 // we are the child process (the result of the fork)
78 // debug() << "amaroK is crashing...\n";
80 QString subject = "CRASH: " VERSION " ";
81 QString body = i18n(
82 "%1 has crashed! We're sorry about this.\n"
83 "\n"
84 "But, all is not lost! You could potentially help us fix the crash. "
85 "Information describing the crash is below, so just click send, "
86 "or if you have time, write a brief description of how the crash happened first.\n\n"
87 "Many thanks." ).arg(kapp->aboutData()->programName()) + "\n\n";
88 body += "\n\n\n\n\n\n" + i18n(
89 "The information below is to help the developers identify the problem, "
90 "please do not modify it." ) + "\n\n\n\n";
93 body += "======== DEBUG INFORMATION =======\n"
94 "Version: " VERSION "\n"
95 "Build date: " __DATE__ "\n"
96 "CC version: " __VERSION__ "\n" //assuming we're using GCC
97 "KDElibs: " KDE_VERSION_STRING "\n"
98 ;// "TagLib: %2.%3.%4\n";
100 /* body = body
101 .arg( TAGLIB_MAJOR_VERSION )
102 .arg( TAGLIB_MINOR_VERSION )
103 .arg( TAGLIB_PATCH_VERSION );*/
105 #ifdef NDEBUG
106 body += "NDEBUG: true";
107 #endif
108 body += "\n";
110 /// obtain the backtrace with gdb
112 KTempFile temp;
113 temp.setAutoDelete( true );
115 const int handle = temp.handle();
117 // QCString gdb_command_string =
118 // "file amarokapp\n"
119 // "attach " + QCString().setNum( ::getppid() ) + "\n"
120 // "bt\n" "echo \\n\n"
121 // "thread apply all bt\n";
123 const Q3CString gdb_batch =
124 "bt\n"
125 "echo \\n\\n\n"
126 "bt full\n"
127 "echo \\n\\n\n"
128 "echo ==== (gdb) thread apply all bt ====\\n\n"
129 "thread apply all bt\n";
131 ::write( handle, gdb_batch, gdb_batch.length() );
132 ::fsync( handle );
134 // so we can read stderr too
135 ::dup2( fileno( stdout ), fileno( stderr ) );
138 Q3CString gdb;
139 gdb = "gdb --nw -n --batch -x ";
140 gdb += temp.name().latin1();
141 gdb += " basket ";
142 gdb += Q3CString().setNum( ::getppid() );
144 QString bt = runCommand( gdb );
146 /// clean up
147 bt.remove( "(no debugging symbols found)..." );
148 bt.remove( "(no debugging symbols found)\n" );
149 bt.replace( QRegExp("\n{2,}"), "\n" ); //clean up multiple \n characters
150 bt.stripWhiteSpace();
152 /// analyze usefulness
153 bool useful = true;
154 const QString fileCommandOutput = runCommand( "file `which basket`" );
156 if( fileCommandOutput.find( "not stripped", false ) == -1 )
157 subject += "[___stripped]"; //same length as below
158 else
159 subject += "[NOTstripped]";
161 if( !bt.isEmpty() ) {
162 const int invalidFrames = bt.contains( QRegExp("\n#[0-9]+\\s+0x[0-9A-Fa-f]+ in \\?\\?") );
163 const int validFrames = bt.contains( QRegExp("\n#[0-9]+\\s+0x[0-9A-Fa-f]+ in [^?]") );
164 const int totalFrames = invalidFrames + validFrames;
166 if( totalFrames > 0 ) {
167 const double validity = double(validFrames) / totalFrames;
168 subject += QString("[validity: %1]").arg( validity, 0, 'f', 2 );
169 if( validity <= 0.5 ) useful = false;
171 subject += QString("[frames: %1]").arg( totalFrames, 3 /*padding*/ );
173 if( bt.find( QRegExp(" at \\w*\\.cpp:\\d+\n") ) >= 0 )
174 subject += "[line numbers]";
176 else
177 useful = false;
179 // subject += QString("[%1]").arg( AmarokConfig::soundSystem().remove( QRegExp("-?engine") ) );
181 // debug() << subject << endl;
184 //TODO -fomit-frame-pointer buggers up the backtrace, so detect it
185 //TODO -O optimization can rearrange execution and stuff so show a warning for the developer
186 //TODO pass the CXXFLAGS used with the email
188 if( useful ) {
189 body += "==== file `which basket` ==========\n";
190 body += fileCommandOutput + "\n";
191 body += "==== (gdb) bt =====================\n";
192 body += bt;//+ "\n\n";
193 // body += "==== kdBacktrace() ================\n";
194 // body += kdBacktrace();
196 //TODO startup notification
197 kapp->invokeMailer(
198 /*to*/ "slaout@linux62.org",
199 /*cc*/ QString(),
200 /*bcc*/ QString(),
201 /*subject*/ subject,
202 /*body*/ body,
203 /*messageFile*/ QString(),
204 /*attachURLs*/ QStringList(),
205 /*startup_id*/ "" );
207 else {
208 std::cout << "\n" + i18n( "%1 has crashed! We're sorry about this.\n\n"
209 "But, all is not lost! Perhaps an upgrade is already available "
210 "which fixes the problem. Please check your distribution's software repository." )
211 .arg(kapp->aboutData()->programName()).local8Bit() << std::endl;
214 //_exit() exits immediately, otherwise this
215 //function is called repeatedly ad finitum
216 ::_exit( 255 );
219 else {
220 // we are the process that crashed
222 ::alarm( 0 );
224 // wait for child to exit
225 ::waitpid( pid, NULL, 0 );
226 ::_exit( 253 );