make it easy to run e under valgrind and debug crashes.
this should help us in near future: * -valgrind[=MODE], to run under valgrind and toggle interesting options as we often request users to give us valgrind logs but they're often running valgrind on wrong binaries and with wrong parameters. See enlightenment_start -help for more, but in sort: -valgrind=all should give us enough information. * -valgrind-log-file=path, so the log will not mix with lots of output we do. * debug: on crashes, always list traceback (execinfo/glibc functions) and check if gdb exists, if so ask it to print out traceback of all threads to stdout. gdb will be detached as soon as messages were printed and everything should work without gdb as well. SVN revision: 41309
This commit is contained in:
parent
df098aa052
commit
f3c1679442
|
@ -25,6 +25,73 @@ _e_x_composite_shutdown(void)
|
|||
_e_x_composite_shutdown_try = 0;
|
||||
}
|
||||
|
||||
#define _e_write_safe(fd, buf) _e_write_safe_int(fd, buf, sizeof(buf))
|
||||
static void
|
||||
_e_write_safe_int(int fd, const char *buf, size_t size)
|
||||
{
|
||||
while (size > 0)
|
||||
{
|
||||
ssize_t done = write(fd, buf, size);
|
||||
if (done >= 0)
|
||||
{
|
||||
buf += done;
|
||||
size -= done;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((errno == EAGAIN) || (errno == EINTR))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
perror("write");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_e_gdb_print_backtrace(int fd)
|
||||
{
|
||||
char cmd[1024];
|
||||
size_t size;
|
||||
|
||||
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");
|
||||
system(cmd); // TODO: use popen() or fork()+pipe()+exec() and save to 'fd'
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
_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);
|
||||
}
|
||||
|
||||
#ifdef OBJECT_PARANOIA_CHECK
|
||||
|
||||
/* a tricky little devil, requires e and it's libs to be built
|
||||
|
@ -33,13 +100,7 @@ _e_x_composite_shutdown(void)
|
|||
EAPI void
|
||||
e_sigseg_act(int x, siginfo_t *info, void *data)
|
||||
{
|
||||
void *array[255];
|
||||
size_t size;
|
||||
|
||||
write(2, "**** SEGMENTATION FAULT ****\n", 29);
|
||||
write(2, "**** Printing Backtrace... *****\n\n", 34);
|
||||
size = backtrace(array, 255);
|
||||
backtrace_symbols_fd(array, size, 2);
|
||||
_e_backtrace("**** SEGMENTATION FAULT ****");
|
||||
_e_x_composite_shutdown();
|
||||
ecore_x_pointer_ungrab();
|
||||
ecore_x_keyboard_ungrab();
|
||||
|
@ -60,7 +121,7 @@ e_sigseg_act(int x, siginfo_t *info, void *data)
|
|||
EAPI void
|
||||
e_sigseg_act(int x, siginfo_t *info, void *data)
|
||||
{
|
||||
write(2, "**** SEGMENTATION FAULT ****\n", 29);
|
||||
_e_backtrace("**** SEGMENTATION FAULT ****");
|
||||
_e_x_composite_shutdown();
|
||||
ecore_x_pointer_ungrab();
|
||||
ecore_x_keyboard_ungrab();
|
||||
|
@ -82,7 +143,7 @@ e_sigseg_act(int x, siginfo_t *info, void *data)
|
|||
EAPI void
|
||||
e_sigill_act(int x, siginfo_t *info, void *data)
|
||||
{
|
||||
write(2, "**** ILLEGAL INSTRUCTION ****\n", 30);
|
||||
_e_backtrace("**** ILLEGAL INSTRUCTION ****");
|
||||
_e_x_composite_shutdown();
|
||||
ecore_x_pointer_ungrab();
|
||||
ecore_x_keyboard_ungrab();
|
||||
|
@ -103,7 +164,7 @@ e_sigill_act(int x, siginfo_t *info, void *data)
|
|||
EAPI void
|
||||
e_sigfpe_act(int x, siginfo_t *info, void *data)
|
||||
{
|
||||
write(2, "**** FLOATING POINT EXCEPTION ****\n", 35);
|
||||
_e_backtrace("**** FLOATING POINT EXCEPTION ****");
|
||||
_e_x_composite_shutdown();
|
||||
ecore_x_pointer_ungrab();
|
||||
ecore_x_keyboard_ungrab();
|
||||
|
@ -124,7 +185,7 @@ e_sigfpe_act(int x, siginfo_t *info, void *data)
|
|||
EAPI void
|
||||
e_sigbus_act(int x, siginfo_t *info, void *data)
|
||||
{
|
||||
write(2, "**** BUS ERROR ****\n", 21);
|
||||
_e_backtrace("**** BUS ERROR ****");
|
||||
_e_x_composite_shutdown();
|
||||
ecore_x_pointer_ungrab();
|
||||
ecore_x_keyboard_ungrab();
|
||||
|
@ -145,7 +206,7 @@ e_sigbus_act(int x, siginfo_t *info, void *data)
|
|||
EAPI void
|
||||
e_sigabrt_act(int x, siginfo_t *info, void *data)
|
||||
{
|
||||
write(2, "**** ABORT ****\n", 21);
|
||||
_e_backtrace("**** ABORT ****");
|
||||
_e_x_composite_shutdown();
|
||||
ecore_x_pointer_ungrab();
|
||||
ecore_x_keyboard_ungrab();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
|
@ -318,11 +319,94 @@ precache(void)
|
|||
exit(0);
|
||||
}
|
||||
|
||||
static int
|
||||
find_valgrind(char *path, size_t path_len)
|
||||
{
|
||||
char *env = getenv("PATH");
|
||||
|
||||
while (env)
|
||||
{
|
||||
const char *p = strchr(env, ':');
|
||||
ssize_t p_len;
|
||||
|
||||
if (p)
|
||||
p_len = p - env;
|
||||
else
|
||||
p_len = strlen(env);
|
||||
|
||||
if (p_len <= 0)
|
||||
goto next;
|
||||
else if (p_len + sizeof("/valgrind") >= path_len)
|
||||
goto next;
|
||||
|
||||
memcpy(path, env, p_len);
|
||||
memcpy(path + p_len, "/valgrind", sizeof("/valgrind"));
|
||||
if (access(path, X_OK | R_OK) == 0)
|
||||
return 1;
|
||||
|
||||
next:
|
||||
if (p)
|
||||
env = p + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
path[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* maximum number of arguments added above */
|
||||
#define VALGRIND_MAX_ARGS 9
|
||||
/* bitmask with all supported bits set */
|
||||
#define VALGRIND_MODE_ALL 15
|
||||
|
||||
static int
|
||||
valgrind_append(char **dst, int valgrind_mode, const char *valgrind_path, const char *valgrind_log)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!valgrind_mode)
|
||||
return 0;
|
||||
dst[i++] = valgrind_path;
|
||||
dst[i++] = "--track-origins=yes";
|
||||
dst[i++] = "--malloc-fill=0xabc79"; /* invalid pointer, make it crash */
|
||||
|
||||
if (valgrind_log)
|
||||
{
|
||||
static char logparam[PATH_MAX + sizeof("--log-file=")];
|
||||
snprintf(logparam, sizeof(logparam), "--log-file=%s", valgrind_log);
|
||||
dst[i++] = logparam;
|
||||
}
|
||||
|
||||
if (valgrind_mode & 2)
|
||||
dst[i++] = "--trace-children=yes";
|
||||
|
||||
if (valgrind_mode & 4)
|
||||
{
|
||||
dst[i++] = "--leak-check=full";
|
||||
dst[i++] = "--leak-resolution=high";
|
||||
dst[i++] = "--track-fds=yes";
|
||||
}
|
||||
|
||||
if (valgrind_mode & 8)
|
||||
dst[i++] = "--show-reachable=yes";
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_args(char **dst, const char **src, size_t count)
|
||||
{
|
||||
for (; count > 0; count--, dst++, src++)
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i, do_precache = 0;
|
||||
int i, do_precache = 0, valgrind_mode = 0;
|
||||
char buf[16384], **args, *p;
|
||||
char valgrind_path[PATH_MAX] = "", *valgrind_log = NULL;
|
||||
|
||||
prefix_determine(argv[0]);
|
||||
|
||||
|
@ -341,6 +425,32 @@ main(int argc, char **argv)
|
|||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "-no-precache")) do_precache = 0;
|
||||
else if (!strncmp(argv[i], "-valgrind", sizeof("-valgrind") - 1))
|
||||
{
|
||||
const char *val = argv[i] + sizeof("-valgrind") - 1;
|
||||
if (*val == '\0')
|
||||
valgrind_mode = 1;
|
||||
else if (*val == '-')
|
||||
{
|
||||
val++;
|
||||
if (!strncmp(val, "log-file=", sizeof("log-file=") - 1))
|
||||
{
|
||||
valgrind_log = val + sizeof("log-file=") - 1;
|
||||
if (*valgrind_log == '\0')
|
||||
valgrind_log = NULL;
|
||||
}
|
||||
}
|
||||
else if (*val == '=')
|
||||
{
|
||||
val++;
|
||||
if (!strcmp(val, "all"))
|
||||
valgrind_mode = VALGRIND_MODE_ALL;
|
||||
else
|
||||
valgrind_mode = atoi(val);
|
||||
}
|
||||
else
|
||||
printf("Unknown valgrind option: %s\n", argv[i]);
|
||||
}
|
||||
else if ((!strcmp(argv[i], "-h")) ||
|
||||
(!strcmp(argv[i], "-help")) ||
|
||||
(!strcmp(argv[i], "--help")))
|
||||
|
@ -349,6 +459,15 @@ main(int argc, char **argv)
|
|||
("Options:\n"
|
||||
"\t-no-precache\n"
|
||||
"\t\tDisable pre-caching of files\n"
|
||||
"\t-valgrind[=MODE]\n"
|
||||
"\t\tRun enlightenment from inside valgrind, mode is OR of:\n"
|
||||
"\t\t 1 = plain valgrind to catch crashes (default)\n"
|
||||
"\t\t 2 = trace children (thumbnailer, efm slaves, ...)\n"
|
||||
"\t\t 4 = check leak\n"
|
||||
"\t\t 8 = show reachable after processes finish.\n"
|
||||
"\t\t all = all of above\n"
|
||||
"\t-valgrind-log-file=<FILENAME>\n"
|
||||
"\t\tSave valgrind log to file, see valgrind's --log-file for details.\n"
|
||||
"\n"
|
||||
"Please run:\n"
|
||||
"\tenlightenment %s\n"
|
||||
|
@ -358,7 +477,25 @@ main(int argc, char **argv)
|
|||
exit(0);
|
||||
}
|
||||
}
|
||||
printf("E - PID=%i, do_precache=%i\n", getpid(), do_precache);
|
||||
|
||||
if (valgrind_mode)
|
||||
{
|
||||
if (!find_valgrind(valgrind_path, sizeof(valgrind_path)))
|
||||
{
|
||||
printf("E - valgrind required but no binary found! Ignoring request.\n");
|
||||
valgrind_mode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("E - PID=%i, do_precache=%i, valgrind=%d", getpid(), do_precache, valgrind_mode);
|
||||
if (valgrind_mode)
|
||||
{
|
||||
printf(" valgrind-command='%s'", valgrind_path);
|
||||
if (valgrind_log)
|
||||
printf(" valgrind-log-file='%s'", valgrind_log);
|
||||
}
|
||||
putchar('\n');
|
||||
|
||||
if (do_precache)
|
||||
{
|
||||
void *lib, *func;
|
||||
|
@ -392,22 +529,25 @@ main(int argc, char **argv)
|
|||
/* try dbus-launch */
|
||||
snprintf(buf, sizeof(buf), "%s/bin/enlightenment", _prefix_path);
|
||||
|
||||
args = alloca((argc + 3) * sizeof(char *));
|
||||
args = alloca((argc + 2 + VALGRIND_MAX_ARGS) * sizeof(char *));
|
||||
if (!getenv("DBUS_SESSION_BUS_ADDRESS"))
|
||||
{
|
||||
args[0] = "dbus-launch";
|
||||
args[1] = "--exit-with-session";
|
||||
args[2] = buf;
|
||||
for (i = 1; i < argc; i++) args[2 + i] = argv[i];
|
||||
args[2 + i] = NULL;
|
||||
|
||||
i = 2 + valgrind_append(args + 2, valgrind_mode, 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 */
|
||||
args[0] = "enlightenment";
|
||||
for (i = 1; i < argc; i++) args[i] = argv[i];
|
||||
args[i] = NULL;
|
||||
execv(buf, args);
|
||||
i = valgrind_append(args, valgrind_mode, valgrind_path, valgrind_log);
|
||||
args[i++] = buf;
|
||||
copy_args(args + i, argv + 1, argc - 1);
|
||||
args[i + argc - 1] = NULL;
|
||||
execv(args[0], args);
|
||||
|
||||
printf("FAILED TO RUN:\n");
|
||||
printf(" %s\n", buf);
|
||||
|
|
Loading…
Reference in New Issue