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:
parent
817e0cd918
commit
a80b5dcb2a
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 "Splash.h"
|
||||
#include "Spawn.h"
|
||||
#include "Crash.h"
|
||||
|
||||
#include <edelib/File.h>
|
||||
#include <edelib/Config.h>
|
||||
@ -84,6 +85,10 @@ int get_string_property_value(Atom at, char* txt, int txt_len) {
|
||||
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) {
|
||||
top_win = NULL;
|
||||
}
|
||||
@ -101,6 +106,8 @@ EvokeService::~EvokeService() {
|
||||
edelib::file_remove(pidfile);
|
||||
free(pidfile);
|
||||
}
|
||||
|
||||
processes.clear();
|
||||
}
|
||||
|
||||
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) {
|
||||
edelib::String home = edelib::user_config_dir();
|
||||
home += "/autostart/";
|
||||
// TODO
|
||||
}
|
||||
|
||||
void EvokeService::setup_atoms(Display* d) {
|
||||
@ -315,6 +323,77 @@ void EvokeService::quit_x11(void) {
|
||||
#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) {
|
||||
logfile->printf("Got event %i\n", ev->type);
|
||||
|
||||
@ -333,16 +412,20 @@ int EvokeService::handle(const XEvent* ev) {
|
||||
} else if(ev->type == PropertyNotify) {
|
||||
if(ev->xproperty.atom == _ede_spawn) {
|
||||
char buff[1024];
|
||||
|
||||
if(get_string_property_value(_ede_spawn, buff, sizeof(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)
|
||||
fl_alert("Unable to start %s. Got code %i", buff, r);
|
||||
} else
|
||||
logfile->printf("Got _EVOKE_SPAWN with malformed data. Ignoring...\n");
|
||||
else
|
||||
register_process(buff, child);
|
||||
|
||||
} else {
|
||||
logfile->printf("Got _EVOKE_SPAWN with malformed data. Ignoring...\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -24,11 +24,20 @@ struct EvokeClient {
|
||||
edelib::String exec; // program name/path to run
|
||||
};
|
||||
|
||||
typedef edelib::list<EvokeClient> ClientList;
|
||||
typedef edelib::list<EvokeClient>::iterator ClientListIter;
|
||||
struct EvokeProcess {
|
||||
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>::iterator StringListIter;
|
||||
|
||||
typedef edelib::list<EvokeProcess> ProcessList;
|
||||
typedef edelib::list<EvokeProcess>::iterator ProcessListIter;
|
||||
|
||||
class Fl_Double_Window;
|
||||
|
||||
class EvokeService {
|
||||
@ -44,7 +53,8 @@ class EvokeService {
|
||||
Atom _ede_spawn;
|
||||
Atom _ede_evoke_quit;
|
||||
|
||||
ClientList clients;
|
||||
ClientList clients;
|
||||
ProcessList processes;
|
||||
|
||||
public:
|
||||
EvokeService();
|
||||
@ -68,6 +78,12 @@ class EvokeService {
|
||||
void register_top(Fl_Double_Window* win) { top_win = win; }
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -10,9 +10,11 @@
|
||||
|
||||
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) ;
|
||||
FltkProgramBare test/evoke_test : test/evoke_test.cpp ;
|
||||
#TranslationStrings locale : $(SOURCE) ;
|
||||
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 <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/time.h> // getrlimit, setrlimit
|
||||
#include <sys/resource.h> //
|
||||
|
||||
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)
|
||||
return SPAWN_EMPTY;
|
||||
|
||||
int nulldev = -1;
|
||||
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();
|
||||
|
||||
if(pid == -1)
|
||||
return SPAWN_FORK_FAILED;
|
||||
|
||||
// run the child
|
||||
if(pid == 0) {
|
||||
// this is child
|
||||
char* argv[4];
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = "-c";
|
||||
@ -53,12 +84,268 @@ int spawn_program(const char* cmd) {
|
||||
close(1); dup(nulldev);
|
||||
close(2); dup(nulldev);
|
||||
|
||||
|
||||
if(execve(argv[0], argv, environ) == -1) {
|
||||
close(nulldev);
|
||||
// should not get here
|
||||
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;
|
||||
}
|
||||
|
||||
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__
|
||||
#define __SPAWN_H__
|
||||
|
||||
#include <unistd.h> // pid_t
|
||||
|
||||
/*
|
||||
* This is little bit modified code from edelib run_program()
|
||||
* so evoke specific stuff can be added. Also, possible option
|
||||
@ -27,7 +29,14 @@
|
||||
#define SPAWN_EXECVE_FAILED 65530 // internal execve failed
|
||||
#define SPAWN_PTY_FAILED 65529 // 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
|
||||
|
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@ "};
|
Loading…
Reference in New Issue
Block a user