From 0939d0ea39e459cce6d1df5aa1fb765c03784ae1 Mon Sep 17 00:00:00 2001 From: hrothgar Date: Thu, 4 Jun 2009 17:20:14 +0000 Subject: [PATCH 1/7] initial commit print stack trace --- redis.h | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 redis.h diff --git a/redis.h b/redis.h new file mode 100644 index 00000000..f2524c1c --- /dev/null +++ b/redis.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006-2009, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __REDIS_H__ +#define __REDIS_H__ + +enum +{ + REG_GS = 0, +# define REG_GS REG_GS + REG_FS, +# define REG_FS REG_FS + REG_ES, +# define REG_ES REG_ES + REG_DS, +# define REG_DS REG_DS + REG_EDI, +# define REG_EDI REG_EDI + REG_ESI, +# define REG_ESI REG_ESI + REG_EBP, +# define REG_EBP REG_EBP + REG_ESP, +# define REG_ESP REG_ESP + REG_EBX, +# define REG_EBX REG_EBX + REG_EDX, +# define REG_EDX REG_EDX + REG_ECX, +# define REG_ECX REG_ECX + REG_EAX, +# define REG_EAX REG_EAX + REG_TRAPNO, +# define REG_TRAPNO REG_TRAPNO + REG_ERR, +# define REG_ERR REG_ERR + REG_EIP, +# define REG_EIP REG_EIP + REG_CS, +# define REG_CS REG_CS + REG_EFL, +# define REG_EFL REG_EFL + REG_UESP, +# define REG_UESP REG_UESP + REG_SS +# define REG_SS REG_SS +}; + +#endif From c9468bcf8a30d1a4c837814bc34d180f2dff992c Mon Sep 17 00:00:00 2001 From: hrothgar Date: Thu, 4 Jun 2009 17:26:21 +0000 Subject: [PATCH 2/7] initial commit print stack trace --- redis.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/redis.c b/redis.c index 39d45a2d..a1d3c722 100644 --- a/redis.c +++ b/redis.c @@ -36,7 +36,10 @@ #include #include #include +#define __USE_POSIX199309 #include +#include +#include #include #include #include @@ -51,6 +54,7 @@ #include #include +#include "redis.h" #include "ae.h" /* Event driven programming library */ #include "sds.h" /* Dynamic safe strings */ #include "anet.h" /* Networking the easy way */ @@ -167,6 +171,12 @@ /* Anti-warning macro... */ #define REDIS_NOTUSED(V) ((void) V) +int die() { + char *err = NULL; + sprintf(err, "gonner"); + return 0; +} + /*================================= Data types ============================== */ @@ -1594,7 +1604,8 @@ static robj *createListObject(void) { static robj *createSetObject(void) { dict *d = dictCreate(&setDictType,NULL); if (!d) oom("dictCreate"); - return createObject(REDIS_SET,d); + die(); +return createObject(REDIS_SET,d); } static void freeStringObject(robj *o) { @@ -4123,7 +4134,44 @@ static void daemonize(void) { } } +static void segvHandler (int sig, siginfo_t *info, void *secret) { + + void *trace[16]; + char **messages = (char **)NULL; + int i, trace_size = 0; + ucontext_t *uc = (ucontext_t *)secret; + + /* Do something useful with siginfo_t */ + if (sig == SIGSEGV) + printf("Got signal %d, faulty address is %p, from %p\n", sig, info->si_addr, + (void *)uc->uc_mcontext.gregs[REG_EIP]); + else + printf("Got signal %d\n", sig); + + trace_size = backtrace(trace, 16); + /* overwrite sigaction with caller's address */ + trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP]; + + messages = backtrace_symbols(trace, trace_size); + /* skip first stack frame (points here) */ + printf("[bt] Execution path:\n"); + for (i=1; i Date: Thu, 4 Jun 2009 18:41:00 +0000 Subject: [PATCH 3/7] add compile options to debug --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 00c0f226..9fc0caf0 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,8 @@ # Copyright (C) 2009 Salvatore Sanfilippo # This file is released under the BSD license, see the COPYING file -DEBUG?= -g -CFLAGS?= -std=c99 -pedantic -O2 -Wall -W -DSDS_ABORT_ON_OOM +DEBUG?= -g -rdynamic -ggdb +CFLAGS?= -std=c99 -pedantic -O0 -Wall -W -DSDS_ABORT_ON_OOM CCOPT= $(CFLAGS) OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o From 8a355d697a957d0c413a9c020d795959a985fd6f Mon Sep 17 00:00:00 2001 From: hrothgar Date: Thu, 4 Jun 2009 18:48:26 +0000 Subject: [PATCH 4/7] remove die() :-) --- redis.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/redis.c b/redis.c index a1d3c722..01ab9158 100644 --- a/redis.c +++ b/redis.c @@ -171,11 +171,6 @@ /* Anti-warning macro... */ #define REDIS_NOTUSED(V) ((void) V) -int die() { - char *err = NULL; - sprintf(err, "gonner"); - return 0; -} /*================================= Data types ============================== */ @@ -1604,8 +1599,7 @@ static robj *createListObject(void) { static robj *createSetObject(void) { dict *d = dictCreate(&setDictType,NULL); if (!d) oom("dictCreate"); - die(); -return createObject(REDIS_SET,d); + return createObject(REDIS_SET,d); } static void freeStringObject(robj *o) { From fe3bbfbe16ebdc77b61c2157421c6794aef57092 Mon Sep 17 00:00:00 2001 From: hrothgar Date: Fri, 5 Jun 2009 10:10:44 +0000 Subject: [PATCH 5/7] - put some order in code - better output --- redis.c | 75 +++++++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/redis.c b/redis.c index 01ab9158..521c7aa0 100644 --- a/redis.c +++ b/redis.c @@ -378,7 +378,7 @@ static void getSetCommand(redisClient *c); static void ttlCommand(redisClient *c); static void slaveofCommand(redisClient *c); static void debugCommand(redisClient *c); - +static void setupSigSegvAction(); /*================================= Globals ================================= */ /* Global vars */ @@ -898,6 +898,7 @@ static void initServer() { signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); + setupSigSegvAction(); server.clients = listCreate(); server.slaves = listCreate(); @@ -4080,6 +4081,39 @@ static void debugCommand(redisClient *c) { } } +static void segvHandler (int sig, siginfo_t *info, void *secret) { + + void *trace[100]; + char **messages = (char **)NULL; + int i, trace_size = 0; + ucontext_t *uc = (ucontext_t *)secret; + + redisLog(REDIS_DEBUG, "Segmentation fault -%d- Redis %s", sig, REDIS_VERSION ); + redisLog(REDIS_DEBUG,"EIP %p", (void *)uc->uc_mcontext.gregs[REG_EIP]); + redisLog(REDIS_DEBUG,"EAX %p, EBX %p, ECX %p, EDX %p", (void *)uc->uc_mcontext.gregs[REG_EAX], (void *)uc->uc_mcontext.gregs[REG_EBX], (void *)uc->uc_mcontext.gregs[REG_ECX], (void *)uc->uc_mcontext.gregs[REG_EDX]); + + + trace_size = backtrace(trace, 100); + /* overwrite sigaction with caller's address */ + trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP]; + + messages = backtrace_symbols(trace, trace_size); + + for (i=1; isi_addr, - (void *)uc->uc_mcontext.gregs[REG_EIP]); - else - printf("Got signal %d\n", sig); - - trace_size = backtrace(trace, 16); - /* overwrite sigaction with caller's address */ - trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP]; - - messages = backtrace_symbols(trace, trace_size); - /* skip first stack frame (points here) */ - printf("[bt] Execution path:\n"); - for (i=1; i Date: Sat, 6 Jun 2009 08:50:43 +0000 Subject: [PATCH 6/7] store static function pointer for a useful stack trace --- redis.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 4 deletions(-) diff --git a/redis.c b/redis.c index 521c7aa0..a9883922 100644 --- a/redis.c +++ b/redis.c @@ -273,6 +273,11 @@ struct redisCommand { int flags; }; +struct redisFunctionSym { + char *name; + long pointer; +}; + typedef struct _redisSortObject { robj *obj; union { @@ -320,6 +325,7 @@ static time_t getExpire(redisDb *db, robj *key); static int setExpire(redisDb *db, robj *key, time_t when); static void updateSalvesWaitingBgsave(int bgsaveerr); static void freeMemoryIfNeeded(void); +static int processCommand(redisClient *c); static void authCommand(redisClient *c); static void pingCommand(redisClient *c); @@ -444,7 +450,91 @@ static struct redisCommand cmdTable[] = { {"debug",debugCommand,-2,REDIS_CMD_INLINE}, {NULL,NULL,0,0} }; - +static struct redisFunctionSym symsTable[] = { +{"freeStringObject", (long)freeStringObject}, +{"freeListObject", (long)freeListObject}, +{"freeSetObject", (long)freeSetObject}, +{"decrRefCount", (long)decrRefCount}, +{"createObject", (long)createObject}, +{"freeClient", (long)freeClient}, +{"rdbLoad", (long)rdbLoad}, +{"addReply", (long)addReply}, +{"addReplySds", (long)addReplySds}, +{"incrRefCount", (long)incrRefCount}, +{"rdbSaveBackground", (long)rdbSaveBackground}, +{"createStringObject", (long)createStringObject}, +{"replicationFeedSlaves", (long)replicationFeedSlaves}, +{"syncWithMaster", (long)syncWithMaster}, +{"tryObjectSharing", (long)tryObjectSharing}, +{"removeExpire", (long)removeExpire}, +{"expireIfNeeded", (long)expireIfNeeded}, +{"deleteIfVolatile", (long)deleteIfVolatile}, +{"deleteKey", (long)deleteKey}, +{"getExpire", (long)getExpire}, +{"setExpire", (long)setExpire}, +{"updateSalvesWaitingBgsave", (long)updateSalvesWaitingBgsave}, +{"freeMemoryIfNeeded", (long)freeMemoryIfNeeded}, +{"authCommand", (long)authCommand}, +{"pingCommand", (long)pingCommand}, +{"echoCommand", (long)echoCommand}, +{"setCommand", (long)setCommand}, +{"setnxCommand", (long)setnxCommand}, +{"getCommand", (long)getCommand}, +{"delCommand", (long)delCommand}, +{"existsCommand", (long)existsCommand}, +{"incrCommand", (long)incrCommand}, +{"decrCommand", (long)decrCommand}, +{"incrbyCommand", (long)incrbyCommand}, +{"decrbyCommand", (long)decrbyCommand}, +{"selectCommand", (long)selectCommand}, +{"randomkeyCommand", (long)randomkeyCommand}, +{"keysCommand", (long)keysCommand}, +{"dbsizeCommand", (long)dbsizeCommand}, +{"lastsaveCommand", (long)lastsaveCommand}, +{"saveCommand", (long)saveCommand}, +{"bgsaveCommand", (long)bgsaveCommand}, +{"shutdownCommand", (long)shutdownCommand}, +{"moveCommand", (long)moveCommand}, +{"renameCommand", (long)renameCommand}, +{"renamenxCommand", (long)renamenxCommand}, +{"lpushCommand", (long)lpushCommand}, +{"rpushCommand", (long)rpushCommand}, +{"lpopCommand", (long)lpopCommand}, +{"rpopCommand", (long)rpopCommand}, +{"llenCommand", (long)llenCommand}, +{"lindexCommand", (long)lindexCommand}, +{"lrangeCommand", (long)lrangeCommand}, +{"ltrimCommand", (long)ltrimCommand}, +{"typeCommand", (long)typeCommand}, +{"lsetCommand", (long)lsetCommand}, +{"saddCommand", (long)saddCommand}, +{"sremCommand", (long)sremCommand}, +{"smoveCommand", (long)smoveCommand}, +{"sismemberCommand", (long)sismemberCommand}, +{"scardCommand", (long)scardCommand}, +{"sinterCommand", (long)sinterCommand}, +{"sinterstoreCommand", (long)sinterstoreCommand}, +{"sunionCommand", (long)sunionCommand}, +{"sunionstoreCommand", (long)sunionstoreCommand}, +{"sdiffCommand", (long)sdiffCommand}, +{"sdiffstoreCommand", (long)sdiffstoreCommand}, +{"syncCommand", (long)syncCommand}, +{"flushdbCommand", (long)flushdbCommand}, +{"flushallCommand", (long)flushallCommand}, +{"sortCommand", (long)sortCommand}, +{"lremCommand", (long)lremCommand}, +{"infoCommand", (long)infoCommand}, +{"mgetCommand", (long)mgetCommand}, +{"monitorCommand", (long)monitorCommand}, +{"expireCommand", (long)expireCommand}, +{"getSetCommand", (long)getSetCommand}, +{"ttlCommand", (long)ttlCommand}, +{"slaveofCommand", (long)slaveofCommand}, +{"debugCommand", (long)debugCommand}, +{"processCommand", (long)processCommand}, +{"setupSigSegvAction", (long)setupSigSegvAction}, +{NULL,0} +}; /*============================ Utility functions ============================ */ /* Glob-style pattern matching. */ @@ -4080,12 +4170,30 @@ static void debugCommand(redisClient *c) { "-ERR Syntax error, try DEBUG [SEGFAULT|OBJECT ]\r\n")); } } +char *findFuncName(void *pointer, long *offset){ + int i, ret=-1; + long val, off; + for(i=0; symsTable[i].pointer!=0; i++){ + val=(long)pointer-symsTable[i].pointer; + if(val>=0 && (off<0 || val <= off)){ + off=val; + ret=i; + } + } + if(ret<0) + *offset=0; + else + *offset=off; + return ret>=0?symsTable[ret].name:"unknown"; +} static void segvHandler (int sig, siginfo_t *info, void *secret) { void *trace[100]; char **messages = (char **)NULL; + char *tmp; int i, trace_size = 0; + long offset=0; ucontext_t *uc = (ucontext_t *)secret; redisLog(REDIS_DEBUG, "Segmentation fault -%d- Redis %s", sig, REDIS_VERSION ); @@ -4094,13 +4202,23 @@ static void segvHandler (int sig, siginfo_t *info, void *secret) { trace_size = backtrace(trace, 100); - /* overwrite sigaction with caller's address */ + char pointer[trace_size][11]; + /* overwrite sigaction with caller's address */ trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP]; + for (i=1; i Date: Sat, 6 Jun 2009 09:49:10 +0000 Subject: [PATCH 7/7] add more output --- redis.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/redis.c b/redis.c index a9883922..57c7ed1f 100644 --- a/redis.c +++ b/redis.c @@ -4195,10 +4195,36 @@ static void segvHandler (int sig, siginfo_t *info, void *secret) { int i, trace_size = 0; long offset=0; ucontext_t *uc = (ucontext_t *)secret; - - redisLog(REDIS_DEBUG, "Segmentation fault -%d- Redis %s", sig, REDIS_VERSION ); - redisLog(REDIS_DEBUG,"EIP %p", (void *)uc->uc_mcontext.gregs[REG_EIP]); - redisLog(REDIS_DEBUG,"EAX %p, EBX %p, ECX %p, EDX %p", (void *)uc->uc_mcontext.gregs[REG_EAX], (void *)uc->uc_mcontext.gregs[REG_EBX], (void *)uc->uc_mcontext.gregs[REG_ECX], (void *)uc->uc_mcontext.gregs[REG_EDX]); + time_t uptime = time(NULL)-server.stat_starttime; + + redisLog(REDIS_WARNING, "application: redis, signal: segmentation fault -%d-",REDIS_VERSION, sig); + redisLog(REDIS_WARNING, "%s", sdscatprintf(sdsempty(), + "redis_version:%s; " + "uptime_in_days:%d; " + "connected_clients:%d; " + "connected_slaves:%d; " + "used_memory:%zu; " + "changes_since_last_save:%lld; " + "bgsave_in_progress:%d; " + "last_save_time:%d; " + "total_connections_received:%lld; " + "total_commands_processed:%lld; " + "role:%s;" + ,REDIS_VERSION, + uptime, + listLength(server.clients)-listLength(server.slaves), + listLength(server.slaves), + server.usedmemory, + server.dirty, + server.bgsaveinprogress, + server.lastsave, + server.stat_numconnections, + server.stat_numcommands, + server.masterhost == NULL ? "master" : "slave" + )); + + redisLog(REDIS_WARNING,"EIP %p", (void *)uc->uc_mcontext.gregs[REG_EIP]); + redisLog(REDIS_WARNING,"EAX %p, EBX %p, ECX %p, EDX %p", (void *)uc->uc_mcontext.gregs[REG_EAX], (void *)uc->uc_mcontext.gregs[REG_EBX], (void *)uc->uc_mcontext.gregs[REG_ECX], (void *)uc->uc_mcontext.gregs[REG_EDX]); trace_size = backtrace(trace, 100); @@ -4214,10 +4240,10 @@ static void segvHandler (int sig, siginfo_t *info, void *secret) { tmp=strstr(messages[i],pointer[i]); if((tmp-2)[0]!=')'){ char *a=findFuncName(trace[i], &offset); - redisLog(REDIS_DEBUG,"[bt] (%s+%x) %s", a, (unsigned int)offset, tmp); + redisLog(REDIS_WARNING,"#%d (%s+0x%x) %s", i, a, (unsigned int)offset, tmp); } else - redisLog(REDIS_DEBUG,"[bt] %s", messages[i]); + redisLog(REDIS_WARNING,"#%d %s", i, messages[i]); } free(messages);