mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
Runing programs can spit core if they crashed. It will be picked up
by gdb and debug it with nice dialog. Processes are now kept in list so pid/cmd can be easily tracked. Rest...
This commit is contained in:
123
evoke/Crash.cpp
Normal file
123
evoke/Crash.cpp
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Evoke, head honcho of everything
|
||||||
|
* Part of Equinox Desktop Environment (EDE).
|
||||||
|
* Copyright (c) 2000-2007 EDE Authors.
|
||||||
|
*
|
||||||
|
* This program is licensed under terms of the
|
||||||
|
* GNU General Public License version 2 or newer.
|
||||||
|
* See COPYING for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "icons/core.xpm"
|
||||||
|
#include "Crash.h"
|
||||||
|
#include "Spawn.h"
|
||||||
|
#include <FL/Fl.h>
|
||||||
|
#include <FL/Fl_Pixmap.h>
|
||||||
|
#include <edelib/Nls.h>
|
||||||
|
#include <edelib/File.h>
|
||||||
|
|
||||||
|
#include <stdio.h> // snprintf
|
||||||
|
|
||||||
|
#define DIALOG_W 380
|
||||||
|
#define DIALOG_H 130
|
||||||
|
#define DIALOG_W_EXPANDED 380
|
||||||
|
#define DIALOG_H_EXPANDED 340
|
||||||
|
|
||||||
|
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 dummy_timeout(void*) { }
|
||||||
|
|
||||||
|
CrashDialog::CrashDialog() : Fl_Window(DIALOG_W, DIALOG_H, _("World is going down...")) {
|
||||||
|
trace_loaded = 0;
|
||||||
|
|
||||||
|
begin();
|
||||||
|
pix = new Fl_Pixmap(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 backtrace"));
|
||||||
|
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->hide();
|
||||||
|
copy = new Fl_Button(185, 305, 90, 25, _("&Copy"));
|
||||||
|
copy->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();
|
||||||
|
copy->hide();
|
||||||
|
details->label(_("@> Show backtrace"));
|
||||||
|
size(DIALOG_W, DIALOG_H);
|
||||||
|
} else {
|
||||||
|
trace_log->show();
|
||||||
|
save_as->show();
|
||||||
|
copy->show();
|
||||||
|
details->label(_("@< Hide backtrace"));
|
||||||
|
size(DIALOG_W_EXPANDED, DIALOG_H_EXPANDED);
|
||||||
|
|
||||||
|
if(!trace_loaded) {
|
||||||
|
trace_buff->remove(0, trace_buff->length());
|
||||||
|
|
||||||
|
// read core
|
||||||
|
spawn_backtrace(cmd.c_str(), "core", "/tmp/gdb_output", "/tmp/gdb_script");
|
||||||
|
|
||||||
|
trace_buff->appendfile("/tmp/gdb_output");
|
||||||
|
trace_loaded = 1;
|
||||||
|
|
||||||
|
// delete core
|
||||||
|
edelib::file_remove("core");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashDialog::set_data(const char* command) {
|
||||||
|
cmd = command;
|
||||||
|
|
||||||
|
char txt[1024];
|
||||||
|
snprintf(txt, sizeof(txt), _("Program just crashed !!!\n\nYou can inspect details about this crash by clicking on 'Show backtrace' below"));
|
||||||
|
txt_box->copy_label(txt);
|
||||||
|
trace_loaded = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashDialog::run(void) {
|
||||||
|
if(!shown()) {
|
||||||
|
set_modal();
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
while(shown())
|
||||||
|
Fl::wait();
|
||||||
|
}
|
50
evoke/Crash.h
Normal file
50
evoke/Crash.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Evoke, head honcho of everything
|
||||||
|
* Part of Equinox Desktop Environment (EDE).
|
||||||
|
* Copyright (c) 2000-2007 EDE Authors.
|
||||||
|
*
|
||||||
|
* This program is licensed under terms of the
|
||||||
|
* GNU General Public License version 2 or newer.
|
||||||
|
* See COPYING for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CRASH_H__
|
||||||
|
#define __CRASH_H__
|
||||||
|
|
||||||
|
#include <FL/Fl_Window.h>
|
||||||
|
#include <FL/Fl_Box.h>
|
||||||
|
#include <FL/Fl_Button.h>
|
||||||
|
#include <FL/Fl_Pixmap.h>
|
||||||
|
#include <FL/Fl_Text_Display.h>
|
||||||
|
#include <FL/Fl_Text_Buffer.h>
|
||||||
|
|
||||||
|
#include <edelib/String.h>
|
||||||
|
|
||||||
|
class CrashDialog : public Fl_Window {
|
||||||
|
private:
|
||||||
|
Fl_Pixmap* pix;
|
||||||
|
Fl_Box* txt_box;
|
||||||
|
Fl_Box* icon_box;
|
||||||
|
Fl_Button* close;
|
||||||
|
Fl_Button* details;
|
||||||
|
|
||||||
|
Fl_Text_Display* trace_log;
|
||||||
|
Fl_Text_Buffer* trace_buff;
|
||||||
|
Fl_Button* save_as;
|
||||||
|
Fl_Button* copy;
|
||||||
|
|
||||||
|
edelib::String cmd;
|
||||||
|
bool trace_loaded;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CrashDialog();
|
||||||
|
~CrashDialog();
|
||||||
|
void show_details(void);
|
||||||
|
|
||||||
|
void set_data(const char* command);
|
||||||
|
void run(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -15,6 +15,7 @@
|
|||||||
#include "EvokeService.h"
|
#include "EvokeService.h"
|
||||||
#include "Splash.h"
|
#include "Splash.h"
|
||||||
#include "Spawn.h"
|
#include "Spawn.h"
|
||||||
|
#include "Crash.h"
|
||||||
|
|
||||||
#include <edelib/File.h>
|
#include <edelib/File.h>
|
||||||
#include <edelib/Config.h>
|
#include <edelib/Config.h>
|
||||||
@ -84,6 +85,10 @@ int get_string_property_value(Atom at, char* txt, int txt_len) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void service_watcher_cb(int pid, int signum) {
|
||||||
|
EvokeService::instance()->service_watcher(pid, signum);
|
||||||
|
}
|
||||||
|
|
||||||
EvokeService::EvokeService() : is_running(0), logfile(NULL), pidfile(NULL), lockfile(NULL) {
|
EvokeService::EvokeService() : is_running(0), logfile(NULL), pidfile(NULL), lockfile(NULL) {
|
||||||
top_win = NULL;
|
top_win = NULL;
|
||||||
}
|
}
|
||||||
@ -101,6 +106,8 @@ EvokeService::~EvokeService() {
|
|||||||
edelib::file_remove(pidfile);
|
edelib::file_remove(pidfile);
|
||||||
free(pidfile);
|
free(pidfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
EvokeService* EvokeService::instance(void) {
|
EvokeService* EvokeService::instance(void) {
|
||||||
@ -243,6 +250,7 @@ bool EvokeService::init_splash(const char* config, bool no_splash, bool dry_run)
|
|||||||
void EvokeService::init_autostart(void) {
|
void EvokeService::init_autostart(void) {
|
||||||
edelib::String home = edelib::user_config_dir();
|
edelib::String home = edelib::user_config_dir();
|
||||||
home += "/autostart/";
|
home += "/autostart/";
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvokeService::setup_atoms(Display* d) {
|
void EvokeService::setup_atoms(Display* d) {
|
||||||
@ -315,6 +323,77 @@ void EvokeService::quit_x11(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Monitor starting service and report if staring
|
||||||
|
* failed. Also if one of runned services crashed
|
||||||
|
* attach gdb on it pid and run backtrace.
|
||||||
|
*/
|
||||||
|
void EvokeService::service_watcher(int pid, int signum) {
|
||||||
|
//if(signum == 11) {
|
||||||
|
if(signum == 139) {
|
||||||
|
EvokeProcess pc;
|
||||||
|
if(find_and_unregister_process(pid, pc)) {
|
||||||
|
printf("%s crashed with core dump\n", pc.cmd.c_str());
|
||||||
|
|
||||||
|
CrashDialog cdialog;
|
||||||
|
cdialog.set_data(pc.cmd.c_str());
|
||||||
|
cdialog.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if(signum == 32512) {
|
||||||
|
fl_alert("No such file");
|
||||||
|
}
|
||||||
|
|
||||||
|
unregister_process(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EvokeService::register_process(const char* cmd, pid_t pid) {
|
||||||
|
EvokeProcess pc;
|
||||||
|
pc.cmd = cmd;
|
||||||
|
pc.pid = pid;
|
||||||
|
printf("registering %s with %i\n", cmd, pid);
|
||||||
|
processes.push_back(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EvokeService::unregister_process(pid_t pid) {
|
||||||
|
if(processes.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProcessListIter it = processes.begin();
|
||||||
|
ProcessListIter it_end = processes.end();
|
||||||
|
|
||||||
|
while(it != it_end) {
|
||||||
|
if((*it).pid == pid) {
|
||||||
|
printf("Found %s with pid %i, cleaning...\n", (*it).cmd.c_str(), pid);
|
||||||
|
processes.erase(it);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EvokeService::find_and_unregister_process(pid_t pid, EvokeProcess& pc) {
|
||||||
|
if(processes.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ProcessListIter it = processes.begin();
|
||||||
|
ProcessListIter it_end = processes.end();
|
||||||
|
|
||||||
|
while(it != it_end) {
|
||||||
|
if((*it).pid == pid) {
|
||||||
|
printf("Found %s with pid %i, cleaning...\n", (*it).cmd.c_str(), pid);
|
||||||
|
pc.cmd = (*it).cmd;
|
||||||
|
pc.pid = pid;
|
||||||
|
|
||||||
|
processes.erase(it);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int EvokeService::handle(const XEvent* ev) {
|
int EvokeService::handle(const XEvent* ev) {
|
||||||
logfile->printf("Got event %i\n", ev->type);
|
logfile->printf("Got event %i\n", ev->type);
|
||||||
|
|
||||||
@ -333,16 +412,20 @@ int EvokeService::handle(const XEvent* ev) {
|
|||||||
} else if(ev->type == PropertyNotify) {
|
} else if(ev->type == PropertyNotify) {
|
||||||
if(ev->xproperty.atom == _ede_spawn) {
|
if(ev->xproperty.atom == _ede_spawn) {
|
||||||
char buff[1024];
|
char buff[1024];
|
||||||
|
|
||||||
if(get_string_property_value(_ede_spawn, buff, sizeof(buff))) {
|
if(get_string_property_value(_ede_spawn, buff, sizeof(buff))) {
|
||||||
logfile->printf("Got _EVOKE_SPAWN with %s. Starting client...\n", buff);
|
logfile->printf("Got _EVOKE_SPAWN with %s. Starting client...\n", buff);
|
||||||
int r = spawn_program(buff);
|
|
||||||
|
pid_t child;
|
||||||
|
int r = spawn_program_with_core(buff, service_watcher_cb, &child);
|
||||||
|
|
||||||
if(r != 0)
|
if(r != 0)
|
||||||
fl_alert("Unable to start %s. Got code %i", buff, r);
|
fl_alert("Unable to start %s. Got code %i", buff, r);
|
||||||
} else
|
else
|
||||||
logfile->printf("Got _EVOKE_SPAWN with malformed data. Ignoring...\n");
|
register_process(buff, child);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logfile->printf("Got _EVOKE_SPAWN with malformed data. Ignoring...\n");
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,11 +24,20 @@ struct EvokeClient {
|
|||||||
edelib::String exec; // program name/path to run
|
edelib::String exec; // program name/path to run
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef edelib::list<EvokeClient> ClientList;
|
struct EvokeProcess {
|
||||||
typedef edelib::list<EvokeClient>::iterator ClientListIter;
|
edelib::String cmd;
|
||||||
|
pid_t pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef edelib::list<EvokeClient> ClientList;
|
||||||
|
typedef edelib::list<EvokeClient>::iterator ClientListIter;
|
||||||
|
|
||||||
typedef edelib::list<edelib::String> StringList;
|
typedef edelib::list<edelib::String> StringList;
|
||||||
typedef edelib::list<edelib::String>::iterator StringListIter;
|
typedef edelib::list<edelib::String>::iterator StringListIter;
|
||||||
|
|
||||||
|
typedef edelib::list<EvokeProcess> ProcessList;
|
||||||
|
typedef edelib::list<EvokeProcess>::iterator ProcessListIter;
|
||||||
|
|
||||||
class Fl_Double_Window;
|
class Fl_Double_Window;
|
||||||
|
|
||||||
class EvokeService {
|
class EvokeService {
|
||||||
@ -44,7 +53,8 @@ class EvokeService {
|
|||||||
Atom _ede_spawn;
|
Atom _ede_spawn;
|
||||||
Atom _ede_evoke_quit;
|
Atom _ede_evoke_quit;
|
||||||
|
|
||||||
ClientList clients;
|
ClientList clients;
|
||||||
|
ProcessList processes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EvokeService();
|
EvokeService();
|
||||||
@ -68,6 +78,12 @@ class EvokeService {
|
|||||||
void register_top(Fl_Double_Window* win) { top_win = win; }
|
void register_top(Fl_Double_Window* win) { top_win = win; }
|
||||||
void unregister_top(void) { top_win = NULL; }
|
void unregister_top(void) { top_win = NULL; }
|
||||||
|
|
||||||
|
void register_process(const char* cmd, pid_t pid);
|
||||||
|
void unregister_process(pid_t pid);
|
||||||
|
bool find_and_unregister_process(pid_t pid, EvokeProcess& pc);
|
||||||
|
|
||||||
|
void service_watcher(int pid, int signum);
|
||||||
|
|
||||||
void quit_x11(void);
|
void quit_x11(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
|
|
||||||
SubDir TOP evoke ;
|
SubDir TOP evoke ;
|
||||||
|
|
||||||
SOURCE = evoke.cpp EvokeService.cpp Spawn.cpp Splash.cpp Log.cpp Logout.cpp ;
|
SOURCE = evoke.cpp EvokeService.cpp Spawn.cpp Splash.cpp Log.cpp Logout.cpp Crash.cpp ;
|
||||||
|
|
||||||
EdeProgram evoke : $(SOURCE) ;
|
EdeProgram evoke : $(SOURCE) ;
|
||||||
FltkProgramBare test/evoke_test : test/evoke_test.cpp ;
|
FltkProgramBare test/evoke_test : test/evoke_test.cpp ;
|
||||||
#TranslationStrings locale : $(SOURCE) ;
|
#TranslationStrings locale : $(SOURCE) ;
|
||||||
EdeManual doc/evoke.txt ;
|
EdeManual doc/evoke.txt ;
|
||||||
|
|
||||||
|
#EdeProgram crash : Crash.cpp ;
|
||||||
|
295
evoke/Spawn.cpp
295
evoke/Spawn.cpp
@ -18,23 +18,54 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/time.h> // getrlimit, setrlimit
|
||||||
|
#include <sys/resource.h> //
|
||||||
|
|
||||||
extern char** environ;
|
extern char** environ;
|
||||||
|
// FIXME: is this safe ??? (or to use somehow sig_atomic_t)
|
||||||
|
SignalWatch* global_watch = 0;
|
||||||
|
|
||||||
int spawn_program(const char* cmd) {
|
void sigchld_handler(int sig) {
|
||||||
|
int pid, status;
|
||||||
|
do {
|
||||||
|
errno = 0;
|
||||||
|
pid = waitpid(WAIT_ANY, &status, WNOHANG);
|
||||||
|
|
||||||
|
if(global_watch != 0)
|
||||||
|
global_watch(pid, status);
|
||||||
|
|
||||||
|
} while(pid <= 0 && errno == EINTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawn_program(const char* cmd, SignalWatch wf, pid_t* child_pid_ret) {
|
||||||
if(!cmd)
|
if(!cmd)
|
||||||
return SPAWN_EMPTY;
|
return SPAWN_EMPTY;
|
||||||
|
|
||||||
int nulldev = -1;
|
int nulldev = -1;
|
||||||
int status_ret = 0;
|
int status_ret = 0;
|
||||||
|
|
||||||
|
if(wf) {
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = sigchld_handler;
|
||||||
|
sa.sa_flags = SA_NOCLDSTOP;
|
||||||
|
//sa.sa_flags = SA_RESTART;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sigaction(SIGCHLD, &sa, (struct sigaction*)0);
|
||||||
|
|
||||||
|
global_watch = wf;
|
||||||
|
}
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
if(pid == -1)
|
if(pid == -1)
|
||||||
return SPAWN_FORK_FAILED;
|
return SPAWN_FORK_FAILED;
|
||||||
|
|
||||||
// run the child
|
|
||||||
if(pid == 0) {
|
if(pid == 0) {
|
||||||
|
// this is child
|
||||||
char* argv[4];
|
char* argv[4];
|
||||||
argv[0] = "/bin/sh";
|
argv[0] = "/bin/sh";
|
||||||
argv[1] = "-c";
|
argv[1] = "-c";
|
||||||
@ -53,12 +84,268 @@ int spawn_program(const char* cmd) {
|
|||||||
close(1); dup(nulldev);
|
close(1); dup(nulldev);
|
||||||
close(2); dup(nulldev);
|
close(2); dup(nulldev);
|
||||||
|
|
||||||
|
|
||||||
if(execve(argv[0], argv, environ) == -1) {
|
if(execve(argv[0], argv, environ) == -1) {
|
||||||
close(nulldev);
|
close(nulldev);
|
||||||
// should not get here
|
// should not get here
|
||||||
return SPAWN_EXECVE_FAILED;
|
return SPAWN_EXECVE_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(nulldev != -1)
|
||||||
|
close(nulldev);
|
||||||
|
/*
|
||||||
|
* Record child pid; it is returned by fork(), but since this
|
||||||
|
* function does not wait until child quits, it will return
|
||||||
|
* immediately, filling (if) requested child pid
|
||||||
|
*/
|
||||||
|
if(child_pid_ret)
|
||||||
|
*child_pid_ret = pid;
|
||||||
|
|
||||||
return status_ret;
|
return status_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spawn_program_with_core(const char* cmd, SignalWatch* wf, pid_t* child_pid_ret) {
|
||||||
|
struct rlimit r;
|
||||||
|
if(getrlimit(RLIMIT_CORE, &r) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rlim_t old = r.rlim_cur;
|
||||||
|
r.rlim_cur = RLIM_INFINITY;
|
||||||
|
|
||||||
|
// FIXME: add own core limit ?
|
||||||
|
if(setrlimit(RLIMIT_CORE, &r) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int ret = spawn_program(cmd, wf, child_pid_ret);
|
||||||
|
|
||||||
|
r.rlim_cur = old;
|
||||||
|
if(setrlimit(RLIMIT_CORE, &r) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawn_backtrace(const char* program, const char* core_path, const char* output, const char* script) {
|
||||||
|
const char* gdb_script = "bt\nquit\n";
|
||||||
|
const int gdb_script_len = 8;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// output file with gdb backtrace
|
||||||
|
int ofd = open(output, O_WRONLY | O_TRUNC | O_CREAT, 0770);
|
||||||
|
if(ofd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
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] = "gdb";
|
||||||
|
argv[1] = "--quiet";
|
||||||
|
argv[2] = "--batch";
|
||||||
|
argv[3] = "-x";
|
||||||
|
argv[4] = (char*)script;
|
||||||
|
argv[5] = (char*)program;
|
||||||
|
argv[6] = (char*)core_path;
|
||||||
|
argv[7] = 0;
|
||||||
|
|
||||||
|
//printf("%s %s %s %s %s %s %s\n", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
|
||||||
|
|
||||||
|
execvp(argv[0], argv);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
int status;
|
||||||
|
if(waitpid(pid, &status, 0) != pid)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int spawn_backtrace(int crash_pid, const char* output, const char* script) {
|
||||||
|
const char* gdb_script = "info threads\nthread apply all bt full\nquit\n";
|
||||||
|
const int gdb_script_len = 43;
|
||||||
|
//const char* gdb_script = "bt\nquit\n";
|
||||||
|
//const int gdb_script_len = 8;
|
||||||
|
|
||||||
|
pid_t parent_pid, child_pid;
|
||||||
|
|
||||||
|
//kill(crash_pid, SIGCONT);
|
||||||
|
|
||||||
|
char parent_pid_str[64];
|
||||||
|
parent_pid = crash_pid;
|
||||||
|
kill(parent_pid, SIGCONT);
|
||||||
|
|
||||||
|
//parent_pid = getpid();
|
||||||
|
sprintf(parent_pid_str, "%ld", (long)parent_pid);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// output file with gdb backtrace
|
||||||
|
int ofd = open(output, O_WRONLY | O_TRUNC | O_CREAT, 0770);
|
||||||
|
if(ofd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
child_pid = fork();
|
||||||
|
|
||||||
|
if(child_pid == -1)
|
||||||
|
return -1;
|
||||||
|
else if(child_pid == 0) {
|
||||||
|
//dup2(ofd, 1);
|
||||||
|
close(ofd);
|
||||||
|
|
||||||
|
char* argv[8];
|
||||||
|
argv[0] = "gdb";
|
||||||
|
argv[1] = "--quiet";
|
||||||
|
argv[2] = "--batch";
|
||||||
|
argv[3] = "-x";
|
||||||
|
argv[4] = (char*)script;
|
||||||
|
argv[5] = "--pid";
|
||||||
|
argv[6] = parent_pid_str;
|
||||||
|
argv[7] = 0;
|
||||||
|
|
||||||
|
//argv[5] = "--pid";
|
||||||
|
//argv[6] = parent_pid_str;
|
||||||
|
//argv[7] = 0;
|
||||||
|
|
||||||
|
printf("%s %s %s %s %s %s %s\n", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
|
||||||
|
|
||||||
|
execvp(argv[0], argv);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
int status;
|
||||||
|
waitpid(child_pid, &status, 0);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//unlink(script);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int spawn_backtrace(const char* output, const char* script){
|
||||||
|
pid_t pid, parent_pid;
|
||||||
|
int ifd[2], ofd[2], efd[2];
|
||||||
|
|
||||||
|
const char* gdb_script = "info threads\nthread apply all by\nquit\n";
|
||||||
|
const int gdb_script_len = 38;
|
||||||
|
|
||||||
|
puts("xxxx");
|
||||||
|
|
||||||
|
// write script for gdb
|
||||||
|
int fds = open(script, O_WRONLY | O_CREAT | O_TRUNC, 0770);
|
||||||
|
if(fds == -1)
|
||||||
|
return -1;
|
||||||
|
write(fds, gdb_script, gdb_script_len);
|
||||||
|
close(fds);
|
||||||
|
|
||||||
|
puts("yyyyy");
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
// open output for gdb trace
|
||||||
|
int fdo = open(output, O_WRONLY, O_CREAT | O_TRUNC, 0770);
|
||||||
|
if(fdo == -1) {
|
||||||
|
printf("can't open fdo(%s): %s\n", output, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_pid = getppid();
|
||||||
|
char parent_pid_str[64];
|
||||||
|
sprintf(parent_pid_str, "%d", parent_pid);
|
||||||
|
|
||||||
|
char* argv[8];
|
||||||
|
argv[0] = "gdb";
|
||||||
|
argv[1] = "--quiet";
|
||||||
|
argv[2] = "--batch";
|
||||||
|
argv[3] = "-x";
|
||||||
|
argv[4] = (char*)script;
|
||||||
|
argv[5] = "--pid";
|
||||||
|
argv[6] = parent_pid_str;
|
||||||
|
argv[7] = 0;
|
||||||
|
|
||||||
|
puts("ayyyy");
|
||||||
|
|
||||||
|
if(pipe(ifd) == -1) {
|
||||||
|
printf("cant open ifd pipe: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pipe(ofd) == -1) {
|
||||||
|
printf("cant open ofd pipe: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pipe(efd) == -1) {
|
||||||
|
printf("cant open efd pipe: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
|
||||||
|
if(pid == -1) {
|
||||||
|
close(ifd[0]); close(ifd[1]);
|
||||||
|
close(ofd[0]); close(ofd[1]);
|
||||||
|
close(efd[0]); close(efd[1]);
|
||||||
|
return -1;
|
||||||
|
} else if(pid == 0) {
|
||||||
|
// child
|
||||||
|
printf("gdb pid is %i\n", getpid());
|
||||||
|
printf("%s %s %s %s %s %s %s\n", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
|
||||||
|
|
||||||
|
close(ifd[1]);
|
||||||
|
fclose(stdin);
|
||||||
|
dup(ifd[0]);
|
||||||
|
|
||||||
|
close(ofd[0]);
|
||||||
|
fclose(stdout);
|
||||||
|
dup(ofd[1]);
|
||||||
|
|
||||||
|
close(efd[0]);
|
||||||
|
fclose(stderr);
|
||||||
|
dup(efd[1]);
|
||||||
|
|
||||||
|
execvp(argv[0], (char**)argv);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
// parent
|
||||||
|
fclose(stdin);
|
||||||
|
|
||||||
|
close(ifd[0]);
|
||||||
|
close(ofd[1]);
|
||||||
|
close(efd[1]);
|
||||||
|
|
||||||
|
write(fdo, "The trace:\n", 11);
|
||||||
|
|
||||||
|
close(ifd[1]);
|
||||||
|
close(ofd[0]);
|
||||||
|
close(efd[0]);
|
||||||
|
|
||||||
|
close(fdo);
|
||||||
|
|
||||||
|
kill(pid, SIGKILL);
|
||||||
|
|
||||||
|
waitpid(pid, NULL, 0);
|
||||||
|
//_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#ifndef __SPAWN_H__
|
#ifndef __SPAWN_H__
|
||||||
#define __SPAWN_H__
|
#define __SPAWN_H__
|
||||||
|
|
||||||
|
#include <unistd.h> // pid_t
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is little bit modified code from edelib run_program()
|
* This is little bit modified code from edelib run_program()
|
||||||
* so evoke specific stuff can be added. Also, possible option
|
* so evoke specific stuff can be added. Also, possible option
|
||||||
@ -27,7 +29,14 @@
|
|||||||
#define SPAWN_EXECVE_FAILED 65530 // internal execve failed
|
#define SPAWN_EXECVE_FAILED 65530 // internal execve failed
|
||||||
#define SPAWN_PTY_FAILED 65529 // TODO
|
#define SPAWN_PTY_FAILED 65529 // TODO
|
||||||
#define SPAWN_USER_CANCELED 65528 // TODO
|
#define SPAWN_USER_CANCELED 65528 // TODO
|
||||||
|
#define SPAWN_CRASHED 65527 // executable crashed
|
||||||
|
#define SPAWN_KILLED 65526 // executable crashed
|
||||||
|
#define SPAWN_NOEXITED 65525
|
||||||
|
|
||||||
int spawn_program(const char* cmd);
|
typedef void (SignalWatch)(int pid, int status);
|
||||||
|
|
||||||
|
int spawn_program(const char* cmd, SignalWatch* wf = 0, pid_t* child_pid_ret = 0);
|
||||||
|
int spawn_program_with_core(const char* cmd, SignalWatch* wf = 0, pid_t* child_pid_ret = 0);
|
||||||
|
int spawn_backtrace(const char* program, const char* core_path, const char* output, const char* script);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
28
evoke/fl/crash.fl
Normal file
28
evoke/fl/crash.fl
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# data file for the Fltk User Interface Designer (fluid)
|
||||||
|
version 1.0108
|
||||||
|
header_name {.h}
|
||||||
|
code_name {.cxx}
|
||||||
|
Function {} {open
|
||||||
|
} {
|
||||||
|
Fl_Window {} {open
|
||||||
|
xywh {354 160 380 130} type Double visible
|
||||||
|
} {
|
||||||
|
Fl_Box {} {
|
||||||
|
image {icons/core.xpm} xywh {10 10 70 75} labelsize 14
|
||||||
|
}
|
||||||
|
Fl_Box {} {
|
||||||
|
label {Program foo just crashed !!!
|
||||||
|
|
||||||
|
You can inspect details about this crash by clicking on 'Show details' below} selected
|
||||||
|
xywh {85 10 285 75} align 148
|
||||||
|
}
|
||||||
|
Fl_Button {} {
|
||||||
|
label {&Close}
|
||||||
|
xywh {280 95 90 25}
|
||||||
|
}
|
||||||
|
Fl_Button {} {
|
||||||
|
label {@> Show details}
|
||||||
|
xywh {10 95 265 25} box FLAT_BOX align 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
evoke/fl/crash_expanded.fl
Normal file
39
evoke/fl/crash_expanded.fl
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# data file for the Fltk User Interface Designer (fluid)
|
||||||
|
version 1.0108
|
||||||
|
header_name {.h}
|
||||||
|
code_name {.cxx}
|
||||||
|
Function {} {open selected
|
||||||
|
} {
|
||||||
|
Fl_Window {} {open
|
||||||
|
xywh {354 160 380 340} type Double visible
|
||||||
|
} {
|
||||||
|
Fl_Box {} {
|
||||||
|
image {icons/core.xpm} xywh {10 10 70 75} labelsize 14
|
||||||
|
}
|
||||||
|
Fl_Box {} {
|
||||||
|
label {Program foo just crashed !!!
|
||||||
|
|
||||||
|
You can inspect details about this crash by clicking on 'Show details' below}
|
||||||
|
xywh {85 10 285 75} align 148
|
||||||
|
}
|
||||||
|
Fl_Button {} {
|
||||||
|
label {&Close}
|
||||||
|
xywh {280 95 90 25}
|
||||||
|
}
|
||||||
|
Fl_Button {} {
|
||||||
|
label {@< Hide details}
|
||||||
|
xywh {10 95 265 25} box FLAT_BOX align 20
|
||||||
|
}
|
||||||
|
Fl_Text_Display {} {
|
||||||
|
xywh {10 130 360 165} labelsize 14 textsize 14
|
||||||
|
}
|
||||||
|
Fl_Button {} {
|
||||||
|
label {&Save As...}
|
||||||
|
xywh {280 305 90 25}
|
||||||
|
}
|
||||||
|
Fl_Button {} {
|
||||||
|
label {&Copy}
|
||||||
|
xywh {185 305 90 25}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
416
evoke/icons/core.xpm
Normal file
416
evoke/icons/core.xpm
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
/* XPM */
|
||||||
|
static char * core_xpm[] = {
|
||||||
|
"48 48 365 2",
|
||||||
|
" c None",
|
||||||
|
". c #FAE601",
|
||||||
|
"+ c #FCF001",
|
||||||
|
"@ c #FEF800",
|
||||||
|
"# c #F9E202",
|
||||||
|
"$ c #F2BE04",
|
||||||
|
"% c #F2BD04",
|
||||||
|
"& c #F5CC03",
|
||||||
|
"* c #FBE901",
|
||||||
|
"= c #FBEC01",
|
||||||
|
"- c #EB9A06",
|
||||||
|
"; c #EEAA05",
|
||||||
|
"> c #FEFC00",
|
||||||
|
", c #F7D506",
|
||||||
|
"' c #E78808",
|
||||||
|
") c #E88D06",
|
||||||
|
"! c #D1B46D",
|
||||||
|
"~ c #C7AF75",
|
||||||
|
"{ c #C2994A",
|
||||||
|
"] c #F1BB04",
|
||||||
|
"^ c #F5CF03",
|
||||||
|
"/ c #FCEE01",
|
||||||
|
"( c #EDD426",
|
||||||
|
"_ c #DCBC76",
|
||||||
|
": c #E3C06E",
|
||||||
|
"< c #CCAB4F",
|
||||||
|
"[ c #E7C16F",
|
||||||
|
"} c #ECC36B",
|
||||||
|
"| c #CCB34C",
|
||||||
|
"1 c #FCFB04",
|
||||||
|
"2 c #D1C652",
|
||||||
|
"3 c #D0B76B",
|
||||||
|
"4 c #DDBA6C",
|
||||||
|
"5 c #DAB96E",
|
||||||
|
"6 c #CFBB40",
|
||||||
|
"7 c #A7A7A7",
|
||||||
|
"8 c #A8A8A8",
|
||||||
|
"9 c #A9A9A9",
|
||||||
|
"0 c #A4A4A4",
|
||||||
|
"a c #9F9F9F",
|
||||||
|
"b c #999999",
|
||||||
|
"c c #919191",
|
||||||
|
"d c #A5B4BE",
|
||||||
|
"e c #E7E7E1",
|
||||||
|
"f c #C3C2C7",
|
||||||
|
"g c #B3AB9B",
|
||||||
|
"h c #B5A679",
|
||||||
|
"i c #C5AF6A",
|
||||||
|
"j c #D6B86A",
|
||||||
|
"k c #CDB16B",
|
||||||
|
"l c #C9B05B",
|
||||||
|
"m c #B7A27C",
|
||||||
|
"n c #EBDC19",
|
||||||
|
"o c #AFAFAF",
|
||||||
|
"p c #B8B8B8",
|
||||||
|
"q c #BBBBBB",
|
||||||
|
"r c #BCBCBC",
|
||||||
|
"s c #BABABA",
|
||||||
|
"t c #B4B4B4",
|
||||||
|
"u c #888888",
|
||||||
|
"v c #7B7B7B",
|
||||||
|
"w c #102032",
|
||||||
|
"x c #808285",
|
||||||
|
"y c #FBF5F2",
|
||||||
|
"z c #D9D0BF",
|
||||||
|
"A c #C6AD71",
|
||||||
|
"B c #DFBB69",
|
||||||
|
"C c #D9B86B",
|
||||||
|
"D c #C0AC7C",
|
||||||
|
"E c #BBA785",
|
||||||
|
"F c #AAAAAA",
|
||||||
|
"G c #ADADAD",
|
||||||
|
"H c #D6D6D6",
|
||||||
|
"I c #EBEBEB",
|
||||||
|
"J c #FCFCFC",
|
||||||
|
"K c #FEFEFE",
|
||||||
|
"L c #FFFFFF",
|
||||||
|
"M c #FBFBFB",
|
||||||
|
"N c #F5F5F5",
|
||||||
|
"O c #E7E7E7",
|
||||||
|
"P c #D2D2D2",
|
||||||
|
"Q c #868686",
|
||||||
|
"R c #636363",
|
||||||
|
"S c #616161",
|
||||||
|
"T c #6E6E6E",
|
||||||
|
"U c #3E3E3D",
|
||||||
|
"V c #3B3A3A",
|
||||||
|
"W c #161311",
|
||||||
|
"X c #65605D",
|
||||||
|
"Y c #C3BCB7",
|
||||||
|
"Z c #D8CFB0",
|
||||||
|
"` c #D1B873",
|
||||||
|
" . c #DFBD6A",
|
||||||
|
".. c #C8B37E",
|
||||||
|
"+. c #AAAEBF",
|
||||||
|
"@. c #FFFD00",
|
||||||
|
"#. c #B1B1B1",
|
||||||
|
"$. c #CACACA",
|
||||||
|
"%. c #E9E9E9",
|
||||||
|
"&. c #F0F0F0",
|
||||||
|
"*. c #E5E5E5",
|
||||||
|
"=. c #E3E3E3",
|
||||||
|
"-. c #E1E1E1",
|
||||||
|
";. c #DFDFDF",
|
||||||
|
">. c #898989",
|
||||||
|
",. c #3C3C3C",
|
||||||
|
"'. c #393939",
|
||||||
|
"). c #262626",
|
||||||
|
"!. c #1D1D1E",
|
||||||
|
"~. c #0F0F0F",
|
||||||
|
"{. c #5A5857",
|
||||||
|
"]. c #5A5955",
|
||||||
|
"^. c #4D4D45",
|
||||||
|
"/. c #918E7A",
|
||||||
|
"(. c #D3CBA7",
|
||||||
|
"_. c #E5DCB3",
|
||||||
|
":. c #E0DECD",
|
||||||
|
"<. c #AEAEAE",
|
||||||
|
"[. c #D3D3D3",
|
||||||
|
"}. c #FAFAFA",
|
||||||
|
"|. c #FDFDFD",
|
||||||
|
"1. c #EFEFEF",
|
||||||
|
"2. c #EAEAEA",
|
||||||
|
"3. c #DDDDDD",
|
||||||
|
"4. c #D7D7D7",
|
||||||
|
"5. c #D0D0D0",
|
||||||
|
"6. c #C9C9C9",
|
||||||
|
"7. c #C1C1C1",
|
||||||
|
"8. c #BDBDBD",
|
||||||
|
"9. c #7D7D7D",
|
||||||
|
"0. c #333333",
|
||||||
|
"a. c #131313",
|
||||||
|
"b. c #4F4F4F",
|
||||||
|
"c. c #484848",
|
||||||
|
"d. c #5F5F60",
|
||||||
|
"e. c #393C3A",
|
||||||
|
"f. c #080C09",
|
||||||
|
"g. c #1F1F1B",
|
||||||
|
"h. c #817F74",
|
||||||
|
"i. c #D8D6C6",
|
||||||
|
"j. c #F2F2E8",
|
||||||
|
"k. c #DFE7F0",
|
||||||
|
"l. c #F9F9F9",
|
||||||
|
"m. c #F3F3F3",
|
||||||
|
"n. c #EDEDED",
|
||||||
|
"o. c #E8E8E8",
|
||||||
|
"p. c #E4E4E4",
|
||||||
|
"q. c #DEDEDE",
|
||||||
|
"r. c #CCCCCC",
|
||||||
|
"s. c #C3C3C3",
|
||||||
|
"t. c #B9B9B9",
|
||||||
|
"u. c #ABABAB",
|
||||||
|
"v. c #A1A1A1",
|
||||||
|
"w. c #151515",
|
||||||
|
"x. c #4B4B4B",
|
||||||
|
"y. c #6B6B6B",
|
||||||
|
"z. c #3F3F3F",
|
||||||
|
"A. c #1B1B1B",
|
||||||
|
"B. c #121211",
|
||||||
|
"C. c #050604",
|
||||||
|
"D. c #000000",
|
||||||
|
"E. c #0C0707",
|
||||||
|
"F. c #433F37",
|
||||||
|
"G. c #7E7F79",
|
||||||
|
"H. c #F7F7F7",
|
||||||
|
"I. c #ECECEC",
|
||||||
|
"J. c #E2E2E2",
|
||||||
|
"K. c #DCDCDC",
|
||||||
|
"L. c #B0B0B0",
|
||||||
|
"M. c #A5A5A5",
|
||||||
|
"N. c #979797",
|
||||||
|
"O. c #969696",
|
||||||
|
"P. c #434343",
|
||||||
|
"Q. c #191919",
|
||||||
|
"R. c #010101",
|
||||||
|
"S. c #060001",
|
||||||
|
"T. c #0C0203",
|
||||||
|
"U. c #050002",
|
||||||
|
"V. c #0B0D14",
|
||||||
|
"W. c #EEEEEE",
|
||||||
|
"X. c #DADADA",
|
||||||
|
"Y. c #C6C6C6",
|
||||||
|
"Z. c #BEBEBE",
|
||||||
|
"`. c #B6B6B6",
|
||||||
|
" + c #9C9C9C",
|
||||||
|
".+ c #909090",
|
||||||
|
"++ c #848484",
|
||||||
|
"@+ c #6C6C6C",
|
||||||
|
"#+ c #1A1A1A",
|
||||||
|
"$+ c #060606",
|
||||||
|
"%+ c #020101",
|
||||||
|
"&+ c #010403",
|
||||||
|
"*+ c #020405",
|
||||||
|
"=+ c #010202",
|
||||||
|
"-+ c #D8D8D8",
|
||||||
|
";+ c #CFCFCF",
|
||||||
|
">+ c #C2C2C2",
|
||||||
|
",+ c #A2A2A2",
|
||||||
|
"'+ c #878787",
|
||||||
|
")+ c #787878",
|
||||||
|
"!+ c #656565",
|
||||||
|
"~+ c #252525",
|
||||||
|
"{+ c #080C0D",
|
||||||
|
"]+ c #F4F4F4",
|
||||||
|
"^+ c #D9D9D9",
|
||||||
|
"/+ c #D4D4D4",
|
||||||
|
"(+ c #CECECE",
|
||||||
|
"_+ c #C5C5C5",
|
||||||
|
":+ c #BFBFBF",
|
||||||
|
"<+ c #B2B2B2",
|
||||||
|
"[+ c #A0A0A0",
|
||||||
|
"}+ c #989898",
|
||||||
|
"|+ c #8E8E8E",
|
||||||
|
"1+ c #737373",
|
||||||
|
"2+ c #6D6D6D",
|
||||||
|
"3+ c #585858",
|
||||||
|
"4+ c #202020",
|
||||||
|
"5+ c #070707",
|
||||||
|
"6+ c #4B4C4C",
|
||||||
|
"7+ c #767676",
|
||||||
|
"8+ c #D1D1D1",
|
||||||
|
"9+ c #A3A3A3",
|
||||||
|
"0+ c #9B9B9B",
|
||||||
|
"a+ c #949494",
|
||||||
|
"b+ c #8C8C8C",
|
||||||
|
"c+ c #838383",
|
||||||
|
"d+ c #797979",
|
||||||
|
"e+ c #6F6F6F",
|
||||||
|
"f+ c #676767",
|
||||||
|
"g+ c #4A4A4A",
|
||||||
|
"h+ c #030303",
|
||||||
|
"i+ c #181818",
|
||||||
|
"j+ c #040404",
|
||||||
|
"k+ c #565656",
|
||||||
|
"l+ c #D5D5D5",
|
||||||
|
"m+ c #C7C7C7",
|
||||||
|
"n+ c #C4C4C4",
|
||||||
|
"o+ c #ACACAC",
|
||||||
|
"p+ c #9E9E9E",
|
||||||
|
"q+ c #7E7E7E",
|
||||||
|
"r+ c #666666",
|
||||||
|
"s+ c #606060",
|
||||||
|
"t+ c #575757",
|
||||||
|
"u+ c #353535",
|
||||||
|
"v+ c #383738",
|
||||||
|
"w+ c #777677",
|
||||||
|
"x+ c #494949",
|
||||||
|
"y+ c #CBCBCB",
|
||||||
|
"z+ c #B5B5B5",
|
||||||
|
"A+ c #9A9A9A",
|
||||||
|
"B+ c #939393",
|
||||||
|
"C+ c #8B8B8B",
|
||||||
|
"D+ c #7C7C7C",
|
||||||
|
"E+ c #5E5E5E",
|
||||||
|
"F+ c #595959",
|
||||||
|
"G+ c #424242",
|
||||||
|
"H+ c #171717",
|
||||||
|
"I+ c #0C0C0C",
|
||||||
|
"J+ c #5D5D5D",
|
||||||
|
"K+ c #2F2F2F",
|
||||||
|
"L+ c #8F8F8F",
|
||||||
|
"M+ c #8A8A8A",
|
||||||
|
"N+ c #858585",
|
||||||
|
"O+ c #7F7F7F",
|
||||||
|
"P+ c #757575",
|
||||||
|
"Q+ c #686868",
|
||||||
|
"R+ c #5B5B5B",
|
||||||
|
"S+ c #4D4D4D",
|
||||||
|
"T+ c #6F6D6E",
|
||||||
|
"U+ c #3B3B3B",
|
||||||
|
"V+ c #9D9D9D",
|
||||||
|
"W+ c #959595",
|
||||||
|
"X+ c #8D8D8D",
|
||||||
|
"Y+ c #828282",
|
||||||
|
"Z+ c #6A6A6A",
|
||||||
|
"`+ c #646464",
|
||||||
|
" @ c #555555",
|
||||||
|
".@ c #2E2E2E",
|
||||||
|
"+@ c #0B0B0B",
|
||||||
|
"@@ c #020202",
|
||||||
|
"#@ c #222222",
|
||||||
|
"$@ c #1D1D1D",
|
||||||
|
"%@ c #080808",
|
||||||
|
"&@ c #808080",
|
||||||
|
"*@ c #7A7A7A",
|
||||||
|
"=@ c #707070",
|
||||||
|
"-@ c #5F5F5F",
|
||||||
|
";@ c #545454",
|
||||||
|
">@ c #525252",
|
||||||
|
",@ c #2B2B2B",
|
||||||
|
"'@ c #0D0D0D",
|
||||||
|
")@ c #050505",
|
||||||
|
"!@ c #111111",
|
||||||
|
"~@ c #5A5A5A",
|
||||||
|
"{@ c #929292",
|
||||||
|
"]@ c #717171",
|
||||||
|
"^@ c #515151",
|
||||||
|
"/@ c #3D3D3D",
|
||||||
|
"(@ c #272727",
|
||||||
|
"_@ c #323232",
|
||||||
|
":@ c #6D6C6C",
|
||||||
|
"<@ c #1C1C1C",
|
||||||
|
"[@ c #535353",
|
||||||
|
"}@ c #414141",
|
||||||
|
"|@ c #0A0A0A",
|
||||||
|
"1@ c #646363",
|
||||||
|
"2@ c #161616",
|
||||||
|
"3@ c #696969",
|
||||||
|
"4@ c #313131",
|
||||||
|
"5@ c #1F1F1F",
|
||||||
|
"6@ c #0E0E0E",
|
||||||
|
"7@ c #090909",
|
||||||
|
"8@ c #121212",
|
||||||
|
"9@ c #444444",
|
||||||
|
"0@ c #464646",
|
||||||
|
"a@ c #282828",
|
||||||
|
"b@ c #5C5C5C",
|
||||||
|
"c@ c #141414",
|
||||||
|
"d@ c #212121",
|
||||||
|
"e@ c #101010",
|
||||||
|
"f@ c #616061",
|
||||||
|
"g@ c #626262",
|
||||||
|
"h@ c #232323",
|
||||||
|
"i@ c #373737",
|
||||||
|
"j@ c #5B5959",
|
||||||
|
"k@ c #1E1E1E",
|
||||||
|
"l@ c #2C2C2C",
|
||||||
|
"m@ c #505050",
|
||||||
|
"n@ c #494646",
|
||||||
|
"o@ c #303030",
|
||||||
|
"p@ c #626162",
|
||||||
|
"q@ c #292929",
|
||||||
|
"r@ c #2A2A2A",
|
||||||
|
"s@ c #616060",
|
||||||
|
"t@ c #2D2D2D",
|
||||||
|
"u@ c #575656",
|
||||||
|
"v@ c #363636",
|
||||||
|
"w@ c #3E3E3E",
|
||||||
|
"x@ c #5F5E5E",
|
||||||
|
"y@ c #3A3A3A",
|
||||||
|
"z@ c #242424",
|
||||||
|
"A@ c #343434",
|
||||||
|
"B@ c #383838",
|
||||||
|
"C@ c #474747",
|
||||||
|
"D@ c #4F4D4D",
|
||||||
|
"E@ c #737272",
|
||||||
|
"F@ c #404040",
|
||||||
|
"G@ c #5B5A5A",
|
||||||
|
"H@ c #696869",
|
||||||
|
"I@ c #4E4E4E",
|
||||||
|
"J@ c #3D3C3C",
|
||||||
|
"K@ c #5D5B5C",
|
||||||
|
"L@ c #6A696A",
|
||||||
|
"M@ c #454545",
|
||||||
|
"N@ c #5B595A",
|
||||||
|
"O@ c #6A6969",
|
||||||
|
"P@ c #515050",
|
||||||
|
"Q@ c #595859",
|
||||||
|
"R@ c #656464",
|
||||||
|
"S@ c #413F3F",
|
||||||
|
"T@ c #747373",
|
||||||
|
"U@ c #5F5E5F",
|
||||||
|
"V@ c #605F5F",
|
||||||
|
"W@ c #595858",
|
||||||
|
"X@ c #545252",
|
||||||
|
" . + ",
|
||||||
|
" @ # $ % & * ",
|
||||||
|
" = - ; $ ",
|
||||||
|
" > , ' ) ",
|
||||||
|
" > ! ~ { ] ^ ",
|
||||||
|
" / ( _ : < . ",
|
||||||
|
" [ } | ",
|
||||||
|
" 1 2 3 4 5 6 ",
|
||||||
|
" 7 8 9 0 a b c d e f g h i j k l m n ",
|
||||||
|
" 8 o p q r s t 8 b u v w x y z A B C D E ",
|
||||||
|
" F G s H I J K L M N O P t Q R S T U V W X Y Z ` ...+. @. ",
|
||||||
|
" 7 #.$.%.L L L M N &.%.*.=.-.;.$.>.,.'.).!.~.{.].^./.(._.:. ",
|
||||||
|
" <.[.}.L L |.N 1.2.=.3.4.5.6.7.8.7.s 9.0.a.b.c.d.e.f.g.h.i.j.k. ",
|
||||||
|
" #.I L L l.m.n.I o.p.q.4.[.r.s.t.u.v.G u w.x.y.z.A.B.C.D.E.F.G. ",
|
||||||
|
" #.m.L H.1.I.I.o.*.J.K.H 5.6.7.t.L.M.N.O.u P.S P.Q.R.D.S.T.U.D.V. ",
|
||||||
|
" 8 W.L &.%.o.O *.J.3.X.[.r.Y.Z.`.G 0 +.+Q ++@+0.#+$+D.R.%+&+*+=+ ",
|
||||||
|
" c q.L I.-.=.-.;.3.-+[.;+$.>+r t u.,+b c '+9.)+!+~+R.D.R.R.D.D.{+ ",
|
||||||
|
" )+L.]+o.^+X.^+H /+P (+6._+:+t.<+8 [+}+|+++v 1+2+3+4+D.D.D.D.D.5+6+ ",
|
||||||
|
" 7+8+%.4.8+8+5.(+$.Y.s.Z.p <+u.9+0+a+b+c+d+e+f+R g+w.D.D.D.h+i+j+k+ ",
|
||||||
|
" y.>.l+H 6.m+m+n+7.Z.q `.L.o+M.p+O..+u q+7+e+r+s+t+u+5+D.D.D.D.D.D.v+w+ ",
|
||||||
|
" x+a+y+_+q r q p z+<+<.9 0 a A+B+C+c+D+1+2+!+E+F+G+H+R.D.D.D.D.D.D.I+r+ ",
|
||||||
|
" J+K+L+Z.z+<.o G F 7 M.[+ +N.c M+N+O+P+e+Q+S R+F+S+~+h+D.D.D.D.D.D.D.D.c.T+ ",
|
||||||
|
" U+i+2+t 9 a [+V+A+}+W+c X+>.Y+v )+1+Z+`+J+t+ @x..@+@@@h+@@@@D.D.D.D.D.#@P+ ",
|
||||||
|
" $@%@U+O.0 B+X+|+b+M+'+c+&@*@P+=@@+`+-@F+;@>@c.,@'@j+j+j+j+j+@@D.D.D.D.)@t+ ",
|
||||||
|
"@++@D.!@~@{@.+&@O+O+v d+7+]@@+Q+!+s+3+ @^@g+/@(@'@)@$+$+j+j+$+$+h+R.D.D.D._@:@ ",
|
||||||
|
"J+@@D.D.<@~@D+D+7+1+=@T y.r+S -@R+3+[@x.}@K+#+|@)@$+$+$+)@$+5+%@%@h+D.D.D.$@1@ ",
|
||||||
|
"3+@@D.D.D.2@G+s+3@Q+r+`+S J+F+[@S+g+}@4@5@6@)@$+)@5+5+5+5+%@7@|@+@5+@@D.D.8@E+ ",
|
||||||
|
";@@@D.D.D.D.|@~+U+9@c.g+g+0@P.U+4@a@$@~.5+$+5+5+5+%@%@7@7@|@+@I+'@'@$+D.D.'@b@ ",
|
||||||
|
"b.@@D.D.D.D.R.@@+@c@$@d@#@5@<@H+!@7@$+5+5+5+%@|@+@+@7@+@I+'@6@6@e@a.6@h+D.I+~@ ",
|
||||||
|
"-@)@D.D.D.D.h+h+@@h+j+)@j+$+$+5+$+$+$+5+5+5+7@+@I+I+I+'@~.e@8@a.a.2@2@5+D.e@E+ ",
|
||||||
|
"-@+@D.D.D.D.h+@@h+j+j+)@)@$+$+5+%@%@%@%@7@|@|@+@'@'@6@~.!@!@a.w.w.2@<@7@D.a.f@ ",
|
||||||
|
"g@!@D.D.D.D.h+j+$+$+$+$+$+5+5+%@7@7@7@|@+@I+I+'@~.~.e@!@a.c@2@i+Q.#+h@I+D.#@!+ ",
|
||||||
|
" 5@@@D.D.D.$+$+$+$+5+5+5+%@7@7@|@|@|@+@I+'@e@8@8@c@2@2@H+#+A.<@$@4+a@~.D.i@j@ ",
|
||||||
|
" P.h+D.D.D.5+%@5+%@|@|@+@|@I+I+'@6@~.~.~.e@8@8@c@H+i+Q.#+<@k@4+d@).l@a.@@m@n@ ",
|
||||||
|
" Q+I+D.D.D.$+%@7@|@|@+@I+I+'@'@~.e@e@e@e@8@c@2@H+Q.A.$@k@4+h@~+).l@o@c@6@p@ ",
|
||||||
|
" ++q@@@D.D.%@|@+@I+I++@I+6@e@!@!@8@c@c@c@w.i+A.A.$@5@#@h@~+a@r@l@u+4@a._@s@ ",
|
||||||
|
" k+5+D.D.%@I+~.6@6@6@~.8@8@a.c@w.H+i+H+Q.<@5@5@d@h@).a@l@t@o@0.,.t@6@u@ ",
|
||||||
|
" =@).D.D.)@+@8@!@!@a.c@c@w.2@H+i+#+A.<@k@4+#@h@).q@,@.@_@0.v@z.w@<@4@x@ ",
|
||||||
|
" 3+6@D.R.$+8@2@w.2@H+i+Q.#+#+A.$@5@d@h@~+).a@,@.@o@0.v@y@P.x+K+2@x@ ",
|
||||||
|
" 9@j+D.@@6@Q.A.Q.Q.A.k@5@k@4+#@h@z@(@r@l@K+_@A@v@B@U+C@S+U+w.x.D@ ",
|
||||||
|
" E@i@R.D.)@8@k@#@d@5@d@h@z@~+(@q@a@l@K+4@A@B@'.,.P.x.b./@Q.F@G@ ",
|
||||||
|
" H@4@D.D.$+c@h@r@r@q@(@(@q@,@.@K+_@A@v@y@w@P.g+^@I@B@<@J@K@ ",
|
||||||
|
" L@0.)@D.)@8@#@o@0.0._@_@_@A@v@i@y@F@M@g+m@^@M@l@k@P.N@ ",
|
||||||
|
" O@z.6@D.@@|@A.r@i@w@/@w@F@}@P.0@x+x.x.P..@4+).P@Q@ ",
|
||||||
|
" F+(@+@j+j++@c@#@t@'.}@9@0@G+'..@#@H+z@^@R@S@ ",
|
||||||
|
" R@k+0.|@5+j+)@@@R.D.D.R.R.j+c@u+F+T@ ",
|
||||||
|
" U@s@;@,.z@|@'@)@5+i+d@,.E@ ",
|
||||||
|
" E+V@W@R+W@X@ "};
|
Reference in New Issue
Block a user