forked from enlightenment/enlightenment
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:
parent
0b5db2653e
commit
380386817b
|
@ -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;
|
||||
|
|
|
@ -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 ;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
@ -519,15 +522,33 @@ _e_alert_draw_text(void)
|
|||
|
||||
if (!tainted)
|
||||
{
|
||||
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 can gdb attach to this process (%d) now \n"
|
||||
"to try debug it or you could exit, or just hit \n"
|
||||
"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);
|
||||
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"
|
||||
"a bug in Enlightenment or the libraries it relies \n"
|
||||
"on. You can gdb attach to this process (%d) now \n"
|
||||
"to try debug it or you could exit, or just hit \n"
|
||||
"restart to try and get your desktop back the way \n"
|
||||
"it was.\n"
|
||||
"\n"
|
||||
"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, "");
|
||||
|
|
|
@ -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")))
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue