You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
basket/src/crashhandler.cpp

227 lines
8.1 KiB

// Code from Amarok.
/***************************************************************************
* Copyright (C) 2005 Max Howell <max.howell@methylblue.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
//#include "amarok.h"
//#include "amarokconfig.h"
#include "crashhandler.h"
//#include "debug.h"
#include "config.h"
#include <tdeapplication.h> //invokeMailer()
#include <tdeaboutdata.h>
#include <tdeversion.h>
#include <tdelocale.h>
#include <tdetempfile.h>
#include <tqfile.h>
#include <tqregexp.h>
#include <tqtextstream.h>
#include <cstdio> //popen, fread
#include <iostream>
#include <sys/types.h> //pid_t
#include <sys/wait.h> //waitpid
//#include <taglib/taglib.h>
#include <unistd.h> //write, getpid
//#ifndef TAGLIB_PATCH_VERSION
//// seems to be wheel's style
//#define TAGLIB_PATCH_VERSION 0
//#endif
#if 0
class CrashHandlerWidget : public KDialog {
public:
CrashHandlerWidget();
};
#endif
static TQString
runCommand( const TQCString &command )
{
static const uint SIZE = 40960; //40 KiB
static char stdoutBuf[ SIZE ];
// debug() << "Running: " << command << endl;
FILE *process = ::popen( command, "r" );
stdoutBuf[ std::fread( static_cast<void*>( stdoutBuf ), sizeof(char), SIZE-1, process ) ] = '\0';
::pclose( process );
return TQString::fromLocal8Bit( stdoutBuf );
}
void
Crash::crashHandler( int /*signal*/ )
{
// we need to fork to be able to get a
// semi-decent bt - I dunno why
const pid_t pid = ::fork();
if( pid <= 0 )
{
// we are the child process (the result of the fork)
// debug() << "amaroK is crashing...\n";
TQString subject = "[basket-crash] " VERSION " ";
TQString body = i18n(
"%1 has crashed! We're sorry about this.\n"
"\n"
"But, all is not lost! You could potentially help us fix the crash. "
"Information describing the crash is below, so just click send, "
"or if you have time, write a brief description of how the crash happened first.\n\n"
"Many thanks." ).arg(kapp->aboutData()->programName()) + "\n\n";
body += "\n\n\n\n\n\n" + i18n(
"The information below is to help the developers identify the problem, "
"please do not modify it." ) + "\n\n\n\n";
body += "======== DEBUG INFORMATION =======\n"
"Version: " VERSION "\n"
"Build date: " __DATE__ "\n"
"CC version: " __VERSION__ "\n" //assuming we're using GCC
"KDElibs: " TDE_VERSION_STRING "\n"
;// "TagLib: %2.%3.%4\n";
/* body = body
.arg( TAGLIB_MAJOR_VERSION )
.arg( TAGLIB_MINOR_VERSION )
.arg( TAGLIB_PATCH_VERSION );*/
#ifdef NDEBUG
body += "NDEBUG: true";
#endif
body += "\n";
/// obtain the backtrace with gdb
KTempFile temp;
temp.setAutoDelete( true );
const int handle = temp.handle();
// TQCString gdb_command_string =
// "file amarokapp\n"
// "attach " + TQCString().setNum( ::getppid() ) + "\n"
// "bt\n" "echo \\n\n"
// "thread apply all bt\n";
const TQCString gdb_batch =
"bt\n"
"echo \\n\\n\n"
"bt full\n"
"echo \\n\\n\n"
"echo ==== (gdb) thread apply all bt ====\\n\n"
"thread apply all bt\n";
::write( handle, gdb_batch, gdb_batch.length() );
::fsync( handle );
// so we can read stderr too
::dup2( fileno( stdout ), fileno( stderr ) );
TQCString gdb;
gdb = "gdb --nw -n --batch -x ";
gdb += temp.name().latin1();
gdb += " basket ";
gdb += TQCString().setNum( ::getppid() );
TQString bt = runCommand( gdb );
/// clean up
bt.remove( "(no debugging symbols found)..." );
bt.remove( "(no debugging symbols found)\n" );
bt.replace( TQRegExp("\n{2,}"), "\n" ); //clean up multiple \n characters
bt.stripWhiteSpace();
/// analyze usefulness
bool useful = true;
const TQString fileCommandOutput = runCommand( "file `which basket`" );
if( fileCommandOutput.find( "not stripped", false ) == -1 )
subject += "[___stripped]"; //same length as below
else
subject += "[NOTstripped]";
if( !bt.isEmpty() ) {
const int invalidFrames = bt.contains( TQRegExp("\n#[0-9]+\\s+0x[0-9A-Fa-f]+ in \\?\\?") );
const int validFrames = bt.contains( TQRegExp("\n#[0-9]+\\s+0x[0-9A-Fa-f]+ in [^?]") );
const int totalFrames = invalidFrames + validFrames;
if( totalFrames > 0 ) {
const double validity = double(validFrames) / totalFrames;
subject += TQString("[validity: %1]").arg( validity, 0, 'f', 2 );
if( validity <= 0.5 ) useful = false;
}
subject += TQString("[frames: %1]").arg( totalFrames, 3 /*padding*/ );
if( bt.find( TQRegExp(" at \\w*\\.cpp:\\d+\n") ) >= 0 )
subject += "[line numbers]";
}
else
useful = false;
// subject += TQString("[%1]").arg( AmarokConfig::soundSystem().remove( TQRegExp("-?engine") ) );
// debug() << subject << endl;
//TODO -fomit-frame-pointer buggers up the backtrace, so detect it
//TODO -O optimization can rearrange execution and stuff so show a warning for the developer
//TODO pass the CXXFLAGS used with the email
if( useful ) {
body += "==== file `which basket` ==========\n";
body += fileCommandOutput + "\n";
body += "==== (gdb) bt =====================\n";
body += bt;//+ "\n\n";
// body += "==== kdBacktrace() ================\n";
// body += kdBacktrace();
//TODO startup notification
kapp->invokeMailer(
/*to*/ "kelvie@ieee.org",
/*cc*/ TQString(),
/*bcc*/ TQString(),
/*subject*/ subject,
/*body*/ body,
/*messageFile*/ TQString(),
/*attachURLs*/ TQStringList(),
/*startup_id*/ "" );
}
else {
std::cout << ("\n" + i18n( "%1 has crashed! We're sorry about this.\n\n"
"But, all is not lost! Perhaps an upgrade is already available "
"which fixes the problem. Please check your distribution's software repository." )
.arg(kapp->aboutData()->programName())).local8Bit().data() << std::endl;
}
//_exit() exits immediately, otherwise this
//function is called repeatedly ad finitum
::_exit( 255 );
}
else {
// we are the process that crashed
::alarm( 0 );
// wait for child to exit
::waitpid( pid, NULL, 0 );
::_exit( 253 );
}
}