mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
Some text alignement in ede-bug-report so it can be easily read in the source.
Rewriten ede-crasher. Now is able to call ede-bug-report, display png icon, do backtrace in random temporary files and etc.
This commit is contained in:
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Ecrasher, a crash handler tool
|
||||
* ede-crasher, a crash handler tool
|
||||
* Part of Equinox Desktop Environment (EDE).
|
||||
* Copyright (c) 2008 EDE Authors.
|
||||
* Copyright (c) 2008-2009 EDE Authors.
|
||||
*
|
||||
* This program is licensed under terms of the
|
||||
* GNU General Public License version 2 or newer.
|
||||
@ -14,261 +14,217 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "icons/core.xpm"
|
||||
#include "CrashDialog.h"
|
||||
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Pixmap.H>
|
||||
#include <FL/Fl_File_Chooser.H>
|
||||
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Text_Display.H>
|
||||
#include <FL/Fl_Text_Buffer.H>
|
||||
#include <FL/Fl_File_Chooser.H>
|
||||
|
||||
#include <edelib/Nls.h>
|
||||
#include <edelib/File.h>
|
||||
#include <edelib/Window.h>
|
||||
#include <edelib/String.h>
|
||||
#include <edelib/Version.h>
|
||||
#include <edelib/MessageBox.h>
|
||||
#include <edelib/FileTest.h>
|
||||
#include <edelib/Run.h>
|
||||
#include <edelib/File.h>
|
||||
|
||||
#define DIALOG_W 380
|
||||
#define DIALOG_H 130
|
||||
#define DIALOG_W_EXPANDED 380
|
||||
#define DIALOG_H_EXPANDED 340
|
||||
#include "CrashDialog.h"
|
||||
#include "GdbOutput.h"
|
||||
#include "CoreIcon.h"
|
||||
#include "icons/core.xpm"
|
||||
|
||||
int spawn_backtrace(const char* gdb_path, const char* program, const char* core, const char* output, const char* script) {
|
||||
const char* gdb_script = "bt\nquit\n";
|
||||
const int gdb_script_len = 8;
|
||||
#define WIN_H_NORMAL 130
|
||||
#define WIN_H_EXPANDED 340
|
||||
|
||||
/* file with gdb commands */
|
||||
int sfd = open(script, O_WRONLY | O_TRUNC | O_CREAT, 0770);
|
||||
if(sfd == -1)
|
||||
return -1;
|
||||
write(sfd, gdb_script, gdb_script_len);
|
||||
close(sfd);
|
||||
EDELIB_NS_USING(String)
|
||||
EDELIB_NS_USING(alert)
|
||||
EDELIB_NS_USING(run_async)
|
||||
EDELIB_NS_USING(file_remove)
|
||||
EDELIB_NS_USING(file_path)
|
||||
|
||||
/* output file with gdb backtrace */
|
||||
int ofd = open(output, O_WRONLY | O_TRUNC | O_CREAT, 0770);
|
||||
if(ofd == -1)
|
||||
return -1;
|
||||
static edelib::Window *win;
|
||||
static Fl_Text_Display *txt_display;
|
||||
static Fl_Text_Buffer *txt_buf;
|
||||
static Fl_Button *save_as;
|
||||
static Fl_Button *show_details;
|
||||
static GdbOutput *gdb;
|
||||
static bool info_was_collected;
|
||||
static const ProgramDetails *pdetails;
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if(pid == -1) {
|
||||
close(ofd);
|
||||
return -1;
|
||||
} else if(pid == 0) {
|
||||
dup2(ofd, 1);
|
||||
close(ofd);
|
||||
|
||||
char* argv[8];
|
||||
argv[0] = (char*)gdb_path;
|
||||
argv[1] = "--quiet";
|
||||
argv[2] = "--batch";
|
||||
argv[3] = "-x";
|
||||
argv[4] = (char*)script;
|
||||
argv[5] = (char*)program;
|
||||
argv[6] = (char*)core;
|
||||
argv[7] = 0;
|
||||
|
||||
execvp(argv[0], argv);
|
||||
return -1;
|
||||
} else {
|
||||
int status;
|
||||
if(waitpid(pid, &status, 0) != pid)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
static void close_cb(Fl_Widget*, void*) {
|
||||
win->hide();
|
||||
}
|
||||
|
||||
edelib::String get_uname(void) {
|
||||
struct utsname ut;
|
||||
uname(&ut);
|
||||
|
||||
edelib::String ret;
|
||||
ret.printf("%s %s %s %s %s", ut.sysname, ut.nodename, ut.release, ut.version, ut.machine);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void show_details_cb(Fl_Widget*, void* cd) {
|
||||
CrashDialog* c = (CrashDialog*)cd;
|
||||
c->show_details();
|
||||
}
|
||||
|
||||
void close_cb(Fl_Widget*, void* cd) {
|
||||
CrashDialog* c = (CrashDialog*)cd;
|
||||
c->hide();
|
||||
}
|
||||
|
||||
void save_cb(Fl_Widget*, void* cd) {
|
||||
CrashDialog* c = (CrashDialog*)cd;
|
||||
c->save();
|
||||
}
|
||||
|
||||
CrashDialog::CrashDialog() : Fl_Window(DIALOG_W, DIALOG_H, _("EDE crash handler")),
|
||||
appname(NULL), apppath(NULL), bugaddress(NULL), pid(NULL), signal_num(NULL) {
|
||||
details_shown = false;
|
||||
|
||||
begin();
|
||||
pix = new Fl_Pixmap((const char**)core_xpm);
|
||||
|
||||
icon_box = new Fl_Box(10, 10, 70, 75);
|
||||
icon_box->image(pix);
|
||||
|
||||
txt_box = new Fl_Box(85, 10, 285, 75);
|
||||
txt_box->align(FL_ALIGN_WRAP | FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
|
||||
|
||||
close = new Fl_Button(280, 95, 90, 25, _("&Close"));
|
||||
close->callback(close_cb, this);
|
||||
|
||||
details = new Fl_Button(10, 95, 265, 25, _("@> Show details"));
|
||||
details->box(FL_FLAT_BOX);
|
||||
details->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT);
|
||||
details->callback(show_details_cb, this);
|
||||
|
||||
/* widgets for expanded dialog */
|
||||
trace_log = new Fl_Text_Display(10, 130, 360, 165);
|
||||
trace_buff = new Fl_Text_Buffer();
|
||||
trace_log->buffer(trace_buff);
|
||||
trace_log->hide();
|
||||
save_as = new Fl_Button(280, 305, 90, 25, _("&Save As..."));
|
||||
save_as->callback(save_cb, this);
|
||||
save_as->hide();
|
||||
end();
|
||||
}
|
||||
|
||||
CrashDialog::~CrashDialog() {
|
||||
/* looks like fltk does not clean image() assigned data */
|
||||
delete pix;
|
||||
}
|
||||
|
||||
void CrashDialog::show_details(void) {
|
||||
if(trace_log->visible()) {
|
||||
trace_log->hide();
|
||||
save_as->hide();
|
||||
details->label(_("@> Show details"));
|
||||
size(DIALOG_W, DIALOG_H);
|
||||
} else {
|
||||
trace_log->show();
|
||||
save_as->show();
|
||||
details->label(_("@< Hide details"));
|
||||
size(DIALOG_W_EXPANDED, DIALOG_H_EXPANDED);
|
||||
|
||||
if(!details_shown) {
|
||||
trace_buff->remove(0, trace_buff->length());
|
||||
|
||||
edelib::String address = _("\nPlease report this at: ");
|
||||
if(bugaddress)
|
||||
address += bugaddress;
|
||||
else
|
||||
address += "http://bugs.equinox-project.org";
|
||||
|
||||
trace_buff->append(address.c_str());
|
||||
trace_buff->append("\n\n");
|
||||
|
||||
trace_buff->append("---------- short summary ----------\n");
|
||||
trace_buff->append("\nEDE version: " PACKAGE_VERSION);
|
||||
trace_buff->append("\nSystem info: ");
|
||||
trace_buff->append(get_uname().c_str());
|
||||
|
||||
trace_buff->append("\nProgram name: ");
|
||||
if(appname)
|
||||
trace_buff->append(appname);
|
||||
else
|
||||
trace_buff->append("(unknown)");
|
||||
|
||||
trace_buff->append("\nExecutable path: ");
|
||||
if(apppath)
|
||||
trace_buff->append(apppath);
|
||||
else
|
||||
trace_buff->append("(unknown)");
|
||||
|
||||
trace_buff->append("\nRunning PID: ");
|
||||
if(pid)
|
||||
trace_buff->append(pid);
|
||||
else
|
||||
trace_buff->append("(unknown)");
|
||||
|
||||
trace_buff->append("\nSignal received: ");
|
||||
if(signal_num)
|
||||
trace_buff->append(signal_num);
|
||||
else
|
||||
trace_buff->append("(unknown)");
|
||||
|
||||
/* try backtrace via gdb */
|
||||
trace_buff->append("\n\n---------- backtrace ----------\n");
|
||||
|
||||
const char* core_file = "core";
|
||||
const char* gdb_output = "/tmp/.gdb_output";
|
||||
const char* gdb_script = "/tmp/.gdb_script";
|
||||
|
||||
if(!edelib::file_test(core_file, edelib::FILE_TEST_IS_REGULAR)) {
|
||||
trace_buff->append("\nUnable to find 'core' file. Backtrace will not be done.");
|
||||
details_shown = false;
|
||||
return;
|
||||
}
|
||||
|
||||
edelib::String gdb_path = edelib::file_path("gdb");
|
||||
if(gdb_path.empty()) {
|
||||
trace_buff->append("\nUnable to find gdb. Please install it first.");
|
||||
/* set to false so next 'Show Details' click can try again with the debugger */
|
||||
details_shown = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: these files should be unique per session */
|
||||
if(spawn_backtrace(gdb_path.c_str(), cmd.c_str(), core_file, gdb_output, gdb_script) == -1) {
|
||||
trace_buff->append("\nUnable to properly execute gdb");
|
||||
details_shown = false;
|
||||
return;
|
||||
}
|
||||
|
||||
trace_buff->append("\n");
|
||||
if(trace_buff->appendfile(gdb_output) != 0) {
|
||||
trace_buff->append("Unable to read gdb output file");
|
||||
details_shown = false;
|
||||
return;
|
||||
}
|
||||
|
||||
edelib::file_remove(gdb_output);
|
||||
edelib::file_remove(gdb_script);
|
||||
edelib::file_remove(core_file);
|
||||
|
||||
details_shown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CrashDialog::save(void) {
|
||||
const char* p = fl_file_chooser(_("Save details to..."), "Text Files (*.txt)\tAll Files(*)", "dump.txt");
|
||||
static void save_as_cb(Fl_Widget*, void*) {
|
||||
const char *p = fl_file_chooser(_("Save details to..."), "Text Files (*.txt)\tAll Files(*)", "dump.txt");
|
||||
if(!p)
|
||||
return;
|
||||
|
||||
// so we can have EOL in file
|
||||
trace_buff->append("\n");
|
||||
/* so we can have EOL */
|
||||
txt_buf->append("\n");
|
||||
|
||||
if(trace_buff->savefile(p) != 0)
|
||||
edelib::alert(_("Unable to save to %s. Please check permissions to write in this directory or file"), p);
|
||||
if(txt_buf->savefile(p) != 0)
|
||||
alert(_("Unable to save to %s. Please check permissions to write in this directory or file"), p);
|
||||
}
|
||||
|
||||
void CrashDialog::run(void) {
|
||||
edelib::String l;
|
||||
static void write_host_info(void) {
|
||||
txt_buf->append("---------- short summary ----------\n");
|
||||
txt_buf->append("\nEDE version: " PACKAGE_VERSION);
|
||||
txt_buf->append("\nedelib version: " EDELIB_VERSION);
|
||||
|
||||
if(appname || apppath) {
|
||||
const char* p = (appname ? appname : apppath);
|
||||
l.printf(_("Program '%s' just crashed!"), p);
|
||||
} else
|
||||
l += _("Program just crashed!");
|
||||
l += _("\n\nYou can inspect details about this crash by clicking on 'Show details' below");
|
||||
struct utsname ut;
|
||||
if(uname(&ut) == 0) {
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "%s %s %s %s %s", ut.sysname, ut.nodename, ut.release, ut.version, ut.machine);
|
||||
|
||||
txt_box->copy_label(l.c_str());
|
||||
txt_buf->append("\nSystem info: ");
|
||||
txt_buf->append(buf);
|
||||
}
|
||||
|
||||
if(!shown())
|
||||
show();
|
||||
txt_buf->append("\nProgram name: ");
|
||||
if(pdetails->name)
|
||||
txt_buf->append(pdetails->name);
|
||||
else
|
||||
txt_buf->append("(unknown)");
|
||||
|
||||
while(shown())
|
||||
Fl::wait();
|
||||
txt_buf->append("\nProgram path: ");
|
||||
if(pdetails->path)
|
||||
txt_buf->append(pdetails->path);
|
||||
else
|
||||
txt_buf->append("(unknown)");
|
||||
|
||||
txt_buf->append("\nProgram PID: ");
|
||||
if(pdetails->pid)
|
||||
txt_buf->append(pdetails->pid);
|
||||
else
|
||||
txt_buf->append("(unknown)");
|
||||
|
||||
txt_buf->append("\nSignal received: ");
|
||||
if(pdetails->sig)
|
||||
txt_buf->append(pdetails->sig);
|
||||
else
|
||||
txt_buf->append("(unknown)");
|
||||
|
||||
txt_buf->append("\n\n---------- backtrace ----------\n\n");
|
||||
}
|
||||
|
||||
static void collect_info_once(void) {
|
||||
if(info_was_collected)
|
||||
return;
|
||||
|
||||
write_host_info();
|
||||
|
||||
if(gdb->fds_opened() && gdb->run())
|
||||
txt_buf->appendfile(gdb->output_path());
|
||||
|
||||
info_was_collected = true;
|
||||
}
|
||||
|
||||
static void show_details_cb(Fl_Widget*, void*) {
|
||||
if(save_as->visible()) {
|
||||
win->size(win->w(), WIN_H_NORMAL);
|
||||
txt_display->hide();
|
||||
save_as->hide();
|
||||
show_details->label(_("@> Show details"));
|
||||
return;
|
||||
}
|
||||
|
||||
win->size(win->w(), WIN_H_EXPANDED);
|
||||
txt_display->show();
|
||||
save_as->show();
|
||||
show_details->label(_("@< Hide details"));
|
||||
|
||||
collect_info_once();
|
||||
}
|
||||
|
||||
static void report_cb(Fl_Widget*, void*) {
|
||||
String bug_tool = file_path("ede-bug-report");
|
||||
if(bug_tool.empty()) {
|
||||
alert(_("Unable to find ede-bug-report tool."
|
||||
" Please check if PATH variable contains directory where this tool was installed"));
|
||||
return;
|
||||
}
|
||||
|
||||
collect_info_once();
|
||||
|
||||
errno = 0;
|
||||
int fd;
|
||||
char tmp[] = "/tmp/.ecrash-dump.XXXXXX";
|
||||
|
||||
if((fd = mkstemp(tmp)) == -1) {
|
||||
alert(_("Unable to create temporary file: (%i) %s"), errno, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
txt_buf->savefile(tmp);
|
||||
|
||||
run_async("%s --gdb-dump %s", bug_tool.c_str(), tmp);
|
||||
|
||||
/* wait some time until the file was read; dumb, I know :( */
|
||||
sleep(1);
|
||||
file_remove(tmp);
|
||||
}
|
||||
|
||||
int crash_dialog_show(const ProgramDetails& p) {
|
||||
info_was_collected = false;
|
||||
pdetails = &p;
|
||||
|
||||
gdb = new GdbOutput();
|
||||
gdb->set_program_path(p.path);
|
||||
gdb->fds_open();
|
||||
|
||||
win = new edelib::Window(380, WIN_H_NORMAL, _("EDE Crash Handler"));
|
||||
win->begin();
|
||||
Fl_Box* image_box = new Fl_Box(10, 10, 65, 60);
|
||||
image_box->image(image_core);
|
||||
|
||||
String s;
|
||||
if(p.name)
|
||||
s.printf(_("Program '%s' quit unexpectedly."), p.name);
|
||||
else
|
||||
s = _("Program quit unexpectedly.");
|
||||
s += _("\n\nYou can inspect the details about this crash by clicking on \'Show details\' below");
|
||||
|
||||
Fl_Box* txt_box = new Fl_Box(85, 10, 285, 75, s.c_str());
|
||||
txt_box->align(132|FL_ALIGN_INSIDE);
|
||||
|
||||
/* only EDE applications can have 'Report' button for reporting issues on EDE bugzilla */
|
||||
if(p.ede_app) {
|
||||
Fl_Button* report = new Fl_Button(185, 95, 90, 25, _("&Report..."));
|
||||
report->callback(report_cb);
|
||||
}
|
||||
|
||||
Fl_Button* close = new Fl_Button(280, 95, 90, 25, _("&Close"));
|
||||
close->callback(close_cb);
|
||||
|
||||
show_details = new Fl_Button(10, 95, 165, 25, _("@> Show details"));
|
||||
show_details->box(FL_FLAT_BOX);
|
||||
show_details->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
|
||||
show_details->callback(show_details_cb);
|
||||
|
||||
txt_display = new Fl_Text_Display(10, 130, 360, 165);
|
||||
txt_buf = new Fl_Text_Buffer();
|
||||
txt_display->buffer(txt_buf);
|
||||
|
||||
txt_display->hide();
|
||||
|
||||
save_as = new Fl_Button(280, 305, 90, 25, _("&Save As..."));
|
||||
save_as->hide();
|
||||
save_as->callback(save_as_cb);
|
||||
win->end();
|
||||
|
||||
win->window_icon(core_xpm);
|
||||
win->show();
|
||||
|
||||
int ret = Fl::run();
|
||||
delete gdb;
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user