e: full rewrite of our WBOD.

NOTE: the new behaviour require a parent process,
here enlightenment_start, to watch over enlightenment.
It does use ptrace to monitor his child and track
what is going on. When a crash happen it ask gdb to
add the backtrace directly into .xsession-errors.

If you use systemd user session, you may want to offload
that work to systemd. You can do so, but don't forget to
pass -nopause to enlightenment when you start it.

WARNING: For all user, you will need to exit your
current session and start a fresh one for this new WBOD
to work at all. Just restarting Enlightenment will not
help you.


SVN revision: 78742
This commit is contained in:
Cedric BAIL 2012-11-01 06:23:49 +00:00
parent 0b5db2653e
commit 380386817b
7 changed files with 200 additions and 156 deletions

View File

@ -278,6 +278,7 @@ extern EAPI Eina_Bool evil;
extern EAPI Eina_Bool starting;
extern EAPI Eina_Bool stopping;
extern EAPI Eina_Bool restart;
extern EAPI Eina_Bool e_nopause;
extern EAPI Eina_Bool e_precache_end;
extern EAPI Eina_Bool x_fatal;

View File

@ -30,62 +30,12 @@ e_alert_composite_win(Ecore_X_Window root, Ecore_X_Window comp)
}
EAPI void
e_alert_show(int sig)
e_alert_show(void)
{
char *args[4];
pid_t pid;
#define E_ALERT_EXE "/enlightenment/utils/enlightenment_alert"
args[0] = alloca(strlen(e_prefix_lib_get()) + strlen(E_ALERT_EXE) + 1);
strcpy(args[0], e_prefix_lib_get());
strcat(args[0], E_ALERT_EXE);
args[1] = alloca(10);
snprintf(args[1], 10, "%d", sig);
args[2] = alloca(21);
snprintf(args[2], 21, "%lu", (long unsigned int)getpid());
args[3] = NULL;
pid = fork();
if (pid < -1)
goto restart_e;
if (pid == 0)
if (!e_nopause)
{
/* The child process */
execvp(args[0], args);
fprintf(stderr, "PAUSE !\n");
pause();
}
else
{
/* The parent process */
pid_t ret;
int status = 0;
do
{
ret = waitpid(pid, &status, 0);
if (errno == ECHILD)
break ;
}
while (ret != pid);
if (status == 0)
goto restart_e;
if (!WIFEXITED(status))
goto restart_e;
if (WEXITSTATUS(status) == 1)
goto restart_e;
exit(-11);
}
restart_e:
if (getenv("E_START_MTRACK"))
e_util_env_set("MTRACK", "track");
ecore_app_restart();
return ;
}

View File

@ -13,7 +13,7 @@ typedef enum _E_Alert_Op_Type
EINTERN int e_alert_init(void);
EINTERN int e_alert_shutdown(void);
EAPI void e_alert_show(int sig);
EAPI void e_alert_show(void);
#endif
#endif

View File

@ -51,6 +51,7 @@ static const char *title = NULL, *str1 = NULL, *str2 = NULL;
static int ret = 0, sig = 0;
static pid_t pid;
static Eina_Bool tainted = EINA_TRUE;
static const char *backtrace = NULL;
int
main(int argc, char **argv)
@ -72,6 +73,8 @@ main(int argc, char **argv)
sig = atoi(argv[i]); // signal
else if (i == 2)
pid = atoi(argv[i]); // E's pid
else if (i == 3)
backtrace = argv[i];
}
tmp = getenv("E17_TAINTED");
@ -518,6 +521,21 @@ _e_alert_draw_text(void)
unsigned int i = 0, j = 0, k = 0;
if (!tainted)
{
if (backtrace)
{
snprintf(msg, sizeof(msg),
"This is not meant to happen and is likely a sign of \n"
"a bug in Enlightenment or the libraries it relies \n"
"on. You will find an backtrace of E17 (%d) in :\n"
"'%s'\n"
"Before reporting issue, compile latest E17 and EFL\n"
"from svn with '-g -ggdb3' in your CFLAGS.\n"
"You can then report this crash on :\n"
"http://trac.enlightenment.org/e/.\n",
pid, backtrace);
}
else
{
snprintf(msg, sizeof(msg),
"This is not meant to happen and is likely a sign of \n"
@ -527,7 +545,10 @@ _e_alert_draw_text(void)
"restart to try and get your desktop back the way \n"
"it was.\n"
"\n"
"Please compile E17 and EFL with -g in your CFLAGS.\n", pid);
"Please compile latest svn E17 and EFL with\n"
"-g and -ggdb3 in your CFLAGS.\n", pid);
}
}
else
{
@ -536,7 +557,8 @@ _e_alert_draw_text(void)
"a sign of a bug, but you are using unsupported\n"
"modules; before reporting this issue, please\n"
"unload them and try to see if the bug is still\n"
"there.\n");
"there. Also update to latest svn and be sure to\n"
"compile E17 and EFL with -g and -ggdb3 in your CFLAGS");
}
strcpy(warn, "");

View File

@ -122,6 +122,7 @@ EAPI Eina_Bool evil = EINA_FALSE;
EAPI Eina_Bool starting = EINA_TRUE;
EAPI Eina_Bool stopping = EINA_FALSE;
EAPI Eina_Bool restart = EINA_FALSE;
EAPI Eina_Bool e_nopause = EINA_FALSE;
static void
_xdg_data_dirs_augment(void)
@ -1200,6 +1201,8 @@ _e_main_parse_arguments(int argc, char **argv)
really_know = EINA_TRUE;
else if (!strcmp(argv[i], "-locked"))
locked = EINA_TRUE;
else if (!strcmp(argv[i], "-nopause"))
e_nopause = EINA_TRUE;
else if ((!strcmp(argv[i], "-h")) ||
(!strcmp(argv[i], "-help")) ||
(!strcmp(argv[i], "--help")))

View File

@ -54,121 +54,60 @@ _e_write_safe_int(int fd, const char *buf, size_t size)
}
}
static void
_e_gdb_print_backtrace(int fd __UNUSED__)
{
// FIXME: we are in a segv'd state. do as few function calls and things
// depending on a known working state as possible. this also prevents the
// white box allowing recovery or deeper gdbing, thus until this works
// properly, it's disabled (properly means always reliable, always
// printf bt and allows e to continue and pop up box, perferably allowing
// debugging in the gui etc. etc.
#if 0
char cmd[1024];
size_t size;
int ret;
if (getenv("E_NO_GDB_BACKTRACE"))
return;
size = snprintf(cmd, sizeof(cmd),
"gdb --pid=%d "
"-ex 'thread apply all bt' "
"-ex detach -ex quit", getpid());
if (size >= sizeof(cmd))
return;
_e_write_safe(fd, "EXECUTING GDB AS: ");
_e_write_safe_int(fd, cmd, size);
_e_write_safe(fd, "\n");
ret = system(cmd); // TODO: use popen() or fork()+pipe()+exec() and save to 'fd'
#endif
}
#define _e_backtrace(msg) _e_backtrace_int(2, msg, sizeof(msg))
static void
_e_backtrace_int(int fd, const char *msg, size_t msg_len)
{
char attachmsg[1024];
void *array[255];
size_t size;
return; // disable. causes hangs and problems
_e_write_safe_int(fd, msg, msg_len);
_e_write_safe(fd, "\nBEGIN TRACEBACK\n");
size = backtrace(array, 255);
backtrace_symbols_fd(array, size, fd);
_e_write_safe(fd, "END TRACEBACK\n");
size = snprintf(attachmsg, sizeof(attachmsg),
"debug with: gdb --pid=%d\n", getpid());
if (size < sizeof(attachmsg))
_e_write_safe_int(fd, attachmsg, size);
_e_gdb_print_backtrace(fd);
}
/* a tricky little devil, requires e and it's libs to be built
* with the -rdynamic flag to GCC for any sort of decent output.
*/
EAPI void
e_sigseg_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
{
_e_backtrace("**** SEGMENTATION FAULT ****");
_e_x_composite_shutdown();
ecore_x_pointer_ungrab();
ecore_x_keyboard_ungrab();
ecore_x_ungrab();
ecore_x_sync();
e_alert_show(SIGSEGV);
e_alert_show();
}
EAPI void
e_sigill_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
{
_e_backtrace("**** ILLEGAL INSTRUCTION ****");
_e_x_composite_shutdown();
ecore_x_pointer_ungrab();
ecore_x_keyboard_ungrab();
ecore_x_ungrab();
ecore_x_sync();
e_alert_show(SIGILL);
e_alert_show();
}
EAPI void
e_sigfpe_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
{
_e_backtrace("**** FLOATING POINT EXCEPTION ****");
_e_x_composite_shutdown();
ecore_x_pointer_ungrab();
ecore_x_keyboard_ungrab();
ecore_x_ungrab();
ecore_x_sync();
e_alert_show(SIGFPE);
e_alert_show();
}
EAPI void
e_sigbus_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
{
_e_backtrace("**** BUS ERROR ****");
_e_x_composite_shutdown();
ecore_x_pointer_ungrab();
ecore_x_keyboard_ungrab();
ecore_x_ungrab();
ecore_x_sync();
e_alert_show(SIGBUS);
e_alert_show();
}
EAPI void
e_sigabrt_act(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
{
_e_backtrace("**** ABORT ****");
_e_x_composite_shutdown();
ecore_x_pointer_ungrab();
ecore_x_keyboard_ungrab();
ecore_x_ungrab();
ecore_x_sync();
e_alert_show(SIGABRT);
e_alert_show();
}

View File

@ -8,13 +8,18 @@
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <sys/ptrace.h>
#include <limits.h>
#include <fcntl.h>
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#endif
#include <signal.h>
#include <Eina.h>
static Eina_Bool tainted = EINA_FALSE;
static void env_set(const char *var, const char *val);
EAPI int prefix_determine(char *argv0);
@ -217,12 +222,28 @@ main(int argc, char **argv)
int i, valgrind_mode = 0;
int valgrind_tool = 0;
int valgrind_gdbserver = 0;
char buf[16384], **args, *p;
char buf[16384], **args, *home;
char valgrind_path[PATH_MAX] = "";
const char *valgrind_log = NULL;
Eina_Bool really_know = EINA_FALSE;
Eina_Bool restart = EINA_TRUE;
eina_init();
/* reexcute myself with dbus-launch if dbus-launch is not running yet */
if ((!getenv("DBUS_SESSION_BUS_ADDRESS")) &&
(!getenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET")))
{
char **dbus_argv;
dbus_argv = alloca(argc + 3 + sizeof (char *));
dbus_argv[0] = "dbus-launch";
dbus_argv[1] = "--exit-with-session";
copy_args(dbus_argv + 2, argv, argc);
dbus_argv[2 + argc] = NULL;
execvp("dbus-launch", dbus_argv);
}
prefix_determine(argv[0]);
env_set("E_START", argv[0]);
@ -254,6 +275,11 @@ main(int argc, char **argv)
else
printf("Unknown valgrind option: %s\n", argv[i]);
}
else if (!strcmp(argv[i], "-display"))
{
i++;
env_set("DISPLAY", argv[i]);
}
else if (!strcmp(argv[i], "-massif"))
valgrind_tool = 1;
else if (!strcmp(argv[i], "-callgrind"))
@ -312,15 +338,15 @@ main(int argc, char **argv)
putchar('\n');
/* mtrack memory tracker support */
p = getenv("HOME");
if (p)
home = getenv("HOME");
if (home)
{
FILE *f;
/* if you have ~/.e-mtrack, then the tracker will be enabled
* using the content of this file as the path to the mtrack.so
* shared object that is the mtrack preload */
snprintf(buf, sizeof(buf), "%s/.e-mtrack", p);
snprintf(buf, sizeof(buf), "%s/.e-mtrack", home);
f = fopen(buf, "r");
if (f)
{
@ -335,40 +361,143 @@ main(int argc, char **argv)
env_set("LD_PRELOAD", buf);
env_set("MTRACK", "track");
env_set("E_START_MTRACK", "track");
snprintf(buf, sizeof(buf), "%s/.e-mtrack.log", p);
snprintf(buf, sizeof(buf), "%s/.e-mtrack.log", home);
env_set("MTRACK_TRACE_FILE", buf);
}
fclose(f);
}
}
/* try dbus-launch */
/* run e directly now */
snprintf(buf, sizeof(buf), "%s/enlightenment", eina_prefix_bin_get(pfx));
args = alloca((argc + 2 + VALGRIND_MAX_ARGS) * sizeof(char *));
if ((!getenv("DBUS_SESSION_BUS_ADDRESS")) &&
(!getenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET")))
{
args[0] = "dbus-launch";
args[1] = "--exit-with-session";
i = 2 + valgrind_append(args + 2, valgrind_gdbserver, valgrind_mode, valgrind_tool, valgrind_path, valgrind_log);
args[i++] = buf;
copy_args(args + i, argv + 1, argc - 1);
args[i + argc - 1] = NULL;
execvp("dbus-launch", args);
}
/* dbus-launch failed - run e direct */
i = valgrind_append(args, valgrind_gdbserver, valgrind_mode, valgrind_tool, valgrind_path, valgrind_log);
args[i++] = buf;
copy_args(args + i, argv + 1, argc - 1);
args[i + argc - 1] = NULL;
execv(args[0], args);
/* execv(args[0], args); */
/* not run at the moment !! */
/* Now looping until */
while (restart)
{
pid_t child;
tainted = EINA_FALSE;
child = fork();
if (child < 0) /* failed attempt */
return -1;
else if (child == 0)
{
/* in the child */
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execv(args[0], args);
return 0; /* We failed, 0 mean normal exit from E with no restart or crash so let exit */
}
else
{
/* in the parent */
pid_t result;
int status;
Eina_Bool done = EINA_FALSE;
ptrace(PTRACE_ATTACH, child, NULL, NULL);
result = waitpid(child, &status, 0);
if (WIFSTOPPED(status))
ptrace(PTRACE_CONT, child, NULL, NULL);
while (!done)
{
result = waitpid(child, &status, 0);
if (result == child)
{
if (WIFSTOPPED(status))
{
char buffer[4096];
char *backtrace = NULL;
siginfo_t sig;
int r;
int back;
r = ptrace(PTRACE_GETSIGINFO, child, NULL, &sig);
back = r == 0 &&
sig.si_signo != SIGTRAP ? sig.si_signo : 0;
if (r != 0 ||
(sig.si_signo != SIGSEGV &&
sig.si_signo != SIGILL &&
sig.si_signo != SIGFPE &&
sig.si_signo != SIGBUS &&
sig.si_signo != SIGABRT))
{
ptrace(PTRACE_CONT, child, NULL, back);
continue ;
}
/* E17 should be in pause, we can detach */
ptrace(PTRACE_DETACH, child, NULL, back);
/* And call gdb if available */
if (home)
{
/* call e_sys gdb */
snprintf(buffer, 4096,
"%s/enlightenment/utils/enlightenment_sys gdb %i %s/.xsession-errors",
eina_prefix_lib_get(pfx),
child,
home);
r = system(buffer);
fprintf(stderr, "called gdb with '%s' = %i\n",
buffer, WEXITSTATUS(r));
snprintf(buffer, 4096,
"%s/.xsession-errors",
home);
backtrace = strdup(buffer);
}
/* call e_alert */
snprintf(buffer, 4096,
backtrace ? "%s/enlightenment/utils/enlightenment_alert %i %i %s" : "%s/enlightenment/utils/enlightenment_alert %i %i %s",
eina_prefix_lib_get(pfx),
sig.si_signo,
child,
backtrace);
r = system(buffer);
/* kill e */
kill(child, SIGKILL);
if (WEXITSTATUS(r) != 1)
{
restart = EINA_FALSE;
}
}
else if (!WIFEXITED(status))
{
done = EINA_TRUE;
}
}
else if (result == - 1)
{
done = EINA_TRUE;
restart = EINA_FALSE;
}
}
}
}
printf("FAILED TO RUN:\n");
printf(" %s\n", buf);
perror("execv");
return -1;
}