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:
Gustavo Sverzut Barbieri 2009-07-11 16:27:37 +00:00
parent df098aa052
commit f3c1679442
2 changed files with 224 additions and 23 deletions

View File

@ -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();

View File

@ -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);