]>
git.saurik.com Git - redis.git/blob - src/debug.c
bddb082e527f3c10a6f6a135875a81495edf1623
   2 #include "sha1.h"   /* SHA1 is used for DEBUG DIGEST */ 
  10 #endif /* HAVE_BACKTRACE */ 
  12 /* ================================= Debugging ============================== */ 
  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. 
  19  * So digest(a,b,c,d) will be the same of digest(b,a,c,d) */ 
  20 void xorDigest(unsigned char *digest
, void *ptr
, size_t len
) { 
  22     unsigned char hash
[20], *s 
= ptr
; 
  26     SHA1Update(&ctx
,s
,len
); 
  29     for (j 
= 0; j 
< 20; j
++) 
  33 void xorObjectDigest(unsigned char *digest
, robj 
*o
) { 
  34     o 
= getDecodedObject(o
); 
  35     xorDigest(digest
,o
->ptr
,sdslen(o
->ptr
)); 
  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. 
  43  * So the final digest will be: 
  45  * digest = SHA1(digest xor SHA1(data)) 
  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) 
  50  * Also note that mixdigest("foo") followed by mixdigest("bar") 
  51  * will lead to a different digest compared to "fo", "obar". 
  53 void mixDigest(unsigned char *digest
, void *ptr
, size_t len
) { 
  57     xorDigest(digest
,s
,len
); 
  59     SHA1Update(&ctx
,digest
,20); 
  60     SHA1Final(digest
,&ctx
); 
  63 void mixObjectDigest(unsigned char *digest
, robj 
*o
) { 
  64     o 
= getDecodedObject(o
); 
  65     mixDigest(digest
,o
->ptr
,sdslen(o
->ptr
)); 
  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 void computeDatasetDigest(unsigned char *final
) { 
  76     unsigned char digest
[20]; 
  78     dictIterator 
*di 
= NULL
; 
  83     memset(final
,0,20); /* Start with a clean result */ 
  85     for (j 
= 0; j 
< server
.dbnum
; j
++) { 
  86         redisDb 
*db 
= server
.db
+j
; 
  88         if (dictSize(db
->dict
) == 0) continue; 
  89         di 
= dictGetIterator(db
->dict
); 
  91         /* hash the DB id, so the same dataset moved in a different 
  92          * DB will lead to a different digest */ 
  94         mixDigest(final
,&aux
,sizeof(aux
)); 
  96         /* Iterate this DB writing every entry */ 
  97         while((de 
= dictNext(di
)) != NULL
) { 
 100             long long expiretime
; 
 102             memset(digest
,0,20); /* This key-val digest */ 
 103             key 
= dictGetKey(de
); 
 104             keyobj 
= createStringObject(key
,sdslen(key
)); 
 106             mixDigest(digest
,key
,sdslen(key
)); 
 108             /* Make sure the key is loaded if VM is active */ 
 111             aux 
= htonl(o
->type
); 
 112             mixDigest(digest
,&aux
,sizeof(aux
)); 
 113             expiretime 
= getExpire(db
,keyobj
); 
 115             /* Save the key and associated value */ 
 116             if (o
->type 
== REDIS_STRING
) { 
 117                 mixObjectDigest(digest
,o
); 
 118             } else if (o
->type 
== REDIS_LIST
) { 
 119                 listTypeIterator 
*li 
= listTypeInitIterator(o
,0,REDIS_TAIL
); 
 121                 while(listTypeNext(li
,&entry
)) { 
 122                     robj 
*eleobj 
= listTypeGet(&entry
); 
 123                     mixObjectDigest(digest
,eleobj
); 
 124                     decrRefCount(eleobj
); 
 126                 listTypeReleaseIterator(li
); 
 127             } else if (o
->type 
== REDIS_SET
) { 
 128                 setTypeIterator 
*si 
= setTypeInitIterator(o
); 
 130                 while((ele 
= setTypeNextObject(si
)) != NULL
) { 
 131                     xorObjectDigest(digest
,ele
); 
 134                 setTypeReleaseIterator(si
); 
 135             } else if (o
->type 
== REDIS_ZSET
) { 
 136                 unsigned char eledigest
[20]; 
 138                 if (o
->encoding 
== REDIS_ENCODING_ZIPLIST
) { 
 139                     unsigned char *zl 
= o
->ptr
; 
 140                     unsigned char *eptr
, *sptr
; 
 146                     eptr 
= ziplistIndex(zl
,0); 
 147                     redisAssert(eptr 
!= NULL
); 
 148                     sptr 
= ziplistNext(zl
,eptr
); 
 149                     redisAssert(sptr 
!= NULL
); 
 151                     while (eptr 
!= NULL
) { 
 152                         redisAssert(ziplistGet(eptr
,&vstr
,&vlen
,&vll
)); 
 153                         score 
= zzlGetScore(sptr
); 
 155                         memset(eledigest
,0,20); 
 157                             mixDigest(eledigest
,vstr
,vlen
); 
 159                             ll2string(buf
,sizeof(buf
),vll
); 
 160                             mixDigest(eledigest
,buf
,strlen(buf
)); 
 163                         snprintf(buf
,sizeof(buf
),"%.17g",score
); 
 164                         mixDigest(eledigest
,buf
,strlen(buf
)); 
 165                         xorDigest(digest
,eledigest
,20); 
 166                         zzlNext(zl
,&eptr
,&sptr
); 
 168                 } else if (o
->encoding 
== REDIS_ENCODING_SKIPLIST
) { 
 170                     dictIterator 
*di 
= dictGetIterator(zs
->dict
); 
 173                     while((de 
= dictNext(di
)) != NULL
) { 
 174                         robj 
*eleobj 
= dictGetKey(de
); 
 175                         double *score 
= dictGetVal(de
); 
 177                         snprintf(buf
,sizeof(buf
),"%.17g",*score
); 
 178                         memset(eledigest
,0,20); 
 179                         mixObjectDigest(eledigest
,eleobj
); 
 180                         mixDigest(eledigest
,buf
,strlen(buf
)); 
 181                         xorDigest(digest
,eledigest
,20); 
 183                     dictReleaseIterator(di
); 
 185                     redisPanic("Unknown sorted set encoding"); 
 187             } else if (o
->type 
== REDIS_HASH
) { 
 188                 hashTypeIterator 
*hi
; 
 191                 hi 
= hashTypeInitIterator(o
); 
 192                 while (hashTypeNext(hi
) != REDIS_ERR
) { 
 193                     unsigned char eledigest
[20]; 
 195                     memset(eledigest
,0,20); 
 196                     obj 
= hashTypeCurrentObject(hi
,REDIS_HASH_KEY
); 
 197                     mixObjectDigest(eledigest
,obj
); 
 199                     obj 
= hashTypeCurrentObject(hi
,REDIS_HASH_VALUE
); 
 200                     mixObjectDigest(eledigest
,obj
); 
 202                     xorDigest(digest
,eledigest
,20); 
 204                 hashTypeReleaseIterator(hi
); 
 206                 redisPanic("Unknown object type"); 
 208             /* If the key has an expire, add it to the mix */ 
 209             if (expiretime 
!= -1) xorDigest(digest
,"!!expire!!",10); 
 210             /* We can finally xor the key-val digest to the final digest */ 
 211             xorDigest(final
,digest
,20); 
 212             decrRefCount(keyobj
); 
 214         dictReleaseIterator(di
); 
 218 void debugCommand(redisClient 
*c
) { 
 219     if (!strcasecmp(c
->argv
[1]->ptr
,"segfault")) { 
 221     } else if (!strcasecmp(c
->argv
[1]->ptr
,"assert")) { 
 222         if (c
->argc 
>= 3) c
->argv
[2] = tryObjectEncoding(c
->argv
[2]); 
 223         redisAssertWithInfo(c
,c
->argv
[0],1 == 2); 
 224     } else if (!strcasecmp(c
->argv
[1]->ptr
,"reload")) { 
 225         if (rdbSave(server
.rdb_filename
) != REDIS_OK
) { 
 226             addReply(c
,shared
.err
); 
 230         if (rdbLoad(server
.rdb_filename
) != REDIS_OK
) { 
 231             addReplyError(c
,"Error trying to load the RDB dump"); 
 234         redisLog(REDIS_WARNING
,"DB reloaded by DEBUG RELOAD"); 
 235         addReply(c
,shared
.ok
); 
 236     } else if (!strcasecmp(c
->argv
[1]->ptr
,"loadaof")) { 
 238         if (loadAppendOnlyFile(server
.aof_filename
) != REDIS_OK
) { 
 239             addReply(c
,shared
.err
); 
 242         server
.dirty 
= 0; /* Prevent AOF / replication */ 
 243         redisLog(REDIS_WARNING
,"Append Only File loaded by DEBUG LOADAOF"); 
 244         addReply(c
,shared
.ok
); 
 245     } else if (!strcasecmp(c
->argv
[1]->ptr
,"object") && c
->argc 
== 3) { 
 250         if ((de 
= dictFind(c
->db
->dict
,c
->argv
[2]->ptr
)) == NULL
) { 
 251             addReply(c
,shared
.nokeyerr
); 
 254         val 
= dictGetVal(de
); 
 255         strenc 
= strEncoding(val
->encoding
); 
 257         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             val
->lru
, estimateObjectIdleTime(val
)); 
 264     } else if (!strcasecmp(c
->argv
[1]->ptr
,"populate") && c
->argc 
== 3) { 
 269         if (getLongFromObjectOrReply(c
, c
->argv
[2], &keys
, NULL
) != REDIS_OK
) 
 271         for (j 
= 0; j 
< keys
; j
++) { 
 272             snprintf(buf
,sizeof(buf
),"key:%lu",j
); 
 273             key 
= createStringObject(buf
,strlen(buf
)); 
 274             if (lookupKeyRead(c
->db
,key
) != NULL
) { 
 278             snprintf(buf
,sizeof(buf
),"value:%lu",j
); 
 279             val 
= createStringObject(buf
,strlen(buf
)); 
 280             dbAdd(c
->db
,key
,val
); 
 283         addReply(c
,shared
.ok
); 
 284     } else if (!strcasecmp(c
->argv
[1]->ptr
,"digest") && c
->argc 
== 2) { 
 285         unsigned char digest
[20]; 
 289         computeDatasetDigest(digest
); 
 290         for (j 
= 0; j 
< 20; j
++) 
 291             d 
= sdscatprintf(d
, "%02x",digest
[j
]); 
 294     } else if (!strcasecmp(c
->argv
[1]->ptr
,"sleep") && c
->argc 
== 3) { 
 295         double dtime 
= strtod(c
->argv
[2]->ptr
,NULL
); 
 296         long long utime 
= dtime
*1000000; 
 299         addReply(c
,shared
.ok
); 
 302             "Syntax error, try DEBUG [SEGFAULT|OBJECT <key>|SWAPIN <key>|SWAPOUT <key>|RELOAD]"); 
 306 /* =========================== Crash handling  ============================== */ 
 308 void _redisAssert(char *estr
, char *file
, int line
) { 
 310     redisLog(REDIS_WARNING
,"=== ASSERTION FAILED ==="); 
 311     redisLog(REDIS_WARNING
,"==> %s:%d '%s' is not true",file
,line
,estr
); 
 312 #ifdef HAVE_BACKTRACE 
 313     server
.assert_failed 
= estr
; 
 314     server
.assert_file 
= file
; 
 315     server
.assert_line 
= line
; 
 316     redisLog(REDIS_WARNING
,"(forcing SIGSEGV to print the bug report.)"); 
 321 void _redisAssertPrintClientInfo(redisClient 
*c
) { 
 325     redisLog(REDIS_WARNING
,"=== ASSERTION FAILED CLIENT CONTEXT ==="); 
 326     redisLog(REDIS_WARNING
,"client->flags = %d", c
->flags
); 
 327     redisLog(REDIS_WARNING
,"client->fd = %d", c
->fd
); 
 328     redisLog(REDIS_WARNING
,"client->argc = %d", c
->argc
); 
 329     for (j
=0; j 
< c
->argc
; j
++) { 
 333         if (c
->argv
[j
]->type 
== REDIS_STRING 
&& 
 334             c
->argv
[j
]->encoding 
== REDIS_ENCODING_RAW
) 
 336             arg 
= (char*) c
->argv
[j
]->ptr
; 
 338             snprintf(buf
,sizeof(buf
),"Object type: %d, encoding: %d", 
 339                 c
->argv
[j
]->type
, c
->argv
[j
]->encoding
); 
 342         redisLog(REDIS_WARNING
,"client->argv[%d] = \"%s\" (refcount: %d)", 
 343             j
, arg
, c
->argv
[j
]->refcount
); 
 347 void redisLogObjectDebugInfo(robj 
*o
) { 
 348     redisLog(REDIS_WARNING
,"Object type: %d", o
->type
); 
 349     redisLog(REDIS_WARNING
,"Object encoding: %d", o
->encoding
); 
 350     redisLog(REDIS_WARNING
,"Object refcount: %d", o
->refcount
); 
 351     if (o
->type 
== REDIS_STRING 
&& o
->encoding 
== REDIS_ENCODING_RAW
) { 
 352         redisLog(REDIS_WARNING
,"Object raw string len: %d", sdslen(o
->ptr
)); 
 353         if (sdslen(o
->ptr
) < 4096) 
 354             redisLog(REDIS_WARNING
,"Object raw string content: \"%s\"", (char*)o
->ptr
); 
 355     } else if (o
->type 
== REDIS_LIST
) { 
 356         redisLog(REDIS_WARNING
,"List length: %d", (int) listTypeLength(o
)); 
 357     } else if (o
->type 
== REDIS_SET
) { 
 358         redisLog(REDIS_WARNING
,"Set size: %d", (int) setTypeSize(o
)); 
 359     } else if (o
->type 
== REDIS_HASH
) { 
 360         redisLog(REDIS_WARNING
,"Hash size: %d", (int) hashTypeLength(o
)); 
 361     } else if (o
->type 
== REDIS_ZSET
) { 
 362         redisLog(REDIS_WARNING
,"Sorted set size: %d", (int) zsetLength(o
)); 
 363         if (o
->encoding 
== REDIS_ENCODING_SKIPLIST
) 
 364             redisLog(REDIS_WARNING
,"Skiplist level: %d", (int) ((zset
*)o
->ptr
)->zsl
->level
); 
 368 void _redisAssertPrintObject(robj 
*o
) { 
 370     redisLog(REDIS_WARNING
,"=== ASSERTION FAILED OBJECT CONTEXT ==="); 
 371     redisLogObjectDebugInfo(o
); 
 374 void _redisAssertWithInfo(redisClient 
*c
, robj 
*o
, char *estr
, char *file
, int line
) { 
 375     if (c
) _redisAssertPrintClientInfo(c
); 
 376     if (o
) _redisAssertPrintObject(o
); 
 377     _redisAssert(estr
,file
,line
); 
 380 void _redisPanic(char *msg
, char *file
, int line
) { 
 382     redisLog(REDIS_WARNING
,"------------------------------------------------"); 
 383     redisLog(REDIS_WARNING
,"!!! Software Failure. Press left mouse button to continue"); 
 384     redisLog(REDIS_WARNING
,"Guru Meditation: %s #%s:%d",msg
,file
,line
); 
 385 #ifdef HAVE_BACKTRACE 
 386     redisLog(REDIS_WARNING
,"(forcing SIGSEGV in order to print the stack trace)"); 
 387     redisLog(REDIS_WARNING
,"------------------------------------------------"); 
 392 #ifdef HAVE_BACKTRACE 
 393 static void *getMcontextEip(ucontext_t 
*uc
) { 
 394 #if defined(__FreeBSD__) 
 395     return (void*) uc
->uc_mcontext
.mc_eip
; 
 396 #elif defined(__dietlibc__) 
 397     return (void*) uc
->uc_mcontext
.eip
; 
 398 #elif defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6) 
 400     return (void*) uc
->uc_mcontext
->__ss
.__rip
; 
 402     return (void*) uc
->uc_mcontext
->__ss
.__eip
; 
 404     return (void*) uc
->uc_mcontext
->__ss
.__srr0
; 
 406 #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6) 
 407   #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__) 
 408     return (void*) uc
->uc_mcontext
->__ss
.__rip
; 
 410     return (void*) uc
->uc_mcontext
->__ss
.__eip
; 
 412 #elif defined(__i386__) 
 413     return (void*) uc
->uc_mcontext
.gregs
[14]; /* Linux 32 */ 
 414 #elif defined(__X86_64__) || defined(__x86_64__) 
 415     return (void*) uc
->uc_mcontext
.gregs
[16]; /* Linux 64 */ 
 416 #elif defined(__ia64__) /* Linux IA64 */ 
 417     return (void*) uc
->uc_mcontext
.sc_ip
; 
 423 void bugReportStart(void) { 
 424     if (server
.bug_report_start 
== 0) { 
 425         redisLog(REDIS_WARNING
, 
 426             "\n\n=== REDIS BUG REPORT START: Cut & paste starting from here ==="); 
 427         server
.bug_report_start 
= 1; 
 431 void logStackContent(void **sp
) { 
 433     for (i 
= 15; i 
>= 0; i
--) { 
 434         redisLog(REDIS_WARNING
, "(%p) -> %p", sp
+i
, sp
[i
]); 
 438 void logRegisters(ucontext_t 
*uc
) { 
 439     redisLog(REDIS_WARNING
, "--- REGISTERS"); 
 440 #if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6) 
 441   #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__) 
 442     redisLog(REDIS_WARNING
, 
 444     "RAX:%p RBX:%p RCX:%p RDX:%p\n" 
 445     "RDI:%p RSI:%p RBP:%p RSP:%p\n" 
 446     "R8:%p  R9:%p  R10:%p R11:%p\n" 
 447     "R12:%p R13:%p R14:%p R15:%p\n" 
 448     "RIP:%p EFL:%p CS:%p  FS:%p GS:%p", 
 449         uc
->uc_mcontext
->__ss
.__rax
, 
 450         uc
->uc_mcontext
->__ss
.__rbx
, 
 451         uc
->uc_mcontext
->__ss
.__rcx
, 
 452         uc
->uc_mcontext
->__ss
.__rdx
, 
 453         uc
->uc_mcontext
->__ss
.__rdi
, 
 454         uc
->uc_mcontext
->__ss
.__rsi
, 
 455         uc
->uc_mcontext
->__ss
.__rbp
, 
 456         uc
->uc_mcontext
->__ss
.__rsp
, 
 457         uc
->uc_mcontext
->__ss
.__r8
, 
 458         uc
->uc_mcontext
->__ss
.__r9
, 
 459         uc
->uc_mcontext
->__ss
.__r10
, 
 460         uc
->uc_mcontext
->__ss
.__r11
, 
 461         uc
->uc_mcontext
->__ss
.__r12
, 
 462         uc
->uc_mcontext
->__ss
.__r13
, 
 463         uc
->uc_mcontext
->__ss
.__r14
, 
 464         uc
->uc_mcontext
->__ss
.__r15
, 
 465         uc
->uc_mcontext
->__ss
.__rip
, 
 466         uc
->uc_mcontext
->__ss
.__rflags
, 
 467         uc
->uc_mcontext
->__ss
.__cs
, 
 468         uc
->uc_mcontext
->__ss
.__fs
, 
 469         uc
->uc_mcontext
->__ss
.__gs
 
 471     logStackContent((void**)uc
->uc_mcontext
->__ss
.__rsp
); 
 473     redisLog(REDIS_WARNING
, 
 475     "EAX:%p EBX:%p ECX:%p EDX:%p\n" 
 476     "EDI:%p ESI:%p EBP:%p ESP:%p\n" 
 477     "SS:%p  EFL:%p EIP:%p CS:%p\n" 
 478     "DS:%p  ES:%p  FS:%p  GS:%p", 
 479         uc
->uc_mcontext
->__ss
.__eax
, 
 480         uc
->uc_mcontext
->__ss
.__ebx
, 
 481         uc
->uc_mcontext
->__ss
.__ecx
, 
 482         uc
->uc_mcontext
->__ss
.__edx
, 
 483         uc
->uc_mcontext
->__ss
.__edi
, 
 484         uc
->uc_mcontext
->__ss
.__esi
, 
 485         uc
->uc_mcontext
->__ss
.__ebp
, 
 486         uc
->uc_mcontext
->__ss
.__esp
, 
 487         uc
->uc_mcontext
->__ss
.__ss
, 
 488         uc
->uc_mcontext
->__ss
.__eflags
, 
 489         uc
->uc_mcontext
->__ss
.__eip
, 
 490         uc
->uc_mcontext
->__ss
.__cs
, 
 491         uc
->uc_mcontext
->__ss
.__ds
, 
 492         uc
->uc_mcontext
->__ss
.__es
, 
 493         uc
->uc_mcontext
->__ss
.__fs
, 
 494         uc
->uc_mcontext
->__ss
.__gs
 
 496     logStackContent((void**)uc
->uc_mcontext
->__ss
.__esp
); 
 498 #elif defined(__i386__) 
 499     return (void*) uc
->uc_mcontext
.gregs
[14]; /* Linux 32 */ 
 500 #elif defined(__X86_64__) || defined(__x86_64__) 
 501     redisLog(REDIS_WARNING
, 
 503     "RAX:%p RBX:%p RCX:%p RDX:%p\n" 
 504     "RDI:%p RSI:%p RBP:%p RSP:%p\n" 
 505     "R8:%p  R9:%p  R10:%p R11:%p\n" 
 506     "R12:%p R13:%p R14:%p R15:%p\n" 
 507     "RIP:%p EFL:%p CSGSFS:%p", 
 508         uc
->uc_mcontext
.gregs
[13], 
 509         uc
->uc_mcontext
.gregs
[11], 
 510         uc
->uc_mcontext
.gregs
[14], 
 511         uc
->uc_mcontext
.gregs
[12], 
 512         uc
->uc_mcontext
.gregs
[8], 
 513         uc
->uc_mcontext
.gregs
[9], 
 514         uc
->uc_mcontext
.gregs
[10], 
 515         uc
->uc_mcontext
.gregs
[15], 
 516         uc
->uc_mcontext
.gregs
[0], 
 517         uc
->uc_mcontext
.gregs
[1], 
 518         uc
->uc_mcontext
.gregs
[2], 
 519         uc
->uc_mcontext
.gregs
[3], 
 520         uc
->uc_mcontext
.gregs
[4], 
 521         uc
->uc_mcontext
.gregs
[5], 
 522         uc
->uc_mcontext
.gregs
[6], 
 523         uc
->uc_mcontext
.gregs
[7], 
 524         uc
->uc_mcontext
.gregs
[16], 
 525         uc
->uc_mcontext
.gregs
[17], 
 526         uc
->uc_mcontext
.gregs
[18] 
 528     logStackContent((void**)uc
->uc_mcontext
.gregs
[15]); 
 530     redisLog(REDIS_WARNING
, 
 531         "  Dumping of registers not supported for this OS/arch"); 
 535 void sigsegvHandler(int sig
, siginfo_t 
*info
, void *secret
) { 
 537     char **messages 
= NULL
; 
 538     int i
, trace_size 
= 0; 
 539     ucontext_t 
*uc 
= (ucontext_t
*) secret
; 
 540     sds infostring
, clients
; 
 541     struct sigaction act
; 
 545     redisLog(REDIS_WARNING
, 
 546         "    Redis %s crashed by signal: %d", REDIS_VERSION
, sig
); 
 547     redisLog(REDIS_WARNING
, 
 548         "    Failed assertion: %s (%s:%d)", server
.assert_failed
, 
 549                         server
.assert_file
, server
.assert_line
); 
 551     /* Generate the stack trace */ 
 552     trace_size 
= backtrace(trace
, 100); 
 554     /* overwrite sigaction with caller's address */ 
 555     if (getMcontextEip(uc
) != NULL
) { 
 556         trace
[1] = getMcontextEip(uc
); 
 558     messages 
= backtrace_symbols(trace
, trace_size
); 
 559     redisLog(REDIS_WARNING
, "--- STACK TRACE"); 
 560     for (i
=1; i
<trace_size
; ++i
) 
 561         redisLog(REDIS_WARNING
,"%s", messages
[i
]); 
 563     /* Log INFO and CLIENT LIST */ 
 564     redisLog(REDIS_WARNING
, "--- INFO OUTPUT"); 
 565     infostring 
= genRedisInfoString("all"); 
 566     redisLogRaw(REDIS_WARNING
, infostring
); 
 567     redisLog(REDIS_WARNING
, "--- CLIENT LIST OUTPUT"); 
 568     clients 
= getAllClientsInfoString(); 
 569     redisLogRaw(REDIS_WARNING
, clients
); 
 570     /* Don't sdsfree() strings to avoid a crash. Memory may be corrupted. */ 
 572     /* Log CURRENT CLIENT info */ 
 573     if (server
.current_client
) { 
 574         redisClient 
*cc 
= server
.current_client
; 
 578         redisLog(REDIS_WARNING
, "--- CURRENT CLIENT INFO"); 
 579         client 
= getClientInfoString(cc
); 
 580         redisLog(REDIS_WARNING
,"client: %s", client
); 
 581         /* Missing sdsfree(client) to avoid crash if memory is corrupted. */ 
 582         for (j 
= 0; j 
< cc
->argc
; j
++) { 
 585             decoded 
= getDecodedObject(cc
->argv
[j
]); 
 586             redisLog(REDIS_WARNING
,"argv[%d]: '%s'", j
, (char*)decoded
->ptr
); 
 587             decrRefCount(decoded
); 
 589         /* Check if the first argument, usually a key, is found inside the 
 590          * selected DB, and if so print info about the associated object. */ 
 595             key 
= getDecodedObject(cc
->argv
[1]); 
 596             de 
= dictFind(cc
->db
->dict
, key
->ptr
); 
 598                 val 
= dictGetVal(de
); 
 599                 redisLog(REDIS_WARNING
,"key '%s' found in DB containing the following object:", key
->ptr
); 
 600                 redisLogObjectDebugInfo(val
); 
 606     /* Log dump of processor registers */ 
 609     redisLog(REDIS_WARNING
, 
 610 "\n=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n" 
 611 "    Please report the crash opening an issue on github:\n\n" 
 612 "        http://github.com/antirez/redis/issues\n\n" 
 614     /* free(messages); Don't call free() with possibly corrupted memory. */ 
 615     if (server
.daemonize
) unlink(server
.pidfile
); 
 617     /* Make sure we exit with the right signal at the end. So for instance 
 618      * the core will be dumped if enabled. */ 
 619     sigemptyset (&act
.sa_mask
); 
 620     /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction 
 621      * is used. Otherwise, sa_handler is used */ 
 622     act
.sa_flags 
= SA_NODEFER 
| SA_ONSTACK 
| SA_RESETHAND
; 
 623     act
.sa_handler 
= SIG_DFL
; 
 624     sigaction (sig
, &act
, NULL
); 
 627 #endif /* HAVE_BACKTRACE */