"Fossies" - the Fresh Open Source Software Archive

Member "redis-6.2.5/src/debug.c" (21 Jul 2021, 76265 Bytes) of package /linux/misc/redis-6.2.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "debug.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.2.4_vs_6.2.5.

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