LCOV - code coverage report
Current view: directory - redis/src - debug.c (source / functions) Found Hit Coverage
Test: redis.info Lines: 333 135 40.5 %
Date: 2012-04-04 Functions: 22 6 27.3 %
Colors: not hit hit

       1                 : #include "redis.h"
       2                 : #include "sha1.h"   /* SHA1 is used for DEBUG DIGEST */
       3                 : 
       4                 : #include <arpa/inet.h>
       5                 : #include <signal.h>
       6                 : 
       7                 : #ifdef HAVE_BACKTRACE
       8                 : #include <execinfo.h>
       9                 : #include <ucontext.h>
      10                 : #endif /* HAVE_BACKTRACE */
      11                 : 
      12                 : /* ================================= Debugging ============================== */
      13                 : 
      14                 : /* Compute the sha1 of string at 's' with 'len' bytes long.
      15                 :  * The SHA1 is then xored againt the string pointed by digest.
      16                 :  * Since xor is commutative, this operation is used in order to
      17                 :  * "add" digests relative to unordered elements.
      18                 :  *
      19                 :  * So digest(a,b,c,d) will be the same of digest(b,a,c,d) */
      20        13883099 : void xorDigest(unsigned char *digest, void *ptr, size_t len) {
      21                 :     SHA1_CTX ctx;
      22        13883099 :     unsigned char hash[20], *s = ptr;
      23                 :     int j;
      24                 : 
      25        13883099 :     SHA1Init(&ctx);
      26        13883099 :     SHA1Update(&ctx,s,len);
      27        13883099 :     SHA1Final(hash,&ctx);
      28                 : 
      29       291545079 :     for (j = 0; j < 20; j++)
      30       277661980 :         digest[j] ^= hash[j];
      31        13883099 : }
      32                 : 
      33           52708 : void xorObjectDigest(unsigned char *digest, robj *o) {
      34           52708 :     o = getDecodedObject(o);
      35          105416 :     xorDigest(digest,o->ptr,sdslen(o->ptr));
      36           52708 :     decrRefCount(o);
      37           52708 : }
      38                 : 
      39                 : /* This function instead of just computing the SHA1 and xoring it
      40                 :  * against diget, also perform the digest of "digest" itself and
      41                 :  * replace the old value with the new one.
      42                 :  *
      43                 :  * So the final digest will be:
      44                 :  *
      45                 :  * digest = SHA1(digest xor SHA1(data))
      46                 :  *
      47                 :  * This function is used every time we want to preserve the order so
      48                 :  * that digest(a,b,c,d) will be different than digest(b,c,d,a)
      49                 :  *
      50                 :  * Also note that mixdigest("foo") followed by mixdigest("bar")
      51                 :  * will lead to a different digest compared to "fo", "obar".
      52                 :  */
      53        10334860 : void mixDigest(unsigned char *digest, void *ptr, size_t len) {
      54                 :     SHA1_CTX ctx;
      55        10334860 :     char *s = ptr;
      56                 : 
      57        10334860 :     xorDigest(digest,s,len);
      58        10334860 :     SHA1Init(&ctx);
      59        10334860 :     SHA1Update(&ctx,digest,20);
      60        10334860 :     SHA1Final(digest,&ctx);
      61        10334860 : }
      62                 : 
      63         3414428 : void mixObjectDigest(unsigned char *digest, robj *o) {
      64         3414428 :     o = getDecodedObject(o);
      65         6828856 :     mixDigest(digest,o->ptr,sdslen(o->ptr));
      66         3414428 :     decrRefCount(o);
      67         3414428 : }
      68                 : 
      69                 : /* Compute the dataset digest. Since keys, sets elements, hashes elements
      70                 :  * are not ordered, we use a trick: every aggregate digest is the xor
      71                 :  * of the digests of their elements. This way the order will not change
      72                 :  * the result. For list instead we use a feedback entering the output digest
      73                 :  * as input in order to ensure that a different ordered list will result in
      74                 :  * a different digest. */
      75              61 : void computeDatasetDigest(unsigned char *final) {
      76                 :     unsigned char digest[20];
      77                 :     char buf[128];
      78              61 :     dictIterator *di = NULL;
      79                 :     dictEntry *de;
      80                 :     int j;
      81                 :     uint32_t aux;
      82                 : 
      83                 :     memset(final,0,20); /* Start with a clean result */
      84                 : 
      85            1037 :     for (j = 0; j < server.dbnum; j++) {
      86             976 :         redisDb *db = server.db+j;
      87                 : 
      88             976 :         if (dictSize(db->dict) == 0) continue;
      89              73 :         di = dictGetIterator(db->dict);
      90                 : 
      91                 :         /* hash the DB id, so the same dataset moved in a different
      92                 :          * DB will lead to a different digest */
      93              73 :         aux = htonl(j);
      94              73 :         mixDigest(final,&aux,sizeof(aux));
      95                 : 
      96                 :         /* Iterate this DB writing every entry */
      97         3416575 :         while((de = dictNext(di)) != NULL) {
      98                 :             sds key;
      99                 :             robj *keyobj, *o;
     100                 :             long long expiretime;
     101                 : 
     102                 :             memset(digest,0,20); /* This key-val digest */
     103         3416429 :             key = dictGetKey(de);
     104         3416429 :             keyobj = createStringObject(key,sdslen(key));
     105                 : 
     106         3416429 :             mixDigest(digest,key,sdslen(key));
     107                 : 
     108                 :             /* Make sure the key is loaded if VM is active */
     109         3416429 :             o = dictGetVal(de);
     110                 : 
     111         3416429 :             aux = htonl(o->type);
     112         3416429 :             mixDigest(digest,&aux,sizeof(aux));
     113         3416429 :             expiretime = getExpire(db,keyobj);
     114                 : 
     115                 :             /* Save the key and associated value */
     116         3416429 :             if (o->type == REDIS_STRING) {
     117         3307241 :                 mixObjectDigest(digest,o);
     118          109188 :             } else if (o->type == REDIS_LIST) {
     119           16029 :                 listTypeIterator *li = listTypeInitIterator(o,0,REDIS_TAIL);
     120                 :                 listTypeEntry entry;
     121           68542 :                 while(listTypeNext(li,&entry)) {
     122           36484 :                     robj *eleobj = listTypeGet(&entry);
     123           36484 :                     mixObjectDigest(digest,eleobj);
     124           36484 :                     decrRefCount(eleobj);
     125                 :                 }
     126           16029 :                 listTypeReleaseIterator(li);
     127           93159 :             } else if (o->type == REDIS_SET) {
     128           38003 :                 setTypeIterator *si = setTypeInitIterator(o);
     129                 :                 robj *ele;
     130          128714 :                 while((ele = setTypeNextObject(si)) != NULL) {
     131           52708 :                     xorObjectDigest(digest,ele);
     132           52708 :                     decrRefCount(ele);
     133                 :                 }
     134           38003 :                 setTypeReleaseIterator(si);
     135           55156 :             } else if (o->type == REDIS_ZSET) {
     136                 :                 unsigned char eledigest[20];
     137                 : 
     138           34723 :                 if (o->encoding == REDIS_ENCODING_ZIPLIST) {
     139           26711 :                     unsigned char *zl = o->ptr;
     140                 :                     unsigned char *eptr, *sptr;
     141                 :                     unsigned char *vstr;
     142                 :                     unsigned int vlen;
     143                 :                     long long vll;
     144                 :                     double score;
     145                 : 
     146           26711 :                     eptr = ziplistIndex(zl,0);
     147           26711 :                     redisAssert(eptr != NULL);
     148           26711 :                     sptr = ziplistNext(zl,eptr);
     149           26711 :                     redisAssert(sptr != NULL);
     150                 : 
     151           61426 :                     while (eptr != NULL) {
     152           34715 :                         redisAssert(ziplistGet(eptr,&vstr,&vlen,&vll));
     153           34715 :                         score = zzlGetScore(sptr);
     154                 : 
     155                 :                         memset(eledigest,0,20);
     156           34715 :                         if (vstr != NULL) {
     157            2419 :                             mixDigest(eledigest,vstr,vlen);
     158                 :                         } else {
     159           32296 :                             ll2string(buf,sizeof(buf),vll);
     160           32296 :                             mixDigest(eledigest,buf,strlen(buf));
     161                 :                         }
     162                 : 
     163           34715 :                         snprintf(buf,sizeof(buf),"%.17g",score);
     164           34715 :                         mixDigest(eledigest,buf,strlen(buf));
     165           34715 :                         xorDigest(digest,eledigest,20);
     166           34715 :                         zzlNext(zl,&eptr,&sptr);
     167                 :                     }
     168            8012 :                 } else if (o->encoding == REDIS_ENCODING_SKIPLIST) {
     169            8012 :                     zset *zs = o->ptr;
     170            8012 :                     dictIterator *di = dictGetIterator(zs->dict);
     171                 :                     dictEntry *de;
     172                 : 
     173           34095 :                     while((de = dictNext(di)) != NULL) {
     174           18071 :                         robj *eleobj = dictGetKey(de);
     175           18071 :                         double *score = dictGetVal(de);
     176                 : 
     177           18071 :                         snprintf(buf,sizeof(buf),"%.17g",*score);
     178                 :                         memset(eledigest,0,20);
     179           18071 :                         mixObjectDigest(eledigest,eleobj);
     180           18071 :                         mixDigest(eledigest,buf,strlen(buf));
     181           18071 :                         xorDigest(digest,eledigest,20);
     182                 :                     }
     183            8012 :                     dictReleaseIterator(di);
     184                 :                 } else {
     185               0 :                     redisPanic("Unknown sorted set encoding");
     186                 :                 }
     187           20433 :             } else if (o->type == REDIS_HASH) {
     188                 :                 hashTypeIterator *hi;
     189                 :                 robj *obj;
     190                 : 
     191           20433 :                 hi = hashTypeInitIterator(o);
     192           67182 :                 while (hashTypeNext(hi) != REDIS_ERR) {
     193                 :                     unsigned char eledigest[20];
     194                 : 
     195                 :                     memset(eledigest,0,20);
     196           26316 :                     obj = hashTypeCurrentObject(hi,REDIS_HASH_KEY);
     197           26316 :                     mixObjectDigest(eledigest,obj);
     198           26316 :                     decrRefCount(obj);
     199           26316 :                     obj = hashTypeCurrentObject(hi,REDIS_HASH_VALUE);
     200           26316 :                     mixObjectDigest(eledigest,obj);
     201           26316 :                     decrRefCount(obj);
     202           26316 :                     xorDigest(digest,eledigest,20);
     203                 :                 }
     204           20433 :                 hashTypeReleaseIterator(hi);
     205                 :             } else {
     206               0 :                 redisPanic("Unknown object type");
     207                 :             }
     208                 :             /* If the key has an expire, add it to the mix */
     209         3416429 :             if (expiretime != -1) xorDigest(digest,"!!expire!!",10);
     210                 :             /* We can finally xor the key-val digest to the final digest */
     211         3416429 :             xorDigest(final,digest,20);
     212         3416429 :             decrRefCount(keyobj);
     213                 :         }
     214              73 :         dictReleaseIterator(di);
     215                 :     }
     216              61 : }
     217                 : 
     218            3493 : void debugCommand(redisClient *c) {
     219            3493 :     if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
     220               0 :         *((char*)-1) = 'x';
     221            3493 :     } else if (!strcasecmp(c->argv[1]->ptr,"assert")) {
     222               0 :         if (c->argc >= 3) c->argv[2] = tryObjectEncoding(c->argv[2]);
     223               0 :         redisAssertWithInfo(c,c->argv[0],1 == 2);
     224            3493 :     } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
     225              10 :         if (rdbSave(server.rdb_filename) != REDIS_OK) {
     226               0 :             addReply(c,shared.err);
     227               0 :             return;
     228                 :         }
     229              10 :         emptyDb();
     230              10 :         if (rdbLoad(server.rdb_filename) != REDIS_OK) {
     231               0 :             addReplyError(c,"Error trying to load the RDB dump");
     232               0 :             return;
     233                 :         }
     234              10 :         redisLog(REDIS_WARNING,"DB reloaded by DEBUG RELOAD");
     235              10 :         addReply(c,shared.ok);
     236            3483 :     } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) {
     237              19 :         emptyDb();
     238              19 :         if (loadAppendOnlyFile(server.aof_filename) != REDIS_OK) {
     239               0 :             addReply(c,shared.err);
     240               0 :             return;
     241                 :         }
     242              19 :         server.dirty = 0; /* Prevent AOF / replication */
     243              19 :         redisLog(REDIS_WARNING,"Append Only File loaded by DEBUG LOADAOF");
     244              19 :         addReply(c,shared.ok);
     245            6864 :     } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
     246                 :         dictEntry *de;
     247                 :         robj *val;
     248                 :         char *strenc;
     249                 : 
     250            3400 :         if ((de = dictFind(c->db->dict,c->argv[2]->ptr)) == NULL) {
     251               0 :             addReply(c,shared.nokeyerr);
     252               0 :             return;
     253                 :         }
     254            3400 :         val = dictGetVal(de);
     255            3400 :         strenc = strEncoding(val->encoding);
     256                 : 
     257            6800 :         addReplyStatusFormat(c,
     258                 :             "Value at:%p refcount:%d "
     259                 :             "encoding:%s serializedlength:%lld "
     260                 :             "lru:%d lru_seconds_idle:%lu",
     261                 :             (void*)val, val->refcount,
     262                 :             strenc, (long long) rdbSavedObjectLen(val),
     263            3400 :             val->lru, estimateObjectIdleTime(val));
     264              64 :     } else if (!strcasecmp(c->argv[1]->ptr,"populate") && c->argc == 3) {
     265                 :         long keys, j;
     266                 :         robj *key, *val;
     267                 :         char buf[128];
     268                 : 
     269               0 :         if (getLongFromObjectOrReply(c, c->argv[2], &keys, NULL) != REDIS_OK)
     270                 :             return;
     271               0 :         for (j = 0; j < keys; j++) {
     272               0 :             snprintf(buf,sizeof(buf),"key:%lu",j);
     273               0 :             key = createStringObject(buf,strlen(buf));
     274               0 :             if (lookupKeyRead(c->db,key) != NULL) {
     275               0 :                 decrRefCount(key);
     276               0 :                 continue;
     277                 :             }
     278               0 :             snprintf(buf,sizeof(buf),"value:%lu",j);
     279               0 :             val = createStringObject(buf,strlen(buf));
     280               0 :             dbAdd(c->db,key,val);
     281               0 :             decrRefCount(key);
     282                 :         }
     283               0 :         addReply(c,shared.ok);
     284             125 :     } else if (!strcasecmp(c->argv[1]->ptr,"digest") && c->argc == 2) {
     285                 :         unsigned char digest[20];
     286              61 :         sds d = sdsempty();
     287                 :         int j;
     288                 : 
     289              61 :         computeDatasetDigest(digest);
     290            1281 :         for (j = 0; j < 20; j++)
     291            1220 :             d = sdscatprintf(d, "%02x",digest[j]);
     292              61 :         addReplyStatus(c,d);
     293              61 :         sdsfree(d);
     294               6 :     } else if (!strcasecmp(c->argv[1]->ptr,"sleep") && c->argc == 3) {
     295               3 :         double dtime = strtod(c->argv[2]->ptr,NULL);
     296               3 :         long long utime = dtime*1000000;
     297                 : 
     298               3 :         usleep(utime);
     299               3 :         addReply(c,shared.ok);
     300                 :     } else {
     301               0 :         addReplyError(c,
     302                 :             "Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key>|SWAPOUT <key>|RELOAD]");
     303                 :     }
     304                 : }
     305                 : 
     306                 : /* =========================== Crash handling  ============================== */
     307                 : 
     308               0 : void _redisAssert(char *estr, char *file, int line) {
     309               0 :     bugReportStart();
     310               0 :     redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
     311               0 :     redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true",file,line,estr);
     312                 : #ifdef HAVE_BACKTRACE
     313               0 :     server.assert_failed = estr;
     314               0 :     server.assert_file = file;
     315               0 :     server.assert_line = line;
     316               0 :     redisLog(REDIS_WARNING,"(forcing SIGSEGV to print the bug report.)");
     317                 : #endif
     318               0 :     *((char*)-1) = 'x';
     319               0 : }
     320                 : 
     321               0 : void _redisAssertPrintClientInfo(redisClient *c) {
     322                 :     int j;
     323                 : 
     324               0 :     bugReportStart();
     325               0 :     redisLog(REDIS_WARNING,"=== ASSERTION FAILED CLIENT CONTEXT ===");
     326               0 :     redisLog(REDIS_WARNING,"client->flags = %d", c->flags);
     327               0 :     redisLog(REDIS_WARNING,"client->fd = %d", c->fd);
     328               0 :     redisLog(REDIS_WARNING,"client->argc = %d", c->argc);
     329               0 :     for (j=0; j < c->argc; j++) {
     330                 :         char buf[128];
     331                 :         char *arg;
     332                 : 
     333               0 :         if (c->argv[j]->type == REDIS_STRING &&
     334                 :             c->argv[j]->encoding == REDIS_ENCODING_RAW)
     335                 :         {
     336               0 :             arg = (char*) c->argv[j]->ptr;
     337                 :         } else {
     338               0 :             snprintf(buf,sizeof(buf),"Object type: %d, encoding: %d",
     339               0 :                 c->argv[j]->type, c->argv[j]->encoding);
     340               0 :             arg = buf;
     341                 :         }
     342               0 :         redisLog(REDIS_WARNING,"client->argv[%d] = \"%s\" (refcount: %d)",
     343               0 :             j, arg, c->argv[j]->refcount);
     344                 :     }
     345               0 : }
     346                 : 
     347               0 : void redisLogObjectDebugInfo(robj *o) {
     348               0 :     redisLog(REDIS_WARNING,"Object type: %d", o->type);
     349               0 :     redisLog(REDIS_WARNING,"Object encoding: %d", o->encoding);
     350               0 :     redisLog(REDIS_WARNING,"Object refcount: %d", o->refcount);
     351               0 :     if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_RAW) {
     352               0 :         redisLog(REDIS_WARNING,"Object raw string len: %d", sdslen(o->ptr));
     353               0 :         if (sdslen(o->ptr) < 4096)
     354               0 :             redisLog(REDIS_WARNING,"Object raw string content: \"%s\"", (char*)o->ptr);
     355               0 :     } else if (o->type == REDIS_LIST) {
     356               0 :         redisLog(REDIS_WARNING,"List length: %d", (int) listTypeLength(o));
     357               0 :     } else if (o->type == REDIS_SET) {
     358               0 :         redisLog(REDIS_WARNING,"Set size: %d", (int) setTypeSize(o));
     359               0 :     } else if (o->type == REDIS_HASH) {
     360               0 :         redisLog(REDIS_WARNING,"Hash size: %d", (int) hashTypeLength(o));
     361               0 :     } else if (o->type == REDIS_ZSET) {
     362               0 :         redisLog(REDIS_WARNING,"Sorted set size: %d", (int) zsetLength(o));
     363               0 :         if (o->encoding == REDIS_ENCODING_SKIPLIST)
     364               0 :             redisLog(REDIS_WARNING,"Skiplist level: %d", (int) ((zset*)o->ptr)->zsl->level);
     365                 :     }
     366               0 : }
     367                 : 
     368               0 : void _redisAssertPrintObject(robj *o) {
     369               0 :     bugReportStart();
     370               0 :     redisLog(REDIS_WARNING,"=== ASSERTION FAILED OBJECT CONTEXT ===");
     371               0 :     redisLogObjectDebugInfo(o);
     372               0 : }
     373                 : 
     374               0 : void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int line) {
     375               0 :     if (c) _redisAssertPrintClientInfo(c);
     376               0 :     if (o) _redisAssertPrintObject(o);
     377               0 :     _redisAssert(estr,file,line);
     378               0 : }
     379                 : 
     380               0 : void _redisPanic(char *msg, char *file, int line) {
     381               0 :     bugReportStart();
     382               0 :     redisLog(REDIS_WARNING,"------------------------------------------------");
     383               0 :     redisLog(REDIS_WARNING,"!!! Software Failure. Press left mouse button to continue");
     384               0 :     redisLog(REDIS_WARNING,"Guru Meditation: %s #%s:%d",msg,file,line);
     385                 : #ifdef HAVE_BACKTRACE
     386               0 :     redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
     387                 : #endif
     388               0 :     redisLog(REDIS_WARNING,"------------------------------------------------");
     389               0 :     *((char*)-1) = 'x';
     390               0 : }
     391                 : 
     392               0 : void bugReportStart(void) {
     393               0 :     if (server.bug_report_start == 0) {
     394               0 :         redisLog(REDIS_WARNING,
     395                 :             "\n\n=== REDIS BUG REPORT START: Cut & paste starting from here ===");
     396               0 :         server.bug_report_start = 1;
     397                 :     }
     398               0 : }
     399                 : 
     400                 : #ifdef HAVE_BACKTRACE
     401                 : static void *getMcontextEip(ucontext_t *uc) {
     402                 : #if defined(__FreeBSD__)
     403                 :     return (void*) uc->uc_mcontext.mc_eip;
     404                 : #elif defined(__dietlibc__)
     405                 :     return (void*) uc->uc_mcontext.eip;
     406                 : #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
     407                 :   #if __x86_64__
     408                 :     return (void*) uc->uc_mcontext->__ss.__rip;
     409                 :   #elif __i386__
     410                 :     return (void*) uc->uc_mcontext->__ss.__eip;
     411                 :   #else
     412                 :     return (void*) uc->uc_mcontext->__ss.__srr0;
     413                 :   #endif
     414                 : #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
     415                 :   #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
     416                 :     return (void*) uc->uc_mcontext->__ss.__rip;
     417                 :   #else
     418                 :     return (void*) uc->uc_mcontext->__ss.__eip;
     419                 :   #endif
     420                 : #elif defined(__i386__)
     421                 :     return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */
     422                 : #elif defined(__X86_64__) || defined(__x86_64__)
     423               0 :     return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */
     424                 : #elif defined(__ia64__) /* Linux IA64 */
     425                 :     return (void*) uc->uc_mcontext.sc_ip;
     426                 : #else
     427                 :     return NULL;
     428                 : #endif
     429                 : }
     430                 : 
     431               0 : void logStackContent(void **sp) {
     432                 :     int i;
     433               0 :     for (i = 15; i >= 0; i--) {
     434                 :         if (sizeof(long) == 4)
     435                 :             redisLog(REDIS_WARNING, "(%08lx) -> %08lx", sp+i, sp[i]);
     436                 :         else
     437               0 :             redisLog(REDIS_WARNING, "(%016lx) -> %016lx", sp+i, sp[i]);
     438                 :     }
     439               0 : }
     440                 : 
     441               0 : void logRegisters(ucontext_t *uc) {
     442               0 :     redisLog(REDIS_WARNING, "--- REGISTERS");
     443                 : #if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
     444                 :   #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
     445                 :     redisLog(REDIS_WARNING,
     446                 :     "\n"
     447                 :     "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
     448                 :     "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
     449                 :     "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
     450                 :     "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
     451                 :     "RIP:%016lx EFL:%016lx\nCS :%016lx FS:%016lx  GS:%016lx",
     452                 :         uc->uc_mcontext->__ss.__rax,
     453                 :         uc->uc_mcontext->__ss.__rbx,
     454                 :         uc->uc_mcontext->__ss.__rcx,
     455                 :         uc->uc_mcontext->__ss.__rdx,
     456                 :         uc->uc_mcontext->__ss.__rdi,
     457                 :         uc->uc_mcontext->__ss.__rsi,
     458                 :         uc->uc_mcontext->__ss.__rbp,
     459                 :         uc->uc_mcontext->__ss.__rsp,
     460                 :         uc->uc_mcontext->__ss.__r8,
     461                 :         uc->uc_mcontext->__ss.__r9,
     462                 :         uc->uc_mcontext->__ss.__r10,
     463                 :         uc->uc_mcontext->__ss.__r11,
     464                 :         uc->uc_mcontext->__ss.__r12,
     465                 :         uc->uc_mcontext->__ss.__r13,
     466                 :         uc->uc_mcontext->__ss.__r14,
     467                 :         uc->uc_mcontext->__ss.__r15,
     468                 :         uc->uc_mcontext->__ss.__rip,
     469                 :         uc->uc_mcontext->__ss.__rflags,
     470                 :         uc->uc_mcontext->__ss.__cs,
     471                 :         uc->uc_mcontext->__ss.__fs,
     472                 :         uc->uc_mcontext->__ss.__gs
     473                 :     );
     474                 :     logStackContent((void**)uc->uc_mcontext->__ss.__rsp);
     475                 :   #else
     476                 :     redisLog(REDIS_WARNING,
     477                 :     "\n"
     478                 :     "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
     479                 :     "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
     480                 :     "SS:%08lx  EFL:%08lx EIP:%08lx CS :%08lx\n"
     481                 :     "DS:%08lx  ES:%08lx  FS :%08lx GS :%08lx",
     482                 :         uc->uc_mcontext->__ss.__eax,
     483                 :         uc->uc_mcontext->__ss.__ebx,
     484                 :         uc->uc_mcontext->__ss.__ecx,
     485                 :         uc->uc_mcontext->__ss.__edx,
     486                 :         uc->uc_mcontext->__ss.__edi,
     487                 :         uc->uc_mcontext->__ss.__esi,
     488                 :         uc->uc_mcontext->__ss.__ebp,
     489                 :         uc->uc_mcontext->__ss.__esp,
     490                 :         uc->uc_mcontext->__ss.__ss,
     491                 :         uc->uc_mcontext->__ss.__eflags,
     492                 :         uc->uc_mcontext->__ss.__eip,
     493                 :         uc->uc_mcontext->__ss.__cs,
     494                 :         uc->uc_mcontext->__ss.__ds,
     495                 :         uc->uc_mcontext->__ss.__es,
     496                 :         uc->uc_mcontext->__ss.__fs,
     497                 :         uc->uc_mcontext->__ss.__gs
     498                 :     );
     499                 :     logStackContent((void**)uc->uc_mcontext->__ss.__esp);
     500                 :   #endif
     501                 : #elif defined(__i386__)
     502                 :     redisLog(REDIS_WARNING,
     503                 :     "\n"
     504                 :     "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
     505                 :     "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
     506                 :     "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
     507                 :     "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
     508                 :         uc->uc_mcontext.gregs[11],
     509                 :         uc->uc_mcontext.gregs[8],
     510                 :         uc->uc_mcontext.gregs[10],
     511                 :         uc->uc_mcontext.gregs[9],
     512                 :         uc->uc_mcontext.gregs[4],
     513                 :         uc->uc_mcontext.gregs[5],
     514                 :         uc->uc_mcontext.gregs[6],
     515                 :         uc->uc_mcontext.gregs[7],
     516                 :         uc->uc_mcontext.gregs[18],
     517                 :         uc->uc_mcontext.gregs[17],
     518                 :         uc->uc_mcontext.gregs[14],
     519                 :         uc->uc_mcontext.gregs[15],
     520                 :         uc->uc_mcontext.gregs[3],
     521                 :         uc->uc_mcontext.gregs[2],
     522                 :         uc->uc_mcontext.gregs[1],
     523                 :         uc->uc_mcontext.gregs[0]
     524                 :     );
     525                 :     logStackContent((void**)uc->uc_mcontext.gregs[7]);
     526                 : #elif defined(__X86_64__) || defined(__x86_64__)
     527               0 :     redisLog(REDIS_WARNING,
     528                 :     "\n"
     529                 :     "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
     530                 :     "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
     531                 :     "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
     532                 :     "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
     533                 :     "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
     534                 :         uc->uc_mcontext.gregs[13],
     535                 :         uc->uc_mcontext.gregs[11],
     536                 :         uc->uc_mcontext.gregs[14],
     537                 :         uc->uc_mcontext.gregs[12],
     538                 :         uc->uc_mcontext.gregs[8],
     539                 :         uc->uc_mcontext.gregs[9],
     540                 :         uc->uc_mcontext.gregs[10],
     541                 :         uc->uc_mcontext.gregs[15],
     542                 :         uc->uc_mcontext.gregs[0],
     543                 :         uc->uc_mcontext.gregs[1],
     544                 :         uc->uc_mcontext.gregs[2],
     545                 :         uc->uc_mcontext.gregs[3],
     546                 :         uc->uc_mcontext.gregs[4],
     547                 :         uc->uc_mcontext.gregs[5],
     548                 :         uc->uc_mcontext.gregs[6],
     549                 :         uc->uc_mcontext.gregs[7],
     550                 :         uc->uc_mcontext.gregs[16],
     551                 :         uc->uc_mcontext.gregs[17],
     552                 :         uc->uc_mcontext.gregs[18]
     553                 :     );
     554               0 :     logStackContent((void**)uc->uc_mcontext.gregs[15]);
     555                 : #else
     556                 :     redisLog(REDIS_WARNING,
     557                 :         "  Dumping of registers not supported for this OS/arch");
     558                 : #endif
     559               0 : }
     560                 : 
     561                 : /* Logs the stack trace using the backtrace() call. */
     562               0 : sds getStackTrace(ucontext_t *uc) {
     563                 :     void *trace[100];
     564               0 :     int i, trace_size = 0;
     565               0 :     char **messages = NULL;
     566               0 :     sds st = sdsempty();
     567                 : 
     568                 :     /* Generate the stack trace */
     569               0 :     trace_size = backtrace(trace, 100);
     570                 : 
     571                 :     /* overwrite sigaction with caller's address */
     572               0 :     if (getMcontextEip(uc) != NULL) {
     573               0 :         trace[1] = getMcontextEip(uc);
     574                 :     }
     575               0 :     messages = backtrace_symbols(trace, trace_size);
     576               0 :     for (i=1; i<trace_size; ++i) {
     577               0 :         st = sdscat(st,messages[i]);
     578               0 :         st = sdscatlen(st,"\n",1);
     579                 :     }
     580               0 :     zlibc_free(messages);
     581               0 :     return st;
     582                 : }
     583                 : 
     584                 : /* Log information about the "current" client, that is, the client that is
     585                 :  * currently being served by Redis. May be NULL if Redis is not serving a
     586                 :  * client right now. */
     587               0 : void logCurrentClient(void) {
     588               0 :     if (server.current_client == NULL) return;
     589                 : 
     590               0 :     redisClient *cc = server.current_client;
     591                 :     sds client;
     592                 :     int j;
     593                 : 
     594               0 :     redisLog(REDIS_WARNING, "--- CURRENT CLIENT INFO");
     595               0 :     client = getClientInfoString(cc);
     596               0 :     redisLog(REDIS_WARNING,"client: %s", client);
     597               0 :     sdsfree(client);
     598               0 :     for (j = 0; j < cc->argc; j++) {
     599                 :         robj *decoded;
     600                 : 
     601               0 :         decoded = getDecodedObject(cc->argv[j]);
     602               0 :         redisLog(REDIS_WARNING,"argv[%d]: '%s'", j, (char*)decoded->ptr);
     603               0 :         decrRefCount(decoded);
     604                 :     }
     605                 :     /* Check if the first argument, usually a key, is found inside the
     606                 :      * selected DB, and if so print info about the associated object. */
     607               0 :     if (cc->argc >= 1) {
     608                 :         robj *val, *key;
     609                 :         dictEntry *de;
     610                 : 
     611               0 :         key = getDecodedObject(cc->argv[1]);
     612               0 :         de = dictFind(cc->db->dict, key->ptr);
     613               0 :         if (de) {
     614               0 :             val = dictGetVal(de);
     615               0 :             redisLog(REDIS_WARNING,"key '%s' found in DB containing the following object:", key->ptr);
     616               0 :             redisLogObjectDebugInfo(val);
     617                 :         }
     618               0 :         decrRefCount(key);
     619                 :     }
     620                 : }
     621                 : 
     622               0 : void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
     623               0 :     ucontext_t *uc = (ucontext_t*) secret;
     624                 :     sds infostring, clients, st;
     625                 :     struct sigaction act;
     626                 :     REDIS_NOTUSED(info);
     627                 : 
     628               0 :     bugReportStart();
     629               0 :     redisLog(REDIS_WARNING,
     630                 :         "    Redis %s crashed by signal: %d", REDIS_VERSION, sig);
     631               0 :     redisLog(REDIS_WARNING,
     632                 :         "    Failed assertion: %s (%s:%d)", server.assert_failed,
     633                 :                         server.assert_file, server.assert_line);
     634                 : 
     635                 :     /* Log the stack trace */
     636               0 :     st = getStackTrace(uc);
     637               0 :     redisLog(REDIS_WARNING, "--- STACK TRACE\n%s", st);
     638               0 :     sdsfree(st);
     639                 : 
     640                 :     /* Log INFO and CLIENT LIST */
     641               0 :     redisLog(REDIS_WARNING, "--- INFO OUTPUT");
     642               0 :     infostring = genRedisInfoString("all");
     643               0 :     infostring = sdscatprintf(infostring, "hash_init_value: %u\n",
     644                 :         dictGetHashFunctionSeed());
     645               0 :     redisLogRaw(REDIS_WARNING, infostring);
     646               0 :     redisLog(REDIS_WARNING, "--- CLIENT LIST OUTPUT");
     647               0 :     clients = getAllClientsInfoString();
     648               0 :     redisLogRaw(REDIS_WARNING, clients);
     649               0 :     sdsfree(infostring);
     650               0 :     sdsfree(clients);
     651                 : 
     652                 :     /* Log the current client */
     653               0 :     logCurrentClient();
     654                 : 
     655                 :     /* Log dump of processor registers */
     656               0 :     logRegisters(uc);
     657                 : 
     658               0 :     redisLog(REDIS_WARNING,
     659                 : "\n=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
     660                 : "       Please report the crash opening an issue on github:\n\n"
     661                 : "           http://github.com/antirez/redis/issues\n\n"
     662                 : "  Suspect RAM error? Use redis-server --test-memory to veryfy it.\n\n"
     663                 : );
     664                 :     /* free(messages); Don't call free() with possibly corrupted memory. */
     665               0 :     if (server.daemonize) unlink(server.pidfile);
     666                 : 
     667                 :     /* Make sure we exit with the right signal at the end. So for instance
     668                 :      * the core will be dumped if enabled. */
     669               0 :     sigemptyset (&act.sa_mask);
     670               0 :     act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
     671               0 :     act.sa_handler = SIG_DFL;
     672               0 :     sigaction (sig, &act, NULL);
     673               0 :     kill(getpid(),sig);
     674               0 : }
     675                 : #endif /* HAVE_BACKTRACE */
     676                 : 
     677                 : /* =========================== Software Watchdog ============================ */
     678                 : #include <sys/time.h>
     679                 : 
     680               0 : void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) {
     681               0 :     ucontext_t *uc = (ucontext_t*) secret;
     682                 :     REDIS_NOTUSED(info);
     683                 :     REDIS_NOTUSED(sig);
     684                 :     sds st, log;
     685                 : 
     686               0 :     log = sdsnew("\n--- WATCHDOG TIMER EXPIRED ---\n");
     687                 : #ifdef HAVE_BACKTRACE
     688               0 :     st = getStackTrace(uc);
     689                 : #else
     690                 :     st = sdsnew("Sorry: no support for backtrace().\n");
     691                 : #endif
     692               0 :     log = sdscatsds(log,st);
     693               0 :     log = sdscat(log,"------\n");
     694               0 :     redisLogFromHandler(REDIS_WARNING,log);
     695               0 :     sdsfree(st);
     696               0 :     sdsfree(log);
     697               0 : }
     698                 : 
     699                 : /* Schedule a SIGALRM delivery after the specified period in milliseconds.
     700                 :  * If a timer is already scheduled, this function will re-schedule it to the
     701                 :  * specified time. If period is 0 the current timer is disabled. */
     702               0 : void watchdogScheduleSignal(int period) {
     703                 :     struct itimerval it;
     704                 : 
     705                 :     /* Will stop the timer if period is 0. */
     706               0 :     it.it_value.tv_sec = period/1000;
     707               0 :     it.it_value.tv_usec = (period%1000)*1000;
     708                 :     /* Don't automatically restart. */
     709               0 :     it.it_interval.tv_sec = 0;
     710               0 :     it.it_interval.tv_usec = 0;
     711               0 :     setitimer(ITIMER_REAL, &it, NULL);
     712               0 : }
     713                 : 
     714                 : /* Enable the software watchdong with the specified period in milliseconds. */
     715               0 : void enableWatchdog(int period) {
     716               0 :     if (server.watchdog_period == 0) {
     717                 :         struct sigaction act;
     718                 : 
     719                 :         /* Watchdog was actually disabled, so we have to setup the signal
     720                 :          * handler. */
     721               0 :         sigemptyset(&act.sa_mask);
     722               0 :         act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_SIGINFO;
     723               0 :         act.sa_sigaction = watchdogSignalHandler;
     724               0 :         sigaction(SIGALRM, &act, NULL);
     725                 :     }
     726               0 :     if (period < 200) period = 200; /* We don't accept periods < 200 ms. */
     727               0 :     watchdogScheduleSignal(period); /* Adjust the current timer. */
     728               0 :     server.watchdog_period = period;
     729               0 : }
     730                 : 
     731                 : /* Disable the software watchdog. */
     732               0 : void disableWatchdog(void) {
     733                 :     struct sigaction act;
     734               0 :     if (server.watchdog_period == 0) return; /* Already disabled. */
     735               0 :     watchdogScheduleSignal(0); /* Stop the current timer. */
     736                 : 
     737                 :     /* Set the signal handler to SIG_IGN, this will also remove pending
     738                 :      * signals from the queue. */
     739               0 :     sigemptyset(&act.sa_mask);
     740               0 :     act.sa_flags = 0;
     741               0 :     act.sa_handler = SIG_IGN;
     742               0 :     sigaction(SIGALRM, &act, NULL);
     743               0 :     server.watchdog_period = 0;
     744                 : }

Generated by: LCOV version 1.7