1/*
2 * Copyright (c) 2009-2020, Salvatore Sanfilippo <antirez at gmail dot com>
3 * Copyright (c) 2020, Redis Labs, Inc
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of Redis nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "server.h"
32#include "util.h"
33#include "sha1.h" /* SHA1 is used for DEBUG DIGEST */
34#include "crc64.h"
35#include "bio.h"
36#include "quicklist.h"
37
38#include <arpa/inet.h>
39#include <signal.h>
40#include <dlfcn.h>
41#include <fcntl.h>
42#include <sys/mman.h>
43#include <unistd.h>
44
45#ifdef HAVE_BACKTRACE
46#include <execinfo.h>
47#ifndef __OpenBSD__
48#include <ucontext.h>
49#else
50typedef ucontext_t sigcontext_t;
51#endif
52#endif /* HAVE_BACKTRACE */
53
54#ifdef __CYGWIN__
55#ifndef SA_ONSTACK
56#define SA_ONSTACK 0x08000000
57#endif
58#endif
59
60#if defined(__APPLE__) && defined(__arm64__)
61#include <mach/mach.h>
62#endif
63
64/* Globals */
65static int bug_report_start = 0; /* True if bug report header was already logged. */
66static pthread_mutex_t bug_report_start_mutex = PTHREAD_MUTEX_INITIALIZER;
67
68/* Forward declarations */
69void bugReportStart(void);
70void printCrashReport(void);
71void bugReportEnd(int killViaSignal, int sig);
72void logStackTrace(void *eip, int uplevel);
73
74/* ================================= Debugging ============================== */
75
76/* Compute the sha1 of string at 's' with 'len' bytes long.
77 * The SHA1 is then xored against the string pointed by digest.
78 * Since xor is commutative, this operation is used in order to
79 * "add" digests relative to unordered elements.
80 *
81 * So digest(a,b,c,d) will be the same of digest(b,a,c,d) */
82void xorDigest(unsigned char *digest, const void *ptr, size_t len) {
83 SHA1_CTX ctx;
84 unsigned char hash[20];
85 int j;
86
87 SHA1Init(&ctx);
88 SHA1Update(&ctx,ptr,len);
89 SHA1Final(hash,&ctx);
90
91 for (j = 0; j < 20; j++)
92 digest[j] ^= hash[j];
93}
94
95void xorStringObjectDigest(unsigned char *digest, robj *o) {
96 o = getDecodedObject(o);
97 xorDigest(digest,o->ptr,sdslen(o->ptr));
98 decrRefCount(o);
99}
100
101/* This function instead of just computing the SHA1 and xoring it
102 * against digest, also perform the digest of "digest" itself and
103 * replace the old value with the new one.
104 *
105 * So the final digest will be:
106 *
107 * digest = SHA1(digest xor SHA1(data))
108 *
109 * This function is used every time we want to preserve the order so
110 * that digest(a,b,c,d) will be different than digest(b,c,d,a)
111 *
112 * Also note that mixdigest("foo") followed by mixdigest("bar")
113 * will lead to a different digest compared to "fo", "obar".
114 */
115void mixDigest(unsigned char *digest, const void *ptr, size_t len) {
116 SHA1_CTX ctx;
117
118 xorDigest(digest,ptr,len);
119 SHA1Init(&ctx);
120 SHA1Update(&ctx,digest,20);
121 SHA1Final(digest,&ctx);
122}
123
124void mixStringObjectDigest(unsigned char *digest, robj *o) {
125 o = getDecodedObject(o);
126 mixDigest(digest,o->ptr,sdslen(o->ptr));
127 decrRefCount(o);
128}
129
130/* This function computes the digest of a data structure stored in the
131 * object 'o'. It is the core of the DEBUG DIGEST command: when taking the
132 * digest of a whole dataset, we take the digest of the key and the value
133 * pair, and xor all those together.
134 *
135 * Note that this function does not reset the initial 'digest' passed, it
136 * will continue mixing this object digest to anything that was already
137 * present. */
138void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o) {
139 uint32_t aux = htonl(o->type);
140 mixDigest(digest,&aux,sizeof(aux));
141 long long expiretime = getExpire(db,keyobj);
142 char buf[128];
143
144 /* Save the key and associated value */
145 if (o->type == OBJ_STRING) {
146 mixStringObjectDigest(digest,o);
147 } else if (o->type == OBJ_LIST) {
148 listTypeIterator *li = listTypeInitIterator(o,0,LIST_TAIL);
149 listTypeEntry entry;
150 while(listTypeNext(li,&entry)) {
151 robj *eleobj = listTypeGet(&entry);
152 mixStringObjectDigest(digest,eleobj);
153 decrRefCount(eleobj);
154 }
155 listTypeReleaseIterator(li);
156 } else if (o->type == OBJ_SET) {
157 setTypeIterator *si = setTypeInitIterator(o);
158 sds sdsele;
159 while((sdsele = setTypeNextObject(si)) != NULL) {
160 xorDigest(digest,sdsele,sdslen(sdsele));
161 sdsfree(sdsele);
162 }
163 setTypeReleaseIterator(si);
164 } else if (o->type == OBJ_ZSET) {
165 unsigned char eledigest[20];
166
167 if (o->encoding == OBJ_ENCODING_LISTPACK) {
168 unsigned char *zl = o->ptr;
169 unsigned char *eptr, *sptr;
170 unsigned char *vstr;
171 unsigned int vlen;
172 long long vll;
173 double score;
174
175 eptr = lpSeek(zl,0);
176 serverAssert(eptr != NULL);
177 sptr = lpNext(zl,eptr);
178 serverAssert(sptr != NULL);
179
180 while (eptr != NULL) {
181 vstr = lpGetValue(eptr,&vlen,&vll);
182 score = zzlGetScore(sptr);
183
184 memset(eledigest,0,20);
185 if (vstr != NULL) {
186 mixDigest(eledigest,vstr,vlen);
187 } else {
188 ll2string(buf,sizeof(buf),vll);
189 mixDigest(eledigest,buf,strlen(buf));
190 }
191
192 snprintf(buf,sizeof(buf),"%.17g",score);
193 mixDigest(eledigest,buf,strlen(buf));
194 xorDigest(digest,eledigest,20);
195 zzlNext(zl,&eptr,&sptr);
196 }
197 } else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
198 zset *zs = o->ptr;
199 dictIterator *di = dictGetIterator(zs->dict);
200 dictEntry *de;
201
202 while((de = dictNext(di)) != NULL) {
203 sds sdsele = dictGetKey(de);
204 double *score = dictGetVal(de);
205
206 snprintf(buf,sizeof(buf),"%.17g",*score);
207 memset(eledigest,0,20);
208 mixDigest(eledigest,sdsele,sdslen(sdsele));
209 mixDigest(eledigest,buf,strlen(buf));
210 xorDigest(digest,eledigest,20);
211 }
212 dictReleaseIterator(di);
213 } else {
214 serverPanic("Unknown sorted set encoding");
215 }
216 } else if (o->type == OBJ_HASH) {
217 hashTypeIterator *hi = hashTypeInitIterator(o);
218 while (hashTypeNext(hi) != C_ERR) {
219 unsigned char eledigest[20];
220 sds sdsele;
221
222 memset(eledigest,0,20);
223 sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY);
224 mixDigest(eledigest,sdsele,sdslen(sdsele));
225 sdsfree(sdsele);
226 sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE);
227 mixDigest(eledigest,sdsele,sdslen(sdsele));
228 sdsfree(sdsele);
229 xorDigest(digest,eledigest,20);
230 }
231 hashTypeReleaseIterator(hi);
232 } else if (o->type == OBJ_STREAM) {
233 streamIterator si;
234 streamIteratorStart(&si,o->ptr,NULL,NULL,0);
235 streamID id;
236 int64_t numfields;
237
238 while(streamIteratorGetID(&si,&id,&numfields)) {
239 sds itemid = sdscatfmt(sdsempty(),"%U.%U",id.ms,id.seq);
240 mixDigest(digest,itemid,sdslen(itemid));
241 sdsfree(itemid);
242
243 while(numfields--) {
244 unsigned char *field, *value;
245 int64_t field_len, value_len;
246 streamIteratorGetField(&si,&field,&value,
247 &field_len,&value_len);
248 mixDigest(digest,field,field_len);
249 mixDigest(digest,value,value_len);
250 }
251 }
252 streamIteratorStop(&si);
253 } else if (o->type == OBJ_MODULE) {
254 RedisModuleDigest md = {{0},{0},keyobj,db->id};
255 moduleValue *mv = o->ptr;
256 moduleType *mt = mv->type;
257 moduleInitDigestContext(md);
258 if (mt->digest) {
259 mt->digest(&md,mv->value);
260 xorDigest(digest,md.x,sizeof(md.x));
261 }
262 } else {
263 serverPanic("Unknown object type");
264 }
265 /* If the key has an expire, add it to the mix */
266 if (expiretime != -1) xorDigest(digest,"!!expire!!",10);
267}
268
269/* Compute the dataset digest. Since keys, sets elements, hashes elements
270 * are not ordered, we use a trick: every aggregate digest is the xor
271 * of the digests of their elements. This way the order will not change
272 * the result. For list instead we use a feedback entering the output digest
273 * as input in order to ensure that a different ordered list will result in
274 * a different digest. */
275void computeDatasetDigest(unsigned char *final) {
276 unsigned char digest[20];
277 dictIterator *di = NULL;
278 dictEntry *de;
279 int j;
280 uint32_t aux;
281
282 memset(final,0,20); /* Start with a clean result */
283
284 for (j = 0; j < server.dbnum; j++) {
285 redisDb *db = server.db+j;
286
287 if (dictSize(db->dict) == 0) continue;
288 di = dictGetSafeIterator(db->dict);
289
290 /* hash the DB id, so the same dataset moved in a different
291 * DB will lead to a different digest */
292 aux = htonl(j);
293 mixDigest(final,&aux,sizeof(aux));
294
295 /* Iterate this DB writing every entry */
296 while((de = dictNext(di)) != NULL) {
297 sds key;
298 robj *keyobj, *o;
299
300 memset(digest,0,20); /* This key-val digest */
301 key = dictGetKey(de);
302 keyobj = createStringObject(key,sdslen(key));
303
304 mixDigest(digest,key,sdslen(key));
305
306 o = dictGetVal(de);
307 xorObjectDigest(db,keyobj,digest,o);
308
309 /* We can finally xor the key-val digest to the final digest */
310 xorDigest(final,digest,20);
311 decrRefCount(keyobj);
312 }
313 dictReleaseIterator(di);
314 }
315}
316
317#ifdef USE_JEMALLOC
318void mallctl_int(client *c, robj **argv, int argc) {
319 int ret;
320 /* start with the biggest size (int64), and if that fails, try smaller sizes (int32, bool) */
321 int64_t old = 0, val;
322 if (argc > 1) {
323 long long ll;
324 if (getLongLongFromObjectOrReply(c, argv[1], &ll, NULL) != C_OK)
325 return;
326 val = ll;
327 }
328 size_t sz = sizeof(old);
329 while (sz > 0) {
330 if ((ret=je_mallctl(argv[0]->ptr, &old, &sz, argc > 1? &val: NULL, argc > 1?sz: 0))) {
331 if (ret == EPERM && argc > 1) {
332 /* if this option is write only, try just writing to it. */
333 if (!(ret=je_mallctl(argv[0]->ptr, NULL, 0, &val, sz))) {
334 addReply(c, shared.ok);
335 return;
336 }
337 }
338 if (ret==EINVAL) {
339 /* size might be wrong, try a smaller one */
340 sz /= 2;
341#if BYTE_ORDER == BIG_ENDIAN
342 val <<= 8*sz;
343#endif
344 continue;
345 }
346 addReplyErrorFormat(c,"%s", strerror(ret));
347 return;
348 } else {
349#if BYTE_ORDER == BIG_ENDIAN
350 old >>= 64 - 8*sz;
351#endif
352 addReplyLongLong(c, old);
353 return;
354 }
355 }
356 addReplyErrorFormat(c,"%s", strerror(EINVAL));
357}
358
359void mallctl_string(client *c, robj **argv, int argc) {
360 int rret, wret;
361 char *old;
362 size_t sz = sizeof(old);
363 /* for strings, it seems we need to first get the old value, before overriding it. */
364 if ((rret=je_mallctl(argv[0]->ptr, &old, &sz, NULL, 0))) {
365 /* return error unless this option is write only. */
366 if (!(rret == EPERM && argc > 1)) {
367 addReplyErrorFormat(c,"%s", strerror(rret));
368 return;
369 }
370 }
371 if(argc > 1) {
372 char *val = argv[1]->ptr;
373 char **valref = &val;
374 if ((!strcmp(val,"VOID")))
375 valref = NULL, sz = 0;
376 wret = je_mallctl(argv[0]->ptr, NULL, 0, valref, sz);
377 }
378 if (!rret)
379 addReplyBulkCString(c, old);
380 else if (wret)
381 addReplyErrorFormat(c,"%s", strerror(wret));
382 else
383 addReply(c, shared.ok);
384}
385#endif
386
387void debugCommand(client *c) {
388 if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) {
389 const char *help[] = {
390"AOF-FLUSH-SLEEP <microsec>",
391" Server will sleep before flushing the AOF, this is used for testing.",
392"ASSERT",
393" Crash by assertion failed.",
394"CHANGE-REPL-ID",
395" Change the replication IDs of the instance.",
396" Dangerous: should be used only for testing the replication subsystem.",
397"CONFIG-REWRITE-FORCE-ALL",
398" Like CONFIG REWRITE but writes all configuration options, including",
399" keywords not listed in original configuration file or default values.",
400"CRASH-AND-RECOVER [<milliseconds>]",
401" Hard crash and restart after a <milliseconds> delay (default 0).",
402"DIGEST",
403" Output a hex signature representing the current DB content.",
404"DIGEST-VALUE <key> [<key> ...]",
405" Output a hex signature of the values of all the specified keys.",
406"ERROR <string>",
407" Return a Redis protocol error with <string> as message. Useful for clients",
408" unit tests to simulate Redis errors.",
409"LEAK <string>",
410" Create a memory leak of the input string.",
411"LOG <message>",
412" Write <message> to the server log.",
413"HTSTATS <dbid>",
414" Return hash table statistics of the specified Redis database.",
415"HTSTATS-KEY <key>",
416" Like HTSTATS but for the hash table stored at <key>'s value.",
417"LOADAOF",
418" Flush the AOF buffers on disk and reload the AOF in memory.",
419"REPLICATE <string>",
420" Replicates the provided string to replicas, allowing data divergence.",
421#ifdef USE_JEMALLOC
422"MALLCTL <key> [<val>]",
423" Get or set a malloc tuning integer.",
424"MALLCTL-STR <key> [<val>]",
425" Get or set a malloc tuning string.",
426#endif
427"OBJECT <key>",
428" Show low level info about `key` and associated value.",
429"DROP-CLUSTER-PACKET-FILTER <packet-type>",
430" Drop all packets that match the filtered type. Set to -1 allow all packets.",
431"OOM",
432" Crash the server simulating an out-of-memory error.",
433"PANIC",
434" Crash the server simulating a panic.",
435"POPULATE <count> [<prefix>] [<size>]",
436" Create <count> string keys named key:<num>. If <prefix> is specified then",
437" it is used instead of the 'key' prefix. These are not propagated to",
438" replicas. Cluster slots are not respected so keys not belonging to the",
439" current node can be created in cluster mode.",
440"PROTOCOL <type>",
441" Reply with a test value of the specified type. <type> can be: string,",
442" integer, double, bignum, null, array, set, map, attrib, push, verbatim,",
443" true, false.",
444"RELOAD [option ...]",
445" Save the RDB on disk and reload it back to memory. Valid <option> values:",
446" * MERGE: conflicting keys will be loaded from RDB.",
447" * NOFLUSH: the existing database will not be removed before load, but",
448" conflicting keys will generate an exception and kill the server.",
449" * NOSAVE: the database will be loaded from an existing RDB file.",
450" Examples:",
451" * DEBUG RELOAD: verify that the server is able to persist, flush and reload",
452" the database.",
453" * DEBUG RELOAD NOSAVE: replace the current database with the contents of an",
454" existing RDB file.",
455" * DEBUG RELOAD NOSAVE NOFLUSH MERGE: add the contents of an existing RDB",
456" file to the database.",
457"RESTART [<milliseconds>]",
458" Graceful restart: save config, db, restart after a <milliseconds> delay (default 0).",
459"SDSLEN <key>",
460" Show low level SDS string info representing `key` and value.",
461"SEGFAULT",
462" Crash the server with sigsegv.",
463"SET-ACTIVE-EXPIRE <0|1>",
464" Setting it to 0 disables expiring keys in background when they are not",
465" accessed (otherwise the Redis behavior). Setting it to 1 reenables back the",
466" default.",
467"QUICKLIST-PACKED-THRESHOLD <size>",
468" Sets the threshold for elements to be inserted as plain vs packed nodes",
469" Default value is 1GB, allows values up to 4GB",
470"SET-SKIP-CHECKSUM-VALIDATION <0|1>",
471" Enables or disables checksum checks for RDB files and RESTORE's payload.",
472"SLEEP <seconds>",
473" Stop the server for <seconds>. Decimals allowed.",
474"STRINGMATCH-TEST",
475" Run a fuzz tester against the stringmatchlen() function.",
476"STRUCTSIZE",
477" Return the size of different Redis core C structures.",
478"LISTPACK <key>",
479" Show low level info about the listpack encoding of <key>.",
480"QUICKLIST <key> [<0|1>]",
481" Show low level info about the quicklist encoding of <key>.",
482" The optional argument (0 by default) sets the level of detail",
483"CLIENT-EVICTION",
484" Show low level client eviction pools info (maxmemory-clients).",
485"PAUSE-CRON <0|1>",
486" Stop periodic cron job processing.",
487"REPLYBUFFER PEAK-RESET-TIME <NEVER||RESET|time>",
488" Sets the time (in milliseconds) to wait between client reply buffer peak resets.",
489" In case NEVER is provided the last observed peak will never be reset",
490" In case RESET is provided the peak reset time will be restored to the default value",
491"REPLYBUFFER RESIZING <0|1>",
492" Enable or disable the replay buffer resize cron job",
493NULL
494 };
495 addReplyHelp(c, help);
496 } else if (!strcasecmp(c->argv[1]->ptr,"segfault")) {
497 /* Compiler gives warnings about writing to a random address
498 * e.g "*((char*)-1) = 'x';". As a workaround, we map a read-only area
499 * and try to write there to trigger segmentation fault. */
500 char* p = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
501 *p = 'x';
502 } else if (!strcasecmp(c->argv[1]->ptr,"panic")) {
503 serverPanic("DEBUG PANIC called at Unix time %lld", (long long)time(NULL));
504 } else if (!strcasecmp(c->argv[1]->ptr,"restart") ||
505 !strcasecmp(c->argv[1]->ptr,"crash-and-recover"))
506 {
507 long long delay = 0;
508 if (c->argc >= 3) {
509 if (getLongLongFromObjectOrReply(c, c->argv[2], &delay, NULL)
510 != C_OK) return;
511 if (delay < 0) delay = 0;
512 }
513 int flags = !strcasecmp(c->argv[1]->ptr,"restart") ?
514 (RESTART_SERVER_GRACEFULLY|RESTART_SERVER_CONFIG_REWRITE) :
515 RESTART_SERVER_NONE;
516 restartServer(flags,delay);
517 addReplyError(c,"failed to restart the server. Check server logs.");
518 } else if (!strcasecmp(c->argv[1]->ptr,"oom")) {
519 void *ptr = zmalloc(ULONG_MAX); /* Should trigger an out of memory. */
520 zfree(ptr);
521 addReply(c,shared.ok);
522 } else if (!strcasecmp(c->argv[1]->ptr,"assert")) {
523 serverAssertWithInfo(c,c->argv[0],1 == 2);
524 } else if (!strcasecmp(c->argv[1]->ptr,"log") && c->argc == 3) {
525 serverLog(LL_WARNING, "DEBUG LOG: %s", (char*)c->argv[2]->ptr);
526 addReply(c,shared.ok);
527 } else if (!strcasecmp(c->argv[1]->ptr,"leak") && c->argc == 3) {
528 sdsdup(c->argv[2]->ptr);
529 addReply(c,shared.ok);
530 } else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
531 int flush = 1, save = 1;
532 int flags = RDBFLAGS_NONE;
533
534 /* Parse the additional options that modify the RELOAD
535 * behavior. */
536 for (int j = 2; j < c->argc; j++) {
537 char *opt = c->argv[j]->ptr;
538 if (!strcasecmp(opt,"MERGE")) {
539 flags |= RDBFLAGS_ALLOW_DUP;
540 } else if (!strcasecmp(opt,"NOFLUSH")) {
541 flush = 0;
542 } else if (!strcasecmp(opt,"NOSAVE")) {
543 save = 0;
544 } else {
545 addReplyError(c,"DEBUG RELOAD only supports the "
546 "MERGE, NOFLUSH and NOSAVE options.");
547 return;
548 }
549 }
550
551 /* The default behavior is to save the RDB file before loading
552 * it back. */
553 if (save) {
554 rdbSaveInfo rsi, *rsiptr;
555 rsiptr = rdbPopulateSaveInfo(&rsi);
556 if (rdbSave(SLAVE_REQ_NONE,server.rdb_filename,rsiptr) != C_OK) {
557 addReplyErrorObject(c,shared.err);
558 return;
559 }
560 }
561
562 /* The default behavior is to remove the current dataset from
563 * memory before loading the RDB file, however when MERGE is
564 * used together with NOFLUSH, we are able to merge two datasets. */
565 if (flush) emptyData(-1,EMPTYDB_NO_FLAGS,NULL);
566
567 protectClient(c);
568 int ret = rdbLoad(server.rdb_filename,NULL,flags);
569 unprotectClient(c);
570 if (ret != C_OK) {
571 addReplyError(c,"Error trying to load the RDB dump");
572 return;
573 }
574 serverLog(LL_WARNING,"DB reloaded by DEBUG RELOAD");
575 addReply(c,shared.ok);
576 } else if (!strcasecmp(c->argv[1]->ptr,"loadaof")) {
577 if (server.aof_state != AOF_OFF) flushAppendOnlyFile(1);
578 emptyData(-1,EMPTYDB_NO_FLAGS,NULL);
579 protectClient(c);
580 if (server.aof_manifest) aofManifestFree(server.aof_manifest);
581 aofLoadManifestFromDisk();
582 aofDelHistoryFiles();
583 int ret = loadAppendOnlyFiles(server.aof_manifest);
584 if (ret != AOF_OK && ret != AOF_EMPTY)
585 exit(1);
586 unprotectClient(c);
587 server.dirty = 0; /* Prevent AOF / replication */
588 serverLog(LL_WARNING,"Append Only File loaded by DEBUG LOADAOF");
589 addReply(c,shared.ok);
590 } else if (!strcasecmp(c->argv[1]->ptr,"drop-cluster-packet-filter") && c->argc == 3) {
591 long packet_type;
592 if (getLongFromObjectOrReply(c, c->argv[2], &packet_type, NULL) != C_OK)
593 return;
594 server.cluster_drop_packet_filter = packet_type;
595 addReply(c,shared.ok);
596 } else if (!strcasecmp(c->argv[1]->ptr,"object") && c->argc == 3) {
597 dictEntry *de;
598 robj *val;
599 char *strenc;
600
601 if ((de = dictFind(c->db->dict,c->argv[2]->ptr)) == NULL) {
602 addReplyErrorObject(c,shared.nokeyerr);
603 return;
604 }
605 val = dictGetVal(de);
606 strenc = strEncoding(val->encoding);
607
608 char extra[138] = {0};
609 if (val->encoding == OBJ_ENCODING_QUICKLIST) {
610 char *nextra = extra;
611 int remaining = sizeof(extra);
612 quicklist *ql = val->ptr;
613 /* Add number of quicklist nodes */
614 int used = snprintf(nextra, remaining, " ql_nodes:%lu", ql->len);
615 nextra += used;
616 remaining -= used;
617 /* Add average quicklist fill factor */
618 double avg = (double)ql->count/ql->len;
619 used = snprintf(nextra, remaining, " ql_avg_node:%.2f", avg);
620 nextra += used;
621 remaining -= used;
622 /* Add quicklist fill level / max listpack size */
623 used = snprintf(nextra, remaining, " ql_listpack_max:%d", ql->fill);
624 nextra += used;
625 remaining -= used;
626 /* Add isCompressed? */
627 int compressed = ql->compress != 0;
628 used = snprintf(nextra, remaining, " ql_compressed:%d", compressed);
629 nextra += used;
630 remaining -= used;
631 /* Add total uncompressed size */
632 unsigned long sz = 0;
633 for (quicklistNode *node = ql->head; node; node = node->next) {
634 sz += node->sz;
635 }
636 used = snprintf(nextra, remaining, " ql_uncompressed_size:%lu", sz);
637 nextra += used;
638 remaining -= used;
639 }
640
641 addReplyStatusFormat(c,
642 "Value at:%p refcount:%d "
643 "encoding:%s serializedlength:%zu "
644 "lru:%d lru_seconds_idle:%llu%s",
645 (void*)val, val->refcount,
646 strenc, rdbSavedObjectLen(val, c->argv[2], c->db->id),
647 val->lru, estimateObjectIdleTime(val)/1000, extra);
648 } else if (!strcasecmp(c->argv[1]->ptr,"sdslen") && c->argc == 3) {
649 dictEntry *de;
650 robj *val;
651 sds key;
652
653 if ((de = dictFind(c->db->dict,c->argv[2]->ptr)) == NULL) {
654 addReplyErrorObject(c,shared.nokeyerr);
655 return;
656 }
657 val = dictGetVal(de);
658 key = dictGetKey(de);
659
660 if (val->type != OBJ_STRING || !sdsEncodedObject(val)) {
661 addReplyError(c,"Not an sds encoded string.");
662 } else {
663 addReplyStatusFormat(c,
664 "key_sds_len:%lld, key_sds_avail:%lld, key_zmalloc: %lld, "
665 "val_sds_len:%lld, val_sds_avail:%lld, val_zmalloc: %lld",
666 (long long) sdslen(key),
667 (long long) sdsavail(key),
668 (long long) sdsZmallocSize(key),
669 (long long) sdslen(val->ptr),
670 (long long) sdsavail(val->ptr),
671 (long long) getStringObjectSdsUsedMemory(val));
672 }
673 } else if (!strcasecmp(c->argv[1]->ptr,"listpack") && c->argc == 3) {
674 robj *o;
675
676 if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nokeyerr))
677 == NULL) return;
678
679 if (o->encoding != OBJ_ENCODING_LISTPACK) {
680 addReplyError(c,"Not a listpack encoded object.");
681 } else {
682 lpRepr(o->ptr);
683 addReplyStatus(c,"Listpack structure printed on stdout");
684 }
685 } else if (!strcasecmp(c->argv[1]->ptr,"quicklist") && (c->argc == 3 || c->argc == 4)) {
686 robj *o;
687
688 if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nokeyerr))
689 == NULL) return;
690
691 int full = 0;
692 if (c->argc == 4)
693 full = atoi(c->argv[3]->ptr);
694 if (o->encoding != OBJ_ENCODING_QUICKLIST) {
695 addReplyError(c,"Not a quicklist encoded object.");
696 } else {
697 quicklistRepr(o->ptr, full);
698 addReplyStatus(c,"Quicklist structure printed on stdout");
699 }
700 } else if (!strcasecmp(c->argv[1]->ptr,"populate") &&
701 c->argc >= 3 && c->argc <= 5) {
702 long keys, j;
703 robj *key, *val;
704 char buf[128];
705
706 if (getPositiveLongFromObjectOrReply(c, c->argv[2], &keys, NULL) != C_OK)
707 return;
708
709 dictExpand(c->db->dict,keys);
710 long valsize = 0;
711 if ( c->argc == 5 && getPositiveLongFromObjectOrReply(c, c->argv[4], &valsize, NULL) != C_OK )
712 return;
713
714 for (j = 0; j < keys; j++) {
715 snprintf(buf,sizeof(buf),"%s:%lu",
716 (c->argc == 3) ? "key" : (char*)c->argv[3]->ptr, j);
717 key = createStringObject(buf,strlen(buf));
718 if (lookupKeyWrite(c->db,key) != NULL) {
719 decrRefCount(key);
720 continue;
721 }
722 snprintf(buf,sizeof(buf),"value:%lu",j);
723 if (valsize==0)
724 val = createStringObject(buf,strlen(buf));
725 else {
726 int buflen = strlen(buf);
727 val = createStringObject(NULL,valsize);
728 memcpy(val->ptr, buf, valsize<=buflen? valsize: buflen);
729 }
730 dbAdd(c->db,key,val);
731 signalModifiedKey(c,c->db,key);
732 decrRefCount(key);
733 }
734 addReply(c,shared.ok);
735 } else if (!strcasecmp(c->argv[1]->ptr,"digest") && c->argc == 2) {
736 /* DEBUG DIGEST (form without keys specified) */
737 unsigned char digest[20];
738 sds d = sdsempty();
739
740 computeDatasetDigest(digest);
741 for (int i = 0; i < 20; i++) d = sdscatprintf(d, "%02x",digest[i]);
742 addReplyStatus(c,d);
743 sdsfree(d);
744 } else if (!strcasecmp(c->argv[1]->ptr,"digest-value") && c->argc >= 2) {
745 /* DEBUG DIGEST-VALUE key key key ... key. */
746 addReplyArrayLen(c,c->argc-2);
747 for (int j = 2; j < c->argc; j++) {
748 unsigned char digest[20];
749 memset(digest,0,20); /* Start with a clean result */
750
751 /* We don't use lookupKey because a debug command should
752 * work on logically expired keys */
753 dictEntry *de;
754 robj *o = ((de = dictFind(c->db->dict,c->argv[j]->ptr)) == NULL) ? NULL : dictGetVal(de);
755 if (o) xorObjectDigest(c->db,c->argv[j],digest,o);
756
757 sds d = sdsempty();
758 for (int i = 0; i < 20; i++) d = sdscatprintf(d, "%02x",digest[i]);
759 addReplyStatus(c,d);
760 sdsfree(d);
761 }
762 } else if (!strcasecmp(c->argv[1]->ptr,"protocol") && c->argc == 3) {
763 /* DEBUG PROTOCOL [string|integer|double|bignum|null|array|set|map|
764 * attrib|push|verbatim|true|false] */
765 char *name = c->argv[2]->ptr;
766 if (!strcasecmp(name,"string")) {
767 addReplyBulkCString(c,"Hello World");
768 } else if (!strcasecmp(name,"integer")) {
769 addReplyLongLong(c,12345);
770 } else if (!strcasecmp(name,"double")) {
771 addReplyDouble(c,3.141);
772 } else if (!strcasecmp(name,"bignum")) {
773 addReplyBigNum(c,"1234567999999999999999999999999999999",37);
774 } else if (!strcasecmp(name,"null")) {
775 addReplyNull(c);
776 } else if (!strcasecmp(name,"array")) {
777 addReplyArrayLen(c,3);
778 for (int j = 0; j < 3; j++) addReplyLongLong(c,j);
779 } else if (!strcasecmp(name,"set")) {
780 addReplySetLen(c,3);
781 for (int j = 0; j < 3; j++) addReplyLongLong(c,j);
782 } else if (!strcasecmp(name,"map")) {
783 addReplyMapLen(c,3);
784 for (int j = 0; j < 3; j++) {
785 addReplyLongLong(c,j);
786 addReplyBool(c, j == 1);
787 }
788 } else if (!strcasecmp(name,"attrib")) {
789 if (c->resp >= 3) {
790 addReplyAttributeLen(c,1);
791 addReplyBulkCString(c,"key-popularity");
792 addReplyArrayLen(c,2);
793 addReplyBulkCString(c,"key:123");
794 addReplyLongLong(c,90);
795 }
796 /* Attributes are not real replies, so a well formed reply should
797 * also have a normal reply type after the attribute. */
798 addReplyBulkCString(c,"Some real reply following the attribute");
799 } else if (!strcasecmp(name,"push")) {
800 if (c->resp < 3) {
801 addReplyError(c,"RESP2 is not supported by this command");
802 return;
803 }
804 addReplyPushLen(c,2);
805 addReplyBulkCString(c,"server-cpu-usage");
806 addReplyLongLong(c,42);
807 /* Push replies are not synchronous replies, so we emit also a
808 * normal reply in order for blocking clients just discarding the
809 * push reply, to actually consume the reply and continue. */
810 addReplyBulkCString(c,"Some real reply following the push reply");
811 } else if (!strcasecmp(name,"true")) {
812 addReplyBool(c,1);
813 } else if (!strcasecmp(name,"false")) {
814 addReplyBool(c,0);
815 } else if (!strcasecmp(name,"verbatim")) {
816 addReplyVerbatim(c,"This is a verbatim\nstring",25,"txt");
817 } else {
818 addReplyError(c,"Wrong protocol type name. Please use one of the following: string|integer|double|bignum|null|array|set|map|attrib|push|verbatim|true|false");
819 }
820 } else if (!strcasecmp(c->argv[1]->ptr,"sleep") && c->argc == 3) {
821 double dtime = strtod(c->argv[2]->ptr,NULL);
822 long long utime = dtime*1000000;
823 struct timespec tv;
824
825 tv.tv_sec = utime / 1000000;
826 tv.tv_nsec = (utime % 1000000) * 1000;
827 nanosleep(&tv, NULL);
828 addReply(c,shared.ok);
829 } else if (!strcasecmp(c->argv[1]->ptr,"set-active-expire") &&
830 c->argc == 3)
831 {
832 server.active_expire_enabled = atoi(c->argv[2]->ptr);
833 addReply(c,shared.ok);
834 } else if (!strcasecmp(c->argv[1]->ptr,"quicklist-packed-threshold") &&
835 c->argc == 3)
836 {
837 int memerr;
838 unsigned long long sz = memtoull((const char *)c->argv[2]->ptr, &memerr);
839 if (memerr || !quicklistisSetPackedThreshold(sz)) {
840 addReplyError(c, "argument must be a memory value bigger than 1 and smaller than 4gb");
841 } else {
842 addReply(c,shared.ok);
843 }
844 } else if (!strcasecmp(c->argv[1]->ptr,"set-skip-checksum-validation") &&
845 c->argc == 3)
846 {
847 server.skip_checksum_validation = atoi(c->argv[2]->ptr);
848 addReply(c,shared.ok);
849 } else if (!strcasecmp(c->argv[1]->ptr,"aof-flush-sleep") &&
850 c->argc == 3)
851 {
852 server.aof_flush_sleep = atoi(c->argv[2]->ptr);
853 addReply(c,shared.ok);
854 } else if (!strcasecmp(c->argv[1]->ptr,"replicate") && c->argc >= 3) {
855 replicationFeedSlaves(server.slaves, server.slaveseldb,
856 c->argv + 2, c->argc - 2);
857 addReply(c,shared.ok);
858 } else if (!strcasecmp(c->argv[1]->ptr,"error") && c->argc == 3) {
859 sds errstr = sdsnewlen("-",1);
860
861 errstr = sdscatsds(errstr,c->argv[2]->ptr);
862 errstr = sdsmapchars(errstr,"\n\r"," ",2); /* no newlines in errors. */
863 errstr = sdscatlen(errstr,"\r\n",2);
864 addReplySds(c,errstr);
865 } else if (!strcasecmp(c->argv[1]->ptr,"structsize") && c->argc == 2) {
866 sds sizes = sdsempty();
867 sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32);
868 sizes = sdscatprintf(sizes,"robj:%d ",(int)sizeof(robj));
869 sizes = sdscatprintf(sizes,"dictentry:%d ",(int)sizeof(dictEntry));
870 sizes = sdscatprintf(sizes,"sdshdr5:%d ",(int)sizeof(struct sdshdr5));
871 sizes = sdscatprintf(sizes,"sdshdr8:%d ",(int)sizeof(struct sdshdr8));
872 sizes = sdscatprintf(sizes,"sdshdr16:%d ",(int)sizeof(struct sdshdr16));
873 sizes = sdscatprintf(sizes,"sdshdr32:%d ",(int)sizeof(struct sdshdr32));
874 sizes = sdscatprintf(sizes,"sdshdr64:%d ",(int)sizeof(struct sdshdr64));
875 addReplyBulkSds(c,sizes);
876 } else if (!strcasecmp(c->argv[1]->ptr,"htstats") && c->argc == 3) {
877 long dbid;
878 sds stats = sdsempty();
879 char buf[4096];
880
881 if (getLongFromObjectOrReply(c, c->argv[2], &dbid, NULL) != C_OK) {
882 sdsfree(stats);
883 return;
884 }
885 if (dbid < 0 || dbid >= server.dbnum) {
886 sdsfree(stats);
887 addReplyError(c,"Out of range database");
888 return;
889 }
890
891 stats = sdscatprintf(stats,"[Dictionary HT]\n");
892 dictGetStats(buf,sizeof(buf),server.db[dbid].dict);
893 stats = sdscat(stats,buf);
894
895 stats = sdscatprintf(stats,"[Expires HT]\n");
896 dictGetStats(buf,sizeof(buf),server.db[dbid].expires);
897 stats = sdscat(stats,buf);
898
899 addReplyVerbatim(c,stats,sdslen(stats),"txt");
900 sdsfree(stats);
901 } else if (!strcasecmp(c->argv[1]->ptr,"htstats-key") && c->argc == 3) {
902 robj *o;
903 dict *ht = NULL;
904
905 if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nokeyerr))
906 == NULL) return;
907
908 /* Get the hash table reference from the object, if possible. */
909 switch (o->encoding) {
910 case OBJ_ENCODING_SKIPLIST:
911 {
912 zset *zs = o->ptr;
913 ht = zs->dict;
914 }
915 break;
916 case OBJ_ENCODING_HT:
917 ht = o->ptr;
918 break;
919 }
920
921 if (ht == NULL) {
922 addReplyError(c,"The value stored at the specified key is not "
923 "represented using an hash table");
924 } else {
925 char buf[4096];
926 dictGetStats(buf,sizeof(buf),ht);
927 addReplyVerbatim(c,buf,strlen(buf),"txt");
928 }
929 } else if (!strcasecmp(c->argv[1]->ptr,"change-repl-id") && c->argc == 2) {
930 serverLog(LL_WARNING,"Changing replication IDs after receiving DEBUG change-repl-id");
931 changeReplicationId();
932 clearReplicationId2();
933 addReply(c,shared.ok);
934 } else if (!strcasecmp(c->argv[1]->ptr,"stringmatch-test") && c->argc == 2)
935 {
936 stringmatchlen_fuzz_test();
937 addReplyStatus(c,"Apparently Redis did not crash: test passed");
938 } else if (!strcasecmp(c->argv[1]->ptr,"set-disable-deny-scripts") && c->argc == 3)
939 {
940 server.script_disable_deny_script = atoi(c->argv[2]->ptr);
941 addReply(c,shared.ok);
942 } else if (!strcasecmp(c->argv[1]->ptr,"config-rewrite-force-all") && c->argc == 2)
943 {
944 if (rewriteConfig(server.configfile, 1) == -1)
945 addReplyErrorFormat(c, "CONFIG-REWRITE-FORCE-ALL failed: %s", strerror(errno));
946 else
947 addReply(c, shared.ok);
948 } else if(!strcasecmp(c->argv[1]->ptr,"client-eviction") && c->argc == 2) {
949 sds bucket_info = sdsempty();
950 for (int j = 0; j < CLIENT_MEM_USAGE_BUCKETS; j++) {
951 if (j == 0)
952 bucket_info = sdscatprintf(bucket_info, "bucket 0");
953 else
954 bucket_info = sdscatprintf(bucket_info, "bucket %10zu", (size_t)1<<(j-1+CLIENT_MEM_USAGE_BUCKET_MIN_LOG));
955 if (j == CLIENT_MEM_USAGE_BUCKETS-1)
956 bucket_info = sdscatprintf(bucket_info, "+ : ");
957 else
958 bucket_info = sdscatprintf(bucket_info, " - %10zu: ", ((size_t)1<<(j+CLIENT_MEM_USAGE_BUCKET_MIN_LOG))-1);
959 bucket_info = sdscatprintf(bucket_info, "tot-mem: %10zu, clients: %lu\n",
960 server.client_mem_usage_buckets[j].mem_usage_sum,
961 server.client_mem_usage_buckets[j].clients->len);
962 }
963 addReplyVerbatim(c,bucket_info,sdslen(bucket_info),"txt");
964 sdsfree(bucket_info);
965#ifdef USE_JEMALLOC
966 } else if(!strcasecmp(c->argv[1]->ptr,"mallctl") && c->argc >= 3) {
967 mallctl_int(c, c->argv+2, c->argc-2);
968 return;
969 } else if(!strcasecmp(c->argv[1]->ptr,"mallctl-str") && c->argc >= 3) {
970 mallctl_string(c, c->argv+2, c->argc-2);
971 return;
972#endif
973 } else if (!strcasecmp(c->argv[1]->ptr,"pause-cron") && c->argc == 3)
974 {
975 server.pause_cron = atoi(c->argv[2]->ptr);
976 addReply(c,shared.ok);
977 } else if (!strcasecmp(c->argv[1]->ptr,"replybuffer") && c->argc == 4 ) {
978 if(!strcasecmp(c->argv[2]->ptr, "peak-reset-time")) {
979 if (!strcasecmp(c->argv[3]->ptr, "never")) {
980 server.reply_buffer_peak_reset_time = -1;
981 } else if(!strcasecmp(c->argv[3]->ptr, "reset")) {
982 server.reply_buffer_peak_reset_time = REPLY_BUFFER_DEFAULT_PEAK_RESET_TIME;
983 } else {
984 if (getLongFromObjectOrReply(c, c->argv[3], &server.reply_buffer_peak_reset_time, NULL) != C_OK)
985 return;
986 }
987 } else if(!strcasecmp(c->argv[2]->ptr,"resizing")) {
988 server.reply_buffer_resizing_enabled = atoi(c->argv[3]->ptr);
989 } else {
990 addReplySubcommandSyntaxError(c);
991 return;
992 }
993 addReply(c, shared.ok);
994 } else {
995 addReplySubcommandSyntaxError(c);
996 return;
997 }
998}
999
1000/* =========================== Crash handling ============================== */
1001
1002void _serverAssert(const char *estr, const char *file, int line) {
1003 bugReportStart();
1004 serverLog(LL_WARNING,"=== ASSERTION FAILED ===");
1005 serverLog(LL_WARNING,"==> %s:%d '%s' is not true",file,line,estr);
1006
1007 if (server.crashlog_enabled) {
1008#ifdef HAVE_BACKTRACE
1009 logStackTrace(NULL, 1);
1010#endif
1011 printCrashReport();
1012 }
1013
1014 // remove the signal handler so on abort() we will output the crash report.
1015 removeSignalHandlers();
1016 bugReportEnd(0, 0);
1017}
1018
1019void _serverAssertPrintClientInfo(const client *c) {
1020 int j;
1021 char conninfo[CONN_INFO_LEN];
1022
1023 bugReportStart();
1024 serverLog(LL_WARNING,"=== ASSERTION FAILED CLIENT CONTEXT ===");
1025 serverLog(LL_WARNING,"client->flags = %llu", (unsigned long long) c->flags);
1026 serverLog(LL_WARNING,"client->conn = %s", connGetInfo(c->conn, conninfo, sizeof(conninfo)));
1027 serverLog(LL_WARNING,"client->argc = %d", c->argc);
1028 for (j=0; j < c->argc; j++) {
1029 char buf[128];
1030 char *arg;
1031
1032 if (c->argv[j]->type == OBJ_STRING && sdsEncodedObject(c->argv[j])) {
1033 arg = (char*) c->argv[j]->ptr;
1034 } else {
1035 snprintf(buf,sizeof(buf),"Object type: %u, encoding: %u",
1036 c->argv[j]->type, c->argv[j]->encoding);
1037 arg = buf;
1038 }
1039 serverLog(LL_WARNING,"client->argv[%d] = \"%s\" (refcount: %d)",
1040 j, arg, c->argv[j]->refcount);
1041 }
1042}
1043
1044void serverLogObjectDebugInfo(const robj *o) {
1045 serverLog(LL_WARNING,"Object type: %u", o->type);
1046 serverLog(LL_WARNING,"Object encoding: %u", o->encoding);
1047 serverLog(LL_WARNING,"Object refcount: %d", o->refcount);
1048#if UNSAFE_CRASH_REPORT
1049 /* This code is now disabled. o->ptr may be unreliable to print. in some
1050 * cases a ziplist could have already been freed by realloc, but not yet
1051 * updated to o->ptr. in other cases the call to ziplistLen may need to
1052 * iterate on all the items in the list (and possibly crash again).
1053 * For some cases it may be ok to crash here again, but these could cause
1054 * invalid memory access which will bother valgrind and also possibly cause
1055 * random memory portion to be "leaked" into the logfile. */
1056 if (o->type == OBJ_STRING && sdsEncodedObject(o)) {
1057 serverLog(LL_WARNING,"Object raw string len: %zu", sdslen(o->ptr));
1058 if (sdslen(o->ptr) < 4096) {
1059 sds repr = sdscatrepr(sdsempty(),o->ptr,sdslen(o->ptr));
1060 serverLog(LL_WARNING,"Object raw string content: %s", repr);
1061 sdsfree(repr);
1062 }
1063 } else if (o->type == OBJ_LIST) {
1064 serverLog(LL_WARNING,"List length: %d", (int) listTypeLength(o));
1065 } else if (o->type == OBJ_SET) {
1066 serverLog(LL_WARNING,"Set size: %d", (int) setTypeSize(o));
1067 } else if (o->type == OBJ_HASH) {
1068 serverLog(LL_WARNING,"Hash size: %d", (int) hashTypeLength(o));
1069 } else if (o->type == OBJ_ZSET) {
1070 serverLog(LL_WARNING,"Sorted set size: %d", (int) zsetLength(o));
1071 if (o->encoding == OBJ_ENCODING_SKIPLIST)
1072 serverLog(LL_WARNING,"Skiplist level: %d", (int) ((const zset*)o->ptr)->zsl->level);
1073 } else if (o->type == OBJ_STREAM) {
1074 serverLog(LL_WARNING,"Stream size: %d", (int) streamLength(o));
1075 }
1076#endif
1077}
1078
1079void _serverAssertPrintObject(const robj *o) {
1080 bugReportStart();
1081 serverLog(LL_WARNING,"=== ASSERTION FAILED OBJECT CONTEXT ===");
1082 serverLogObjectDebugInfo(o);
1083}
1084
1085void _serverAssertWithInfo(const client *c, const robj *o, const char *estr, const char *file, int line) {
1086 if (c) _serverAssertPrintClientInfo(c);
1087 if (o) _serverAssertPrintObject(o);
1088 _serverAssert(estr,file,line);
1089}
1090
1091void _serverPanic(const char *file, int line, const char *msg, ...) {
1092 va_list ap;
1093 va_start(ap,msg);
1094 char fmtmsg[256];
1095 vsnprintf(fmtmsg,sizeof(fmtmsg),msg,ap);
1096 va_end(ap);
1097
1098 bugReportStart();
1099 serverLog(LL_WARNING,"------------------------------------------------");
1100 serverLog(LL_WARNING,"!!! Software Failure. Press left mouse button to continue");
1101 serverLog(LL_WARNING,"Guru Meditation: %s #%s:%d",fmtmsg,file,line);
1102
1103 if (server.crashlog_enabled) {
1104#ifdef HAVE_BACKTRACE
1105 logStackTrace(NULL, 1);
1106#endif
1107 printCrashReport();
1108 }
1109
1110 // remove the signal handler so on abort() we will output the crash report.
1111 removeSignalHandlers();
1112 bugReportEnd(0, 0);
1113}
1114
1115void bugReportStart(void) {
1116 pthread_mutex_lock(&bug_report_start_mutex);
1117 if (bug_report_start == 0) {
1118 serverLogRaw(LL_WARNING|LL_RAW,
1119 "\n\n=== REDIS BUG REPORT START: Cut & paste starting from here ===\n");
1120 bug_report_start = 1;
1121 }
1122 pthread_mutex_unlock(&bug_report_start_mutex);
1123}
1124
1125#ifdef HAVE_BACKTRACE
1126static void *getMcontextEip(ucontext_t *uc) {
1127#define NOT_SUPPORTED() do {\
1128 UNUSED(uc);\
1129 return NULL;\
1130} while(0)
1131#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
1132 /* OSX < 10.6 */
1133 #if defined(__x86_64__)
1134 return (void*) uc->uc_mcontext->__ss.__rip;
1135 #elif defined(__i386__)
1136 return (void*) uc->uc_mcontext->__ss.__eip;
1137 #else
1138 return (void*) uc->uc_mcontext->__ss.__srr0;
1139 #endif
1140#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
1141 /* OSX >= 10.6 */
1142 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
1143 return (void*) uc->uc_mcontext->__ss.__rip;
1144 #elif defined(__i386__)
1145 return (void*) uc->uc_mcontext->__ss.__eip;
1146 #else
1147 /* OSX ARM64 */
1148 return (void*) arm_thread_state64_get_pc(uc->uc_mcontext->__ss);
1149 #endif
1150#elif defined(__linux__)
1151 /* Linux */
1152 #if defined(__i386__) || ((defined(__X86_64__) || defined(__x86_64__)) && defined(__ILP32__))
1153 return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */
1154 #elif defined(__X86_64__) || defined(__x86_64__)
1155 return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */
1156 #elif defined(__ia64__) /* Linux IA64 */
1157 return (void*) uc->uc_mcontext.sc_ip;
1158 #elif defined(__arm__) /* Linux ARM */
1159 return (void*) uc->uc_mcontext.arm_pc;
1160 #elif defined(__aarch64__) /* Linux AArch64 */
1161 return (void*) uc->uc_mcontext.pc;
1162 #else
1163 NOT_SUPPORTED();
1164 #endif
1165#elif defined(__FreeBSD__)
1166 /* FreeBSD */
1167 #if defined(__i386__)
1168 return (void*) uc->uc_mcontext.mc_eip;
1169 #elif defined(__x86_64__)
1170 return (void*) uc->uc_mcontext.mc_rip;
1171 #else
1172 NOT_SUPPORTED();
1173 #endif
1174#elif defined(__OpenBSD__)
1175 /* OpenBSD */
1176 #if defined(__i386__)
1177 return (void*) uc->sc_eip;
1178 #elif defined(__x86_64__)
1179 return (void*) uc->sc_rip;
1180 #else
1181 NOT_SUPPORTED();
1182 #endif
1183#elif defined(__NetBSD__)
1184 #if defined(__i386__)
1185 return (void*) uc->uc_mcontext.__gregs[_REG_EIP];
1186 #elif defined(__x86_64__)
1187 return (void*) uc->uc_mcontext.__gregs[_REG_RIP];
1188 #else
1189 NOT_SUPPORTED();
1190 #endif
1191#elif defined(__DragonFly__)
1192 return (void*) uc->uc_mcontext.mc_rip;
1193#else
1194 NOT_SUPPORTED();
1195#endif
1196#undef NOT_SUPPORTED
1197}
1198
1199REDIS_NO_SANITIZE("address")
1200void logStackContent(void **sp) {
1201 int i;
1202 for (i = 15; i >= 0; i--) {
1203 unsigned long addr = (unsigned long) sp+i;
1204 unsigned long val = (unsigned long) sp[i];
1205
1206 if (sizeof(long) == 4)
1207 serverLog(LL_WARNING, "(%08lx) -> %08lx", addr, val);
1208 else
1209 serverLog(LL_WARNING, "(%016lx) -> %016lx", addr, val);
1210 }
1211}
1212
1213/* Log dump of processor registers */
1214void logRegisters(ucontext_t *uc) {
1215 serverLog(LL_WARNING|LL_RAW, "\n------ REGISTERS ------\n");
1216#define NOT_SUPPORTED() do {\
1217 UNUSED(uc);\
1218 serverLog(LL_WARNING,\
1219 " Dumping of registers not supported for this OS/arch");\
1220} while(0)
1221
1222/* OSX */
1223#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
1224 /* OSX AMD64 */
1225 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
1226 serverLog(LL_WARNING,
1227 "\n"
1228 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1229 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1230 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1231 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1232 "RIP:%016lx EFL:%016lx\nCS :%016lx FS:%016lx GS:%016lx",
1233 (unsigned long) uc->uc_mcontext->__ss.__rax,
1234 (unsigned long) uc->uc_mcontext->__ss.__rbx,
1235 (unsigned long) uc->uc_mcontext->__ss.__rcx,
1236 (unsigned long) uc->uc_mcontext->__ss.__rdx,
1237 (unsigned long) uc->uc_mcontext->__ss.__rdi,
1238 (unsigned long) uc->uc_mcontext->__ss.__rsi,
1239 (unsigned long) uc->uc_mcontext->__ss.__rbp,
1240 (unsigned long) uc->uc_mcontext->__ss.__rsp,
1241 (unsigned long) uc->uc_mcontext->__ss.__r8,
1242 (unsigned long) uc->uc_mcontext->__ss.__r9,
1243 (unsigned long) uc->uc_mcontext->__ss.__r10,
1244 (unsigned long) uc->uc_mcontext->__ss.__r11,
1245 (unsigned long) uc->uc_mcontext->__ss.__r12,
1246 (unsigned long) uc->uc_mcontext->__ss.__r13,
1247 (unsigned long) uc->uc_mcontext->__ss.__r14,
1248 (unsigned long) uc->uc_mcontext->__ss.__r15,
1249 (unsigned long) uc->uc_mcontext->__ss.__rip,
1250 (unsigned long) uc->uc_mcontext->__ss.__rflags,
1251 (unsigned long) uc->uc_mcontext->__ss.__cs,
1252 (unsigned long) uc->uc_mcontext->__ss.__fs,
1253 (unsigned long) uc->uc_mcontext->__ss.__gs
1254 );
1255 logStackContent((void**)uc->uc_mcontext->__ss.__rsp);
1256 #elif defined(__i386__)
1257 /* OSX x86 */
1258 serverLog(LL_WARNING,
1259 "\n"
1260 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1261 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1262 "SS:%08lx EFL:%08lx EIP:%08lx CS :%08lx\n"
1263 "DS:%08lx ES:%08lx FS :%08lx GS :%08lx",
1264 (unsigned long) uc->uc_mcontext->__ss.__eax,
1265 (unsigned long) uc->uc_mcontext->__ss.__ebx,
1266 (unsigned long) uc->uc_mcontext->__ss.__ecx,
1267 (unsigned long) uc->uc_mcontext->__ss.__edx,
1268 (unsigned long) uc->uc_mcontext->__ss.__edi,
1269 (unsigned long) uc->uc_mcontext->__ss.__esi,
1270 (unsigned long) uc->uc_mcontext->__ss.__ebp,
1271 (unsigned long) uc->uc_mcontext->__ss.__esp,
1272 (unsigned long) uc->uc_mcontext->__ss.__ss,
1273 (unsigned long) uc->uc_mcontext->__ss.__eflags,
1274 (unsigned long) uc->uc_mcontext->__ss.__eip,
1275 (unsigned long) uc->uc_mcontext->__ss.__cs,
1276 (unsigned long) uc->uc_mcontext->__ss.__ds,
1277 (unsigned long) uc->uc_mcontext->__ss.__es,
1278 (unsigned long) uc->uc_mcontext->__ss.__fs,
1279 (unsigned long) uc->uc_mcontext->__ss.__gs
1280 );
1281 logStackContent((void**)uc->uc_mcontext->__ss.__esp);
1282 #else
1283 /* OSX ARM64 */
1284 serverLog(LL_WARNING,
1285 "\n"
1286 "x0:%016lx x1:%016lx x2:%016lx x3:%016lx\n"
1287 "x4:%016lx x5:%016lx x6:%016lx x7:%016lx\n"
1288 "x8:%016lx x9:%016lx x10:%016lx x11:%016lx\n"
1289 "x12:%016lx x13:%016lx x14:%016lx x15:%016lx\n"
1290 "x16:%016lx x17:%016lx x18:%016lx x19:%016lx\n"
1291 "x20:%016lx x21:%016lx x22:%016lx x23:%016lx\n"
1292 "x24:%016lx x25:%016lx x26:%016lx x27:%016lx\n"
1293 "x28:%016lx fp:%016lx lr:%016lx\n"
1294 "sp:%016lx pc:%016lx cpsr:%08lx\n",
1295 (unsigned long) uc->uc_mcontext->__ss.__x[0],
1296 (unsigned long) uc->uc_mcontext->__ss.__x[1],
1297 (unsigned long) uc->uc_mcontext->__ss.__x[2],
1298 (unsigned long) uc->uc_mcontext->__ss.__x[3],
1299 (unsigned long) uc->uc_mcontext->__ss.__x[4],
1300 (unsigned long) uc->uc_mcontext->__ss.__x[5],
1301 (unsigned long) uc->uc_mcontext->__ss.__x[6],
1302 (unsigned long) uc->uc_mcontext->__ss.__x[7],
1303 (unsigned long) uc->uc_mcontext->__ss.__x[8],
1304 (unsigned long) uc->uc_mcontext->__ss.__x[9],
1305 (unsigned long) uc->uc_mcontext->__ss.__x[10],
1306 (unsigned long) uc->uc_mcontext->__ss.__x[11],
1307 (unsigned long) uc->uc_mcontext->__ss.__x[12],
1308 (unsigned long) uc->uc_mcontext->__ss.__x[13],
1309 (unsigned long) uc->uc_mcontext->__ss.__x[14],
1310 (unsigned long) uc->uc_mcontext->__ss.__x[15],
1311 (unsigned long) uc->uc_mcontext->__ss.__x[16],
1312 (unsigned long) uc->uc_mcontext->__ss.__x[17],
1313 (unsigned long) uc->uc_mcontext->__ss.__x[18],
1314 (unsigned long) uc->uc_mcontext->__ss.__x[19],
1315 (unsigned long) uc->uc_mcontext->__ss.__x[20],
1316 (unsigned long) uc->uc_mcontext->__ss.__x[21],
1317 (unsigned long) uc->uc_mcontext->__ss.__x[22],
1318 (unsigned long) uc->uc_mcontext->__ss.__x[23],
1319 (unsigned long) uc->uc_mcontext->__ss.__x[24],
1320 (unsigned long) uc->uc_mcontext->__ss.__x[25],
1321 (unsigned long) uc->uc_mcontext->__ss.__x[26],
1322 (unsigned long) uc->uc_mcontext->__ss.__x[27],
1323 (unsigned long) uc->uc_mcontext->__ss.__x[28],
1324 (unsigned long) arm_thread_state64_get_fp(uc->uc_mcontext->__ss),
1325 (unsigned long) arm_thread_state64_get_lr(uc->uc_mcontext->__ss),
1326 (unsigned long) arm_thread_state64_get_sp(uc->uc_mcontext->__ss),
1327 (unsigned long) arm_thread_state64_get_pc(uc->uc_mcontext->__ss),
1328 (unsigned long) uc->uc_mcontext->__ss.__cpsr
1329 );
1330 logStackContent((void**) arm_thread_state64_get_sp(uc->uc_mcontext->__ss));
1331 #endif
1332/* Linux */
1333#elif defined(__linux__)
1334 /* Linux x86 */
1335 #if defined(__i386__) || ((defined(__X86_64__) || defined(__x86_64__)) && defined(__ILP32__))
1336 serverLog(LL_WARNING,
1337 "\n"
1338 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1339 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1340 "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
1341 "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
1342 (unsigned long) uc->uc_mcontext.gregs[11],
1343 (unsigned long) uc->uc_mcontext.gregs[8],
1344 (unsigned long) uc->uc_mcontext.gregs[10],
1345 (unsigned long) uc->uc_mcontext.gregs[9],
1346 (unsigned long) uc->uc_mcontext.gregs[4],
1347 (unsigned long) uc->uc_mcontext.gregs[5],
1348 (unsigned long) uc->uc_mcontext.gregs[6],
1349 (unsigned long) uc->uc_mcontext.gregs[7],
1350 (unsigned long) uc->uc_mcontext.gregs[18],
1351 (unsigned long) uc->uc_mcontext.gregs[17],
1352 (unsigned long) uc->uc_mcontext.gregs[14],
1353 (unsigned long) uc->uc_mcontext.gregs[15],
1354 (unsigned long) uc->uc_mcontext.gregs[3],
1355 (unsigned long) uc->uc_mcontext.gregs[2],
1356 (unsigned long) uc->uc_mcontext.gregs[1],
1357 (unsigned long) uc->uc_mcontext.gregs[0]
1358 );
1359 logStackContent((void**)uc->uc_mcontext.gregs[7]);
1360 #elif defined(__X86_64__) || defined(__x86_64__)
1361 /* Linux AMD64 */
1362 serverLog(LL_WARNING,
1363 "\n"
1364 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1365 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1366 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1367 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1368 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1369 (unsigned long) uc->uc_mcontext.gregs[13],
1370 (unsigned long) uc->uc_mcontext.gregs[11],
1371 (unsigned long) uc->uc_mcontext.gregs[14],
1372 (unsigned long) uc->uc_mcontext.gregs[12],
1373 (unsigned long) uc->uc_mcontext.gregs[8],
1374 (unsigned long) uc->uc_mcontext.gregs[9],
1375 (unsigned long) uc->uc_mcontext.gregs[10],
1376 (unsigned long) uc->uc_mcontext.gregs[15],
1377 (unsigned long) uc->uc_mcontext.gregs[0],
1378 (unsigned long) uc->uc_mcontext.gregs[1],
1379 (unsigned long) uc->uc_mcontext.gregs[2],
1380 (unsigned long) uc->uc_mcontext.gregs[3],
1381 (unsigned long) uc->uc_mcontext.gregs[4],
1382 (unsigned long) uc->uc_mcontext.gregs[5],
1383 (unsigned long) uc->uc_mcontext.gregs[6],
1384 (unsigned long) uc->uc_mcontext.gregs[7],
1385 (unsigned long) uc->uc_mcontext.gregs[16],
1386 (unsigned long) uc->uc_mcontext.gregs[17],
1387 (unsigned long) uc->uc_mcontext.gregs[18]
1388 );
1389 logStackContent((void**)uc->uc_mcontext.gregs[15]);
1390 #elif defined(__aarch64__) /* Linux AArch64 */
1391 serverLog(LL_WARNING,
1392 "\n"
1393 "X18:%016lx X19:%016lx\nX20:%016lx X21:%016lx\n"
1394 "X22:%016lx X23:%016lx\nX24:%016lx X25:%016lx\n"
1395 "X26:%016lx X27:%016lx\nX28:%016lx X29:%016lx\n"
1396 "X30:%016lx\n"
1397 "pc:%016lx sp:%016lx\npstate:%016lx fault_address:%016lx\n",
1398 (unsigned long) uc->uc_mcontext.regs[18],
1399 (unsigned long) uc->uc_mcontext.regs[19],
1400 (unsigned long) uc->uc_mcontext.regs[20],
1401 (unsigned long) uc->uc_mcontext.regs[21],
1402 (unsigned long) uc->uc_mcontext.regs[22],
1403 (unsigned long) uc->uc_mcontext.regs[23],
1404 (unsigned long) uc->uc_mcontext.regs[24],
1405 (unsigned long) uc->uc_mcontext.regs[25],
1406 (unsigned long) uc->uc_mcontext.regs[26],
1407 (unsigned long) uc->uc_mcontext.regs[27],
1408 (unsigned long) uc->uc_mcontext.regs[28],
1409 (unsigned long) uc->uc_mcontext.regs[29],
1410 (unsigned long) uc->uc_mcontext.regs[30],
1411 (unsigned long) uc->uc_mcontext.pc,
1412 (unsigned long) uc->uc_mcontext.sp,
1413 (unsigned long) uc->uc_mcontext.pstate,
1414 (unsigned long) uc->uc_mcontext.fault_address
1415 );
1416 logStackContent((void**)uc->uc_mcontext.sp);
1417 #elif defined(__arm__) /* Linux ARM */
1418 serverLog(LL_WARNING,
1419 "\n"
1420 "R10:%016lx R9 :%016lx\nR8 :%016lx R7 :%016lx\n"
1421 "R6 :%016lx R5 :%016lx\nR4 :%016lx R3 :%016lx\n"
1422 "R2 :%016lx R1 :%016lx\nR0 :%016lx EC :%016lx\n"
1423 "fp: %016lx ip:%016lx\n"
1424 "pc:%016lx sp:%016lx\ncpsr:%016lx fault_address:%016lx\n",
1425 (unsigned long) uc->uc_mcontext.arm_r10,
1426 (unsigned long) uc->uc_mcontext.arm_r9,
1427 (unsigned long) uc->uc_mcontext.arm_r8,
1428 (unsigned long) uc->uc_mcontext.arm_r7,
1429 (unsigned long) uc->uc_mcontext.arm_r6,
1430 (unsigned long) uc->uc_mcontext.arm_r5,
1431 (unsigned long) uc->uc_mcontext.arm_r4,
1432 (unsigned long) uc->uc_mcontext.arm_r3,
1433 (unsigned long) uc->uc_mcontext.arm_r2,
1434 (unsigned long) uc->uc_mcontext.arm_r1,
1435 (unsigned long) uc->uc_mcontext.arm_r0,
1436 (unsigned long) uc->uc_mcontext.error_code,
1437 (unsigned long) uc->uc_mcontext.arm_fp,
1438 (unsigned long) uc->uc_mcontext.arm_ip,
1439 (unsigned long) uc->uc_mcontext.arm_pc,
1440 (unsigned long) uc->uc_mcontext.arm_sp,
1441 (unsigned long) uc->uc_mcontext.arm_cpsr,
1442 (unsigned long) uc->uc_mcontext.fault_address
1443 );
1444 logStackContent((void**)uc->uc_mcontext.arm_sp);
1445 #else
1446 NOT_SUPPORTED();
1447 #endif
1448#elif defined(__FreeBSD__)
1449 #if defined(__x86_64__)
1450 serverLog(LL_WARNING,
1451 "\n"
1452 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1453 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1454 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1455 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1456 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1457 (unsigned long) uc->uc_mcontext.mc_rax,
1458 (unsigned long) uc->uc_mcontext.mc_rbx,
1459 (unsigned long) uc->uc_mcontext.mc_rcx,
1460 (unsigned long) uc->uc_mcontext.mc_rdx,
1461 (unsigned long) uc->uc_mcontext.mc_rdi,
1462 (unsigned long) uc->uc_mcontext.mc_rsi,
1463 (unsigned long) uc->uc_mcontext.mc_rbp,
1464 (unsigned long) uc->uc_mcontext.mc_rsp,
1465 (unsigned long) uc->uc_mcontext.mc_r8,
1466 (unsigned long) uc->uc_mcontext.mc_r9,
1467 (unsigned long) uc->uc_mcontext.mc_r10,
1468 (unsigned long) uc->uc_mcontext.mc_r11,
1469 (unsigned long) uc->uc_mcontext.mc_r12,
1470 (unsigned long) uc->uc_mcontext.mc_r13,
1471 (unsigned long) uc->uc_mcontext.mc_r14,
1472 (unsigned long) uc->uc_mcontext.mc_r15,
1473 (unsigned long) uc->uc_mcontext.mc_rip,
1474 (unsigned long) uc->uc_mcontext.mc_rflags,
1475 (unsigned long) uc->uc_mcontext.mc_cs
1476 );
1477 logStackContent((void**)uc->uc_mcontext.mc_rsp);
1478 #elif defined(__i386__)
1479 serverLog(LL_WARNING,
1480 "\n"
1481 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1482 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1483 "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
1484 "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
1485 (unsigned long) uc->uc_mcontext.mc_eax,
1486 (unsigned long) uc->uc_mcontext.mc_ebx,
1487 (unsigned long) uc->uc_mcontext.mc_ebx,
1488 (unsigned long) uc->uc_mcontext.mc_edx,
1489 (unsigned long) uc->uc_mcontext.mc_edi,
1490 (unsigned long) uc->uc_mcontext.mc_esi,
1491 (unsigned long) uc->uc_mcontext.mc_ebp,
1492 (unsigned long) uc->uc_mcontext.mc_esp,
1493 (unsigned long) uc->uc_mcontext.mc_ss,
1494 (unsigned long) uc->uc_mcontext.mc_eflags,
1495 (unsigned long) uc->uc_mcontext.mc_eip,
1496 (unsigned long) uc->uc_mcontext.mc_cs,
1497 (unsigned long) uc->uc_mcontext.mc_es,
1498 (unsigned long) uc->uc_mcontext.mc_fs,
1499 (unsigned long) uc->uc_mcontext.mc_gs
1500 );
1501 logStackContent((void**)uc->uc_mcontext.mc_esp);
1502 #else
1503 NOT_SUPPORTED();
1504 #endif
1505#elif defined(__OpenBSD__)
1506 #if defined(__x86_64__)
1507 serverLog(LL_WARNING,
1508 "\n"
1509 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1510 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1511 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1512 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1513 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1514 (unsigned long) uc->sc_rax,
1515 (unsigned long) uc->sc_rbx,
1516 (unsigned long) uc->sc_rcx,
1517 (unsigned long) uc->sc_rdx,
1518 (unsigned long) uc->sc_rdi,
1519 (unsigned long) uc->sc_rsi,
1520 (unsigned long) uc->sc_rbp,
1521 (unsigned long) uc->sc_rsp,
1522 (unsigned long) uc->sc_r8,
1523 (unsigned long) uc->sc_r9,
1524 (unsigned long) uc->sc_r10,
1525 (unsigned long) uc->sc_r11,
1526 (unsigned long) uc->sc_r12,
1527 (unsigned long) uc->sc_r13,
1528 (unsigned long) uc->sc_r14,
1529 (unsigned long) uc->sc_r15,
1530 (unsigned long) uc->sc_rip,
1531 (unsigned long) uc->sc_rflags,
1532 (unsigned long) uc->sc_cs
1533 );
1534 logStackContent((void**)uc->sc_rsp);
1535 #elif defined(__i386__)
1536 serverLog(LL_WARNING,
1537 "\n"
1538 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1539 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1540 "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
1541 "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
1542 (unsigned long) uc->sc_eax,
1543 (unsigned long) uc->sc_ebx,
1544 (unsigned long) uc->sc_ebx,
1545 (unsigned long) uc->sc_edx,
1546 (unsigned long) uc->sc_edi,
1547 (unsigned long) uc->sc_esi,
1548 (unsigned long) uc->sc_ebp,
1549 (unsigned long) uc->sc_esp,
1550 (unsigned long) uc->sc_ss,
1551 (unsigned long) uc->sc_eflags,
1552 (unsigned long) uc->sc_eip,
1553 (unsigned long) uc->sc_cs,
1554 (unsigned long) uc->sc_es,
1555 (unsigned long) uc->sc_fs,
1556 (unsigned long) uc->sc_gs
1557 );
1558 logStackContent((void**)uc->sc_esp);
1559 #else
1560 NOT_SUPPORTED();
1561 #endif
1562#elif defined(__NetBSD__)
1563 #if defined(__x86_64__)
1564 serverLog(LL_WARNING,
1565 "\n"
1566 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1567 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1568 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1569 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1570 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1571 (unsigned long) uc->uc_mcontext.__gregs[_REG_RAX],
1572 (unsigned long) uc->uc_mcontext.__gregs[_REG_RBX],
1573 (unsigned long) uc->uc_mcontext.__gregs[_REG_RCX],
1574 (unsigned long) uc->uc_mcontext.__gregs[_REG_RDX],
1575 (unsigned long) uc->uc_mcontext.__gregs[_REG_RDI],
1576 (unsigned long) uc->uc_mcontext.__gregs[_REG_RSI],
1577 (unsigned long) uc->uc_mcontext.__gregs[_REG_RBP],
1578 (unsigned long) uc->uc_mcontext.__gregs[_REG_RSP],
1579 (unsigned long) uc->uc_mcontext.__gregs[_REG_R8],
1580 (unsigned long) uc->uc_mcontext.__gregs[_REG_R9],
1581 (unsigned long) uc->uc_mcontext.__gregs[_REG_R10],
1582 (unsigned long) uc->uc_mcontext.__gregs[_REG_R11],
1583 (unsigned long) uc->uc_mcontext.__gregs[_REG_R12],
1584 (unsigned long) uc->uc_mcontext.__gregs[_REG_R13],
1585 (unsigned long) uc->uc_mcontext.__gregs[_REG_R14],
1586 (unsigned long) uc->uc_mcontext.__gregs[_REG_R15],
1587 (unsigned long) uc->uc_mcontext.__gregs[_REG_RIP],
1588 (unsigned long) uc->uc_mcontext.__gregs[_REG_RFLAGS],
1589 (unsigned long) uc->uc_mcontext.__gregs[_REG_CS]
1590 );
1591 logStackContent((void**)uc->uc_mcontext.__gregs[_REG_RSP]);
1592 #elif defined(__i386__)
1593 serverLog(LL_WARNING,
1594 "\n"
1595 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1596 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1597 "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
1598 "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
1599 (unsigned long) uc->uc_mcontext.__gregs[_REG_EAX],
1600 (unsigned long) uc->uc_mcontext.__gregs[_REG_EBX],
1601 (unsigned long) uc->uc_mcontext.__gregs[_REG_EDX],
1602 (unsigned long) uc->uc_mcontext.__gregs[_REG_EDI],
1603 (unsigned long) uc->uc_mcontext.__gregs[_REG_ESI],
1604 (unsigned long) uc->uc_mcontext.__gregs[_REG_EBP],
1605 (unsigned long) uc->uc_mcontext.__gregs[_REG_ESP],
1606 (unsigned long) uc->uc_mcontext.__gregs[_REG_SS],
1607 (unsigned long) uc->uc_mcontext.__gregs[_REG_EFLAGS],
1608 (unsigned long) uc->uc_mcontext.__gregs[_REG_EIP],
1609 (unsigned long) uc->uc_mcontext.__gregs[_REG_CS],
1610 (unsigned long) uc->uc_mcontext.__gregs[_REG_ES],
1611 (unsigned long) uc->uc_mcontext.__gregs[_REG_FS],
1612 (unsigned long) uc->uc_mcontext.__gregs[_REG_GS]
1613 );
1614 #else
1615 NOT_SUPPORTED();
1616 #endif
1617#elif defined(__DragonFly__)
1618 serverLog(LL_WARNING,
1619 "\n"
1620 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1621 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1622 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1623 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1624 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1625 (unsigned long) uc->uc_mcontext.mc_rax,
1626 (unsigned long) uc->uc_mcontext.mc_rbx,
1627 (unsigned long) uc->uc_mcontext.mc_rcx,
1628 (unsigned long) uc->uc_mcontext.mc_rdx,
1629 (unsigned long) uc->uc_mcontext.mc_rdi,
1630 (unsigned long) uc->uc_mcontext.mc_rsi,
1631 (unsigned long) uc->uc_mcontext.mc_rbp,
1632 (unsigned long) uc->uc_mcontext.mc_rsp,
1633 (unsigned long) uc->uc_mcontext.mc_r8,
1634 (unsigned long) uc->uc_mcontext.mc_r9,
1635 (unsigned long) uc->uc_mcontext.mc_r10,
1636 (unsigned long) uc->uc_mcontext.mc_r11,
1637 (unsigned long) uc->uc_mcontext.mc_r12,
1638 (unsigned long) uc->uc_mcontext.mc_r13,
1639 (unsigned long) uc->uc_mcontext.mc_r14,
1640 (unsigned long) uc->uc_mcontext.mc_r15,
1641 (unsigned long) uc->uc_mcontext.mc_rip,
1642 (unsigned long) uc->uc_mcontext.mc_rflags,
1643 (unsigned long) uc->uc_mcontext.mc_cs
1644 );
1645 logStackContent((void**)uc->uc_mcontext.mc_rsp);
1646#else
1647 NOT_SUPPORTED();
1648#endif
1649#undef NOT_SUPPORTED
1650}
1651
1652#endif /* HAVE_BACKTRACE */
1653
1654/* Return a file descriptor to write directly to the Redis log with the
1655 * write(2) syscall, that can be used in critical sections of the code
1656 * where the rest of Redis can't be trusted (for example during the memory
1657 * test) or when an API call requires a raw fd.
1658 *
1659 * Close it with closeDirectLogFiledes(). */
1660int openDirectLogFiledes(void) {
1661 int log_to_stdout = server.logfile[0] == '\0';
1662 int fd = log_to_stdout ?
1663 STDOUT_FILENO :
1664 open(server.logfile, O_APPEND|O_CREAT|O_WRONLY, 0644);
1665 return fd;
1666}
1667
1668/* Used to close what closeDirectLogFiledes() returns. */
1669void closeDirectLogFiledes(int fd) {
1670 int log_to_stdout = server.logfile[0] == '\0';
1671 if (!log_to_stdout) close(fd);
1672}
1673
1674#ifdef HAVE_BACKTRACE
1675
1676/* Logs the stack trace using the backtrace() call. This function is designed
1677 * to be called from signal handlers safely.
1678 * The eip argument is optional (can take NULL).
1679 * The uplevel argument indicates how many of the calling functions to skip.
1680 */
1681void logStackTrace(void *eip, int uplevel) {
1682 void *trace[100];
1683 int trace_size = 0, fd = openDirectLogFiledes();
1684 char *msg;
1685 uplevel++; /* skip this function */
1686
1687 if (fd == -1) return; /* If we can't log there is anything to do. */
1688
1689 /* Get the stack trace first! */
1690 trace_size = backtrace(trace, 100);
1691
1692 msg = "\n------ STACK TRACE ------\n";
1693 if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */};
1694
1695 if (eip) {
1696 /* Write EIP to the log file*/
1697 msg = "EIP:\n";
1698 if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */};
1699 backtrace_symbols_fd(&eip, 1, fd);
1700 }
1701
1702 /* Write symbols to log file */
1703 msg = "\nBacktrace:\n";
1704 if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */};
1705 backtrace_symbols_fd(trace+uplevel, trace_size-uplevel, fd);
1706
1707 /* Cleanup */
1708 closeDirectLogFiledes(fd);
1709}
1710
1711#endif /* HAVE_BACKTRACE */
1712
1713/* Log global server info */
1714void logServerInfo(void) {
1715 sds infostring, clients;
1716 serverLogRaw(LL_WARNING|LL_RAW, "\n------ INFO OUTPUT ------\n");
1717 int all = 0, everything = 0;
1718 robj *argv[1];
1719 argv[0] = createStringObject("all", strlen("all"));
1720 dict *section_dict = genInfoSectionDict(argv, 1, NULL, &all, &everything);
1721 infostring = genRedisInfoString(section_dict, all, everything);
1722 serverLogRaw(LL_WARNING|LL_RAW, infostring);
1723 serverLogRaw(LL_WARNING|LL_RAW, "\n------ CLIENT LIST OUTPUT ------\n");
1724 clients = getAllClientsInfoString(-1);
1725 serverLogRaw(LL_WARNING|LL_RAW, clients);
1726 sdsfree(infostring);
1727 sdsfree(clients);
1728 releaseInfoSectionDict(section_dict);
1729 decrRefCount(argv[0]);
1730}
1731
1732/* Log certain config values, which can be used for debuggin */
1733void logConfigDebugInfo(void) {
1734 sds configstring;
1735 configstring = getConfigDebugInfo();
1736 serverLogRaw(LL_WARNING|LL_RAW, "\n------ CONFIG DEBUG OUTPUT ------\n");
1737 serverLogRaw(LL_WARNING|LL_RAW, configstring);
1738 sdsfree(configstring);
1739}
1740
1741/* Log modules info. Something we wanna do last since we fear it may crash. */
1742void logModulesInfo(void) {
1743 serverLogRaw(LL_WARNING|LL_RAW, "\n------ MODULES INFO OUTPUT ------\n");
1744 sds infostring = modulesCollectInfo(sdsempty(), NULL, 1, 0);
1745 serverLogRaw(LL_WARNING|LL_RAW, infostring);
1746 sdsfree(infostring);
1747}
1748
1749/* Log information about the "current" client, that is, the client that is
1750 * currently being served by Redis. May be NULL if Redis is not serving a
1751 * client right now. */
1752void logCurrentClient(void) {
1753 if (server.current_client == NULL) return;
1754
1755 client *cc = server.current_client;
1756 sds client;
1757 int j;
1758
1759 serverLogRaw(LL_WARNING|LL_RAW, "\n------ CURRENT CLIENT INFO ------\n");
1760 client = catClientInfoString(sdsempty(),cc);
1761 serverLog(LL_WARNING|LL_RAW,"%s\n", client);
1762 sdsfree(client);
1763 for (j = 0; j < cc->argc; j++) {
1764 robj *decoded;
1765 decoded = getDecodedObject(cc->argv[j]);
1766 sds repr = sdscatrepr(sdsempty(),decoded->ptr, min(sdslen(decoded->ptr), 128));
1767 serverLog(LL_WARNING|LL_RAW,"argv[%d]: '%s'\n", j, (char*)repr);
1768 sdsfree(repr);
1769 decrRefCount(decoded);
1770 }
1771 /* Check if the first argument, usually a key, is found inside the
1772 * selected DB, and if so print info about the associated object. */
1773 if (cc->argc > 1) {
1774 robj *val, *key;
1775 dictEntry *de;
1776
1777 key = getDecodedObject(cc->argv[1]);
1778 de = dictFind(cc->db->dict, key->ptr);
1779 if (de) {
1780 val = dictGetVal(de);
1781 serverLog(LL_WARNING,"key '%s' found in DB containing the following object:", (char*)key->ptr);
1782 serverLogObjectDebugInfo(val);
1783 }
1784 decrRefCount(key);
1785 }
1786}
1787
1788#if defined(HAVE_PROC_MAPS)
1789
1790#define MEMTEST_MAX_REGIONS 128
1791
1792/* A non destructive memory test executed during segfault. */
1793int memtest_test_linux_anonymous_maps(void) {
1794 FILE *fp;
1795 char line[1024];
1796 char logbuf[1024];
1797 size_t start_addr, end_addr, size;
1798 size_t start_vect[MEMTEST_MAX_REGIONS];
1799 size_t size_vect[MEMTEST_MAX_REGIONS];
1800 int regions = 0, j;
1801
1802 int fd = openDirectLogFiledes();
1803 if (!fd) return 0;
1804
1805 fp = fopen("/proc/self/maps","r");
1806 if (!fp) {
1807 closeDirectLogFiledes(fd);
1808 return 0;
1809 }
1810 while(fgets(line,sizeof(line),fp) != NULL) {
1811 char *start, *end, *p = line;
1812
1813 start = p;
1814 p = strchr(p,'-');
1815 if (!p) continue;
1816 *p++ = '\0';
1817 end = p;
1818 p = strchr(p,' ');
1819 if (!p) continue;
1820 *p++ = '\0';
1821 if (strstr(p,"stack") ||
1822 strstr(p,"vdso") ||
1823 strstr(p,"vsyscall")) continue;
1824 if (!strstr(p,"00:00")) continue;
1825 if (!strstr(p,"rw")) continue;
1826
1827 start_addr = strtoul(start,NULL,16);
1828 end_addr = strtoul(end,NULL,16);
1829 size = end_addr-start_addr;
1830
1831 start_vect[regions] = start_addr;
1832 size_vect[regions] = size;
1833 snprintf(logbuf,sizeof(logbuf),
1834 "*** Preparing to test memory region %lx (%lu bytes)\n",
1835 (unsigned long) start_vect[regions],
1836 (unsigned long) size_vect[regions]);
1837 if (write(fd,logbuf,strlen(logbuf)) == -1) { /* Nothing to do. */ }
1838 regions++;
1839 }
1840
1841 int errors = 0;
1842 for (j = 0; j < regions; j++) {
1843 if (write(fd,".",1) == -1) { /* Nothing to do. */ }
1844 errors += memtest_preserving_test((void*)start_vect[j],size_vect[j],1);
1845 if (write(fd, errors ? "E" : "O",1) == -1) { /* Nothing to do. */ }
1846 }
1847 if (write(fd,"\n",1) == -1) { /* Nothing to do. */ }
1848
1849 /* NOTE: It is very important to close the file descriptor only now
1850 * because closing it before may result into unmapping of some memory
1851 * region that we are testing. */
1852 fclose(fp);
1853 closeDirectLogFiledes(fd);
1854 return errors;
1855}
1856#endif /* HAVE_PROC_MAPS */
1857
1858static void killMainThread(void) {
1859 int err;
1860 if (pthread_self() != server.main_thread_id && pthread_cancel(server.main_thread_id) == 0) {
1861 if ((err = pthread_join(server.main_thread_id,NULL)) != 0) {
1862 serverLog(LL_WARNING, "main thread can not be joined: %s", strerror(err));
1863 } else {
1864 serverLog(LL_WARNING, "main thread terminated");
1865 }
1866 }
1867}
1868
1869/* Kill the running threads (other than current) in an unclean way. This function
1870 * should be used only when it's critical to stop the threads for some reason.
1871 * Currently Redis does this only on crash (for instance on SIGSEGV) in order
1872 * to perform a fast memory check without other threads messing with memory. */
1873void killThreads(void) {
1874 killMainThread();
1875 bioKillThreads();
1876 killIOThreads();
1877}
1878
1879void doFastMemoryTest(void) {
1880#if defined(HAVE_PROC_MAPS)
1881 if (server.memcheck_enabled) {
1882 /* Test memory */
1883 serverLogRaw(LL_WARNING|LL_RAW, "\n------ FAST MEMORY TEST ------\n");
1884 killThreads();
1885 if (memtest_test_linux_anonymous_maps()) {
1886 serverLogRaw(LL_WARNING|LL_RAW,
1887 "!!! MEMORY ERROR DETECTED! Check your memory ASAP !!!\n");
1888 } else {
1889 serverLogRaw(LL_WARNING|LL_RAW,
1890 "Fast memory test PASSED, however your memory can still be broken. Please run a memory test for several hours if possible.\n");
1891 }
1892 }
1893#endif /* HAVE_PROC_MAPS */
1894}
1895
1896/* Scans the (assumed) x86 code starting at addr, for a max of `len`
1897 * bytes, searching for E8 (callq) opcodes, and dumping the symbols
1898 * and the call offset if they appear to be valid. */
1899void dumpX86Calls(void *addr, size_t len) {
1900 size_t j;
1901 unsigned char *p = addr;
1902 Dl_info info;
1903 /* Hash table to best-effort avoid printing the same symbol
1904 * multiple times. */
1905 unsigned long ht[256] = {0};
1906
1907 if (len < 5) return;
1908 for (j = 0; j < len-4; j++) {
1909 if (p[j] != 0xE8) continue; /* Not an E8 CALL opcode. */
1910 unsigned long target = (unsigned long)addr+j+5;
1911 uint32_t tmp;
1912 memcpy(&tmp, p+j+1, sizeof(tmp));
1913 target += tmp;
1914 if (dladdr((void*)target, &info) != 0 && info.dli_sname != NULL) {
1915 if (ht[target&0xff] != target) {
1916 printf("Function at 0x%lx is %s\n",target,info.dli_sname);
1917 ht[target&0xff] = target;
1918 }
1919 j += 4; /* Skip the 32 bit immediate. */
1920 }
1921 }
1922}
1923
1924void dumpCodeAroundEIP(void *eip) {
1925 Dl_info info;
1926 if (dladdr(eip, &info) != 0) {
1927 serverLog(LL_WARNING|LL_RAW,
1928 "\n------ DUMPING CODE AROUND EIP ------\n"
1929 "Symbol: %s (base: %p)\n"
1930 "Module: %s (base %p)\n"
1931 "$ xxd -r -p /tmp/dump.hex /tmp/dump.bin\n"
1932 "$ objdump --adjust-vma=%p -D -b binary -m i386:x86-64 /tmp/dump.bin\n"
1933 "------\n",
1934 info.dli_sname, info.dli_saddr, info.dli_fname, info.dli_fbase,
1935 info.dli_saddr);
1936 size_t len = (long)eip - (long)info.dli_saddr;
1937 unsigned long sz = sysconf(_SC_PAGESIZE);
1938 if (len < 1<<13) { /* we don't have functions over 8k (verified) */
1939 /* Find the address of the next page, which is our "safety"
1940 * limit when dumping. Then try to dump just 128 bytes more
1941 * than EIP if there is room, or stop sooner. */
1942 void *base = (void *)info.dli_saddr;
1943 unsigned long next = ((unsigned long)eip + sz) & ~(sz-1);
1944 unsigned long end = (unsigned long)eip + 128;
1945 if (end > next) end = next;
1946 len = end - (unsigned long)base;
1947 serverLogHexDump(LL_WARNING, "dump of function",
1948 base, len);
1949 dumpX86Calls(base, len);
1950 }
1951 }
1952}
1953
1954void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
1955 UNUSED(secret);
1956 UNUSED(info);
1957
1958 bugReportStart();
1959 serverLog(LL_WARNING,
1960 "Redis %s crashed by signal: %d, si_code: %d", REDIS_VERSION, sig, info->si_code);
1961 if (sig == SIGSEGV || sig == SIGBUS) {
1962 serverLog(LL_WARNING,
1963 "Accessing address: %p", (void*)info->si_addr);
1964 }
1965 if (info->si_code == SI_USER && info->si_pid != -1) {
1966 serverLog(LL_WARNING, "Killed by PID: %ld, UID: %d", (long) info->si_pid, info->si_uid);
1967 }
1968
1969#ifdef HAVE_BACKTRACE
1970 ucontext_t *uc = (ucontext_t*) secret;
1971 void *eip = getMcontextEip(uc);
1972 if (eip != NULL) {
1973 serverLog(LL_WARNING,
1974 "Crashed running the instruction at: %p", eip);
1975 }
1976
1977 logStackTrace(getMcontextEip(uc), 1);
1978
1979 logRegisters(uc);
1980#endif
1981
1982 printCrashReport();
1983
1984#ifdef HAVE_BACKTRACE
1985 if (eip != NULL)
1986 dumpCodeAroundEIP(eip);
1987#endif
1988
1989 bugReportEnd(1, sig);
1990}
1991
1992void printCrashReport(void) {
1993 /* Log INFO and CLIENT LIST */
1994 logServerInfo();
1995
1996 /* Log the current client */
1997 logCurrentClient();
1998
1999 /* Log modules info. Something we wanna do last since we fear it may crash. */
2000 logModulesInfo();
2001
2002 /* Log debug config information, which are some values
2003 * which may be useful for debugging crashes. */
2004 logConfigDebugInfo();
2005
2006 /* Run memory test in case the crash was triggered by memory corruption. */
2007 doFastMemoryTest();
2008}
2009
2010void bugReportEnd(int killViaSignal, int sig) {
2011 struct sigaction act;
2012
2013 serverLogRaw(LL_WARNING|LL_RAW,
2014"\n=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
2015" Please report the crash by opening an issue on github:\n\n"
2016" http://github.com/redis/redis/issues\n\n"
2017" If a Redis module was involved, please open in the module's repo instead.\n\n"
2018" Suspect RAM error? Use redis-server --test-memory to verify it.\n\n"
2019" Some other issues could be detected by redis-server --check-system\n"
2020);
2021
2022 /* free(messages); Don't call free() with possibly corrupted memory. */
2023 if (server.daemonize && server.supervised == 0 && server.pidfile) unlink(server.pidfile);
2024
2025 if (!killViaSignal) {
2026 /* To avoid issues with valgrind, we may wanna exit rahter than generate a signal */
2027 if (server.use_exit_on_panic) {
2028 /* Using _exit to bypass false leak reports by gcc ASAN */
2029 fflush(stdout);
2030 _exit(1);
2031 }
2032 abort();
2033 }
2034
2035 /* Make sure we exit with the right signal at the end. So for instance
2036 * the core will be dumped if enabled. */
2037 sigemptyset (&act.sa_mask);
2038 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
2039 act.sa_handler = SIG_DFL;
2040 sigaction (sig, &act, NULL);
2041 kill(getpid(),sig);
2042}
2043
2044/* ==================== Logging functions for debugging ===================== */
2045
2046void serverLogHexDump(int level, char *descr, void *value, size_t len) {
2047 char buf[65], *b;
2048 unsigned char *v = value;
2049 char charset[] = "0123456789abcdef";
2050
2051 serverLog(level,"%s (hexdump of %zu bytes):", descr, len);
2052 b = buf;
2053 while(len) {
2054 b[0] = charset[(*v)>>4];
2055 b[1] = charset[(*v)&0xf];
2056 b[2] = '\0';
2057 b += 2;
2058 len--;
2059 v++;
2060 if (b-buf == 64 || len == 0) {
2061 serverLogRaw(level|LL_RAW,buf);
2062 b = buf;
2063 }
2064 }
2065 serverLogRaw(level|LL_RAW,"\n");
2066}
2067
2068/* =========================== Software Watchdog ============================ */
2069#include <sys/time.h>
2070
2071void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) {
2072#ifdef HAVE_BACKTRACE
2073 ucontext_t *uc = (ucontext_t*) secret;
2074#else
2075 (void)secret;
2076#endif
2077 UNUSED(info);
2078 UNUSED(sig);
2079
2080 serverLogFromHandler(LL_WARNING,"\n--- WATCHDOG TIMER EXPIRED ---");
2081#ifdef HAVE_BACKTRACE
2082 logStackTrace(getMcontextEip(uc), 1);
2083#else
2084 serverLogFromHandler(LL_WARNING,"Sorry: no support for backtrace().");
2085#endif
2086 serverLogFromHandler(LL_WARNING,"--------\n");
2087}
2088
2089/* Schedule a SIGALRM delivery after the specified period in milliseconds.
2090 * If a timer is already scheduled, this function will re-schedule it to the
2091 * specified time. If period is 0 the current timer is disabled. */
2092void watchdogScheduleSignal(int period) {
2093 struct itimerval it;
2094
2095 /* Will stop the timer if period is 0. */
2096 it.it_value.tv_sec = period/1000;
2097 it.it_value.tv_usec = (period%1000)*1000;
2098 /* Don't automatically restart. */
2099 it.it_interval.tv_sec = 0;
2100 it.it_interval.tv_usec = 0;
2101 setitimer(ITIMER_REAL, &it, NULL);
2102}
2103void applyWatchdogPeriod() {
2104 struct sigaction act;
2105
2106 /* Disable watchdog when period is 0 */
2107 if (server.watchdog_period == 0) {
2108 watchdogScheduleSignal(0); /* Stop the current timer. */
2109
2110 /* Set the signal handler to SIG_IGN, this will also remove pending
2111 * signals from the queue. */
2112 sigemptyset(&act.sa_mask);
2113 act.sa_flags = 0;
2114 act.sa_handler = SIG_IGN;
2115 sigaction(SIGALRM, &act, NULL);
2116 } else {
2117 /* Setup the signal handler. */
2118 sigemptyset(&act.sa_mask);
2119 act.sa_flags = SA_SIGINFO;
2120 act.sa_sigaction = watchdogSignalHandler;
2121 sigaction(SIGALRM, &act, NULL);
2122
2123 /* If the configured period is smaller than twice the timer period, it is
2124 * too short for the software watchdog to work reliably. Fix it now
2125 * if needed. */
2126 int min_period = (1000/server.hz)*2;
2127 if (server.watchdog_period < min_period) server.watchdog_period = min_period;
2128 watchdogScheduleSignal(server.watchdog_period); /* Adjust the current timer. */
2129 }
2130}
2131
2132/* Positive input is sleep time in microseconds. Negative input is fractions
2133 * of microseconds, i.e. -10 means 100 nanoseconds. */
2134void debugDelay(int usec) {
2135 /* Since even the shortest sleep results in context switch and system call,
2136 * the way we achieve short sleeps is by statistically sleeping less often. */
2137 if (usec < 0) usec = (rand() % -usec) == 0 ? 1: 0;
2138 if (usec) usleep(usec);
2139}
2140