mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
all the stack trace related functions are now in debug.c. Now Redis dumps registers and stack content on crash. Currently osx supported, adding Linux right now.
This commit is contained in:
parent
f7ccc4830b
commit
d4d208595c
218
src/debug.c
218
src/debug.c
@ -2,6 +2,12 @@
|
|||||||
#include "sha1.h" /* SHA1 is used for DEBUG DIGEST */
|
#include "sha1.h" /* SHA1 is used for DEBUG DIGEST */
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_BACKTRACE
|
||||||
|
#include <execinfo.h>
|
||||||
|
#include <ucontext.h>
|
||||||
|
#endif /* HAVE_BACKTRACE */
|
||||||
|
|
||||||
/* ================================= Debugging ============================== */
|
/* ================================= Debugging ============================== */
|
||||||
|
|
||||||
@ -297,6 +303,8 @@ void debugCommand(redisClient *c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =========================== Crash handling ============================== */
|
||||||
|
|
||||||
void _redisAssert(char *estr, char *file, int line) {
|
void _redisAssert(char *estr, char *file, int line) {
|
||||||
bugReportStart();
|
bugReportStart();
|
||||||
redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
|
redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
|
||||||
@ -380,3 +388,213 @@ void _redisPanic(char *msg, char *file, int line) {
|
|||||||
*((char*)-1) = 'x';
|
*((char*)-1) = 'x';
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BACKTRACE
|
||||||
|
static void *getMcontextEip(ucontext_t *uc) {
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
return (void*) uc->uc_mcontext.mc_eip;
|
||||||
|
#elif defined(__dietlibc__)
|
||||||
|
return (void*) uc->uc_mcontext.eip;
|
||||||
|
#elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
|
||||||
|
#if __x86_64__
|
||||||
|
return (void*) uc->uc_mcontext->__ss.__rip;
|
||||||
|
#elif __i386__
|
||||||
|
return (void*) uc->uc_mcontext->__ss.__eip;
|
||||||
|
#else
|
||||||
|
return (void*) uc->uc_mcontext->__ss.__srr0;
|
||||||
|
#endif
|
||||||
|
#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
|
||||||
|
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
|
||||||
|
return (void*) uc->uc_mcontext->__ss.__rip;
|
||||||
|
#else
|
||||||
|
return (void*) uc->uc_mcontext->__ss.__eip;
|
||||||
|
#endif
|
||||||
|
#elif defined(__i386__)
|
||||||
|
return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */
|
||||||
|
#elif defined(__X86_64__) || defined(__x86_64__)
|
||||||
|
return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */
|
||||||
|
#elif defined(__ia64__) /* Linux IA64 */
|
||||||
|
return (void*) uc->uc_mcontext.sc_ip;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void bugReportStart(void) {
|
||||||
|
if (server.bug_report_start == 0) {
|
||||||
|
redisLog(REDIS_WARNING,
|
||||||
|
"\n\n=== REDIS BUG REPORT START: Cut & paste starting from here ===");
|
||||||
|
server.bug_report_start = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void logStackContent(void **sp) {
|
||||||
|
int i;
|
||||||
|
for (i = 15; i >= 0; i--) {
|
||||||
|
redisLog(REDIS_WARNING, "(%p) -> %p", sp+i, sp[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void logRegisters(ucontext_t *uc) {
|
||||||
|
redisLog(REDIS_WARNING, "--- REGISTERS");
|
||||||
|
#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
|
||||||
|
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
|
||||||
|
redisLog(REDIS_WARNING,
|
||||||
|
"\n"
|
||||||
|
"RAX:%p RBX:%p RCX:%p RDX:%p\n"
|
||||||
|
"RDI:%p RSI:%p RBP:%p RSP:%p\n"
|
||||||
|
"R8:%p R9:%p R10:%p R11:%p\n"
|
||||||
|
"R12:%p R13:%p R14:%p R15:%p\n"
|
||||||
|
"RIP:%p EFL:%p CS:%p FS:%p GS:%p",
|
||||||
|
uc->uc_mcontext->__ss.__rax,
|
||||||
|
uc->uc_mcontext->__ss.__rbx,
|
||||||
|
uc->uc_mcontext->__ss.__rcx,
|
||||||
|
uc->uc_mcontext->__ss.__rdx,
|
||||||
|
uc->uc_mcontext->__ss.__rdi,
|
||||||
|
uc->uc_mcontext->__ss.__rsi,
|
||||||
|
uc->uc_mcontext->__ss.__rbp,
|
||||||
|
uc->uc_mcontext->__ss.__rsp,
|
||||||
|
uc->uc_mcontext->__ss.__r8,
|
||||||
|
uc->uc_mcontext->__ss.__r9,
|
||||||
|
uc->uc_mcontext->__ss.__r10,
|
||||||
|
uc->uc_mcontext->__ss.__r11,
|
||||||
|
uc->uc_mcontext->__ss.__r12,
|
||||||
|
uc->uc_mcontext->__ss.__r13,
|
||||||
|
uc->uc_mcontext->__ss.__r14,
|
||||||
|
uc->uc_mcontext->__ss.__r15,
|
||||||
|
uc->uc_mcontext->__ss.__rip,
|
||||||
|
uc->uc_mcontext->__ss.__rflags,
|
||||||
|
uc->uc_mcontext->__ss.__cs,
|
||||||
|
uc->uc_mcontext->__ss.__fs,
|
||||||
|
uc->uc_mcontext->__ss.__gs
|
||||||
|
);
|
||||||
|
logStackContent((void**)uc->uc_mcontext->__ss.__rsp);
|
||||||
|
#else
|
||||||
|
redisLog(REDIS_WARNING,
|
||||||
|
"\n"
|
||||||
|
"EAX:%p EBX:%p ECX:%p EDX:%p\n"
|
||||||
|
"EDI:%p ESI:%p EBP:%p ESP:%p\n"
|
||||||
|
"SS:%p EFL:%p EIP:%p CS:%p\n"
|
||||||
|
"DS:%p ES:%p FS:%p GS:%p",
|
||||||
|
uc->uc_mcontext->__ss.__eax,
|
||||||
|
uc->uc_mcontext->__ss.__ebx,
|
||||||
|
uc->uc_mcontext->__ss.__ecx,
|
||||||
|
uc->uc_mcontext->__ss.__edx,
|
||||||
|
uc->uc_mcontext->__ss.__edi,
|
||||||
|
uc->uc_mcontext->__ss.__esi,
|
||||||
|
uc->uc_mcontext->__ss.__ebp,
|
||||||
|
uc->uc_mcontext->__ss.__esp,
|
||||||
|
uc->uc_mcontext->__ss.__ss,
|
||||||
|
uc->uc_mcontext->__ss.__eflags,
|
||||||
|
uc->uc_mcontext->__ss.__eip,
|
||||||
|
uc->uc_mcontext->__ss.__cs,
|
||||||
|
uc->uc_mcontext->__ss.__ds,
|
||||||
|
uc->uc_mcontext->__ss.__es,
|
||||||
|
uc->uc_mcontext->__ss.__fs,
|
||||||
|
uc->uc_mcontext->__ss.__gs
|
||||||
|
);
|
||||||
|
logStackContent((void**)uc->uc_mcontext->__ss.__esp);
|
||||||
|
#endif
|
||||||
|
#elif defined(__i386__)
|
||||||
|
return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */
|
||||||
|
#elif defined(__X86_64__) || defined(__x86_64__)
|
||||||
|
return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */
|
||||||
|
#else
|
||||||
|
redisLog(REDIS_WARNING,
|
||||||
|
" Dumping of registers not supported for this OS/arch");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
|
||||||
|
void *trace[100];
|
||||||
|
char **messages = NULL;
|
||||||
|
int i, trace_size = 0;
|
||||||
|
ucontext_t *uc = (ucontext_t*) secret;
|
||||||
|
sds infostring, clients;
|
||||||
|
struct sigaction act;
|
||||||
|
REDIS_NOTUSED(info);
|
||||||
|
|
||||||
|
bugReportStart();
|
||||||
|
redisLog(REDIS_WARNING,
|
||||||
|
" Redis %s crashed by signal: %d", REDIS_VERSION, sig);
|
||||||
|
redisLog(REDIS_WARNING,
|
||||||
|
" Failed assertion: %s (%s:%d)", server.assert_failed,
|
||||||
|
server.assert_file, server.assert_line);
|
||||||
|
|
||||||
|
/* Generate the stack trace */
|
||||||
|
trace_size = backtrace(trace, 100);
|
||||||
|
|
||||||
|
/* overwrite sigaction with caller's address */
|
||||||
|
if (getMcontextEip(uc) != NULL) {
|
||||||
|
trace[1] = getMcontextEip(uc);
|
||||||
|
}
|
||||||
|
messages = backtrace_symbols(trace, trace_size);
|
||||||
|
redisLog(REDIS_WARNING, "--- STACK TRACE");
|
||||||
|
for (i=1; i<trace_size; ++i)
|
||||||
|
redisLog(REDIS_WARNING,"%s", messages[i]);
|
||||||
|
|
||||||
|
/* Log INFO and CLIENT LIST */
|
||||||
|
redisLog(REDIS_WARNING, "--- INFO OUTPUT");
|
||||||
|
infostring = genRedisInfoString("all");
|
||||||
|
redisLogRaw(REDIS_WARNING, infostring);
|
||||||
|
redisLog(REDIS_WARNING, "--- CLIENT LIST OUTPUT");
|
||||||
|
clients = getAllClientsInfoString();
|
||||||
|
redisLogRaw(REDIS_WARNING, clients);
|
||||||
|
/* Don't sdsfree() strings to avoid a crash. Memory may be corrupted. */
|
||||||
|
|
||||||
|
/* Log CURRENT CLIENT info */
|
||||||
|
if (server.current_client) {
|
||||||
|
redisClient *cc = server.current_client;
|
||||||
|
sds client;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
redisLog(REDIS_WARNING, "--- CURRENT CLIENT INFO");
|
||||||
|
client = getClientInfoString(cc);
|
||||||
|
redisLog(REDIS_WARNING,"client: %s", client);
|
||||||
|
/* Missing sdsfree(client) to avoid crash if memory is corrupted. */
|
||||||
|
for (j = 0; j < cc->argc; j++) {
|
||||||
|
robj *decoded;
|
||||||
|
|
||||||
|
decoded = getDecodedObject(cc->argv[j]);
|
||||||
|
redisLog(REDIS_WARNING,"argv[%d]: '%s'", j, (char*)decoded->ptr);
|
||||||
|
decrRefCount(decoded);
|
||||||
|
}
|
||||||
|
/* Check if the first argument, usually a key, is found inside the
|
||||||
|
* selected DB, and if so print info about the associated object. */
|
||||||
|
if (cc->argc >= 1) {
|
||||||
|
robj *val, *key;
|
||||||
|
dictEntry *de;
|
||||||
|
|
||||||
|
key = getDecodedObject(cc->argv[1]);
|
||||||
|
de = dictFind(cc->db->dict, key->ptr);
|
||||||
|
if (de) {
|
||||||
|
val = dictGetVal(de);
|
||||||
|
redisLog(REDIS_WARNING,"key '%s' found in DB containing the following object:", key->ptr);
|
||||||
|
redisLogObjectDebugInfo(val);
|
||||||
|
}
|
||||||
|
decrRefCount(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Log dump of processor registers */
|
||||||
|
logRegisters(uc);
|
||||||
|
|
||||||
|
redisLog(REDIS_WARNING,
|
||||||
|
"\n=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
|
||||||
|
" Please report the crash opening an issue on github:\n\n"
|
||||||
|
" http://github.com/antirez/redis/issues\n\n"
|
||||||
|
);
|
||||||
|
/* free(messages); Don't call free() with possibly corrupted memory. */
|
||||||
|
if (server.daemonize) unlink(server.pidfile);
|
||||||
|
|
||||||
|
/* Make sure we exit with the right signal at the end. So for instance
|
||||||
|
* the core will be dumped if enabled. */
|
||||||
|
sigemptyset (&act.sa_mask);
|
||||||
|
/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
|
||||||
|
* is used. Otherwise, sa_handler is used */
|
||||||
|
act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
|
||||||
|
act.sa_handler = SIG_DFL;
|
||||||
|
sigaction (sig, &act, NULL);
|
||||||
|
kill(getpid(),sig);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_BACKTRACE */
|
||||||
|
135
src/redis.c
135
src/redis.c
@ -31,11 +31,6 @@
|
|||||||
#include "slowlog.h"
|
#include "slowlog.h"
|
||||||
#include "bio.h"
|
#include "bio.h"
|
||||||
|
|
||||||
#ifdef HAVE_BACKTRACE
|
|
||||||
#include <execinfo.h>
|
|
||||||
#include <ucontext.h>
|
|
||||||
#endif /* HAVE_BACKTRACE */
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@ -1933,136 +1928,6 @@ void redisAsciiArt(void) {
|
|||||||
zfree(buf);
|
zfree(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_BACKTRACE
|
|
||||||
static void *getMcontextEip(ucontext_t *uc) {
|
|
||||||
#if defined(__FreeBSD__)
|
|
||||||
return (void*) uc->uc_mcontext.mc_eip;
|
|
||||||
#elif defined(__dietlibc__)
|
|
||||||
return (void*) uc->uc_mcontext.eip;
|
|
||||||
#elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
|
|
||||||
#if __x86_64__
|
|
||||||
return (void*) uc->uc_mcontext->__ss.__rip;
|
|
||||||
#elif __i386__
|
|
||||||
return (void*) uc->uc_mcontext->__ss.__eip;
|
|
||||||
#else
|
|
||||||
return (void*) uc->uc_mcontext->__ss.__srr0;
|
|
||||||
#endif
|
|
||||||
#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
|
|
||||||
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
|
|
||||||
return (void*) uc->uc_mcontext->__ss.__rip;
|
|
||||||
#else
|
|
||||||
return (void*) uc->uc_mcontext->__ss.__eip;
|
|
||||||
#endif
|
|
||||||
#elif defined(__i386__)
|
|
||||||
return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */
|
|
||||||
#elif defined(__X86_64__) || defined(__x86_64__)
|
|
||||||
return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */
|
|
||||||
#elif defined(__ia64__) /* Linux IA64 */
|
|
||||||
return (void*) uc->uc_mcontext.sc_ip;
|
|
||||||
#else
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void bugReportStart(void) {
|
|
||||||
if (server.bug_report_start == 0) {
|
|
||||||
redisLog(REDIS_WARNING,
|
|
||||||
"=== REDIS BUG REPORT START: Cut & paste starting from here ===");
|
|
||||||
server.bug_report_start = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
|
|
||||||
void *trace[100];
|
|
||||||
char **messages = NULL;
|
|
||||||
int i, trace_size = 0;
|
|
||||||
ucontext_t *uc = (ucontext_t*) secret;
|
|
||||||
sds infostring, clients;
|
|
||||||
struct sigaction act;
|
|
||||||
REDIS_NOTUSED(info);
|
|
||||||
|
|
||||||
bugReportStart();
|
|
||||||
redisLog(REDIS_WARNING,
|
|
||||||
" Redis %s crashed by signal: %d", REDIS_VERSION, sig);
|
|
||||||
redisLog(REDIS_WARNING,
|
|
||||||
" Failed assertion: %s (%s:%d)", server.assert_failed,
|
|
||||||
server.assert_file, server.assert_line);
|
|
||||||
|
|
||||||
/* Generate the stack trace */
|
|
||||||
trace_size = backtrace(trace, 100);
|
|
||||||
|
|
||||||
/* overwrite sigaction with caller's address */
|
|
||||||
if (getMcontextEip(uc) != NULL) {
|
|
||||||
trace[1] = getMcontextEip(uc);
|
|
||||||
}
|
|
||||||
messages = backtrace_symbols(trace, trace_size);
|
|
||||||
redisLog(REDIS_WARNING, "--- STACK TRACE");
|
|
||||||
for (i=1; i<trace_size; ++i)
|
|
||||||
redisLog(REDIS_WARNING,"%s", messages[i]);
|
|
||||||
|
|
||||||
/* Log INFO and CLIENT LIST */
|
|
||||||
redisLog(REDIS_WARNING, "--- INFO OUTPUT");
|
|
||||||
infostring = genRedisInfoString("all");
|
|
||||||
redisLogRaw(REDIS_WARNING, infostring);
|
|
||||||
redisLog(REDIS_WARNING, "--- CLIENT LIST OUTPUT");
|
|
||||||
clients = getAllClientsInfoString();
|
|
||||||
redisLogRaw(REDIS_WARNING, clients);
|
|
||||||
/* Don't sdsfree() strings to avoid a crash. Memory may be corrupted. */
|
|
||||||
|
|
||||||
/* Log CURRENT CLIENT info */
|
|
||||||
if (server.current_client) {
|
|
||||||
redisClient *cc = server.current_client;
|
|
||||||
sds client;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
redisLog(REDIS_WARNING, "--- CURRENT CLIENT INFO");
|
|
||||||
client = getClientInfoString(cc);
|
|
||||||
redisLog(REDIS_WARNING,"client: %s", client);
|
|
||||||
/* Missing sdsfree(client) to avoid crash if memory is corrupted. */
|
|
||||||
for (j = 0; j < cc->argc; j++) {
|
|
||||||
robj *decoded;
|
|
||||||
|
|
||||||
decoded = getDecodedObject(cc->argv[j]);
|
|
||||||
redisLog(REDIS_WARNING,"argv[%d]: '%s'", j, (char*)decoded->ptr);
|
|
||||||
decrRefCount(decoded);
|
|
||||||
}
|
|
||||||
/* Check if the first argument, usually a key, is found inside the
|
|
||||||
* selected DB, and if so print info about the associated object. */
|
|
||||||
if (cc->argc >= 1) {
|
|
||||||
robj *val, *key;
|
|
||||||
dictEntry *de;
|
|
||||||
|
|
||||||
key = getDecodedObject(cc->argv[1]);
|
|
||||||
de = dictFind(cc->db->dict, key->ptr);
|
|
||||||
if (de) {
|
|
||||||
val = dictGetVal(de);
|
|
||||||
redisLog(REDIS_WARNING,"key '%s' found in DB containing the following object:", key->ptr);
|
|
||||||
redisLogObjectDebugInfo(val);
|
|
||||||
}
|
|
||||||
decrRefCount(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
redisLog(REDIS_WARNING,
|
|
||||||
"=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
|
|
||||||
" Please report the crash opening an issue on github:\n\n"
|
|
||||||
" http://github.com/antirez/redis/issues\n\n"
|
|
||||||
);
|
|
||||||
/* free(messages); Don't call free() with possibly corrupted memory. */
|
|
||||||
if (server.daemonize) unlink(server.pidfile);
|
|
||||||
|
|
||||||
/* Make sure we exit with the right signal at the end. So for instance
|
|
||||||
* the core will be dumped if enabled. */
|
|
||||||
sigemptyset (&act.sa_mask);
|
|
||||||
/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
|
|
||||||
* is used. Otherwise, sa_handler is used */
|
|
||||||
act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
|
|
||||||
act.sa_handler = SIG_DFL;
|
|
||||||
sigaction (sig, &act, NULL);
|
|
||||||
kill(getpid(),sig);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_BACKTRACE */
|
|
||||||
|
|
||||||
static void sigtermHandler(int sig) {
|
static void sigtermHandler(int sig) {
|
||||||
REDIS_NOTUSED(sig);
|
REDIS_NOTUSED(sig);
|
||||||
|
|
||||||
|
@ -1161,5 +1161,6 @@ void _redisAssert(char *estr, char *file, int line);
|
|||||||
void _redisPanic(char *msg, char *file, int line);
|
void _redisPanic(char *msg, char *file, int line);
|
||||||
void bugReportStart(void);
|
void bugReportStart(void);
|
||||||
void redisLogObjectDebugInfo(robj *o);
|
void redisLogObjectDebugInfo(robj *o);
|
||||||
|
void sigsegvHandler(int sig, siginfo_t *info, void *secret);
|
||||||
|
sds genRedisInfoString(char *section);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user