xref: /f-stack/app/redis-5.0.5/src/debug.c (revision 572c4311)
1*572c4311Sfengbojiang /*
2*572c4311Sfengbojiang  * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
3*572c4311Sfengbojiang  * All rights reserved.
4*572c4311Sfengbojiang  *
5*572c4311Sfengbojiang  * Redistribution and use in source and binary forms, with or without
6*572c4311Sfengbojiang  * modification, are permitted provided that the following conditions are met:
7*572c4311Sfengbojiang  *
8*572c4311Sfengbojiang  *   * Redistributions of source code must retain the above copyright notice,
9*572c4311Sfengbojiang  *     this list of conditions and the following disclaimer.
10*572c4311Sfengbojiang  *   * Redistributions in binary form must reproduce the above copyright
11*572c4311Sfengbojiang  *     notice, this list of conditions and the following disclaimer in the
12*572c4311Sfengbojiang  *     documentation and/or other materials provided with the distribution.
13*572c4311Sfengbojiang  *   * Neither the name of Redis nor the names of its contributors may be used
14*572c4311Sfengbojiang  *     to endorse or promote products derived from this software without
15*572c4311Sfengbojiang  *     specific prior written permission.
16*572c4311Sfengbojiang  *
17*572c4311Sfengbojiang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*572c4311Sfengbojiang  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*572c4311Sfengbojiang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*572c4311Sfengbojiang  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21*572c4311Sfengbojiang  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*572c4311Sfengbojiang  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*572c4311Sfengbojiang  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*572c4311Sfengbojiang  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*572c4311Sfengbojiang  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*572c4311Sfengbojiang  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*572c4311Sfengbojiang  * POSSIBILITY OF SUCH DAMAGE.
28*572c4311Sfengbojiang  */
29*572c4311Sfengbojiang 
30*572c4311Sfengbojiang #include "server.h"
31*572c4311Sfengbojiang #include "sha1.h"   /* SHA1 is used for DEBUG DIGEST */
32*572c4311Sfengbojiang #include "crc64.h"
33*572c4311Sfengbojiang 
34*572c4311Sfengbojiang #include <arpa/inet.h>
35*572c4311Sfengbojiang #include <signal.h>
36*572c4311Sfengbojiang #include <dlfcn.h>
37*572c4311Sfengbojiang 
38*572c4311Sfengbojiang #ifdef HAVE_BACKTRACE
39*572c4311Sfengbojiang #include <execinfo.h>
40*572c4311Sfengbojiang #ifndef __OpenBSD__
41*572c4311Sfengbojiang #include <ucontext.h>
42*572c4311Sfengbojiang #else
43*572c4311Sfengbojiang typedef ucontext_t sigcontext_t;
44*572c4311Sfengbojiang #endif
45*572c4311Sfengbojiang #include <fcntl.h>
46*572c4311Sfengbojiang #include "bio.h"
47*572c4311Sfengbojiang #include <unistd.h>
48*572c4311Sfengbojiang #endif /* HAVE_BACKTRACE */
49*572c4311Sfengbojiang 
50*572c4311Sfengbojiang #ifdef __CYGWIN__
51*572c4311Sfengbojiang #ifndef SA_ONSTACK
52*572c4311Sfengbojiang #define SA_ONSTACK 0x08000000
53*572c4311Sfengbojiang #endif
54*572c4311Sfengbojiang #endif
55*572c4311Sfengbojiang 
56*572c4311Sfengbojiang /* ================================= Debugging ============================== */
57*572c4311Sfengbojiang 
58*572c4311Sfengbojiang /* Compute the sha1 of string at 's' with 'len' bytes long.
59*572c4311Sfengbojiang  * The SHA1 is then xored against the string pointed by digest.
60*572c4311Sfengbojiang  * Since xor is commutative, this operation is used in order to
61*572c4311Sfengbojiang  * "add" digests relative to unordered elements.
62*572c4311Sfengbojiang  *
63*572c4311Sfengbojiang  * So digest(a,b,c,d) will be the same of digest(b,a,c,d) */
xorDigest(unsigned char * digest,void * ptr,size_t len)64*572c4311Sfengbojiang void xorDigest(unsigned char *digest, void *ptr, size_t len) {
65*572c4311Sfengbojiang     SHA1_CTX ctx;
66*572c4311Sfengbojiang     unsigned char hash[20], *s = ptr;
67*572c4311Sfengbojiang     int j;
68*572c4311Sfengbojiang 
69*572c4311Sfengbojiang     SHA1Init(&ctx);
70*572c4311Sfengbojiang     SHA1Update(&ctx,s,len);
71*572c4311Sfengbojiang     SHA1Final(hash,&ctx);
72*572c4311Sfengbojiang 
73*572c4311Sfengbojiang     for (j = 0; j < 20; j++)
74*572c4311Sfengbojiang         digest[j] ^= hash[j];
75*572c4311Sfengbojiang }
76*572c4311Sfengbojiang 
xorStringObjectDigest(unsigned char * digest,robj * o)77*572c4311Sfengbojiang void xorStringObjectDigest(unsigned char *digest, robj *o) {
78*572c4311Sfengbojiang     o = getDecodedObject(o);
79*572c4311Sfengbojiang     xorDigest(digest,o->ptr,sdslen(o->ptr));
80*572c4311Sfengbojiang     decrRefCount(o);
81*572c4311Sfengbojiang }
82*572c4311Sfengbojiang 
83*572c4311Sfengbojiang /* This function instead of just computing the SHA1 and xoring it
84*572c4311Sfengbojiang  * against digest, also perform the digest of "digest" itself and
85*572c4311Sfengbojiang  * replace the old value with the new one.
86*572c4311Sfengbojiang  *
87*572c4311Sfengbojiang  * So the final digest will be:
88*572c4311Sfengbojiang  *
89*572c4311Sfengbojiang  * digest = SHA1(digest xor SHA1(data))
90*572c4311Sfengbojiang  *
91*572c4311Sfengbojiang  * This function is used every time we want to preserve the order so
92*572c4311Sfengbojiang  * that digest(a,b,c,d) will be different than digest(b,c,d,a)
93*572c4311Sfengbojiang  *
94*572c4311Sfengbojiang  * Also note that mixdigest("foo") followed by mixdigest("bar")
95*572c4311Sfengbojiang  * will lead to a different digest compared to "fo", "obar".
96*572c4311Sfengbojiang  */
mixDigest(unsigned char * digest,void * ptr,size_t len)97*572c4311Sfengbojiang void mixDigest(unsigned char *digest, void *ptr, size_t len) {
98*572c4311Sfengbojiang     SHA1_CTX ctx;
99*572c4311Sfengbojiang     char *s = ptr;
100*572c4311Sfengbojiang 
101*572c4311Sfengbojiang     xorDigest(digest,s,len);
102*572c4311Sfengbojiang     SHA1Init(&ctx);
103*572c4311Sfengbojiang     SHA1Update(&ctx,digest,20);
104*572c4311Sfengbojiang     SHA1Final(digest,&ctx);
105*572c4311Sfengbojiang }
106*572c4311Sfengbojiang 
mixStringObjectDigest(unsigned char * digest,robj * o)107*572c4311Sfengbojiang void mixStringObjectDigest(unsigned char *digest, robj *o) {
108*572c4311Sfengbojiang     o = getDecodedObject(o);
109*572c4311Sfengbojiang     mixDigest(digest,o->ptr,sdslen(o->ptr));
110*572c4311Sfengbojiang     decrRefCount(o);
111*572c4311Sfengbojiang }
112*572c4311Sfengbojiang 
113*572c4311Sfengbojiang /* This function computes the digest of a data structure stored in the
114*572c4311Sfengbojiang  * object 'o'. It is the core of the DEBUG DIGEST command: when taking the
115*572c4311Sfengbojiang  * digest of a whole dataset, we take the digest of the key and the value
116*572c4311Sfengbojiang  * pair, and xor all those together.
117*572c4311Sfengbojiang  *
118*572c4311Sfengbojiang  * Note that this function does not reset the initial 'digest' passed, it
119*572c4311Sfengbojiang  * will continue mixing this object digest to anything that was already
120*572c4311Sfengbojiang  * present. */
xorObjectDigest(redisDb * db,robj * keyobj,unsigned char * digest,robj * o)121*572c4311Sfengbojiang void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o) {
122*572c4311Sfengbojiang     uint32_t aux = htonl(o->type);
123*572c4311Sfengbojiang     mixDigest(digest,&aux,sizeof(aux));
124*572c4311Sfengbojiang     long long expiretime = getExpire(db,keyobj);
125*572c4311Sfengbojiang     char buf[128];
126*572c4311Sfengbojiang 
127*572c4311Sfengbojiang     /* Save the key and associated value */
128*572c4311Sfengbojiang     if (o->type == OBJ_STRING) {
129*572c4311Sfengbojiang         mixStringObjectDigest(digest,o);
130*572c4311Sfengbojiang     } else if (o->type == OBJ_LIST) {
131*572c4311Sfengbojiang         listTypeIterator *li = listTypeInitIterator(o,0,LIST_TAIL);
132*572c4311Sfengbojiang         listTypeEntry entry;
133*572c4311Sfengbojiang         while(listTypeNext(li,&entry)) {
134*572c4311Sfengbojiang             robj *eleobj = listTypeGet(&entry);
135*572c4311Sfengbojiang             mixStringObjectDigest(digest,eleobj);
136*572c4311Sfengbojiang             decrRefCount(eleobj);
137*572c4311Sfengbojiang         }
138*572c4311Sfengbojiang         listTypeReleaseIterator(li);
139*572c4311Sfengbojiang     } else if (o->type == OBJ_SET) {
140*572c4311Sfengbojiang         setTypeIterator *si = setTypeInitIterator(o);
141*572c4311Sfengbojiang         sds sdsele;
142*572c4311Sfengbojiang         while((sdsele = setTypeNextObject(si)) != NULL) {
143*572c4311Sfengbojiang             xorDigest(digest,sdsele,sdslen(sdsele));
144*572c4311Sfengbojiang             sdsfree(sdsele);
145*572c4311Sfengbojiang         }
146*572c4311Sfengbojiang         setTypeReleaseIterator(si);
147*572c4311Sfengbojiang     } else if (o->type == OBJ_ZSET) {
148*572c4311Sfengbojiang         unsigned char eledigest[20];
149*572c4311Sfengbojiang 
150*572c4311Sfengbojiang         if (o->encoding == OBJ_ENCODING_ZIPLIST) {
151*572c4311Sfengbojiang             unsigned char *zl = o->ptr;
152*572c4311Sfengbojiang             unsigned char *eptr, *sptr;
153*572c4311Sfengbojiang             unsigned char *vstr;
154*572c4311Sfengbojiang             unsigned int vlen;
155*572c4311Sfengbojiang             long long vll;
156*572c4311Sfengbojiang             double score;
157*572c4311Sfengbojiang 
158*572c4311Sfengbojiang             eptr = ziplistIndex(zl,0);
159*572c4311Sfengbojiang             serverAssert(eptr != NULL);
160*572c4311Sfengbojiang             sptr = ziplistNext(zl,eptr);
161*572c4311Sfengbojiang             serverAssert(sptr != NULL);
162*572c4311Sfengbojiang 
163*572c4311Sfengbojiang             while (eptr != NULL) {
164*572c4311Sfengbojiang                 serverAssert(ziplistGet(eptr,&vstr,&vlen,&vll));
165*572c4311Sfengbojiang                 score = zzlGetScore(sptr);
166*572c4311Sfengbojiang 
167*572c4311Sfengbojiang                 memset(eledigest,0,20);
168*572c4311Sfengbojiang                 if (vstr != NULL) {
169*572c4311Sfengbojiang                     mixDigest(eledigest,vstr,vlen);
170*572c4311Sfengbojiang                 } else {
171*572c4311Sfengbojiang                     ll2string(buf,sizeof(buf),vll);
172*572c4311Sfengbojiang                     mixDigest(eledigest,buf,strlen(buf));
173*572c4311Sfengbojiang                 }
174*572c4311Sfengbojiang 
175*572c4311Sfengbojiang                 snprintf(buf,sizeof(buf),"%.17g",score);
176*572c4311Sfengbojiang                 mixDigest(eledigest,buf,strlen(buf));
177*572c4311Sfengbojiang                 xorDigest(digest,eledigest,20);
178*572c4311Sfengbojiang                 zzlNext(zl,&eptr,&sptr);
179*572c4311Sfengbojiang             }
180*572c4311Sfengbojiang         } else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
181*572c4311Sfengbojiang             zset *zs = o->ptr;
182*572c4311Sfengbojiang             dictIterator *di = dictGetIterator(zs->dict);
183*572c4311Sfengbojiang             dictEntry *de;
184*572c4311Sfengbojiang 
185*572c4311Sfengbojiang             while((de = dictNext(di)) != NULL) {
186*572c4311Sfengbojiang                 sds sdsele = dictGetKey(de);
187*572c4311Sfengbojiang                 double *score = dictGetVal(de);
188*572c4311Sfengbojiang 
189*572c4311Sfengbojiang                 snprintf(buf,sizeof(buf),"%.17g",*score);
190*572c4311Sfengbojiang                 memset(eledigest,0,20);
191*572c4311Sfengbojiang                 mixDigest(eledigest,sdsele,sdslen(sdsele));
192*572c4311Sfengbojiang                 mixDigest(eledigest,buf,strlen(buf));
193*572c4311Sfengbojiang                 xorDigest(digest,eledigest,20);
194*572c4311Sfengbojiang             }
195*572c4311Sfengbojiang             dictReleaseIterator(di);
196*572c4311Sfengbojiang         } else {
197*572c4311Sfengbojiang             serverPanic("Unknown sorted set encoding");
198*572c4311Sfengbojiang         }
199*572c4311Sfengbojiang     } else if (o->type == OBJ_HASH) {
200*572c4311Sfengbojiang         hashTypeIterator *hi = hashTypeInitIterator(o);
201*572c4311Sfengbojiang         while (hashTypeNext(hi) != C_ERR) {
202*572c4311Sfengbojiang             unsigned char eledigest[20];
203*572c4311Sfengbojiang             sds sdsele;
204*572c4311Sfengbojiang 
205*572c4311Sfengbojiang             memset(eledigest,0,20);
206*572c4311Sfengbojiang             sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY);
207*572c4311Sfengbojiang             mixDigest(eledigest,sdsele,sdslen(sdsele));
208*572c4311Sfengbojiang             sdsfree(sdsele);
209*572c4311Sfengbojiang             sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE);
210*572c4311Sfengbojiang             mixDigest(eledigest,sdsele,sdslen(sdsele));
211*572c4311Sfengbojiang             sdsfree(sdsele);
212*572c4311Sfengbojiang             xorDigest(digest,eledigest,20);
213*572c4311Sfengbojiang         }
214*572c4311Sfengbojiang         hashTypeReleaseIterator(hi);
215*572c4311Sfengbojiang     } else if (o->type == OBJ_STREAM) {
216*572c4311Sfengbojiang         streamIterator si;
217*572c4311Sfengbojiang         streamIteratorStart(&si,o->ptr,NULL,NULL,0);
218*572c4311Sfengbojiang         streamID id;
219*572c4311Sfengbojiang         int64_t numfields;
220*572c4311Sfengbojiang 
221*572c4311Sfengbojiang         while(streamIteratorGetID(&si,&id,&numfields)) {
222*572c4311Sfengbojiang             sds itemid = sdscatfmt(sdsempty(),"%U.%U",id.ms,id.seq);
223*572c4311Sfengbojiang             mixDigest(digest,itemid,sdslen(itemid));
224*572c4311Sfengbojiang             sdsfree(itemid);
225*572c4311Sfengbojiang 
226*572c4311Sfengbojiang             while(numfields--) {
227*572c4311Sfengbojiang                 unsigned char *field, *value;
228*572c4311Sfengbojiang                 int64_t field_len, value_len;
229*572c4311Sfengbojiang                 streamIteratorGetField(&si,&field,&value,
230*572c4311Sfengbojiang                                            &field_len,&value_len);
231*572c4311Sfengbojiang                 mixDigest(digest,field,field_len);
232*572c4311Sfengbojiang                 mixDigest(digest,value,value_len);
233*572c4311Sfengbojiang             }
234*572c4311Sfengbojiang         }
235*572c4311Sfengbojiang         streamIteratorStop(&si);
236*572c4311Sfengbojiang     } else if (o->type == OBJ_MODULE) {
237*572c4311Sfengbojiang         RedisModuleDigest md;
238*572c4311Sfengbojiang         moduleValue *mv = o->ptr;
239*572c4311Sfengbojiang         moduleType *mt = mv->type;
240*572c4311Sfengbojiang         moduleInitDigestContext(md);
241*572c4311Sfengbojiang         if (mt->digest) {
242*572c4311Sfengbojiang             mt->digest(&md,mv->value);
243*572c4311Sfengbojiang             xorDigest(digest,md.x,sizeof(md.x));
244*572c4311Sfengbojiang         }
245*572c4311Sfengbojiang     } else {
246*572c4311Sfengbojiang         serverPanic("Unknown object type");
247*572c4311Sfengbojiang     }
248*572c4311Sfengbojiang     /* If the key has an expire, add it to the mix */
249*572c4311Sfengbojiang     if (expiretime != -1) xorDigest(digest,"!!expire!!",10);
250*572c4311Sfengbojiang }
251*572c4311Sfengbojiang 
252*572c4311Sfengbojiang /* Compute the dataset digest. Since keys, sets elements, hashes elements
253*572c4311Sfengbojiang  * are not ordered, we use a trick: every aggregate digest is the xor
254*572c4311Sfengbojiang  * of the digests of their elements. This way the order will not change
255*572c4311Sfengbojiang  * the result. For list instead we use a feedback entering the output digest
256*572c4311Sfengbojiang  * as input in order to ensure that a different ordered list will result in
257*572c4311Sfengbojiang  * a different digest. */
computeDatasetDigest(unsigned char * final)258*572c4311Sfengbojiang void computeDatasetDigest(unsigned char *final) {
259*572c4311Sfengbojiang     unsigned char digest[20];
260*572c4311Sfengbojiang     dictIterator *di = NULL;
261*572c4311Sfengbojiang     dictEntry *de;
262*572c4311Sfengbojiang     int j;
263*572c4311Sfengbojiang     uint32_t aux;
264*572c4311Sfengbojiang 
265*572c4311Sfengbojiang     memset(final,0,20); /* Start with a clean result */
266*572c4311Sfengbojiang 
267*572c4311Sfengbojiang     for (j = 0; j < server.dbnum; j++) {
268*572c4311Sfengbojiang         redisDb *db = server.db+j;
269*572c4311Sfengbojiang 
270*572c4311Sfengbojiang         if (dictSize(db->dict) == 0) continue;
271*572c4311Sfengbojiang         di = dictGetSafeIterator(db->dict);
272*572c4311Sfengbojiang 
273*572c4311Sfengbojiang         /* hash the DB id, so the same dataset moved in a different
274*572c4311Sfengbojiang          * DB will lead to a different digest */
275*572c4311Sfengbojiang         aux = htonl(j);
276*572c4311Sfengbojiang         mixDigest(final,&aux,sizeof(aux));
277*572c4311Sfengbojiang 
278*572c4311Sfengbojiang         /* Iterate this DB writing every entry */
279*572c4311Sfengbojiang         while((de = dictNext(di)) != NULL) {
280*572c4311Sfengbojiang             sds key;
281*572c4311Sfengbojiang             robj *keyobj, *o;
282*572c4311Sfengbojiang 
283*572c4311Sfengbojiang             memset(digest,0,20); /* This key-val digest */
284*572c4311Sfengbojiang             key = dictGetKey(de);
285*572c4311Sfengbojiang             keyobj = createStringObject(key,sdslen(key));
286*572c4311Sfengbojiang 
287*572c4311Sfengbojiang             mixDigest(digest,key,sdslen(key));
288*572c4311Sfengbojiang 
289*572c4311Sfengbojiang             o = dictGetVal(de);
290*572c4311Sfengbojiang             xorObjectDigest(db,keyobj,digest,o);
291*572c4311Sfengbojiang 
292*572c4311Sfengbojiang             /* We can finally xor the key-val digest to the final digest */
293*572c4311Sfengbojiang             xorDigest(final,digest,20);
294*572c4311Sfengbojiang             decrRefCount(keyobj);
295*572c4311Sfengbojiang         }
296*572c4311Sfengbojiang         dictReleaseIterator(di);
297*572c4311Sfengbojiang     }
298*572c4311Sfengbojiang }
299*572c4311Sfengbojiang 
debugCommand(client * c)300*572c4311Sfengbojiang void debugCommand(client *c) {
301*572c4311Sfengbojiang     if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) {
302*572c4311Sfengbojiang         const char *help[] = {
303*572c4311Sfengbojiang "ASSERT -- Crash by assertion failed.",
304*572c4311Sfengbojiang "CHANGE-REPL-ID -- Change the replication IDs of the instance. Dangerous, should be used only for testing the replication subsystem.",
305*572c4311Sfengbojiang "CRASH-AND-RECOVER <milliseconds> -- Hard crash and restart after <milliseconds> delay.",
306*572c4311Sfengbojiang "DIGEST -- Output a hex signature representing the current DB content.",
307*572c4311Sfengbojiang "DIGEST-VALUE <key-1> ... <key-N>-- Output a hex signature of the values of all the specified keys.",
308*572c4311Sfengbojiang "ERROR <string> -- Return a Redis protocol error with <string> as message. Useful for clients unit tests to simulate Redis errors.",
309*572c4311Sfengbojiang "LOG <message> -- write message to the server log.",
310*572c4311Sfengbojiang "HTSTATS <dbid> -- Return hash table statistics of the specified Redis database.",
311*572c4311Sfengbojiang "HTSTATS-KEY <key> -- Like htstats but for the hash table stored as key's value.",
312*572c4311Sfengbojiang "LOADAOF -- Flush the AOF buffers on disk and reload the AOF in memory.",
313*572c4311Sfengbojiang "LUA-ALWAYS-REPLICATE-COMMANDS <0|1> -- Setting it to 1 makes Lua replication defaulting to replicating single commands, without the script having to enable effects replication.",
314*572c4311Sfengbojiang "OBJECT <key> -- Show low level info about key and associated value.",
315*572c4311Sfengbojiang "PANIC -- Crash the server simulating a panic.",
316*572c4311Sfengbojiang "POPULATE <count> [prefix] [size] -- Create <count> string keys named key:<num>. If a prefix is specified is used instead of the 'key' prefix.",
317*572c4311Sfengbojiang "RELOAD -- Save the RDB on disk and reload it back in memory.",
318*572c4311Sfengbojiang "RESTART -- Graceful restart: save config, db, restart.",
319*572c4311Sfengbojiang "SDSLEN <key> -- Show low level SDS string info representing key and value.",
320*572c4311Sfengbojiang "SEGFAULT -- Crash the server with sigsegv.",
321*572c4311Sfengbojiang "SET-ACTIVE-EXPIRE <0|1> -- Setting it to 0 disables expiring keys in background when they are not accessed (otherwise the Redis behavior). Setting it to 1 reenables back the default.",
322*572c4311Sfengbojiang "SLEEP <seconds> -- Stop the server for <seconds>. Decimals allowed.",
323*572c4311Sfengbojiang "STRUCTSIZE -- Return the size of different Redis core C structures.",
324*572c4311Sfengbojiang "ZIPLIST <key> -- Show low level info about the ziplist encoding.",
325*572c4311Sfengbojiang "STRINGMATCH-TEST -- Run a fuzz tester against the stringmatchlen() function.",
326*572c4311Sfengbojiang NULL
327*572c4311Sfengbojiang         };
328*572c4311Sfengbojiang         addReplyHelp(c, help);
329*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
330*572c4311Sfengbojiang         *((char*)-1) = 'x';
331*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"panic")) {
332*572c4311Sfengbojiang         serverPanic("DEBUG PANIC called at Unix time %ld", time(NULL));
333*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"restart") ||
334*572c4311Sfengbojiang                !strcasecmp(c->argv[1]->ptr,"crash-and-recover"))
335*572c4311Sfengbojiang     {
336*572c4311Sfengbojiang         long long delay = 0;
337*572c4311Sfengbojiang         if (c->argc >= 3) {
338*572c4311Sfengbojiang             if (getLongLongFromObjectOrReply(c, c->argv[2], &delay, NULL)
339*572c4311Sfengbojiang                 != C_OK) return;
340*572c4311Sfengbojiang             if (delay < 0) delay = 0;
341*572c4311Sfengbojiang         }
342*572c4311Sfengbojiang         int flags = !strcasecmp(c->argv[1]->ptr,"restart") ?
343*572c4311Sfengbojiang             (RESTART_SERVER_GRACEFULLY|RESTART_SERVER_CONFIG_REWRITE) :
344*572c4311Sfengbojiang              RESTART_SERVER_NONE;
345*572c4311Sfengbojiang         restartServer(flags,delay);
346*572c4311Sfengbojiang         addReplyError(c,"failed to restart the server. Check server logs.");
347*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"oom")) {
348*572c4311Sfengbojiang         void *ptr = zmalloc(ULONG_MAX); /* Should trigger an out of memory. */
349*572c4311Sfengbojiang         zfree(ptr);
350*572c4311Sfengbojiang         addReply(c,shared.ok);
351*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"assert")) {
352*572c4311Sfengbojiang         serverAssertWithInfo(c,c->argv[0],1 == 2);
353*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"log") && c->argc == 3) {
354*572c4311Sfengbojiang         serverLog(LL_WARNING, "DEBUG LOG: %s", (char*)c->argv[2]->ptr);
355*572c4311Sfengbojiang         addReply(c,shared.ok);
356*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
357*572c4311Sfengbojiang         rdbSaveInfo rsi, *rsiptr;
358*572c4311Sfengbojiang         rsiptr = rdbPopulateSaveInfo(&rsi);
359*572c4311Sfengbojiang         if (rdbSave(server.rdb_filename,rsiptr) != C_OK) {
360*572c4311Sfengbojiang             addReply(c,shared.err);
361*572c4311Sfengbojiang             return;
362*572c4311Sfengbojiang         }
363*572c4311Sfengbojiang         emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
364*572c4311Sfengbojiang         protectClient(c);
365*572c4311Sfengbojiang         int ret = rdbLoad(server.rdb_filename,NULL);
366*572c4311Sfengbojiang         unprotectClient(c);
367*572c4311Sfengbojiang         if (ret != C_OK) {
368*572c4311Sfengbojiang             addReplyError(c,"Error trying to load the RDB dump");
369*572c4311Sfengbojiang             return;
370*572c4311Sfengbojiang         }
371*572c4311Sfengbojiang         serverLog(LL_WARNING,"DB reloaded by DEBUG RELOAD");
372*572c4311Sfengbojiang         addReply(c,shared.ok);
373*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) {
374*572c4311Sfengbojiang         if (server.aof_state != AOF_OFF) flushAppendOnlyFile(1);
375*572c4311Sfengbojiang         emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
376*572c4311Sfengbojiang         protectClient(c);
377*572c4311Sfengbojiang         int ret = loadAppendOnlyFile(server.aof_filename);
378*572c4311Sfengbojiang         unprotectClient(c);
379*572c4311Sfengbojiang         if (ret != C_OK) {
380*572c4311Sfengbojiang             addReply(c,shared.err);
381*572c4311Sfengbojiang             return;
382*572c4311Sfengbojiang         }
383*572c4311Sfengbojiang         server.dirty = 0; /* Prevent AOF / replication */
384*572c4311Sfengbojiang         serverLog(LL_WARNING,"Append Only File loaded by DEBUG LOADAOF");
385*572c4311Sfengbojiang         addReply(c,shared.ok);
386*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
387*572c4311Sfengbojiang         dictEntry *de;
388*572c4311Sfengbojiang         robj *val;
389*572c4311Sfengbojiang         char *strenc;
390*572c4311Sfengbojiang 
391*572c4311Sfengbojiang         if ((de = dictFind(c->db->dict,c->argv[2]->ptr)) == NULL) {
392*572c4311Sfengbojiang             addReply(c,shared.nokeyerr);
393*572c4311Sfengbojiang             return;
394*572c4311Sfengbojiang         }
395*572c4311Sfengbojiang         val = dictGetVal(de);
396*572c4311Sfengbojiang         strenc = strEncoding(val->encoding);
397*572c4311Sfengbojiang 
398*572c4311Sfengbojiang         char extra[138] = {0};
399*572c4311Sfengbojiang         if (val->encoding == OBJ_ENCODING_QUICKLIST) {
400*572c4311Sfengbojiang             char *nextra = extra;
401*572c4311Sfengbojiang             int remaining = sizeof(extra);
402*572c4311Sfengbojiang             quicklist *ql = val->ptr;
403*572c4311Sfengbojiang             /* Add number of quicklist nodes */
404*572c4311Sfengbojiang             int used = snprintf(nextra, remaining, " ql_nodes:%lu", ql->len);
405*572c4311Sfengbojiang             nextra += used;
406*572c4311Sfengbojiang             remaining -= used;
407*572c4311Sfengbojiang             /* Add average quicklist fill factor */
408*572c4311Sfengbojiang             double avg = (double)ql->count/ql->len;
409*572c4311Sfengbojiang             used = snprintf(nextra, remaining, " ql_avg_node:%.2f", avg);
410*572c4311Sfengbojiang             nextra += used;
411*572c4311Sfengbojiang             remaining -= used;
412*572c4311Sfengbojiang             /* Add quicklist fill level / max ziplist size */
413*572c4311Sfengbojiang             used = snprintf(nextra, remaining, " ql_ziplist_max:%d", ql->fill);
414*572c4311Sfengbojiang             nextra += used;
415*572c4311Sfengbojiang             remaining -= used;
416*572c4311Sfengbojiang             /* Add isCompressed? */
417*572c4311Sfengbojiang             int compressed = ql->compress != 0;
418*572c4311Sfengbojiang             used = snprintf(nextra, remaining, " ql_compressed:%d", compressed);
419*572c4311Sfengbojiang             nextra += used;
420*572c4311Sfengbojiang             remaining -= used;
421*572c4311Sfengbojiang             /* Add total uncompressed size */
422*572c4311Sfengbojiang             unsigned long sz = 0;
423*572c4311Sfengbojiang             for (quicklistNode *node = ql->head; node; node = node->next) {
424*572c4311Sfengbojiang                 sz += node->sz;
425*572c4311Sfengbojiang             }
426*572c4311Sfengbojiang             used = snprintf(nextra, remaining, " ql_uncompressed_size:%lu", sz);
427*572c4311Sfengbojiang             nextra += used;
428*572c4311Sfengbojiang             remaining -= used;
429*572c4311Sfengbojiang         }
430*572c4311Sfengbojiang 
431*572c4311Sfengbojiang         addReplyStatusFormat(c,
432*572c4311Sfengbojiang             "Value at:%p refcount:%d "
433*572c4311Sfengbojiang             "encoding:%s serializedlength:%zu "
434*572c4311Sfengbojiang             "lru:%d lru_seconds_idle:%llu%s",
435*572c4311Sfengbojiang             (void*)val, val->refcount,
436*572c4311Sfengbojiang             strenc, rdbSavedObjectLen(val),
437*572c4311Sfengbojiang             val->lru, estimateObjectIdleTime(val)/1000, extra);
438*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"sdslen") && c->argc == 3) {
439*572c4311Sfengbojiang         dictEntry *de;
440*572c4311Sfengbojiang         robj *val;
441*572c4311Sfengbojiang         sds key;
442*572c4311Sfengbojiang 
443*572c4311Sfengbojiang         if ((de = dictFind(c->db->dict,c->argv[2]->ptr)) == NULL) {
444*572c4311Sfengbojiang             addReply(c,shared.nokeyerr);
445*572c4311Sfengbojiang             return;
446*572c4311Sfengbojiang         }
447*572c4311Sfengbojiang         val = dictGetVal(de);
448*572c4311Sfengbojiang         key = dictGetKey(de);
449*572c4311Sfengbojiang 
450*572c4311Sfengbojiang         if (val->type != OBJ_STRING || !sdsEncodedObject(val)) {
451*572c4311Sfengbojiang             addReplyError(c,"Not an sds encoded string.");
452*572c4311Sfengbojiang         } else {
453*572c4311Sfengbojiang             addReplyStatusFormat(c,
454*572c4311Sfengbojiang                 "key_sds_len:%lld, key_sds_avail:%lld, key_zmalloc: %lld, "
455*572c4311Sfengbojiang                 "val_sds_len:%lld, val_sds_avail:%lld, val_zmalloc: %lld",
456*572c4311Sfengbojiang                 (long long) sdslen(key),
457*572c4311Sfengbojiang                 (long long) sdsavail(key),
458*572c4311Sfengbojiang                 (long long) sdsZmallocSize(key),
459*572c4311Sfengbojiang                 (long long) sdslen(val->ptr),
460*572c4311Sfengbojiang                 (long long) sdsavail(val->ptr),
461*572c4311Sfengbojiang                 (long long) getStringObjectSdsUsedMemory(val));
462*572c4311Sfengbojiang         }
463*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"ziplist") && c->argc == 3) {
464*572c4311Sfengbojiang         robj *o;
465*572c4311Sfengbojiang 
466*572c4311Sfengbojiang         if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nokeyerr))
467*572c4311Sfengbojiang                 == NULL) return;
468*572c4311Sfengbojiang 
469*572c4311Sfengbojiang         if (o->encoding != OBJ_ENCODING_ZIPLIST) {
470*572c4311Sfengbojiang             addReplyError(c,"Not an sds encoded string.");
471*572c4311Sfengbojiang         } else {
472*572c4311Sfengbojiang             ziplistRepr(o->ptr);
473*572c4311Sfengbojiang             addReplyStatus(c,"Ziplist structure printed on stdout");
474*572c4311Sfengbojiang         }
475*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"populate") &&
476*572c4311Sfengbojiang                c->argc >= 3 && c->argc <= 5) {
477*572c4311Sfengbojiang         long keys, j;
478*572c4311Sfengbojiang         robj *key, *val;
479*572c4311Sfengbojiang         char buf[128];
480*572c4311Sfengbojiang 
481*572c4311Sfengbojiang         if (getLongFromObjectOrReply(c, c->argv[2], &keys, NULL) != C_OK)
482*572c4311Sfengbojiang             return;
483*572c4311Sfengbojiang         dictExpand(c->db->dict,keys);
484*572c4311Sfengbojiang         for (j = 0; j < keys; j++) {
485*572c4311Sfengbojiang             long valsize = 0;
486*572c4311Sfengbojiang             snprintf(buf,sizeof(buf),"%s:%lu",
487*572c4311Sfengbojiang                 (c->argc == 3) ? "key" : (char*)c->argv[3]->ptr, j);
488*572c4311Sfengbojiang             key = createStringObject(buf,strlen(buf));
489*572c4311Sfengbojiang             if (c->argc == 5)
490*572c4311Sfengbojiang                 if (getLongFromObjectOrReply(c, c->argv[4], &valsize, NULL) != C_OK)
491*572c4311Sfengbojiang                     return;
492*572c4311Sfengbojiang             if (lookupKeyWrite(c->db,key) != NULL) {
493*572c4311Sfengbojiang                 decrRefCount(key);
494*572c4311Sfengbojiang                 continue;
495*572c4311Sfengbojiang             }
496*572c4311Sfengbojiang             snprintf(buf,sizeof(buf),"value:%lu",j);
497*572c4311Sfengbojiang             if (valsize==0)
498*572c4311Sfengbojiang                 val = createStringObject(buf,strlen(buf));
499*572c4311Sfengbojiang             else {
500*572c4311Sfengbojiang                 int buflen = strlen(buf);
501*572c4311Sfengbojiang                 val = createStringObject(NULL,valsize);
502*572c4311Sfengbojiang                 memcpy(val->ptr, buf, valsize<=buflen? valsize: buflen);
503*572c4311Sfengbojiang             }
504*572c4311Sfengbojiang             dbAdd(c->db,key,val);
505*572c4311Sfengbojiang             signalModifiedKey(c->db,key);
506*572c4311Sfengbojiang             decrRefCount(key);
507*572c4311Sfengbojiang         }
508*572c4311Sfengbojiang         addReply(c,shared.ok);
509*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"digest") && c->argc == 2) {
510*572c4311Sfengbojiang         /* DEBUG DIGEST (form without keys specified) */
511*572c4311Sfengbojiang         unsigned char digest[20];
512*572c4311Sfengbojiang         sds d = sdsempty();
513*572c4311Sfengbojiang 
514*572c4311Sfengbojiang         computeDatasetDigest(digest);
515*572c4311Sfengbojiang         for (int i = 0; i < 20; i++) d = sdscatprintf(d, "%02x",digest[i]);
516*572c4311Sfengbojiang         addReplyStatus(c,d);
517*572c4311Sfengbojiang         sdsfree(d);
518*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"digest-value") && c->argc >= 2) {
519*572c4311Sfengbojiang         /* DEBUG DIGEST-VALUE key key key ... key. */
520*572c4311Sfengbojiang         addReplyMultiBulkLen(c,c->argc-2);
521*572c4311Sfengbojiang         for (int j = 2; j < c->argc; j++) {
522*572c4311Sfengbojiang             unsigned char digest[20];
523*572c4311Sfengbojiang             memset(digest,0,20); /* Start with a clean result */
524*572c4311Sfengbojiang             robj *o = lookupKeyReadWithFlags(c->db,c->argv[j],LOOKUP_NOTOUCH);
525*572c4311Sfengbojiang             if (o) xorObjectDigest(c->db,c->argv[j],digest,o);
526*572c4311Sfengbojiang 
527*572c4311Sfengbojiang             sds d = sdsempty();
528*572c4311Sfengbojiang             for (int i = 0; i < 20; i++) d = sdscatprintf(d, "%02x",digest[i]);
529*572c4311Sfengbojiang             addReplyStatus(c,d);
530*572c4311Sfengbojiang             sdsfree(d);
531*572c4311Sfengbojiang         }
532*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"sleep") && c->argc == 3) {
533*572c4311Sfengbojiang         double dtime = strtod(c->argv[2]->ptr,NULL);
534*572c4311Sfengbojiang         long long utime = dtime*1000000;
535*572c4311Sfengbojiang         struct timespec tv;
536*572c4311Sfengbojiang 
537*572c4311Sfengbojiang         tv.tv_sec = utime / 1000000;
538*572c4311Sfengbojiang         tv.tv_nsec = (utime % 1000000) * 1000;
539*572c4311Sfengbojiang         nanosleep(&tv, NULL);
540*572c4311Sfengbojiang         addReply(c,shared.ok);
541*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"set-active-expire") &&
542*572c4311Sfengbojiang                c->argc == 3)
543*572c4311Sfengbojiang     {
544*572c4311Sfengbojiang         server.active_expire_enabled = atoi(c->argv[2]->ptr);
545*572c4311Sfengbojiang         addReply(c,shared.ok);
546*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"lua-always-replicate-commands") &&
547*572c4311Sfengbojiang                c->argc == 3)
548*572c4311Sfengbojiang     {
549*572c4311Sfengbojiang         server.lua_always_replicate_commands = atoi(c->argv[2]->ptr);
550*572c4311Sfengbojiang         addReply(c,shared.ok);
551*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"error") && c->argc == 3) {
552*572c4311Sfengbojiang         sds errstr = sdsnewlen("-",1);
553*572c4311Sfengbojiang 
554*572c4311Sfengbojiang         errstr = sdscatsds(errstr,c->argv[2]->ptr);
555*572c4311Sfengbojiang         errstr = sdsmapchars(errstr,"\n\r","  ",2); /* no newlines in errors. */
556*572c4311Sfengbojiang         errstr = sdscatlen(errstr,"\r\n",2);
557*572c4311Sfengbojiang         addReplySds(c,errstr);
558*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"structsize") && c->argc == 2) {
559*572c4311Sfengbojiang         sds sizes = sdsempty();
560*572c4311Sfengbojiang         sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32);
561*572c4311Sfengbojiang         sizes = sdscatprintf(sizes,"robj:%d ",(int)sizeof(robj));
562*572c4311Sfengbojiang         sizes = sdscatprintf(sizes,"dictentry:%d ",(int)sizeof(dictEntry));
563*572c4311Sfengbojiang         sizes = sdscatprintf(sizes,"sdshdr5:%d ",(int)sizeof(struct sdshdr5));
564*572c4311Sfengbojiang         sizes = sdscatprintf(sizes,"sdshdr8:%d ",(int)sizeof(struct sdshdr8));
565*572c4311Sfengbojiang         sizes = sdscatprintf(sizes,"sdshdr16:%d ",(int)sizeof(struct sdshdr16));
566*572c4311Sfengbojiang         sizes = sdscatprintf(sizes,"sdshdr32:%d ",(int)sizeof(struct sdshdr32));
567*572c4311Sfengbojiang         sizes = sdscatprintf(sizes,"sdshdr64:%d ",(int)sizeof(struct sdshdr64));
568*572c4311Sfengbojiang         addReplyBulkSds(c,sizes);
569*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"htstats") && c->argc == 3) {
570*572c4311Sfengbojiang         long dbid;
571*572c4311Sfengbojiang         sds stats = sdsempty();
572*572c4311Sfengbojiang         char buf[4096];
573*572c4311Sfengbojiang 
574*572c4311Sfengbojiang         if (getLongFromObjectOrReply(c, c->argv[2], &dbid, NULL) != C_OK)
575*572c4311Sfengbojiang             return;
576*572c4311Sfengbojiang         if (dbid < 0 || dbid >= server.dbnum) {
577*572c4311Sfengbojiang             addReplyError(c,"Out of range database");
578*572c4311Sfengbojiang             return;
579*572c4311Sfengbojiang         }
580*572c4311Sfengbojiang 
581*572c4311Sfengbojiang         stats = sdscatprintf(stats,"[Dictionary HT]\n");
582*572c4311Sfengbojiang         dictGetStats(buf,sizeof(buf),server.db[dbid].dict);
583*572c4311Sfengbojiang         stats = sdscat(stats,buf);
584*572c4311Sfengbojiang 
585*572c4311Sfengbojiang         stats = sdscatprintf(stats,"[Expires HT]\n");
586*572c4311Sfengbojiang         dictGetStats(buf,sizeof(buf),server.db[dbid].expires);
587*572c4311Sfengbojiang         stats = sdscat(stats,buf);
588*572c4311Sfengbojiang 
589*572c4311Sfengbojiang         addReplyBulkSds(c,stats);
590*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"htstats-key") && c->argc == 3) {
591*572c4311Sfengbojiang         robj *o;
592*572c4311Sfengbojiang         dict *ht = NULL;
593*572c4311Sfengbojiang 
594*572c4311Sfengbojiang         if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nokeyerr))
595*572c4311Sfengbojiang                 == NULL) return;
596*572c4311Sfengbojiang 
597*572c4311Sfengbojiang         /* Get the hash table reference from the object, if possible. */
598*572c4311Sfengbojiang         switch (o->encoding) {
599*572c4311Sfengbojiang         case OBJ_ENCODING_SKIPLIST:
600*572c4311Sfengbojiang             {
601*572c4311Sfengbojiang                 zset *zs = o->ptr;
602*572c4311Sfengbojiang                 ht = zs->dict;
603*572c4311Sfengbojiang             }
604*572c4311Sfengbojiang             break;
605*572c4311Sfengbojiang         case OBJ_ENCODING_HT:
606*572c4311Sfengbojiang             ht = o->ptr;
607*572c4311Sfengbojiang             break;
608*572c4311Sfengbojiang         }
609*572c4311Sfengbojiang 
610*572c4311Sfengbojiang         if (ht == NULL) {
611*572c4311Sfengbojiang             addReplyError(c,"The value stored at the specified key is not "
612*572c4311Sfengbojiang                             "represented using an hash table");
613*572c4311Sfengbojiang         } else {
614*572c4311Sfengbojiang             char buf[4096];
615*572c4311Sfengbojiang             dictGetStats(buf,sizeof(buf),ht);
616*572c4311Sfengbojiang             addReplyBulkCString(c,buf);
617*572c4311Sfengbojiang         }
618*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"change-repl-id") && c->argc == 2) {
619*572c4311Sfengbojiang         serverLog(LL_WARNING,"Changing replication IDs after receiving DEBUG change-repl-id");
620*572c4311Sfengbojiang         changeReplicationId();
621*572c4311Sfengbojiang         clearReplicationId2();
622*572c4311Sfengbojiang         addReply(c,shared.ok);
623*572c4311Sfengbojiang     } else if (!strcasecmp(c->argv[1]->ptr,"stringmatch-test") && c->argc == 2)
624*572c4311Sfengbojiang     {
625*572c4311Sfengbojiang         stringmatchlen_fuzz_test();
626*572c4311Sfengbojiang         addReplyStatus(c,"Apparently Redis did not crash: test passed");
627*572c4311Sfengbojiang     } else {
628*572c4311Sfengbojiang         addReplySubcommandSyntaxError(c);
629*572c4311Sfengbojiang         return;
630*572c4311Sfengbojiang     }
631*572c4311Sfengbojiang }
632*572c4311Sfengbojiang 
633*572c4311Sfengbojiang /* =========================== Crash handling  ============================== */
634*572c4311Sfengbojiang 
_serverAssert(const char * estr,const char * file,int line)635*572c4311Sfengbojiang void _serverAssert(const char *estr, const char *file, int line) {
636*572c4311Sfengbojiang     bugReportStart();
637*572c4311Sfengbojiang     serverLog(LL_WARNING,"=== ASSERTION FAILED ===");
638*572c4311Sfengbojiang     serverLog(LL_WARNING,"==> %s:%d '%s' is not true",file,line,estr);
639*572c4311Sfengbojiang #ifdef HAVE_BACKTRACE
640*572c4311Sfengbojiang     server.assert_failed = estr;
641*572c4311Sfengbojiang     server.assert_file = file;
642*572c4311Sfengbojiang     server.assert_line = line;
643*572c4311Sfengbojiang     serverLog(LL_WARNING,"(forcing SIGSEGV to print the bug report.)");
644*572c4311Sfengbojiang #endif
645*572c4311Sfengbojiang     *((char*)-1) = 'x';
646*572c4311Sfengbojiang }
647*572c4311Sfengbojiang 
_serverAssertPrintClientInfo(const client * c)648*572c4311Sfengbojiang void _serverAssertPrintClientInfo(const client *c) {
649*572c4311Sfengbojiang     int j;
650*572c4311Sfengbojiang 
651*572c4311Sfengbojiang     bugReportStart();
652*572c4311Sfengbojiang     serverLog(LL_WARNING,"=== ASSERTION FAILED CLIENT CONTEXT ===");
653*572c4311Sfengbojiang     serverLog(LL_WARNING,"client->flags = %d", c->flags);
654*572c4311Sfengbojiang     serverLog(LL_WARNING,"client->fd = %d", c->fd);
655*572c4311Sfengbojiang     serverLog(LL_WARNING,"client->argc = %d", c->argc);
656*572c4311Sfengbojiang     for (j=0; j < c->argc; j++) {
657*572c4311Sfengbojiang         char buf[128];
658*572c4311Sfengbojiang         char *arg;
659*572c4311Sfengbojiang 
660*572c4311Sfengbojiang         if (c->argv[j]->type == OBJ_STRING && sdsEncodedObject(c->argv[j])) {
661*572c4311Sfengbojiang             arg = (char*) c->argv[j]->ptr;
662*572c4311Sfengbojiang         } else {
663*572c4311Sfengbojiang             snprintf(buf,sizeof(buf),"Object type: %u, encoding: %u",
664*572c4311Sfengbojiang                 c->argv[j]->type, c->argv[j]->encoding);
665*572c4311Sfengbojiang             arg = buf;
666*572c4311Sfengbojiang         }
667*572c4311Sfengbojiang         serverLog(LL_WARNING,"client->argv[%d] = \"%s\" (refcount: %d)",
668*572c4311Sfengbojiang             j, arg, c->argv[j]->refcount);
669*572c4311Sfengbojiang     }
670*572c4311Sfengbojiang }
671*572c4311Sfengbojiang 
serverLogObjectDebugInfo(const robj * o)672*572c4311Sfengbojiang void serverLogObjectDebugInfo(const robj *o) {
673*572c4311Sfengbojiang     serverLog(LL_WARNING,"Object type: %d", o->type);
674*572c4311Sfengbojiang     serverLog(LL_WARNING,"Object encoding: %d", o->encoding);
675*572c4311Sfengbojiang     serverLog(LL_WARNING,"Object refcount: %d", o->refcount);
676*572c4311Sfengbojiang     if (o->type == OBJ_STRING && sdsEncodedObject(o)) {
677*572c4311Sfengbojiang         serverLog(LL_WARNING,"Object raw string len: %zu", sdslen(o->ptr));
678*572c4311Sfengbojiang         if (sdslen(o->ptr) < 4096) {
679*572c4311Sfengbojiang             sds repr = sdscatrepr(sdsempty(),o->ptr,sdslen(o->ptr));
680*572c4311Sfengbojiang             serverLog(LL_WARNING,"Object raw string content: %s", repr);
681*572c4311Sfengbojiang             sdsfree(repr);
682*572c4311Sfengbojiang         }
683*572c4311Sfengbojiang     } else if (o->type == OBJ_LIST) {
684*572c4311Sfengbojiang         serverLog(LL_WARNING,"List length: %d", (int) listTypeLength(o));
685*572c4311Sfengbojiang     } else if (o->type == OBJ_SET) {
686*572c4311Sfengbojiang         serverLog(LL_WARNING,"Set size: %d", (int) setTypeSize(o));
687*572c4311Sfengbojiang     } else if (o->type == OBJ_HASH) {
688*572c4311Sfengbojiang         serverLog(LL_WARNING,"Hash size: %d", (int) hashTypeLength(o));
689*572c4311Sfengbojiang     } else if (o->type == OBJ_ZSET) {
690*572c4311Sfengbojiang         serverLog(LL_WARNING,"Sorted set size: %d", (int) zsetLength(o));
691*572c4311Sfengbojiang         if (o->encoding == OBJ_ENCODING_SKIPLIST)
692*572c4311Sfengbojiang             serverLog(LL_WARNING,"Skiplist level: %d", (int) ((const zset*)o->ptr)->zsl->level);
693*572c4311Sfengbojiang     }
694*572c4311Sfengbojiang }
695*572c4311Sfengbojiang 
_serverAssertPrintObject(const robj * o)696*572c4311Sfengbojiang void _serverAssertPrintObject(const robj *o) {
697*572c4311Sfengbojiang     bugReportStart();
698*572c4311Sfengbojiang     serverLog(LL_WARNING,"=== ASSERTION FAILED OBJECT CONTEXT ===");
699*572c4311Sfengbojiang     serverLogObjectDebugInfo(o);
700*572c4311Sfengbojiang }
701*572c4311Sfengbojiang 
_serverAssertWithInfo(const client * c,const robj * o,const char * estr,const char * file,int line)702*572c4311Sfengbojiang void _serverAssertWithInfo(const client *c, const robj *o, const char *estr, const char *file, int line) {
703*572c4311Sfengbojiang     if (c) _serverAssertPrintClientInfo(c);
704*572c4311Sfengbojiang     if (o) _serverAssertPrintObject(o);
705*572c4311Sfengbojiang     _serverAssert(estr,file,line);
706*572c4311Sfengbojiang }
707*572c4311Sfengbojiang 
_serverPanic(const char * file,int line,const char * msg,...)708*572c4311Sfengbojiang void _serverPanic(const char *file, int line, const char *msg, ...) {
709*572c4311Sfengbojiang     va_list ap;
710*572c4311Sfengbojiang     va_start(ap,msg);
711*572c4311Sfengbojiang     char fmtmsg[256];
712*572c4311Sfengbojiang     vsnprintf(fmtmsg,sizeof(fmtmsg),msg,ap);
713*572c4311Sfengbojiang     va_end(ap);
714*572c4311Sfengbojiang 
715*572c4311Sfengbojiang     bugReportStart();
716*572c4311Sfengbojiang     serverLog(LL_WARNING,"------------------------------------------------");
717*572c4311Sfengbojiang     serverLog(LL_WARNING,"!!! Software Failure. Press left mouse button to continue");
718*572c4311Sfengbojiang     serverLog(LL_WARNING,"Guru Meditation: %s #%s:%d",fmtmsg,file,line);
719*572c4311Sfengbojiang #ifdef HAVE_BACKTRACE
720*572c4311Sfengbojiang     serverLog(LL_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
721*572c4311Sfengbojiang #endif
722*572c4311Sfengbojiang     serverLog(LL_WARNING,"------------------------------------------------");
723*572c4311Sfengbojiang     *((char*)-1) = 'x';
724*572c4311Sfengbojiang }
725*572c4311Sfengbojiang 
bugReportStart(void)726*572c4311Sfengbojiang void bugReportStart(void) {
727*572c4311Sfengbojiang     if (server.bug_report_start == 0) {
728*572c4311Sfengbojiang         serverLogRaw(LL_WARNING|LL_RAW,
729*572c4311Sfengbojiang         "\n\n=== REDIS BUG REPORT START: Cut & paste starting from here ===\n");
730*572c4311Sfengbojiang         server.bug_report_start = 1;
731*572c4311Sfengbojiang     }
732*572c4311Sfengbojiang }
733*572c4311Sfengbojiang 
734*572c4311Sfengbojiang #ifdef HAVE_BACKTRACE
getMcontextEip(ucontext_t * uc)735*572c4311Sfengbojiang static void *getMcontextEip(ucontext_t *uc) {
736*572c4311Sfengbojiang #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
737*572c4311Sfengbojiang     /* OSX < 10.6 */
738*572c4311Sfengbojiang     #if defined(__x86_64__)
739*572c4311Sfengbojiang     return (void*) uc->uc_mcontext->__ss.__rip;
740*572c4311Sfengbojiang     #elif defined(__i386__)
741*572c4311Sfengbojiang     return (void*) uc->uc_mcontext->__ss.__eip;
742*572c4311Sfengbojiang     #else
743*572c4311Sfengbojiang     return (void*) uc->uc_mcontext->__ss.__srr0;
744*572c4311Sfengbojiang     #endif
745*572c4311Sfengbojiang #elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
746*572c4311Sfengbojiang     /* OSX >= 10.6 */
747*572c4311Sfengbojiang     #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
748*572c4311Sfengbojiang     return (void*) uc->uc_mcontext->__ss.__rip;
749*572c4311Sfengbojiang     #else
750*572c4311Sfengbojiang     return (void*) uc->uc_mcontext->__ss.__eip;
751*572c4311Sfengbojiang     #endif
752*572c4311Sfengbojiang #elif defined(__linux__)
753*572c4311Sfengbojiang     /* Linux */
754*572c4311Sfengbojiang     #if defined(__i386__)
755*572c4311Sfengbojiang     return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */
756*572c4311Sfengbojiang     #elif defined(__X86_64__) || defined(__x86_64__)
757*572c4311Sfengbojiang     return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */
758*572c4311Sfengbojiang     #elif defined(__ia64__) /* Linux IA64 */
759*572c4311Sfengbojiang     return (void*) uc->uc_mcontext.sc_ip;
760*572c4311Sfengbojiang     #elif defined(__arm__) /* Linux ARM */
761*572c4311Sfengbojiang     return (void*) uc->uc_mcontext.arm_pc;
762*572c4311Sfengbojiang     #elif defined(__aarch64__) /* Linux AArch64 */
763*572c4311Sfengbojiang     return (void*) uc->uc_mcontext.pc;
764*572c4311Sfengbojiang     #endif
765*572c4311Sfengbojiang #elif defined(__FreeBSD__)
766*572c4311Sfengbojiang     /* FreeBSD */
767*572c4311Sfengbojiang     #if defined(__i386__)
768*572c4311Sfengbojiang     return (void*) uc->uc_mcontext.mc_eip;
769*572c4311Sfengbojiang     #elif defined(__x86_64__)
770*572c4311Sfengbojiang     return (void*) uc->uc_mcontext.mc_rip;
771*572c4311Sfengbojiang     #endif
772*572c4311Sfengbojiang #elif defined(__OpenBSD__)
773*572c4311Sfengbojiang     /* OpenBSD */
774*572c4311Sfengbojiang     #if defined(__i386__)
775*572c4311Sfengbojiang     return (void*) uc->sc_eip;
776*572c4311Sfengbojiang     #elif defined(__x86_64__)
777*572c4311Sfengbojiang     return (void*) uc->sc_rip;
778*572c4311Sfengbojiang     #endif
779*572c4311Sfengbojiang #elif defined(__DragonFly__)
780*572c4311Sfengbojiang     return (void*) uc->uc_mcontext.mc_rip;
781*572c4311Sfengbojiang #else
782*572c4311Sfengbojiang     return NULL;
783*572c4311Sfengbojiang #endif
784*572c4311Sfengbojiang }
785*572c4311Sfengbojiang 
logStackContent(void ** sp)786*572c4311Sfengbojiang void logStackContent(void **sp) {
787*572c4311Sfengbojiang     int i;
788*572c4311Sfengbojiang     for (i = 15; i >= 0; i--) {
789*572c4311Sfengbojiang         unsigned long addr = (unsigned long) sp+i;
790*572c4311Sfengbojiang         unsigned long val = (unsigned long) sp[i];
791*572c4311Sfengbojiang 
792*572c4311Sfengbojiang         if (sizeof(long) == 4)
793*572c4311Sfengbojiang             serverLog(LL_WARNING, "(%08lx) -> %08lx", addr, val);
794*572c4311Sfengbojiang         else
795*572c4311Sfengbojiang             serverLog(LL_WARNING, "(%016lx) -> %016lx", addr, val);
796*572c4311Sfengbojiang     }
797*572c4311Sfengbojiang }
798*572c4311Sfengbojiang 
logRegisters(ucontext_t * uc)799*572c4311Sfengbojiang void logRegisters(ucontext_t *uc) {
800*572c4311Sfengbojiang     serverLog(LL_WARNING|LL_RAW, "\n------ REGISTERS ------\n");
801*572c4311Sfengbojiang 
802*572c4311Sfengbojiang /* OSX */
803*572c4311Sfengbojiang #if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
804*572c4311Sfengbojiang   /* OSX AMD64 */
805*572c4311Sfengbojiang     #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
806*572c4311Sfengbojiang     serverLog(LL_WARNING,
807*572c4311Sfengbojiang     "\n"
808*572c4311Sfengbojiang     "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
809*572c4311Sfengbojiang     "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
810*572c4311Sfengbojiang     "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
811*572c4311Sfengbojiang     "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
812*572c4311Sfengbojiang     "RIP:%016lx EFL:%016lx\nCS :%016lx FS:%016lx  GS:%016lx",
813*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rax,
814*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rbx,
815*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rcx,
816*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rdx,
817*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rdi,
818*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rsi,
819*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rbp,
820*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rsp,
821*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__r8,
822*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__r9,
823*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__r10,
824*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__r11,
825*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__r12,
826*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__r13,
827*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__r14,
828*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__r15,
829*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rip,
830*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__rflags,
831*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__cs,
832*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__fs,
833*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__gs
834*572c4311Sfengbojiang     );
835*572c4311Sfengbojiang     logStackContent((void**)uc->uc_mcontext->__ss.__rsp);
836*572c4311Sfengbojiang     #else
837*572c4311Sfengbojiang     /* OSX x86 */
838*572c4311Sfengbojiang     serverLog(LL_WARNING,
839*572c4311Sfengbojiang     "\n"
840*572c4311Sfengbojiang     "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
841*572c4311Sfengbojiang     "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
842*572c4311Sfengbojiang     "SS:%08lx  EFL:%08lx EIP:%08lx CS :%08lx\n"
843*572c4311Sfengbojiang     "DS:%08lx  ES:%08lx  FS :%08lx GS :%08lx",
844*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__eax,
845*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__ebx,
846*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__ecx,
847*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__edx,
848*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__edi,
849*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__esi,
850*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__ebp,
851*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__esp,
852*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__ss,
853*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__eflags,
854*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__eip,
855*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__cs,
856*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__ds,
857*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__es,
858*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__fs,
859*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext->__ss.__gs
860*572c4311Sfengbojiang     );
861*572c4311Sfengbojiang     logStackContent((void**)uc->uc_mcontext->__ss.__esp);
862*572c4311Sfengbojiang     #endif
863*572c4311Sfengbojiang /* Linux */
864*572c4311Sfengbojiang #elif defined(__linux__)
865*572c4311Sfengbojiang     /* Linux x86 */
866*572c4311Sfengbojiang     #if defined(__i386__)
867*572c4311Sfengbojiang     serverLog(LL_WARNING,
868*572c4311Sfengbojiang     "\n"
869*572c4311Sfengbojiang     "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
870*572c4311Sfengbojiang     "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
871*572c4311Sfengbojiang     "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
872*572c4311Sfengbojiang     "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
873*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[11],
874*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[8],
875*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[10],
876*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[9],
877*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[4],
878*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[5],
879*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[6],
880*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[7],
881*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[18],
882*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[17],
883*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[14],
884*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[15],
885*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[3],
886*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[2],
887*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[1],
888*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[0]
889*572c4311Sfengbojiang     );
890*572c4311Sfengbojiang     logStackContent((void**)uc->uc_mcontext.gregs[7]);
891*572c4311Sfengbojiang     #elif defined(__X86_64__) || defined(__x86_64__)
892*572c4311Sfengbojiang     /* Linux AMD64 */
893*572c4311Sfengbojiang     serverLog(LL_WARNING,
894*572c4311Sfengbojiang     "\n"
895*572c4311Sfengbojiang     "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
896*572c4311Sfengbojiang     "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
897*572c4311Sfengbojiang     "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
898*572c4311Sfengbojiang     "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
899*572c4311Sfengbojiang     "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
900*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[13],
901*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[11],
902*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[14],
903*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[12],
904*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[8],
905*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[9],
906*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[10],
907*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[15],
908*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[0],
909*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[1],
910*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[2],
911*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[3],
912*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[4],
913*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[5],
914*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[6],
915*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[7],
916*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[16],
917*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[17],
918*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.gregs[18]
919*572c4311Sfengbojiang     );
920*572c4311Sfengbojiang     logStackContent((void**)uc->uc_mcontext.gregs[15]);
921*572c4311Sfengbojiang     #endif
922*572c4311Sfengbojiang #elif defined(__FreeBSD__)
923*572c4311Sfengbojiang     #if defined(__x86_64__)
924*572c4311Sfengbojiang     serverLog(LL_WARNING,
925*572c4311Sfengbojiang     "\n"
926*572c4311Sfengbojiang     "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
927*572c4311Sfengbojiang     "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
928*572c4311Sfengbojiang     "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
929*572c4311Sfengbojiang     "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
930*572c4311Sfengbojiang     "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
931*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rax,
932*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rbx,
933*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rcx,
934*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rdx,
935*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rdi,
936*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rsi,
937*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rbp,
938*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rsp,
939*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r8,
940*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r9,
941*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r10,
942*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r11,
943*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r12,
944*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r13,
945*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r14,
946*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r15,
947*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rip,
948*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rflags,
949*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_cs
950*572c4311Sfengbojiang     );
951*572c4311Sfengbojiang     logStackContent((void**)uc->uc_mcontext.mc_rsp);
952*572c4311Sfengbojiang     #elif defined(__i386__)
953*572c4311Sfengbojiang     serverLog(LL_WARNING,
954*572c4311Sfengbojiang     "\n"
955*572c4311Sfengbojiang     "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
956*572c4311Sfengbojiang     "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
957*572c4311Sfengbojiang     "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
958*572c4311Sfengbojiang     "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
959*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_eax,
960*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_ebx,
961*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_ebx,
962*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_edx,
963*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_edi,
964*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_esi,
965*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_ebp,
966*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_esp,
967*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_ss,
968*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_eflags,
969*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_eip,
970*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_cs,
971*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_es,
972*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_fs,
973*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_gs
974*572c4311Sfengbojiang     );
975*572c4311Sfengbojiang     logStackContent((void**)uc->uc_mcontext.mc_esp);
976*572c4311Sfengbojiang     #endif
977*572c4311Sfengbojiang #elif defined(__OpenBSD__)
978*572c4311Sfengbojiang     #if defined(__x86_64__)
979*572c4311Sfengbojiang     serverLog(LL_WARNING,
980*572c4311Sfengbojiang     "\n"
981*572c4311Sfengbojiang     "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
982*572c4311Sfengbojiang     "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
983*572c4311Sfengbojiang     "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
984*572c4311Sfengbojiang     "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
985*572c4311Sfengbojiang     "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
986*572c4311Sfengbojiang         (unsigned long) uc->sc_rax,
987*572c4311Sfengbojiang         (unsigned long) uc->sc_rbx,
988*572c4311Sfengbojiang         (unsigned long) uc->sc_rcx,
989*572c4311Sfengbojiang         (unsigned long) uc->sc_rdx,
990*572c4311Sfengbojiang         (unsigned long) uc->sc_rdi,
991*572c4311Sfengbojiang         (unsigned long) uc->sc_rsi,
992*572c4311Sfengbojiang         (unsigned long) uc->sc_rbp,
993*572c4311Sfengbojiang         (unsigned long) uc->sc_rsp,
994*572c4311Sfengbojiang         (unsigned long) uc->sc_r8,
995*572c4311Sfengbojiang         (unsigned long) uc->sc_r9,
996*572c4311Sfengbojiang         (unsigned long) uc->sc_r10,
997*572c4311Sfengbojiang         (unsigned long) uc->sc_r11,
998*572c4311Sfengbojiang         (unsigned long) uc->sc_r12,
999*572c4311Sfengbojiang         (unsigned long) uc->sc_r13,
1000*572c4311Sfengbojiang         (unsigned long) uc->sc_r14,
1001*572c4311Sfengbojiang         (unsigned long) uc->sc_r15,
1002*572c4311Sfengbojiang         (unsigned long) uc->sc_rip,
1003*572c4311Sfengbojiang         (unsigned long) uc->sc_rflags,
1004*572c4311Sfengbojiang         (unsigned long) uc->sc_cs
1005*572c4311Sfengbojiang     );
1006*572c4311Sfengbojiang     logStackContent((void**)uc->sc_rsp);
1007*572c4311Sfengbojiang     #elif defined(__i386__)
1008*572c4311Sfengbojiang     serverLog(LL_WARNING,
1009*572c4311Sfengbojiang     "\n"
1010*572c4311Sfengbojiang     "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1011*572c4311Sfengbojiang     "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1012*572c4311Sfengbojiang     "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
1013*572c4311Sfengbojiang     "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
1014*572c4311Sfengbojiang         (unsigned long) uc->sc_eax,
1015*572c4311Sfengbojiang         (unsigned long) uc->sc_ebx,
1016*572c4311Sfengbojiang         (unsigned long) uc->sc_ebx,
1017*572c4311Sfengbojiang         (unsigned long) uc->sc_edx,
1018*572c4311Sfengbojiang         (unsigned long) uc->sc_edi,
1019*572c4311Sfengbojiang         (unsigned long) uc->sc_esi,
1020*572c4311Sfengbojiang         (unsigned long) uc->sc_ebp,
1021*572c4311Sfengbojiang         (unsigned long) uc->sc_esp,
1022*572c4311Sfengbojiang         (unsigned long) uc->sc_ss,
1023*572c4311Sfengbojiang         (unsigned long) uc->sc_eflags,
1024*572c4311Sfengbojiang         (unsigned long) uc->sc_eip,
1025*572c4311Sfengbojiang         (unsigned long) uc->sc_cs,
1026*572c4311Sfengbojiang         (unsigned long) uc->sc_es,
1027*572c4311Sfengbojiang         (unsigned long) uc->sc_fs,
1028*572c4311Sfengbojiang         (unsigned long) uc->sc_gs
1029*572c4311Sfengbojiang     );
1030*572c4311Sfengbojiang     logStackContent((void**)uc->sc_esp);
1031*572c4311Sfengbojiang     #endif
1032*572c4311Sfengbojiang #elif defined(__DragonFly__)
1033*572c4311Sfengbojiang     serverLog(LL_WARNING,
1034*572c4311Sfengbojiang     "\n"
1035*572c4311Sfengbojiang     "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1036*572c4311Sfengbojiang     "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1037*572c4311Sfengbojiang     "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1038*572c4311Sfengbojiang     "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1039*572c4311Sfengbojiang     "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1040*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rax,
1041*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rbx,
1042*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rcx,
1043*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rdx,
1044*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rdi,
1045*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rsi,
1046*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rbp,
1047*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rsp,
1048*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r8,
1049*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r9,
1050*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r10,
1051*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r11,
1052*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r12,
1053*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r13,
1054*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r14,
1055*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_r15,
1056*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rip,
1057*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_rflags,
1058*572c4311Sfengbojiang         (unsigned long) uc->uc_mcontext.mc_cs
1059*572c4311Sfengbojiang     );
1060*572c4311Sfengbojiang     logStackContent((void**)uc->uc_mcontext.mc_rsp);
1061*572c4311Sfengbojiang #else
1062*572c4311Sfengbojiang     serverLog(LL_WARNING,
1063*572c4311Sfengbojiang         "  Dumping of registers not supported for this OS/arch");
1064*572c4311Sfengbojiang #endif
1065*572c4311Sfengbojiang }
1066*572c4311Sfengbojiang 
1067*572c4311Sfengbojiang /* Return a file descriptor to write directly to the Redis log with the
1068*572c4311Sfengbojiang  * write(2) syscall, that can be used in critical sections of the code
1069*572c4311Sfengbojiang  * where the rest of Redis can't be trusted (for example during the memory
1070*572c4311Sfengbojiang  * test) or when an API call requires a raw fd.
1071*572c4311Sfengbojiang  *
1072*572c4311Sfengbojiang  * Close it with closeDirectLogFiledes(). */
openDirectLogFiledes(void)1073*572c4311Sfengbojiang int openDirectLogFiledes(void) {
1074*572c4311Sfengbojiang     int log_to_stdout = server.logfile[0] == '\0';
1075*572c4311Sfengbojiang     int fd = log_to_stdout ?
1076*572c4311Sfengbojiang         STDOUT_FILENO :
1077*572c4311Sfengbojiang         open(server.logfile, O_APPEND|O_CREAT|O_WRONLY, 0644);
1078*572c4311Sfengbojiang     return fd;
1079*572c4311Sfengbojiang }
1080*572c4311Sfengbojiang 
1081*572c4311Sfengbojiang /* Used to close what closeDirectLogFiledes() returns. */
closeDirectLogFiledes(int fd)1082*572c4311Sfengbojiang void closeDirectLogFiledes(int fd) {
1083*572c4311Sfengbojiang     int log_to_stdout = server.logfile[0] == '\0';
1084*572c4311Sfengbojiang     if (!log_to_stdout) close(fd);
1085*572c4311Sfengbojiang }
1086*572c4311Sfengbojiang 
1087*572c4311Sfengbojiang /* Logs the stack trace using the backtrace() call. This function is designed
1088*572c4311Sfengbojiang  * to be called from signal handlers safely. */
logStackTrace(ucontext_t * uc)1089*572c4311Sfengbojiang void logStackTrace(ucontext_t *uc) {
1090*572c4311Sfengbojiang     void *trace[101];
1091*572c4311Sfengbojiang     int trace_size = 0, fd = openDirectLogFiledes();
1092*572c4311Sfengbojiang 
1093*572c4311Sfengbojiang     if (fd == -1) return; /* If we can't log there is anything to do. */
1094*572c4311Sfengbojiang 
1095*572c4311Sfengbojiang     /* Generate the stack trace */
1096*572c4311Sfengbojiang     trace_size = backtrace(trace+1, 100);
1097*572c4311Sfengbojiang 
1098*572c4311Sfengbojiang     if (getMcontextEip(uc) != NULL) {
1099*572c4311Sfengbojiang         char *msg1 = "EIP:\n";
1100*572c4311Sfengbojiang         char *msg2 = "\nBacktrace:\n";
1101*572c4311Sfengbojiang         if (write(fd,msg1,strlen(msg1)) == -1) {/* Avoid warning. */};
1102*572c4311Sfengbojiang         trace[0] = getMcontextEip(uc);
1103*572c4311Sfengbojiang         backtrace_symbols_fd(trace, 1, fd);
1104*572c4311Sfengbojiang         if (write(fd,msg2,strlen(msg2)) == -1) {/* Avoid warning. */};
1105*572c4311Sfengbojiang     }
1106*572c4311Sfengbojiang 
1107*572c4311Sfengbojiang     /* Write symbols to log file */
1108*572c4311Sfengbojiang     backtrace_symbols_fd(trace+1, trace_size, fd);
1109*572c4311Sfengbojiang 
1110*572c4311Sfengbojiang     /* Cleanup */
1111*572c4311Sfengbojiang     closeDirectLogFiledes(fd);
1112*572c4311Sfengbojiang }
1113*572c4311Sfengbojiang 
1114*572c4311Sfengbojiang /* Log information about the "current" client, that is, the client that is
1115*572c4311Sfengbojiang  * currently being served by Redis. May be NULL if Redis is not serving a
1116*572c4311Sfengbojiang  * client right now. */
logCurrentClient(void)1117*572c4311Sfengbojiang void logCurrentClient(void) {
1118*572c4311Sfengbojiang     if (server.current_client == NULL) return;
1119*572c4311Sfengbojiang 
1120*572c4311Sfengbojiang     client *cc = server.current_client;
1121*572c4311Sfengbojiang     sds client;
1122*572c4311Sfengbojiang     int j;
1123*572c4311Sfengbojiang 
1124*572c4311Sfengbojiang     serverLogRaw(LL_WARNING|LL_RAW, "\n------ CURRENT CLIENT INFO ------\n");
1125*572c4311Sfengbojiang     client = catClientInfoString(sdsempty(),cc);
1126*572c4311Sfengbojiang     serverLog(LL_WARNING|LL_RAW,"%s\n", client);
1127*572c4311Sfengbojiang     sdsfree(client);
1128*572c4311Sfengbojiang     for (j = 0; j < cc->argc; j++) {
1129*572c4311Sfengbojiang         robj *decoded;
1130*572c4311Sfengbojiang 
1131*572c4311Sfengbojiang         decoded = getDecodedObject(cc->argv[j]);
1132*572c4311Sfengbojiang         serverLog(LL_WARNING|LL_RAW,"argv[%d]: '%s'\n", j,
1133*572c4311Sfengbojiang             (char*)decoded->ptr);
1134*572c4311Sfengbojiang         decrRefCount(decoded);
1135*572c4311Sfengbojiang     }
1136*572c4311Sfengbojiang     /* Check if the first argument, usually a key, is found inside the
1137*572c4311Sfengbojiang      * selected DB, and if so print info about the associated object. */
1138*572c4311Sfengbojiang     if (cc->argc >= 1) {
1139*572c4311Sfengbojiang         robj *val, *key;
1140*572c4311Sfengbojiang         dictEntry *de;
1141*572c4311Sfengbojiang 
1142*572c4311Sfengbojiang         key = getDecodedObject(cc->argv[1]);
1143*572c4311Sfengbojiang         de = dictFind(cc->db->dict, key->ptr);
1144*572c4311Sfengbojiang         if (de) {
1145*572c4311Sfengbojiang             val = dictGetVal(de);
1146*572c4311Sfengbojiang             serverLog(LL_WARNING,"key '%s' found in DB containing the following object:", (char*)key->ptr);
1147*572c4311Sfengbojiang             serverLogObjectDebugInfo(val);
1148*572c4311Sfengbojiang         }
1149*572c4311Sfengbojiang         decrRefCount(key);
1150*572c4311Sfengbojiang     }
1151*572c4311Sfengbojiang }
1152*572c4311Sfengbojiang 
1153*572c4311Sfengbojiang #if defined(HAVE_PROC_MAPS)
1154*572c4311Sfengbojiang 
1155*572c4311Sfengbojiang #define MEMTEST_MAX_REGIONS 128
1156*572c4311Sfengbojiang 
1157*572c4311Sfengbojiang /* A non destructive memory test executed during segfauls. */
memtest_test_linux_anonymous_maps(void)1158*572c4311Sfengbojiang int memtest_test_linux_anonymous_maps(void) {
1159*572c4311Sfengbojiang     FILE *fp;
1160*572c4311Sfengbojiang     char line[1024];
1161*572c4311Sfengbojiang     char logbuf[1024];
1162*572c4311Sfengbojiang     size_t start_addr, end_addr, size;
1163*572c4311Sfengbojiang     size_t start_vect[MEMTEST_MAX_REGIONS];
1164*572c4311Sfengbojiang     size_t size_vect[MEMTEST_MAX_REGIONS];
1165*572c4311Sfengbojiang     int regions = 0, j;
1166*572c4311Sfengbojiang 
1167*572c4311Sfengbojiang     int fd = openDirectLogFiledes();
1168*572c4311Sfengbojiang     if (!fd) return 0;
1169*572c4311Sfengbojiang 
1170*572c4311Sfengbojiang     fp = fopen("/proc/self/maps","r");
1171*572c4311Sfengbojiang     if (!fp) return 0;
1172*572c4311Sfengbojiang     while(fgets(line,sizeof(line),fp) != NULL) {
1173*572c4311Sfengbojiang         char *start, *end, *p = line;
1174*572c4311Sfengbojiang 
1175*572c4311Sfengbojiang         start = p;
1176*572c4311Sfengbojiang         p = strchr(p,'-');
1177*572c4311Sfengbojiang         if (!p) continue;
1178*572c4311Sfengbojiang         *p++ = '\0';
1179*572c4311Sfengbojiang         end = p;
1180*572c4311Sfengbojiang         p = strchr(p,' ');
1181*572c4311Sfengbojiang         if (!p) continue;
1182*572c4311Sfengbojiang         *p++ = '\0';
1183*572c4311Sfengbojiang         if (strstr(p,"stack") ||
1184*572c4311Sfengbojiang             strstr(p,"vdso") ||
1185*572c4311Sfengbojiang             strstr(p,"vsyscall")) continue;
1186*572c4311Sfengbojiang         if (!strstr(p,"00:00")) continue;
1187*572c4311Sfengbojiang         if (!strstr(p,"rw")) continue;
1188*572c4311Sfengbojiang 
1189*572c4311Sfengbojiang         start_addr = strtoul(start,NULL,16);
1190*572c4311Sfengbojiang         end_addr = strtoul(end,NULL,16);
1191*572c4311Sfengbojiang         size = end_addr-start_addr;
1192*572c4311Sfengbojiang 
1193*572c4311Sfengbojiang         start_vect[regions] = start_addr;
1194*572c4311Sfengbojiang         size_vect[regions] = size;
1195*572c4311Sfengbojiang         snprintf(logbuf,sizeof(logbuf),
1196*572c4311Sfengbojiang             "*** Preparing to test memory region %lx (%lu bytes)\n",
1197*572c4311Sfengbojiang                 (unsigned long) start_vect[regions],
1198*572c4311Sfengbojiang                 (unsigned long) size_vect[regions]);
1199*572c4311Sfengbojiang         if (write(fd,logbuf,strlen(logbuf)) == -1) { /* Nothing to do. */ }
1200*572c4311Sfengbojiang         regions++;
1201*572c4311Sfengbojiang     }
1202*572c4311Sfengbojiang 
1203*572c4311Sfengbojiang     int errors = 0;
1204*572c4311Sfengbojiang     for (j = 0; j < regions; j++) {
1205*572c4311Sfengbojiang         if (write(fd,".",1) == -1) { /* Nothing to do. */ }
1206*572c4311Sfengbojiang         errors += memtest_preserving_test((void*)start_vect[j],size_vect[j],1);
1207*572c4311Sfengbojiang         if (write(fd, errors ? "E" : "O",1) == -1) { /* Nothing to do. */ }
1208*572c4311Sfengbojiang     }
1209*572c4311Sfengbojiang     if (write(fd,"\n",1) == -1) { /* Nothing to do. */ }
1210*572c4311Sfengbojiang 
1211*572c4311Sfengbojiang     /* NOTE: It is very important to close the file descriptor only now
1212*572c4311Sfengbojiang      * because closing it before may result into unmapping of some memory
1213*572c4311Sfengbojiang      * region that we are testing. */
1214*572c4311Sfengbojiang     fclose(fp);
1215*572c4311Sfengbojiang     closeDirectLogFiledes(fd);
1216*572c4311Sfengbojiang     return errors;
1217*572c4311Sfengbojiang }
1218*572c4311Sfengbojiang #endif
1219*572c4311Sfengbojiang 
1220*572c4311Sfengbojiang /* Scans the (assumed) x86 code starting at addr, for a max of `len`
1221*572c4311Sfengbojiang  * bytes, searching for E8 (callq) opcodes, and dumping the symbols
1222*572c4311Sfengbojiang  * and the call offset if they appear to be valid. */
dumpX86Calls(void * addr,size_t len)1223*572c4311Sfengbojiang void dumpX86Calls(void *addr, size_t len) {
1224*572c4311Sfengbojiang     size_t j;
1225*572c4311Sfengbojiang     unsigned char *p = addr;
1226*572c4311Sfengbojiang     Dl_info info;
1227*572c4311Sfengbojiang     /* Hash table to best-effort avoid printing the same symbol
1228*572c4311Sfengbojiang      * multiple times. */
1229*572c4311Sfengbojiang     unsigned long ht[256] = {0};
1230*572c4311Sfengbojiang 
1231*572c4311Sfengbojiang     if (len < 5) return;
1232*572c4311Sfengbojiang     for (j = 0; j < len-4; j++) {
1233*572c4311Sfengbojiang         if (p[j] != 0xE8) continue; /* Not an E8 CALL opcode. */
1234*572c4311Sfengbojiang         unsigned long target = (unsigned long)addr+j+5;
1235*572c4311Sfengbojiang         target += *((int32_t*)(p+j+1));
1236*572c4311Sfengbojiang         if (dladdr((void*)target, &info) != 0 && info.dli_sname != NULL) {
1237*572c4311Sfengbojiang             if (ht[target&0xff] != target) {
1238*572c4311Sfengbojiang                 printf("Function at 0x%lx is %s\n",target,info.dli_sname);
1239*572c4311Sfengbojiang                 ht[target&0xff] = target;
1240*572c4311Sfengbojiang             }
1241*572c4311Sfengbojiang             j += 4; /* Skip the 32 bit immediate. */
1242*572c4311Sfengbojiang         }
1243*572c4311Sfengbojiang     }
1244*572c4311Sfengbojiang }
1245*572c4311Sfengbojiang 
sigsegvHandler(int sig,siginfo_t * info,void * secret)1246*572c4311Sfengbojiang void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
1247*572c4311Sfengbojiang     ucontext_t *uc = (ucontext_t*) secret;
1248*572c4311Sfengbojiang     void *eip = getMcontextEip(uc);
1249*572c4311Sfengbojiang     sds infostring, clients;
1250*572c4311Sfengbojiang     struct sigaction act;
1251*572c4311Sfengbojiang     UNUSED(info);
1252*572c4311Sfengbojiang 
1253*572c4311Sfengbojiang     bugReportStart();
1254*572c4311Sfengbojiang     serverLog(LL_WARNING,
1255*572c4311Sfengbojiang         "Redis %s crashed by signal: %d", REDIS_VERSION, sig);
1256*572c4311Sfengbojiang     if (eip != NULL) {
1257*572c4311Sfengbojiang         serverLog(LL_WARNING,
1258*572c4311Sfengbojiang         "Crashed running the instruction at: %p", eip);
1259*572c4311Sfengbojiang     }
1260*572c4311Sfengbojiang     if (sig == SIGSEGV || sig == SIGBUS) {
1261*572c4311Sfengbojiang         serverLog(LL_WARNING,
1262*572c4311Sfengbojiang         "Accessing address: %p", (void*)info->si_addr);
1263*572c4311Sfengbojiang     }
1264*572c4311Sfengbojiang     serverLog(LL_WARNING,
1265*572c4311Sfengbojiang         "Failed assertion: %s (%s:%d)", server.assert_failed,
1266*572c4311Sfengbojiang                         server.assert_file, server.assert_line);
1267*572c4311Sfengbojiang 
1268*572c4311Sfengbojiang     /* Log the stack trace */
1269*572c4311Sfengbojiang     serverLogRaw(LL_WARNING|LL_RAW, "\n------ STACK TRACE ------\n");
1270*572c4311Sfengbojiang     logStackTrace(uc);
1271*572c4311Sfengbojiang 
1272*572c4311Sfengbojiang     /* Log INFO and CLIENT LIST */
1273*572c4311Sfengbojiang     serverLogRaw(LL_WARNING|LL_RAW, "\n------ INFO OUTPUT ------\n");
1274*572c4311Sfengbojiang     infostring = genRedisInfoString("all");
1275*572c4311Sfengbojiang     serverLogRaw(LL_WARNING|LL_RAW, infostring);
1276*572c4311Sfengbojiang     serverLogRaw(LL_WARNING|LL_RAW, "\n------ CLIENT LIST OUTPUT ------\n");
1277*572c4311Sfengbojiang     clients = getAllClientsInfoString(-1);
1278*572c4311Sfengbojiang     serverLogRaw(LL_WARNING|LL_RAW, clients);
1279*572c4311Sfengbojiang     sdsfree(infostring);
1280*572c4311Sfengbojiang     sdsfree(clients);
1281*572c4311Sfengbojiang 
1282*572c4311Sfengbojiang     /* Log the current client */
1283*572c4311Sfengbojiang     logCurrentClient();
1284*572c4311Sfengbojiang 
1285*572c4311Sfengbojiang     /* Log dump of processor registers */
1286*572c4311Sfengbojiang     logRegisters(uc);
1287*572c4311Sfengbojiang 
1288*572c4311Sfengbojiang #if defined(HAVE_PROC_MAPS)
1289*572c4311Sfengbojiang     /* Test memory */
1290*572c4311Sfengbojiang     serverLogRaw(LL_WARNING|LL_RAW, "\n------ FAST MEMORY TEST ------\n");
1291*572c4311Sfengbojiang     bioKillThreads();
1292*572c4311Sfengbojiang     if (memtest_test_linux_anonymous_maps()) {
1293*572c4311Sfengbojiang         serverLogRaw(LL_WARNING|LL_RAW,
1294*572c4311Sfengbojiang             "!!! MEMORY ERROR DETECTED! Check your memory ASAP !!!\n");
1295*572c4311Sfengbojiang     } else {
1296*572c4311Sfengbojiang         serverLogRaw(LL_WARNING|LL_RAW,
1297*572c4311Sfengbojiang             "Fast memory test PASSED, however your memory can still be broken. Please run a memory test for several hours if possible.\n");
1298*572c4311Sfengbojiang     }
1299*572c4311Sfengbojiang #endif
1300*572c4311Sfengbojiang 
1301*572c4311Sfengbojiang     if (eip != NULL) {
1302*572c4311Sfengbojiang         Dl_info info;
1303*572c4311Sfengbojiang         if (dladdr(eip, &info) != 0) {
1304*572c4311Sfengbojiang             serverLog(LL_WARNING|LL_RAW,
1305*572c4311Sfengbojiang                 "\n------ DUMPING CODE AROUND EIP ------\n"
1306*572c4311Sfengbojiang                 "Symbol: %s (base: %p)\n"
1307*572c4311Sfengbojiang                 "Module: %s (base %p)\n"
1308*572c4311Sfengbojiang                 "$ xxd -r -p /tmp/dump.hex /tmp/dump.bin\n"
1309*572c4311Sfengbojiang                 "$ objdump --adjust-vma=%p -D -b binary -m i386:x86-64 /tmp/dump.bin\n"
1310*572c4311Sfengbojiang                 "------\n",
1311*572c4311Sfengbojiang                 info.dli_sname, info.dli_saddr, info.dli_fname, info.dli_fbase,
1312*572c4311Sfengbojiang                 info.dli_saddr);
1313*572c4311Sfengbojiang             size_t len = (long)eip - (long)info.dli_saddr;
1314*572c4311Sfengbojiang             unsigned long sz = sysconf(_SC_PAGESIZE);
1315*572c4311Sfengbojiang             if (len < 1<<13) { /* we don't have functions over 8k (verified) */
1316*572c4311Sfengbojiang                 /* Find the address of the next page, which is our "safety"
1317*572c4311Sfengbojiang                  * limit when dumping. Then try to dump just 128 bytes more
1318*572c4311Sfengbojiang                  * than EIP if there is room, or stop sooner. */
1319*572c4311Sfengbojiang                 unsigned long next = ((unsigned long)eip + sz) & ~(sz-1);
1320*572c4311Sfengbojiang                 unsigned long end = (unsigned long)eip + 128;
1321*572c4311Sfengbojiang                 if (end > next) end = next;
1322*572c4311Sfengbojiang                 len = end - (unsigned long)info.dli_saddr;
1323*572c4311Sfengbojiang                 serverLogHexDump(LL_WARNING, "dump of function",
1324*572c4311Sfengbojiang                     info.dli_saddr ,len);
1325*572c4311Sfengbojiang                 dumpX86Calls(info.dli_saddr,len);
1326*572c4311Sfengbojiang             }
1327*572c4311Sfengbojiang         }
1328*572c4311Sfengbojiang     }
1329*572c4311Sfengbojiang 
1330*572c4311Sfengbojiang     serverLogRaw(LL_WARNING|LL_RAW,
1331*572c4311Sfengbojiang "\n=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
1332*572c4311Sfengbojiang "       Please report the crash by opening an issue on github:\n\n"
1333*572c4311Sfengbojiang "           http://github.com/antirez/redis/issues\n\n"
1334*572c4311Sfengbojiang "  Suspect RAM error? Use redis-server --test-memory to verify it.\n\n"
1335*572c4311Sfengbojiang );
1336*572c4311Sfengbojiang 
1337*572c4311Sfengbojiang     /* free(messages); Don't call free() with possibly corrupted memory. */
1338*572c4311Sfengbojiang     if (server.daemonize && server.supervised == 0) unlink(server.pidfile);
1339*572c4311Sfengbojiang 
1340*572c4311Sfengbojiang     /* Make sure we exit with the right signal at the end. So for instance
1341*572c4311Sfengbojiang      * the core will be dumped if enabled. */
1342*572c4311Sfengbojiang     sigemptyset (&act.sa_mask);
1343*572c4311Sfengbojiang     act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
1344*572c4311Sfengbojiang     act.sa_handler = SIG_DFL;
1345*572c4311Sfengbojiang     sigaction (sig, &act, NULL);
1346*572c4311Sfengbojiang     kill(getpid(),sig);
1347*572c4311Sfengbojiang }
1348*572c4311Sfengbojiang #endif /* HAVE_BACKTRACE */
1349*572c4311Sfengbojiang 
1350*572c4311Sfengbojiang /* ==================== Logging functions for debugging ===================== */
1351*572c4311Sfengbojiang 
serverLogHexDump(int level,char * descr,void * value,size_t len)1352*572c4311Sfengbojiang void serverLogHexDump(int level, char *descr, void *value, size_t len) {
1353*572c4311Sfengbojiang     char buf[65], *b;
1354*572c4311Sfengbojiang     unsigned char *v = value;
1355*572c4311Sfengbojiang     char charset[] = "0123456789abcdef";
1356*572c4311Sfengbojiang 
1357*572c4311Sfengbojiang     serverLog(level,"%s (hexdump of %zu bytes):", descr, len);
1358*572c4311Sfengbojiang     b = buf;
1359*572c4311Sfengbojiang     while(len) {
1360*572c4311Sfengbojiang         b[0] = charset[(*v)>>4];
1361*572c4311Sfengbojiang         b[1] = charset[(*v)&0xf];
1362*572c4311Sfengbojiang         b[2] = '\0';
1363*572c4311Sfengbojiang         b += 2;
1364*572c4311Sfengbojiang         len--;
1365*572c4311Sfengbojiang         v++;
1366*572c4311Sfengbojiang         if (b-buf == 64 || len == 0) {
1367*572c4311Sfengbojiang             serverLogRaw(level|LL_RAW,buf);
1368*572c4311Sfengbojiang             b = buf;
1369*572c4311Sfengbojiang         }
1370*572c4311Sfengbojiang     }
1371*572c4311Sfengbojiang     serverLogRaw(level|LL_RAW,"\n");
1372*572c4311Sfengbojiang }
1373*572c4311Sfengbojiang 
1374*572c4311Sfengbojiang /* =========================== Software Watchdog ============================ */
1375*572c4311Sfengbojiang #include <sys/time.h>
1376*572c4311Sfengbojiang 
watchdogSignalHandler(int sig,siginfo_t * info,void * secret)1377*572c4311Sfengbojiang void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) {
1378*572c4311Sfengbojiang #ifdef HAVE_BACKTRACE
1379*572c4311Sfengbojiang     ucontext_t *uc = (ucontext_t*) secret;
1380*572c4311Sfengbojiang #else
1381*572c4311Sfengbojiang     (void)secret;
1382*572c4311Sfengbojiang #endif
1383*572c4311Sfengbojiang     UNUSED(info);
1384*572c4311Sfengbojiang     UNUSED(sig);
1385*572c4311Sfengbojiang 
1386*572c4311Sfengbojiang     serverLogFromHandler(LL_WARNING,"\n--- WATCHDOG TIMER EXPIRED ---");
1387*572c4311Sfengbojiang #ifdef HAVE_BACKTRACE
1388*572c4311Sfengbojiang     logStackTrace(uc);
1389*572c4311Sfengbojiang #else
1390*572c4311Sfengbojiang     serverLogFromHandler(LL_WARNING,"Sorry: no support for backtrace().");
1391*572c4311Sfengbojiang #endif
1392*572c4311Sfengbojiang     serverLogFromHandler(LL_WARNING,"--------\n");
1393*572c4311Sfengbojiang }
1394*572c4311Sfengbojiang 
1395*572c4311Sfengbojiang /* Schedule a SIGALRM delivery after the specified period in milliseconds.
1396*572c4311Sfengbojiang  * If a timer is already scheduled, this function will re-schedule it to the
1397*572c4311Sfengbojiang  * specified time. If period is 0 the current timer is disabled. */
watchdogScheduleSignal(int period)1398*572c4311Sfengbojiang void watchdogScheduleSignal(int period) {
1399*572c4311Sfengbojiang     struct itimerval it;
1400*572c4311Sfengbojiang 
1401*572c4311Sfengbojiang     /* Will stop the timer if period is 0. */
1402*572c4311Sfengbojiang     it.it_value.tv_sec = period/1000;
1403*572c4311Sfengbojiang     it.it_value.tv_usec = (period%1000)*1000;
1404*572c4311Sfengbojiang     /* Don't automatically restart. */
1405*572c4311Sfengbojiang     it.it_interval.tv_sec = 0;
1406*572c4311Sfengbojiang     it.it_interval.tv_usec = 0;
1407*572c4311Sfengbojiang     setitimer(ITIMER_REAL, &it, NULL);
1408*572c4311Sfengbojiang }
1409*572c4311Sfengbojiang 
1410*572c4311Sfengbojiang /* Enable the software watchdog with the specified period in milliseconds. */
enableWatchdog(int period)1411*572c4311Sfengbojiang void enableWatchdog(int period) {
1412*572c4311Sfengbojiang     int min_period;
1413*572c4311Sfengbojiang 
1414*572c4311Sfengbojiang     if (server.watchdog_period == 0) {
1415*572c4311Sfengbojiang         struct sigaction act;
1416*572c4311Sfengbojiang 
1417*572c4311Sfengbojiang         /* Watchdog was actually disabled, so we have to setup the signal
1418*572c4311Sfengbojiang          * handler. */
1419*572c4311Sfengbojiang         sigemptyset(&act.sa_mask);
1420*572c4311Sfengbojiang         act.sa_flags = SA_ONSTACK | SA_SIGINFO;
1421*572c4311Sfengbojiang         act.sa_sigaction = watchdogSignalHandler;
1422*572c4311Sfengbojiang         sigaction(SIGALRM, &act, NULL);
1423*572c4311Sfengbojiang     }
1424*572c4311Sfengbojiang     /* If the configured period is smaller than twice the timer period, it is
1425*572c4311Sfengbojiang      * too short for the software watchdog to work reliably. Fix it now
1426*572c4311Sfengbojiang      * if needed. */
1427*572c4311Sfengbojiang     min_period = (1000/server.hz)*2;
1428*572c4311Sfengbojiang     if (period < min_period) period = min_period;
1429*572c4311Sfengbojiang     watchdogScheduleSignal(period); /* Adjust the current timer. */
1430*572c4311Sfengbojiang     server.watchdog_period = period;
1431*572c4311Sfengbojiang }
1432*572c4311Sfengbojiang 
1433*572c4311Sfengbojiang /* Disable the software watchdog. */
disableWatchdog(void)1434*572c4311Sfengbojiang void disableWatchdog(void) {
1435*572c4311Sfengbojiang     struct sigaction act;
1436*572c4311Sfengbojiang     if (server.watchdog_period == 0) return; /* Already disabled. */
1437*572c4311Sfengbojiang     watchdogScheduleSignal(0); /* Stop the current timer. */
1438*572c4311Sfengbojiang 
1439*572c4311Sfengbojiang     /* Set the signal handler to SIG_IGN, this will also remove pending
1440*572c4311Sfengbojiang      * signals from the queue. */
1441*572c4311Sfengbojiang     sigemptyset(&act.sa_mask);
1442*572c4311Sfengbojiang     act.sa_flags = 0;
1443*572c4311Sfengbojiang     act.sa_handler = SIG_IGN;
1444*572c4311Sfengbojiang     sigaction(SIGALRM, &act, NULL);
1445*572c4311Sfengbojiang     server.watchdog_period = 0;
1446*572c4311Sfengbojiang }
1447