Bug Summary

File:src/debug.c
Warning:line 604, column 13
Value stored to 'remaining' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name debug.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mthread-model posix -mframe-pointer=none -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -D REDIS_STATIC= -I ../deps/hiredis -I ../deps/linenoise -I ../deps/lua/src -I ../deps/hdr_histogram -D USE_JEMALLOC -I ../deps/jemalloc/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-c11-extensions -Wno-missing-field-initializers -std=c11 -fdebug-compilation-dir /home/netto/Desktop/redis-6.2.1/src -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-03-14-133648-8817-1 -x c debug.c
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_BACKTRACE1
43#include <execinfo.h>
44#ifndef __OpenBSD__
45#include <ucontext.h>
46#else
47typedef ucontext_t sigcontext_t;
48#endif
49#endif /* HAVE_BACKTRACE */
50
51#ifdef __CYGWIN__
52#ifndef SA_ONSTACK0x08000000
53#define SA_ONSTACK0x08000000 0x08000000
54#endif
55#endif
56
57#if defined(__APPLE__) && defined(__arm64__)
58#include <mach/mach.h>
59#endif
60
61/* Globals */
62static int bug_report_start = 0; /* True if bug report header was already logged. */
63static pthread_mutex_t bug_report_start_mutex = PTHREAD_MUTEX_INITIALIZER{ { 0, 0, 0, 0, PTHREAD_MUTEX_TIMED_NP, 0, 0, { 0, 0 } } };
64
65/* Forward declarations */
66void bugReportStart(void);
67void printCrashReport(void);
68void bugReportEnd(int killViaSignal, int sig);
69void 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) */
79void 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
92void 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 */
112void 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
122void 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. */
136void xorObjectDigest(redisDb *db, robj *keyobj, unsigned char *digest, robj *o) {
137 uint32_t aux = htonl(o->type)__bswap_32 (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_STRING0) {
144 mixStringObjectDigest(digest,o);
145 } else if (o->type == OBJ_LIST1) {
146 listTypeIterator *li = listTypeInitIterator(o,0,LIST_TAIL1);
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_SET2) {
155 setTypeIterator *si = setTypeInitIterator(o);
156 sds sdsele;
157 while((sdsele = setTypeNextObject(si)) != NULL((void*)0)) {
158 xorDigest(digest,sdsele,sdslen(sdsele));
159 sdsfree(sdsele);
160 }
161 setTypeReleaseIterator(si);
162 } else if (o->type == OBJ_ZSET3) {
163 unsigned char eledigest[20];
164
165 if (o->encoding == OBJ_ENCODING_ZIPLIST5) {
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)((eptr != ((void*)0))?(void)0 : (_serverAssert("eptr != NULL"
,"debug.c",174),__builtin_unreachable()))
;
175 sptr = ziplistNext(zl,eptr);
176 serverAssert(sptr != NULL)((sptr != ((void*)0))?(void)0 : (_serverAssert("sptr != NULL"
,"debug.c",176),__builtin_unreachable()))
;
177
178 while (eptr != NULL((void*)0)) {
179 serverAssert(ziplistGet(eptr,&vstr,&vlen,&vll))((ziplistGet(eptr,&vstr,&vlen,&vll))?(void)0 : (_serverAssert
("ziplistGet(eptr,&vstr,&vlen,&vll)","debug.c",179
),__builtin_unreachable()))
;
180 score = zzlGetScore(sptr);
181
182 memset(eledigest,0,20);
183 if (vstr != NULL((void*)0)) {
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_SKIPLIST7) {
196 zset *zs = o->ptr;
197 dictIterator *di = dictGetIterator(zs->dict);
198 dictEntry *de;
199
200 while((de = dictNext(di)) != NULL((void*)0)) {
201 sds sdsele = dictGetKey(de)((de)->key);
202 double *score = dictGetVal(de)((de)->v.val);
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")_serverPanic("debug.c",212,"Unknown sorted set encoding"),__builtin_unreachable
()
;
213 }
214 } else if (o->type == OBJ_HASH4) {
215 hashTypeIterator *hi = hashTypeInitIterator(o);
216 while (hashTypeNext(hi) != C_ERR-1) {
217 unsigned char eledigest[20];
218 sds sdsele;
219
220 memset(eledigest,0,20);
221 sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY1);
222 mixDigest(eledigest,sdsele,sdslen(sdsele));
223 sdsfree(sdsele);
224 sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE2);
225 mixDigest(eledigest,sdsele,sdslen(sdsele));
226 sdsfree(sdsele);
227 xorDigest(digest,eledigest,20);
228 }
229 hashTypeReleaseIterator(hi);
230 } else if (o->type == OBJ_STREAM6) {
231 streamIterator si;
232 streamIteratorStart(&si,o->ptr,NULL((void*)0),NULL((void*)0),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_MODULE5) {
252 RedisModuleDigest md;
253 moduleValue *mv = o->ptr;
254 moduleType *mt = mv->type;
255 moduleInitDigestContext(md)do { memset(md.o,0,sizeof(md.o)); memset(md.x,0,sizeof(md.x))
; } while(0)
;
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")_serverPanic("debug.c",261,"Unknown object type"),__builtin_unreachable
()
;
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. */
273void computeDatasetDigest(unsigned char *final) {
274 unsigned char digest[20];
275 dictIterator *di = NULL((void*)0);
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)((db->dict)->ht[0].used+(db->dict)->ht[1].used) == 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)__bswap_32 (j);
291 mixDigest(final,&aux,sizeof(aux));
292
293 /* Iterate this DB writing every entry */
294 while((de = dictNext(di)) != NULL((void*)0)) {
295 sds key;
296 robj *keyobj, *o;
297
298 memset(digest,0,20); /* This key-val digest */
299 key = dictGetKey(de)((de)->key);
300 keyobj = createStringObject(key,sdslen(key));
301
302 mixDigest(digest,key,sdslen(key));
303
304 o = dictGetVal(de)((de)->v.val);
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_JEMALLOC1
316void 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((void*)0)) != C_OK0)
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((void*)0), argc > 1?sz: 0))) {
329 if (ret == EPERM1 && argc > 1) {
330 /* if this option is write only, try just writing to it. */
331 if (!(ret=je_mallctl(argv[0]->ptr, NULL((void*)0), 0, &val, sz))) {
332 addReply(c, shared.ok);
333 return;
334 }
335 }
336 if (ret==EINVAL22) {
337 /* size might be wrong, try a smaller one */
338 sz /= 2;
339#if BYTE_ORDER1234 == BIG_ENDIAN4321
340 val <<= 8*sz;
341#endif
342 continue;
343 }
344 addReplyErrorFormat(c,"%s", strerror(ret));
345 return;
346 } else {
347#if BYTE_ORDER1234 == BIG_ENDIAN4321
348 old >>= 64 - 8*sz;
349#endif
350 addReplyLongLong(c, old);
351 return;
352 }
353 }
354 addReplyErrorFormat(c,"%s", strerror(EINVAL22));
355}
356
357void 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((void*)0), 0))) {
363 /* return error unless this option is write only. */
364 if (!(rret == EPERM1 && 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((void*)0), sz = 0;
374 wret = je_mallctl(argv[0]->ptr, NULL((void*)0), 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
385void 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_JEMALLOC1
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, flsuh 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>.",
470NULL((void*)0)
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 %ld", time(NULL))_serverPanic("debug.c",476,"DEBUG PANIC called at Unix time %ld"
, time(((void*)0))),__builtin_unreachable()
;
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((void*)0))
483 != C_OK0) return;
484 if (delay < 0) delay = 0;
485 }
486 int flags = !strcasecmp(c->argv[1]->ptr,"restart") ?
487 (RESTART_SERVER_GRACEFULLY(1<<0)|RESTART_SERVER_CONFIG_REWRITE(1<<1)) :
488 RESTART_SERVER_NONE0;
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(9223372036854775807L *2UL+1UL)); /* 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)((1 == 2)?(void)0 : (_serverAssertWithInfo(c,c->argv[0],"1 == 2"
,"debug.c",496),__builtin_unreachable()))
;
497 } else if (!strcasecmp(c->argv[1]->ptr,"log") && c->argc == 3) {
498 serverLog(LL_WARNING3, "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_NONE0;
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(1<<2);
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_OK0) {
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_FLAGS0,NULL((void*)0));
539
540 protectClient(c);
541 int ret = rdbLoad(server.rdb_filename,NULL((void*)0),flags);
542 unprotectClient(c);
543 if (ret != C_OK0) {
544 addReplyError(c,"Error trying to load the RDB dump");
545 return;
546 }
547 serverLog(LL_WARNING3,"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_OFF0) flushAppendOnlyFile(1);
551 emptyDb(-1,EMPTYDB_NO_FLAGS0,NULL((void*)0));
552 protectClient(c);
553 int ret = loadAppendOnlyFile(server.aof_filename);
554 unprotectClient(c);
555 if (ret != C_OK0) {
556 addReplyErrorObject(c,shared.err);
557 return;
558 }
559 server.dirty = 0; /* Prevent AOF / replication */
560 serverLog(LL_WARNING3,"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((void*)0)) {
568 addReplyErrorObject(c,shared.nokeyerr);
569 return;
570 }
571 val = dictGetVal(de)((de)->v.val);
572 strenc = strEncoding(val->encoding);
573
574 char extra[138] = {0};
575 if (val->encoding == OBJ_ENCODING_QUICKLIST9) {
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;
Value stored to 'remaining' is never read
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((void*)0)) {
620 addReplyErrorObject(c,shared.nokeyerr);
621 return;
622 }
623 val = dictGetVal(de)((de)->v.val);
624 key = dictGetKey(de)((de)->key);
625
626 if (val->type != OBJ_STRING0 || !sdsEncodedObject(val)(val->encoding == 0 || val->encoding == 8)) {
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((void*)0)) return;
644
645 if (o->encoding != OBJ_ENCODING_ZIPLIST5) {
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((void*)0)) != C_OK0)
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((void*)0)) != C_OK0 )
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((void*)0)) {
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((void*)0),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((void*)0)) ? NULL((void*)0) : dictGetVal(de)((de)->v.val);
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 addReplyProto(c,"(1234567999999999999999999999999999999\r\n",40);
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 addReplyAttributeLen(c,1);
741 addReplyBulkCString(c,"key-popularity");
742 addReplyArrayLen(c,2);
743 addReplyBulkCString(c,"key:123");
744 addReplyLongLong(c,90);
745 /* Attributes are not real replies, so a well formed reply should
746 * also have a normal reply type after the attribute. */
747 addReplyBulkCString(c,"Some real reply following the attribute");
748 } else if (!strcasecmp(name,"push")) {
749 addReplyPushLen(c,2);
750 addReplyBulkCString(c,"server-cpu-usage");
751 addReplyLongLong(c,42);
752 /* Push replies are not synchronous replies, so we emit also a
753 * normal reply in order for blocking clients just discarding the
754 * push reply, to actually consume the reply and continue. */
755 addReplyBulkCString(c,"Some real reply following the push reply");
756 } else if (!strcasecmp(name,"true")) {
757 addReplyBool(c,1);
758 } else if (!strcasecmp(name,"false")) {
759 addReplyBool(c,0);
760 } else if (!strcasecmp(name,"verbatim")) {
761 addReplyVerbatim(c,"This is a verbatim\nstring",25,"txt");
762 } else {
763 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");
764 }
765 } else if (!strcasecmp(c->argv[1]->ptr,"sleep") && c->argc == 3) {
766 double dtime = strtod(c->argv[2]->ptr,NULL((void*)0));
767 long long utime = dtime*1000000;
768 struct timespec tv;
769
770 tv.tv_sec = utime / 1000000;
771 tv.tv_nsec = (utime % 1000000) * 1000;
772 nanosleep(&tv, NULL((void*)0));
773 addReply(c,shared.ok);
774 } else if (!strcasecmp(c->argv[1]->ptr,"set-active-expire") &&
775 c->argc == 3)
776 {
777 server.active_expire_enabled = atoi(c->argv[2]->ptr);
778 addReply(c,shared.ok);
779 } else if (!strcasecmp(c->argv[1]->ptr,"set-skip-checksum-validation") &&
780 c->argc == 3)
781 {
782 server.skip_checksum_validation = atoi(c->argv[2]->ptr);
783 addReply(c,shared.ok);
784 } else if (!strcasecmp(c->argv[1]->ptr,"aof-flush-sleep") &&
785 c->argc == 3)
786 {
787 server.aof_flush_sleep = atoi(c->argv[2]->ptr);
788 addReply(c,shared.ok);
789 } else if (!strcasecmp(c->argv[1]->ptr,"lua-always-replicate-commands") &&
790 c->argc == 3)
791 {
792 server.lua_always_replicate_commands = atoi(c->argv[2]->ptr);
793 addReply(c,shared.ok);
794 } else if (!strcasecmp(c->argv[1]->ptr,"error") && c->argc == 3) {
795 sds errstr = sdsnewlen("-",1);
796
797 errstr = sdscatsds(errstr,c->argv[2]->ptr);
798 errstr = sdsmapchars(errstr,"\n\r"," ",2); /* no newlines in errors. */
799 errstr = sdscatlen(errstr,"\r\n",2);
800 addReplySds(c,errstr);
801 } else if (!strcasecmp(c->argv[1]->ptr,"structsize") && c->argc == 2) {
802 sds sizes = sdsempty();
803 sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32);
804 sizes = sdscatprintf(sizes,"robj:%d ",(int)sizeof(robj));
805 sizes = sdscatprintf(sizes,"dictentry:%d ",(int)sizeof(dictEntry));
806 sizes = sdscatprintf(sizes,"sdshdr5:%d ",(int)sizeof(struct sdshdr5));
807 sizes = sdscatprintf(sizes,"sdshdr8:%d ",(int)sizeof(struct sdshdr8));
808 sizes = sdscatprintf(sizes,"sdshdr16:%d ",(int)sizeof(struct sdshdr16));
809 sizes = sdscatprintf(sizes,"sdshdr32:%d ",(int)sizeof(struct sdshdr32));
810 sizes = sdscatprintf(sizes,"sdshdr64:%d ",(int)sizeof(struct sdshdr64));
811 addReplyBulkSds(c,sizes);
812 } else if (!strcasecmp(c->argv[1]->ptr,"htstats") && c->argc == 3) {
813 long dbid;
814 sds stats = sdsempty();
815 char buf[4096];
816
817 if (getLongFromObjectOrReply(c, c->argv[2], &dbid, NULL((void*)0)) != C_OK0) {
818 sdsfree(stats);
819 return;
820 }
821 if (dbid < 0 || dbid >= server.dbnum) {
822 sdsfree(stats);
823 addReplyError(c,"Out of range database");
824 return;
825 }
826
827 stats = sdscatprintf(stats,"[Dictionary HT]\n");
828 dictGetStats(buf,sizeof(buf),server.db[dbid].dict);
829 stats = sdscat(stats,buf);
830
831 stats = sdscatprintf(stats,"[Expires HT]\n");
832 dictGetStats(buf,sizeof(buf),server.db[dbid].expires);
833 stats = sdscat(stats,buf);
834
835 addReplyVerbatim(c,stats,sdslen(stats),"txt");
836 sdsfree(stats);
837 } else if (!strcasecmp(c->argv[1]->ptr,"htstats-key") && c->argc == 3) {
838 robj *o;
839 dict *ht = NULL((void*)0);
840
841 if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nokeyerr))
842 == NULL((void*)0)) return;
843
844 /* Get the hash table reference from the object, if possible. */
845 switch (o->encoding) {
846 case OBJ_ENCODING_SKIPLIST7:
847 {
848 zset *zs = o->ptr;
849 ht = zs->dict;
850 }
851 break;
852 case OBJ_ENCODING_HT2:
853 ht = o->ptr;
854 break;
855 }
856
857 if (ht == NULL((void*)0)) {
858 addReplyError(c,"The value stored at the specified key is not "
859 "represented using an hash table");
860 } else {
861 char buf[4096];
862 dictGetStats(buf,sizeof(buf),ht);
863 addReplyVerbatim(c,buf,strlen(buf),"txt");
864 }
865 } else if (!strcasecmp(c->argv[1]->ptr,"change-repl-id") && c->argc == 2) {
866 serverLog(LL_WARNING3,"Changing replication IDs after receiving DEBUG change-repl-id");
867 changeReplicationId();
868 clearReplicationId2();
869 addReply(c,shared.ok);
870 } else if (!strcasecmp(c->argv[1]->ptr,"stringmatch-test") && c->argc == 2)
871 {
872 stringmatchlen_fuzz_test();
873 addReplyStatus(c,"Apparently Redis did not crash: test passed");
874 } else if (!strcasecmp(c->argv[1]->ptr,"config-rewrite-force-all") && c->argc == 2)
875 {
876 if (rewriteConfig(server.configfile, 1) == -1)
877 addReplyError(c, "CONFIG-REWRITE-FORCE-ALL failed");
878 else
879 addReply(c, shared.ok);
880#ifdef USE_JEMALLOC1
881 } else if(!strcasecmp(c->argv[1]->ptr,"mallctl") && c->argc >= 3) {
882 mallctl_int(c, c->argv+2, c->argc-2);
883 return;
884 } else if(!strcasecmp(c->argv[1]->ptr,"mallctl-str") && c->argc >= 3) {
885 mallctl_string(c, c->argv+2, c->argc-2);
886 return;
887#endif
888 } else {
889 addReplySubcommandSyntaxError(c);
890 return;
891 }
892}
893
894/* =========================== Crash handling ============================== */
895
896void _serverAssert(const char *estr, const char *file, int line) {
897 bugReportStart();
898 serverLog(LL_WARNING3,"=== ASSERTION FAILED ===");
899 serverLog(LL_WARNING3,"==> %s:%d '%s' is not true",file,line,estr);
900
901 if (server.crashlog_enabled) {
902#ifdef HAVE_BACKTRACE1
903 logStackTrace(NULL((void*)0), 1);
904#endif
905 printCrashReport();
906 }
907
908 // remove the signal handler so on abort() we will output the crash report.
909 removeSignalHandlers();
910 bugReportEnd(0, 0);
911}
912
913void _serverAssertPrintClientInfo(const client *c) {
914 int j;
915 char conninfo[CONN_INFO_LEN32];
916
917 bugReportStart();
918 serverLog(LL_WARNING3,"=== ASSERTION FAILED CLIENT CONTEXT ===");
919 serverLog(LL_WARNING3,"client->flags = %llu", (unsigned long long) c->flags);
920 serverLog(LL_WARNING3,"client->conn = %s", connGetInfo(c->conn, conninfo, sizeof(conninfo)));
921 serverLog(LL_WARNING3,"client->argc = %d", c->argc);
922 for (j=0; j < c->argc; j++) {
923 char buf[128];
924 char *arg;
925
926 if (c->argv[j]->type == OBJ_STRING0 && sdsEncodedObject(c->argv[j])(c->argv[j]->encoding == 0 || c->argv[j]->encoding
== 8)
) {
927 arg = (char*) c->argv[j]->ptr;
928 } else {
929 snprintf(buf,sizeof(buf),"Object type: %u, encoding: %u",
930 c->argv[j]->type, c->argv[j]->encoding);
931 arg = buf;
932 }
933 serverLog(LL_WARNING3,"client->argv[%d] = \"%s\" (refcount: %d)",
934 j, arg, c->argv[j]->refcount);
935 }
936}
937
938void serverLogObjectDebugInfo(const robj *o) {
939 serverLog(LL_WARNING3,"Object type: %d", o->type);
940 serverLog(LL_WARNING3,"Object encoding: %d", o->encoding);
941 serverLog(LL_WARNING3,"Object refcount: %d", o->refcount);
942#if UNSAFE_CRASH_REPORT
943 /* This code is now disabled. o->ptr may be unreliable to print. in some
944 * cases a ziplist could have already been freed by realloc, but not yet
945 * updated to o->ptr. in other cases the call to ziplistLen may need to
946 * iterate on all the items in the list (and possibly crash again).
947 * For some cases it may be ok to crash here again, but these could cause
948 * invalid memory access which will bother valgrind and also possibly cause
949 * random memory portion to be "leaked" into the logfile. */
950 if (o->type == OBJ_STRING0 && sdsEncodedObject(o)(o->encoding == 0 || o->encoding == 8)) {
951 serverLog(LL_WARNING3,"Object raw string len: %zu", sdslen(o->ptr));
952 if (sdslen(o->ptr) < 4096) {
953 sds repr = sdscatrepr(sdsempty(),o->ptr,sdslen(o->ptr));
954 serverLog(LL_WARNING3,"Object raw string content: %s", repr);
955 sdsfree(repr);
956 }
957 } else if (o->type == OBJ_LIST1) {
958 serverLog(LL_WARNING3,"List length: %d", (int) listTypeLength(o));
959 } else if (o->type == OBJ_SET2) {
960 serverLog(LL_WARNING3,"Set size: %d", (int) setTypeSize(o));
961 } else if (o->type == OBJ_HASH4) {
962 serverLog(LL_WARNING3,"Hash size: %d", (int) hashTypeLength(o));
963 } else if (o->type == OBJ_ZSET3) {
964 serverLog(LL_WARNING3,"Sorted set size: %d", (int) zsetLength(o));
965 if (o->encoding == OBJ_ENCODING_SKIPLIST7)
966 serverLog(LL_WARNING3,"Skiplist level: %d", (int) ((const zset*)o->ptr)->zsl->level);
967 } else if (o->type == OBJ_STREAM6) {
968 serverLog(LL_WARNING3,"Stream size: %d", (int) streamLength(o));
969 }
970#endif
971}
972
973void _serverAssertPrintObject(const robj *o) {
974 bugReportStart();
975 serverLog(LL_WARNING3,"=== ASSERTION FAILED OBJECT CONTEXT ===");
976 serverLogObjectDebugInfo(o);
977}
978
979void _serverAssertWithInfo(const client *c, const robj *o, const char *estr, const char *file, int line) {
980 if (c) _serverAssertPrintClientInfo(c);
981 if (o) _serverAssertPrintObject(o);
982 _serverAssert(estr,file,line);
983}
984
985void _serverPanic(const char *file, int line, const char *msg, ...) {
986 va_list ap;
987 va_start(ap,msg)__builtin_va_start(ap, msg);
988 char fmtmsg[256];
989 vsnprintf(fmtmsg,sizeof(fmtmsg),msg,ap);
990 va_end(ap)__builtin_va_end(ap);
991
992 bugReportStart();
993 serverLog(LL_WARNING3,"------------------------------------------------");
994 serverLog(LL_WARNING3,"!!! Software Failure. Press left mouse button to continue");
995 serverLog(LL_WARNING3,"Guru Meditation: %s #%s:%d",fmtmsg,file,line);
996
997 if (server.crashlog_enabled) {
998#ifdef HAVE_BACKTRACE1
999 logStackTrace(NULL((void*)0), 1);
1000#endif
1001 printCrashReport();
1002 }
1003
1004 // remove the signal handler so on abort() we will output the crash report.
1005 removeSignalHandlers();
1006 bugReportEnd(0, 0);
1007}
1008
1009void bugReportStart(void) {
1010 pthread_mutex_lock(&bug_report_start_mutex);
1011 if (bug_report_start == 0) {
1012 serverLogRaw(LL_WARNING3|LL_RAW(1<<10),
1013 "\n\n=== REDIS BUG REPORT START: Cut & paste starting from here ===\n");
1014 bug_report_start = 1;
1015 }
1016 pthread_mutex_unlock(&bug_report_start_mutex);
1017}
1018
1019#ifdef HAVE_BACKTRACE1
1020static void *getMcontextEip(ucontext_t *uc) {
1021#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
1022 /* OSX < 10.6 */
1023 #if defined(__x86_64__1)
1024 return (void*) uc->uc_mcontext->__ss.__rip;
1025 #elif defined(__i386__)
1026 return (void*) uc->uc_mcontext->__ss.__eip;
1027 #else
1028 return (void*) uc->uc_mcontext->__ss.__srr0;
1029 #endif
1030#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
1031 /* OSX >= 10.6 */
1032 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
1033 return (void*) uc->uc_mcontext->__ss.__rip;
1034 #elif defined(__i386__)
1035 return (void*) uc->uc_mcontext->__ss.__eip;
1036 #else
1037 /* OSX ARM64 */
1038 return (void*) arm_thread_state64_get_pc(uc->uc_mcontext->__ss);
1039 #endif
1040#elif defined(__linux__1)
1041 /* Linux */
1042 #if defined(__i386__) || ((defined(__X86_64__) || defined(__x86_64__1)) && defined(__ILP32__))
1043 return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */
1044 #elif defined(__X86_64__) || defined(__x86_64__1)
1045 return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */
1046 #elif defined(__ia64__) /* Linux IA64 */
1047 return (void*) uc->uc_mcontext.sc_ip;
1048 #elif defined(__arm__) /* Linux ARM */
1049 return (void*) uc->uc_mcontext.arm_pc;
1050 #elif defined(__aarch64__) /* Linux AArch64 */
1051 return (void*) uc->uc_mcontext.pc;
1052 #endif
1053#elif defined(__FreeBSD__)
1054 /* FreeBSD */
1055 #if defined(__i386__)
1056 return (void*) uc->uc_mcontext.mc_eip;
1057 #elif defined(__x86_64__1)
1058 return (void*) uc->uc_mcontext.mc_rip;
1059 #endif
1060#elif defined(__OpenBSD__)
1061 /* OpenBSD */
1062 #if defined(__i386__)
1063 return (void*) uc->sc_eip;
1064 #elif defined(__x86_64__1)
1065 return (void*) uc->sc_rip;
1066 #endif
1067#elif defined(__NetBSD__)
1068 #if defined(__i386__)
1069 return (void*) uc->uc_mcontext.__gregs[_REG_EIP];
1070 #elif defined(__x86_64__1)
1071 return (void*) uc->uc_mcontext.__gregs[_REG_RIP];
1072 #endif
1073#elif defined(__DragonFly__)
1074 return (void*) uc->uc_mcontext.mc_rip;
1075#else
1076 return NULL((void*)0);
1077#endif
1078}
1079
1080void logStackContent(void **sp) {
1081 int i;
1082 for (i = 15; i >= 0; i--) {
1083 unsigned long addr = (unsigned long) sp+i;
1084 unsigned long val = (unsigned long) sp[i];
1085
1086 if (sizeof(long) == 4)
1087 serverLog(LL_WARNING3, "(%08lx) -> %08lx", addr, val);
1088 else
1089 serverLog(LL_WARNING3, "(%016lx) -> %016lx", addr, val);
1090 }
1091}
1092
1093/* Log dump of processor registers */
1094void logRegisters(ucontext_t *uc) {
1095 serverLog(LL_WARNING3|LL_RAW(1<<10), "\n------ REGISTERS ------\n");
1096
1097/* OSX */
1098#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
1099 /* OSX AMD64 */
1100 #if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
1101 serverLog(LL_WARNING3,
1102 "\n"
1103 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1104 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1105 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1106 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1107 "RIP:%016lx EFL:%016lx\nCS :%016lx FS:%016lx GS:%016lx",
1108 (unsigned long) uc->uc_mcontext->__ss.__rax,
1109 (unsigned long) uc->uc_mcontext->__ss.__rbx,
1110 (unsigned long) uc->uc_mcontext->__ss.__rcx,
1111 (unsigned long) uc->uc_mcontext->__ss.__rdx,
1112 (unsigned long) uc->uc_mcontext->__ss.__rdi,
1113 (unsigned long) uc->uc_mcontext->__ss.__rsi,
1114 (unsigned long) uc->uc_mcontext->__ss.__rbp,
1115 (unsigned long) uc->uc_mcontext->__ss.__rsp,
1116 (unsigned long) uc->uc_mcontext->__ss.__r8,
1117 (unsigned long) uc->uc_mcontext->__ss.__r9,
1118 (unsigned long) uc->uc_mcontext->__ss.__r10,
1119 (unsigned long) uc->uc_mcontext->__ss.__r11,
1120 (unsigned long) uc->uc_mcontext->__ss.__r12,
1121 (unsigned long) uc->uc_mcontext->__ss.__r13,
1122 (unsigned long) uc->uc_mcontext->__ss.__r14,
1123 (unsigned long) uc->uc_mcontext->__ss.__r15,
1124 (unsigned long) uc->uc_mcontext->__ss.__rip,
1125 (unsigned long) uc->uc_mcontext->__ss.__rflags,
1126 (unsigned long) uc->uc_mcontext->__ss.__cs,
1127 (unsigned long) uc->uc_mcontext->__ss.__fs,
1128 (unsigned long) uc->uc_mcontext->__ss.__gs
1129 );
1130 logStackContent((void**)uc->uc_mcontext->__ss.__rsp);
1131 #elif defined(__i386__)
1132 /* OSX x86 */
1133 serverLog(LL_WARNING3,
1134 "\n"
1135 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1136 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1137 "SS:%08lx EFL:%08lx EIP:%08lx CS :%08lx\n"
1138 "DS:%08lx ES:%08lx FS :%08lx GS :%08lx",
1139 (unsigned long) uc->uc_mcontext->__ss.__eax,
1140 (unsigned long) uc->uc_mcontext->__ss.__ebx,
1141 (unsigned long) uc->uc_mcontext->__ss.__ecx,
1142 (unsigned long) uc->uc_mcontext->__ss.__edx,
1143 (unsigned long) uc->uc_mcontext->__ss.__edi,
1144 (unsigned long) uc->uc_mcontext->__ss.__esi,
1145 (unsigned long) uc->uc_mcontext->__ss.__ebp,
1146 (unsigned long) uc->uc_mcontext->__ss.__esp,
1147 (unsigned long) uc->uc_mcontext->__ss.__ss,
1148 (unsigned long) uc->uc_mcontext->__ss.__eflags,
1149 (unsigned long) uc->uc_mcontext->__ss.__eip,
1150 (unsigned long) uc->uc_mcontext->__ss.__cs,
1151 (unsigned long) uc->uc_mcontext->__ss.__ds,
1152 (unsigned long) uc->uc_mcontext->__ss.__es,
1153 (unsigned long) uc->uc_mcontext->__ss.__fs,
1154 (unsigned long) uc->uc_mcontext->__ss.__gs
1155 );
1156 logStackContent((void**)uc->uc_mcontext->__ss.__esp);
1157 #else
1158 /* OSX ARM64 */
1159 serverLog(LL_WARNING3,
1160 "\n"
1161 "x0:%016lx x1:%016lx x2:%016lx x3:%016lx\n"
1162 "x4:%016lx x5:%016lx x6:%016lx x7:%016lx\n"
1163 "x8:%016lx x9:%016lx x10:%016lx x11:%016lx\n"
1164 "x12:%016lx x13:%016lx x14:%016lx x15:%016lx\n"
1165 "x16:%016lx x17:%016lx x18:%016lx x19:%016lx\n"
1166 "x20:%016lx x21:%016lx x22:%016lx x23:%016lx\n"
1167 "x24:%016lx x25:%016lx x26:%016lx x27:%016lx\n"
1168 "x28:%016lx fp:%016lx lr:%016lx\n"
1169 "sp:%016lx pc:%016lx cpsr:%08lx\n",
1170 (unsigned long) uc->uc_mcontext->__ss.__x[0],
1171 (unsigned long) uc->uc_mcontext->__ss.__x[1],
1172 (unsigned long) uc->uc_mcontext->__ss.__x[2],
1173 (unsigned long) uc->uc_mcontext->__ss.__x[3],
1174 (unsigned long) uc->uc_mcontext->__ss.__x[4],
1175 (unsigned long) uc->uc_mcontext->__ss.__x[5],
1176 (unsigned long) uc->uc_mcontext->__ss.__x[6],
1177 (unsigned long) uc->uc_mcontext->__ss.__x[7],
1178 (unsigned long) uc->uc_mcontext->__ss.__x[8],
1179 (unsigned long) uc->uc_mcontext->__ss.__x[9],
1180 (unsigned long) uc->uc_mcontext->__ss.__x[10],
1181 (unsigned long) uc->uc_mcontext->__ss.__x[11],
1182 (unsigned long) uc->uc_mcontext->__ss.__x[12],
1183 (unsigned long) uc->uc_mcontext->__ss.__x[13],
1184 (unsigned long) uc->uc_mcontext->__ss.__x[14],
1185 (unsigned long) uc->uc_mcontext->__ss.__x[15],
1186 (unsigned long) uc->uc_mcontext->__ss.__x[16],
1187 (unsigned long) uc->uc_mcontext->__ss.__x[17],
1188 (unsigned long) uc->uc_mcontext->__ss.__x[18],
1189 (unsigned long) uc->uc_mcontext->__ss.__x[19],
1190 (unsigned long) uc->uc_mcontext->__ss.__x[20],
1191 (unsigned long) uc->uc_mcontext->__ss.__x[21],
1192 (unsigned long) uc->uc_mcontext->__ss.__x[22],
1193 (unsigned long) uc->uc_mcontext->__ss.__x[23],
1194 (unsigned long) uc->uc_mcontext->__ss.__x[24],
1195 (unsigned long) uc->uc_mcontext->__ss.__x[25],
1196 (unsigned long) uc->uc_mcontext->__ss.__x[26],
1197 (unsigned long) uc->uc_mcontext->__ss.__x[27],
1198 (unsigned long) uc->uc_mcontext->__ss.__x[28],
1199 (unsigned long) arm_thread_state64_get_fp(uc->uc_mcontext->__ss),
1200 (unsigned long) arm_thread_state64_get_lr(uc->uc_mcontext->__ss),
1201 (unsigned long) arm_thread_state64_get_sp(uc->uc_mcontext->__ss),
1202 (unsigned long) arm_thread_state64_get_pc(uc->uc_mcontext->__ss),
1203 (unsigned long) uc->uc_mcontext->__ss.__cpsr
1204 );
1205 logStackContent((void**) arm_thread_state64_get_sp(uc->uc_mcontext->__ss));
1206 #endif
1207/* Linux */
1208#elif defined(__linux__1)
1209 /* Linux x86 */
1210 #if defined(__i386__) || ((defined(__X86_64__) || defined(__x86_64__1)) && defined(__ILP32__))
1211 serverLog(LL_WARNING3,
1212 "\n"
1213 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1214 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1215 "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
1216 "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
1217 (unsigned long) uc->uc_mcontext.gregs[11],
1218 (unsigned long) uc->uc_mcontext.gregs[8],
1219 (unsigned long) uc->uc_mcontext.gregs[10],
1220 (unsigned long) uc->uc_mcontext.gregs[9],
1221 (unsigned long) uc->uc_mcontext.gregs[4],
1222 (unsigned long) uc->uc_mcontext.gregs[5],
1223 (unsigned long) uc->uc_mcontext.gregs[6],
1224 (unsigned long) uc->uc_mcontext.gregs[7],
1225 (unsigned long) uc->uc_mcontext.gregs[18],
1226 (unsigned long) uc->uc_mcontext.gregs[17],
1227 (unsigned long) uc->uc_mcontext.gregs[14],
1228 (unsigned long) uc->uc_mcontext.gregs[15],
1229 (unsigned long) uc->uc_mcontext.gregs[3],
1230 (unsigned long) uc->uc_mcontext.gregs[2],
1231 (unsigned long) uc->uc_mcontext.gregs[1],
1232 (unsigned long) uc->uc_mcontext.gregs[0]
1233 );
1234 logStackContent((void**)uc->uc_mcontext.gregs[7]);
1235 #elif defined(__X86_64__) || defined(__x86_64__1)
1236 /* Linux AMD64 */
1237 serverLog(LL_WARNING3,
1238 "\n"
1239 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1240 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1241 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1242 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1243 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1244 (unsigned long) uc->uc_mcontext.gregs[13],
1245 (unsigned long) uc->uc_mcontext.gregs[11],
1246 (unsigned long) uc->uc_mcontext.gregs[14],
1247 (unsigned long) uc->uc_mcontext.gregs[12],
1248 (unsigned long) uc->uc_mcontext.gregs[8],
1249 (unsigned long) uc->uc_mcontext.gregs[9],
1250 (unsigned long) uc->uc_mcontext.gregs[10],
1251 (unsigned long) uc->uc_mcontext.gregs[15],
1252 (unsigned long) uc->uc_mcontext.gregs[0],
1253 (unsigned long) uc->uc_mcontext.gregs[1],
1254 (unsigned long) uc->uc_mcontext.gregs[2],
1255 (unsigned long) uc->uc_mcontext.gregs[3],
1256 (unsigned long) uc->uc_mcontext.gregs[4],
1257 (unsigned long) uc->uc_mcontext.gregs[5],
1258 (unsigned long) uc->uc_mcontext.gregs[6],
1259 (unsigned long) uc->uc_mcontext.gregs[7],
1260 (unsigned long) uc->uc_mcontext.gregs[16],
1261 (unsigned long) uc->uc_mcontext.gregs[17],
1262 (unsigned long) uc->uc_mcontext.gregs[18]
1263 );
1264 logStackContent((void**)uc->uc_mcontext.gregs[15]);
1265 #elif defined(__aarch64__) /* Linux AArch64 */
1266 serverLog(LL_WARNING3,
1267 "\n"
1268 "X18:%016lx X19:%016lx\nX20:%016lx X21:%016lx\n"
1269 "X22:%016lx X23:%016lx\nX24:%016lx X25:%016lx\n"
1270 "X26:%016lx X27:%016lx\nX28:%016lx X29:%016lx\n"
1271 "X30:%016lx\n"
1272 "pc:%016lx sp:%016lx\npstate:%016lx fault_address:%016lx\n",
1273 (unsigned long) uc->uc_mcontext.regs[18],
1274 (unsigned long) uc->uc_mcontext.regs[19],
1275 (unsigned long) uc->uc_mcontext.regs[20],
1276 (unsigned long) uc->uc_mcontext.regs[21],
1277 (unsigned long) uc->uc_mcontext.regs[22],
1278 (unsigned long) uc->uc_mcontext.regs[23],
1279 (unsigned long) uc->uc_mcontext.regs[24],
1280 (unsigned long) uc->uc_mcontext.regs[25],
1281 (unsigned long) uc->uc_mcontext.regs[26],
1282 (unsigned long) uc->uc_mcontext.regs[27],
1283 (unsigned long) uc->uc_mcontext.regs[28],
1284 (unsigned long) uc->uc_mcontext.regs[29],
1285 (unsigned long) uc->uc_mcontext.regs[30],
1286 (unsigned long) uc->uc_mcontext.pc,
1287 (unsigned long) uc->uc_mcontext.sp,
1288 (unsigned long) uc->uc_mcontext.pstate,
1289 (unsigned long) uc->uc_mcontext.fault_address
1290 );
1291 logStackContent((void**)uc->uc_mcontext.sp);
1292 #elif defined(__arm__) /* Linux ARM */
1293 serverLog(LL_WARNING3,
1294 "\n"
1295 "R10:%016lx R9 :%016lx\nR8 :%016lx R7 :%016lx\n"
1296 "R6 :%016lx R5 :%016lx\nR4 :%016lx R3 :%016lx\n"
1297 "R2 :%016lx R1 :%016lx\nR0 :%016lx EC :%016lx\n"
1298 "fp: %016lx ip:%016lx\n"
1299 "pc:%016lx sp:%016lx\ncpsr:%016lx fault_address:%016lx\n",
1300 (unsigned long) uc->uc_mcontext.arm_r10,
1301 (unsigned long) uc->uc_mcontext.arm_r9,
1302 (unsigned long) uc->uc_mcontext.arm_r8,
1303 (unsigned long) uc->uc_mcontext.arm_r7,
1304 (unsigned long) uc->uc_mcontext.arm_r6,
1305 (unsigned long) uc->uc_mcontext.arm_r5,
1306 (unsigned long) uc->uc_mcontext.arm_r4,
1307 (unsigned long) uc->uc_mcontext.arm_r3,
1308 (unsigned long) uc->uc_mcontext.arm_r2,
1309 (unsigned long) uc->uc_mcontext.arm_r1,
1310 (unsigned long) uc->uc_mcontext.arm_r0,
1311 (unsigned long) uc->uc_mcontext.error_code,
1312 (unsigned long) uc->uc_mcontext.arm_fp,
1313 (unsigned long) uc->uc_mcontext.arm_ip,
1314 (unsigned long) uc->uc_mcontext.arm_pc,
1315 (unsigned long) uc->uc_mcontext.arm_sp,
1316 (unsigned long) uc->uc_mcontext.arm_cpsr,
1317 (unsigned long) uc->uc_mcontext.fault_address
1318 );
1319 logStackContent((void**)uc->uc_mcontext.arm_sp);
1320 #endif
1321#elif defined(__FreeBSD__)
1322 #if defined(__x86_64__1)
1323 serverLog(LL_WARNING3,
1324 "\n"
1325 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1326 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1327 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1328 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1329 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1330 (unsigned long) uc->uc_mcontext.mc_rax,
1331 (unsigned long) uc->uc_mcontext.mc_rbx,
1332 (unsigned long) uc->uc_mcontext.mc_rcx,
1333 (unsigned long) uc->uc_mcontext.mc_rdx,
1334 (unsigned long) uc->uc_mcontext.mc_rdi,
1335 (unsigned long) uc->uc_mcontext.mc_rsi,
1336 (unsigned long) uc->uc_mcontext.mc_rbp,
1337 (unsigned long) uc->uc_mcontext.mc_rsp,
1338 (unsigned long) uc->uc_mcontext.mc_r8,
1339 (unsigned long) uc->uc_mcontext.mc_r9,
1340 (unsigned long) uc->uc_mcontext.mc_r10,
1341 (unsigned long) uc->uc_mcontext.mc_r11,
1342 (unsigned long) uc->uc_mcontext.mc_r12,
1343 (unsigned long) uc->uc_mcontext.mc_r13,
1344 (unsigned long) uc->uc_mcontext.mc_r14,
1345 (unsigned long) uc->uc_mcontext.mc_r15,
1346 (unsigned long) uc->uc_mcontext.mc_rip,
1347 (unsigned long) uc->uc_mcontext.mc_rflags,
1348 (unsigned long) uc->uc_mcontext.mc_cs
1349 );
1350 logStackContent((void**)uc->uc_mcontext.mc_rsp);
1351 #elif defined(__i386__)
1352 serverLog(LL_WARNING3,
1353 "\n"
1354 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1355 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1356 "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
1357 "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
1358 (unsigned long) uc->uc_mcontext.mc_eax,
1359 (unsigned long) uc->uc_mcontext.mc_ebx,
1360 (unsigned long) uc->uc_mcontext.mc_ebx,
1361 (unsigned long) uc->uc_mcontext.mc_edx,
1362 (unsigned long) uc->uc_mcontext.mc_edi,
1363 (unsigned long) uc->uc_mcontext.mc_esi,
1364 (unsigned long) uc->uc_mcontext.mc_ebp,
1365 (unsigned long) uc->uc_mcontext.mc_esp,
1366 (unsigned long) uc->uc_mcontext.mc_ss,
1367 (unsigned long) uc->uc_mcontext.mc_eflags,
1368 (unsigned long) uc->uc_mcontext.mc_eip,
1369 (unsigned long) uc->uc_mcontext.mc_cs,
1370 (unsigned long) uc->uc_mcontext.mc_es,
1371 (unsigned long) uc->uc_mcontext.mc_fs,
1372 (unsigned long) uc->uc_mcontext.mc_gs
1373 );
1374 logStackContent((void**)uc->uc_mcontext.mc_esp);
1375 #endif
1376#elif defined(__OpenBSD__)
1377 #if defined(__x86_64__1)
1378 serverLog(LL_WARNING3,
1379 "\n"
1380 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1381 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1382 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1383 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1384 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1385 (unsigned long) uc->sc_rax,
1386 (unsigned long) uc->sc_rbx,
1387 (unsigned long) uc->sc_rcx,
1388 (unsigned long) uc->sc_rdx,
1389 (unsigned long) uc->sc_rdi,
1390 (unsigned long) uc->sc_rsi,
1391 (unsigned long) uc->sc_rbp,
1392 (unsigned long) uc->sc_rsp,
1393 (unsigned long) uc->sc_r8,
1394 (unsigned long) uc->sc_r9,
1395 (unsigned long) uc->sc_r10,
1396 (unsigned long) uc->sc_r11,
1397 (unsigned long) uc->sc_r12,
1398 (unsigned long) uc->sc_r13,
1399 (unsigned long) uc->sc_r14,
1400 (unsigned long) uc->sc_r15,
1401 (unsigned long) uc->sc_rip,
1402 (unsigned long) uc->sc_rflags,
1403 (unsigned long) uc->sc_cs
1404 );
1405 logStackContent((void**)uc->sc_rsp);
1406 #elif defined(__i386__)
1407 serverLog(LL_WARNING3,
1408 "\n"
1409 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1410 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1411 "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
1412 "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
1413 (unsigned long) uc->sc_eax,
1414 (unsigned long) uc->sc_ebx,
1415 (unsigned long) uc->sc_ebx,
1416 (unsigned long) uc->sc_edx,
1417 (unsigned long) uc->sc_edi,
1418 (unsigned long) uc->sc_esi,
1419 (unsigned long) uc->sc_ebp,
1420 (unsigned long) uc->sc_esp,
1421 (unsigned long) uc->sc_ss,
1422 (unsigned long) uc->sc_eflags,
1423 (unsigned long) uc->sc_eip,
1424 (unsigned long) uc->sc_cs,
1425 (unsigned long) uc->sc_es,
1426 (unsigned long) uc->sc_fs,
1427 (unsigned long) uc->sc_gs
1428 );
1429 logStackContent((void**)uc->sc_esp);
1430 #endif
1431#elif defined(__NetBSD__)
1432 #if defined(__x86_64__1)
1433 serverLog(LL_WARNING3,
1434 "\n"
1435 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1436 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1437 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1438 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1439 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1440 (unsigned long) uc->uc_mcontext.__gregs[_REG_RAX],
1441 (unsigned long) uc->uc_mcontext.__gregs[_REG_RBX],
1442 (unsigned long) uc->uc_mcontext.__gregs[_REG_RCX],
1443 (unsigned long) uc->uc_mcontext.__gregs[_REG_RDX],
1444 (unsigned long) uc->uc_mcontext.__gregs[_REG_RDI],
1445 (unsigned long) uc->uc_mcontext.__gregs[_REG_RSI],
1446 (unsigned long) uc->uc_mcontext.__gregs[_REG_RBP],
1447 (unsigned long) uc->uc_mcontext.__gregs[_REG_RSP],
1448 (unsigned long) uc->uc_mcontext.__gregs[_REG_R8],
1449 (unsigned long) uc->uc_mcontext.__gregs[_REG_R9],
1450 (unsigned long) uc->uc_mcontext.__gregs[_REG_R10],
1451 (unsigned long) uc->uc_mcontext.__gregs[_REG_R11],
1452 (unsigned long) uc->uc_mcontext.__gregs[_REG_R12],
1453 (unsigned long) uc->uc_mcontext.__gregs[_REG_R13],
1454 (unsigned long) uc->uc_mcontext.__gregs[_REG_R14],
1455 (unsigned long) uc->uc_mcontext.__gregs[_REG_R15],
1456 (unsigned long) uc->uc_mcontext.__gregs[_REG_RIP],
1457 (unsigned long) uc->uc_mcontext.__gregs[_REG_RFLAGS],
1458 (unsigned long) uc->uc_mcontext.__gregs[_REG_CS]
1459 );
1460 logStackContent((void**)uc->uc_mcontext.__gregs[_REG_RSP]);
1461 #elif defined(__i386__)
1462 serverLog(LL_WARNING3,
1463 "\n"
1464 "EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n"
1465 "EDI:%08lx ESI:%08lx EBP:%08lx ESP:%08lx\n"
1466 "SS :%08lx EFL:%08lx EIP:%08lx CS:%08lx\n"
1467 "DS :%08lx ES :%08lx FS :%08lx GS:%08lx",
1468 (unsigned long) uc->uc_mcontext.__gregs[_REG_EAX],
1469 (unsigned long) uc->uc_mcontext.__gregs[_REG_EBX],
1470 (unsigned long) uc->uc_mcontext.__gregs[_REG_EDX],
1471 (unsigned long) uc->uc_mcontext.__gregs[_REG_EDI],
1472 (unsigned long) uc->uc_mcontext.__gregs[_REG_ESI],
1473 (unsigned long) uc->uc_mcontext.__gregs[_REG_EBP],
1474 (unsigned long) uc->uc_mcontext.__gregs[_REG_ESP],
1475 (unsigned long) uc->uc_mcontext.__gregs[_REG_SS],
1476 (unsigned long) uc->uc_mcontext.__gregs[_REG_EFLAGS],
1477 (unsigned long) uc->uc_mcontext.__gregs[_REG_EIP],
1478 (unsigned long) uc->uc_mcontext.__gregs[_REG_CS],
1479 (unsigned long) uc->uc_mcontext.__gregs[_REG_ES],
1480 (unsigned long) uc->uc_mcontext.__gregs[_REG_FS],
1481 (unsigned long) uc->uc_mcontext.__gregs[_REG_GS]
1482 );
1483 #endif
1484#elif defined(__DragonFly__)
1485 serverLog(LL_WARNING3,
1486 "\n"
1487 "RAX:%016lx RBX:%016lx\nRCX:%016lx RDX:%016lx\n"
1488 "RDI:%016lx RSI:%016lx\nRBP:%016lx RSP:%016lx\n"
1489 "R8 :%016lx R9 :%016lx\nR10:%016lx R11:%016lx\n"
1490 "R12:%016lx R13:%016lx\nR14:%016lx R15:%016lx\n"
1491 "RIP:%016lx EFL:%016lx\nCSGSFS:%016lx",
1492 (unsigned long) uc->uc_mcontext.mc_rax,
1493 (unsigned long) uc->uc_mcontext.mc_rbx,
1494 (unsigned long) uc->uc_mcontext.mc_rcx,
1495 (unsigned long) uc->uc_mcontext.mc_rdx,
1496 (unsigned long) uc->uc_mcontext.mc_rdi,
1497 (unsigned long) uc->uc_mcontext.mc_rsi,
1498 (unsigned long) uc->uc_mcontext.mc_rbp,
1499 (unsigned long) uc->uc_mcontext.mc_rsp,
1500 (unsigned long) uc->uc_mcontext.mc_r8,
1501 (unsigned long) uc->uc_mcontext.mc_r9,
1502 (unsigned long) uc->uc_mcontext.mc_r10,
1503 (unsigned long) uc->uc_mcontext.mc_r11,
1504 (unsigned long) uc->uc_mcontext.mc_r12,
1505 (unsigned long) uc->uc_mcontext.mc_r13,
1506 (unsigned long) uc->uc_mcontext.mc_r14,
1507 (unsigned long) uc->uc_mcontext.mc_r15,
1508 (unsigned long) uc->uc_mcontext.mc_rip,
1509 (unsigned long) uc->uc_mcontext.mc_rflags,
1510 (unsigned long) uc->uc_mcontext.mc_cs
1511 );
1512 logStackContent((void**)uc->uc_mcontext.mc_rsp);
1513#else
1514 serverLog(LL_WARNING3,
1515 " Dumping of registers not supported for this OS/arch");
1516#endif
1517}
1518
1519#endif /* HAVE_BACKTRACE */
1520
1521/* Return a file descriptor to write directly to the Redis log with the
1522 * write(2) syscall, that can be used in critical sections of the code
1523 * where the rest of Redis can't be trusted (for example during the memory
1524 * test) or when an API call requires a raw fd.
1525 *
1526 * Close it with closeDirectLogFiledes(). */
1527int openDirectLogFiledes(void) {
1528 int log_to_stdout = server.logfile[0] == '\0';
1529 int fd = log_to_stdout ?
1530 STDOUT_FILENO1 :
1531 open(server.logfile, O_APPEND02000|O_CREAT0100|O_WRONLY01, 0644);
1532 return fd;
1533}
1534
1535/* Used to close what closeDirectLogFiledes() returns. */
1536void closeDirectLogFiledes(int fd) {
1537 int log_to_stdout = server.logfile[0] == '\0';
1538 if (!log_to_stdout) close(fd);
1539}
1540
1541#ifdef HAVE_BACKTRACE1
1542
1543/* Logs the stack trace using the backtrace() call. This function is designed
1544 * to be called from signal handlers safely.
1545 * The eip argument is optional (can take NULL).
1546 * The uplevel argument indicates how many of the calling functions to skip.
1547 */
1548void logStackTrace(void *eip, int uplevel) {
1549 void *trace[100];
1550 int trace_size = 0, fd = openDirectLogFiledes();
1551 char *msg;
1552 uplevel++; /* skip this function */
1553
1554 if (fd == -1) return; /* If we can't log there is anything to do. */
1555
1556 /* Get the stack trace first! */
1557 trace_size = backtrace(trace, 100);
1558
1559 msg = "\n------ STACK TRACE ------\n";
1560 if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */};
1561
1562 if (eip) {
1563 /* Write EIP to the log file*/
1564 msg = "EIP:\n";
1565 if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */};
1566 backtrace_symbols_fd(&eip, 1, fd);
1567 }
1568
1569 /* Write symbols to log file */
1570 msg = "\nBacktrace:\n";
1571 if (write(fd,msg,strlen(msg)) == -1) {/* Avoid warning. */};
1572 backtrace_symbols_fd(trace+uplevel, trace_size-uplevel, fd);
1573
1574 /* Cleanup */
1575 closeDirectLogFiledes(fd);
1576}
1577
1578#endif /* HAVE_BACKTRACE */
1579
1580/* Log global server info */
1581void logServerInfo(void) {
1582 sds infostring, clients;
1583 serverLogRaw(LL_WARNING3|LL_RAW(1<<10), "\n------ INFO OUTPUT ------\n");
1584 infostring = genRedisInfoString("all");
1585 serverLogRaw(LL_WARNING3|LL_RAW(1<<10), infostring);
1586 serverLogRaw(LL_WARNING3|LL_RAW(1<<10), "\n------ CLIENT LIST OUTPUT ------\n");
1587 clients = getAllClientsInfoString(-1);
1588 serverLogRaw(LL_WARNING3|LL_RAW(1<<10), clients);
1589 sdsfree(infostring);
1590 sdsfree(clients);
1591}
1592
1593/* Log modules info. Something we wanna do last since we fear it may crash. */
1594void logModulesInfo(void) {
1595 serverLogRaw(LL_WARNING3|LL_RAW(1<<10), "\n------ MODULES INFO OUTPUT ------\n");
1596 sds infostring = modulesCollectInfo(sdsempty(), NULL((void*)0), 1, 0);
1597 serverLogRaw(LL_WARNING3|LL_RAW(1<<10), infostring);
1598 sdsfree(infostring);
1599}
1600
1601/* Log information about the "current" client, that is, the client that is
1602 * currently being served by Redis. May be NULL if Redis is not serving a
1603 * client right now. */
1604void logCurrentClient(void) {
1605 if (server.current_client == NULL((void*)0)) return;
1606
1607 client *cc = server.current_client;
1608 sds client;
1609 int j;
1610
1611 serverLogRaw(LL_WARNING3|LL_RAW(1<<10), "\n------ CURRENT CLIENT INFO ------\n");
1612 client = catClientInfoString(sdsempty(),cc);
1613 serverLog(LL_WARNING3|LL_RAW(1<<10),"%s\n", client);
1614 sdsfree(client);
1615 for (j = 0; j < cc->argc; j++) {
1616 robj *decoded;
1617
1618 decoded = getDecodedObject(cc->argv[j]);
1619 serverLog(LL_WARNING3|LL_RAW(1<<10),"argv[%d]: '%s'\n", j,
1620 (char*)decoded->ptr);
1621 decrRefCount(decoded);
1622 }
1623 /* Check if the first argument, usually a key, is found inside the
1624 * selected DB, and if so print info about the associated object. */
1625 if (cc->argc > 1) {
1626 robj *val, *key;
1627 dictEntry *de;
1628
1629 key = getDecodedObject(cc->argv[1]);
1630 de = dictFind(cc->db->dict, key->ptr);
1631 if (de) {
1632 val = dictGetVal(de)((de)->v.val);
1633 serverLog(LL_WARNING3,"key '%s' found in DB containing the following object:", (char*)key->ptr);
1634 serverLogObjectDebugInfo(val);
1635 }
1636 decrRefCount(key);
1637 }
1638}
1639
1640#if defined(HAVE_PROC_MAPS1)
1641
1642#define MEMTEST_MAX_REGIONS128 128
1643
1644/* A non destructive memory test executed during segfault. */
1645int memtest_test_linux_anonymous_maps(void) {
1646 FILE *fp;
1647 char line[1024];
1648 char logbuf[1024];
1649 size_t start_addr, end_addr, size;
1650 size_t start_vect[MEMTEST_MAX_REGIONS128];
1651 size_t size_vect[MEMTEST_MAX_REGIONS128];
1652 int regions = 0, j;
1653
1654 int fd = openDirectLogFiledes();
1655 if (!fd) return 0;
1656
1657 fp = fopen("/proc/self/maps","r");
1658 if (!fp) return 0;
1659 while(fgets(line,sizeof(line),fp) != NULL((void*)0)) {
1660 char *start, *end, *p = line;
1661
1662 start = p;
1663 p = strchr(p,'-');
1664 if (!p) continue;
1665 *p++ = '\0';
1666 end = p;
1667 p = strchr(p,' ');
1668 if (!p) continue;
1669 *p++ = '\0';
1670 if (strstr(p,"stack") ||
1671 strstr(p,"vdso") ||
1672 strstr(p,"vsyscall")) continue;
1673 if (!strstr(p,"00:00")) continue;
1674 if (!strstr(p,"rw")) continue;
1675
1676 start_addr = strtoul(start,NULL((void*)0),16);
1677 end_addr = strtoul(end,NULL((void*)0),16);
1678 size = end_addr-start_addr;
1679
1680 start_vect[regions] = start_addr;
1681 size_vect[regions] = size;
1682 snprintf(logbuf,sizeof(logbuf),
1683 "*** Preparing to test memory region %lx (%lu bytes)\n",
1684 (unsigned long) start_vect[regions],
1685 (unsigned long) size_vect[regions]);
1686 if (write(fd,logbuf,strlen(logbuf)) == -1) { /* Nothing to do. */ }
1687 regions++;
1688 }
1689
1690 int errors = 0;
1691 for (j = 0; j < regions; j++) {
1692 if (write(fd,".",1) == -1) { /* Nothing to do. */ }
1693 errors += memtest_preserving_test((void*)start_vect[j],size_vect[j],1);
1694 if (write(fd, errors ? "E" : "O",1) == -1) { /* Nothing to do. */ }
1695 }
1696 if (write(fd,"\n",1) == -1) { /* Nothing to do. */ }
1697
1698 /* NOTE: It is very important to close the file descriptor only now
1699 * because closing it before may result into unmapping of some memory
1700 * region that we are testing. */
1701 fclose(fp);
1702 closeDirectLogFiledes(fd);
1703 return errors;
1704}
1705#endif /* HAVE_PROC_MAPS */
1706
1707static void killMainThread(void) {
1708 int err;
1709 if (pthread_self() != server.main_thread_id && pthread_cancel(server.main_thread_id) == 0) {
1710 if ((err = pthread_join(server.main_thread_id,NULL((void*)0))) != 0) {
1711 serverLog(LL_WARNING3, "main thread can not be joined: %s", strerror(err));
1712 } else {
1713 serverLog(LL_WARNING3, "main thread terminated");
1714 }
1715 }
1716}
1717
1718/* Kill the running threads (other than current) in an unclean way. This function
1719 * should be used only when it's critical to stop the threads for some reason.
1720 * Currently Redis does this only on crash (for instance on SIGSEGV) in order
1721 * to perform a fast memory check without other threads messing with memory. */
1722void killThreads(void) {
1723 killMainThread();
1724 bioKillThreads();
1725 killIOThreads();
1726}
1727
1728void doFastMemoryTest(void) {
1729#if defined(HAVE_PROC_MAPS1)
1730 if (server.memcheck_enabled) {
1731 /* Test memory */
1732 serverLogRaw(LL_WARNING3|LL_RAW(1<<10), "\n------ FAST MEMORY TEST ------\n");
1733 killThreads();
1734 if (memtest_test_linux_anonymous_maps()) {
1735 serverLogRaw(LL_WARNING3|LL_RAW(1<<10),
1736 "!!! MEMORY ERROR DETECTED! Check your memory ASAP !!!\n");
1737 } else {
1738 serverLogRaw(LL_WARNING3|LL_RAW(1<<10),
1739 "Fast memory test PASSED, however your memory can still be broken. Please run a memory test for several hours if possible.\n");
1740 }
1741 }
1742#endif /* HAVE_PROC_MAPS */
1743}
1744
1745/* Scans the (assumed) x86 code starting at addr, for a max of `len`
1746 * bytes, searching for E8 (callq) opcodes, and dumping the symbols
1747 * and the call offset if they appear to be valid. */
1748void dumpX86Calls(void *addr, size_t len) {
1749 size_t j;
1750 unsigned char *p = addr;
1751 Dl_info info;
1752 /* Hash table to best-effort avoid printing the same symbol
1753 * multiple times. */
1754 unsigned long ht[256] = {0};
1755
1756 if (len < 5) return;
1757 for (j = 0; j < len-4; j++) {
1758 if (p[j] != 0xE8) continue; /* Not an E8 CALL opcode. */
1759 unsigned long target = (unsigned long)addr+j+5;
1760 target += *((int32_t*)(p+j+1));
1761 if (dladdr((void*)target, &info) != 0 && info.dli_sname != NULL((void*)0)) {
1762 if (ht[target&0xff] != target) {
1763 printf("Function at 0x%lx is %s\n",target,info.dli_sname);
1764 ht[target&0xff] = target;
1765 }
1766 j += 4; /* Skip the 32 bit immediate. */
1767 }
1768 }
1769}
1770
1771void dumpCodeAroundEIP(void *eip) {
1772 Dl_info info;
1773 if (dladdr(eip, &info) != 0) {
1774 serverLog(LL_WARNING3|LL_RAW(1<<10),
1775 "\n------ DUMPING CODE AROUND EIP ------\n"
1776 "Symbol: %s (base: %p)\n"
1777 "Module: %s (base %p)\n"
1778 "$ xxd -r -p /tmp/dump.hex /tmp/dump.bin\n"
1779 "$ objdump --adjust-vma=%p -D -b binary -m i386:x86-64 /tmp/dump.bin\n"
1780 "------\n",
1781 info.dli_sname, info.dli_saddr, info.dli_fname, info.dli_fbase,
1782 info.dli_saddr);
1783 size_t len = (long)eip - (long)info.dli_saddr;
1784 unsigned long sz = sysconf(_SC_PAGESIZE_SC_PAGESIZE);
1785 if (len < 1<<13) { /* we don't have functions over 8k (verified) */
1786 /* Find the address of the next page, which is our "safety"
1787 * limit when dumping. Then try to dump just 128 bytes more
1788 * than EIP if there is room, or stop sooner. */
1789 void *base = (void *)info.dli_saddr;
1790 unsigned long next = ((unsigned long)eip + sz) & ~(sz-1);
1791 unsigned long end = (unsigned long)eip + 128;
1792 if (end > next) end = next;
1793 len = end - (unsigned long)base;
1794 serverLogHexDump(LL_WARNING3, "dump of function",
1795 base, len);
1796 dumpX86Calls(base, len);
1797 }
1798 }
1799}
1800
1801void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
1802 UNUSED(secret)((void) secret);
1803 UNUSED(info)((void) info);
1804
1805 bugReportStart();
1806 serverLog(LL_WARNING3,
1807 "Redis %s crashed by signal: %d, si_code: %d", REDIS_VERSION"6.2.1", sig, info->si_code);
1808 if (sig == SIGSEGV11 || sig == SIGBUS7) {
1809 serverLog(LL_WARNING3,
1810 "Accessing address: %p", (void*)info->si_addr_sifields._sigfault.si_addr);
1811 }
1812 if (info->si_pid_sifields._kill.si_pid != -1) {
1813 serverLog(LL_WARNING3, "Killed by PID: %ld, UID: %d", (long) info->si_pid_sifields._kill.si_pid, info->si_uid_sifields._kill.si_uid);
1814 }
1815
1816#ifdef HAVE_BACKTRACE1
1817 ucontext_t *uc = (ucontext_t*) secret;
1818 void *eip = getMcontextEip(uc);
1819 if (eip != NULL((void*)0)) {
1820 serverLog(LL_WARNING3,
1821 "Crashed running the instruction at: %p", eip);
1822 }
1823
1824 logStackTrace(getMcontextEip(uc), 1);
1825
1826 logRegisters(uc);
1827#endif
1828
1829 printCrashReport();
1830
1831#ifdef HAVE_BACKTRACE1
1832 if (eip != NULL((void*)0))
1833 dumpCodeAroundEIP(eip);
1834#endif
1835
1836 bugReportEnd(1, sig);
1837}
1838
1839void printCrashReport(void) {
1840 /* Log INFO and CLIENT LIST */
1841 logServerInfo();
1842
1843 /* Log the current client */
1844 logCurrentClient();
1845
1846 /* Log modules info. Something we wanna do last since we fear it may crash. */
1847 logModulesInfo();
1848
1849 /* Run memory test in case the crash was triggered by memory corruption. */
1850 doFastMemoryTest();
1851}
1852
1853void bugReportEnd(int killViaSignal, int sig) {
1854 struct sigaction act;
1855
1856 serverLogRaw(LL_WARNING3|LL_RAW(1<<10),
1857"\n=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
1858" Please report the crash by opening an issue on github:\n\n"
1859" http://github.com/redis/redis/issues\n\n"
1860" Suspect RAM error? Use redis-server --test-memory to verify it.\n\n"
1861);
1862
1863 /* free(messages); Don't call free() with possibly corrupted memory. */
1864 if (server.daemonize && server.supervised == 0 && server.pidfile) unlink(server.pidfile);
1865
1866 if (!killViaSignal) {
1867 if (server.use_exit_on_panic)
1868 exit(1);
1869 abort();
1870 }
1871
1872 /* Make sure we exit with the right signal at the end. So for instance
1873 * the core will be dumped if enabled. */
1874 sigemptyset (&act.sa_mask);
1875 act.sa_flags = SA_NODEFER0x40000000 | SA_ONSTACK0x08000000 | SA_RESETHAND0x80000000;
1876 act.sa_handler__sigaction_handler.sa_handler = SIG_DFL((__sighandler_t) 0);
1877 sigaction (sig, &act, NULL((void*)0));
1878 kill(getpid(),sig);
1879}
1880
1881/* ==================== Logging functions for debugging ===================== */
1882
1883void serverLogHexDump(int level, char *descr, void *value, size_t len) {
1884 char buf[65], *b;
1885 unsigned char *v = value;
1886 char charset[] = "0123456789abcdef";
1887
1888 serverLog(level,"%s (hexdump of %zu bytes):", descr, len);
1889 b = buf;
1890 while(len) {
1891 b[0] = charset[(*v)>>4];
1892 b[1] = charset[(*v)&0xf];
1893 b[2] = '\0';
1894 b += 2;
1895 len--;
1896 v++;
1897 if (b-buf == 64 || len == 0) {
1898 serverLogRaw(level|LL_RAW(1<<10),buf);
1899 b = buf;
1900 }
1901 }
1902 serverLogRaw(level|LL_RAW(1<<10),"\n");
1903}
1904
1905/* =========================== Software Watchdog ============================ */
1906#include <sys/time.h>
1907
1908void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) {
1909#ifdef HAVE_BACKTRACE1
1910 ucontext_t *uc = (ucontext_t*) secret;
1911#else
1912 (void)secret;
1913#endif
1914 UNUSED(info)((void) info);
1915 UNUSED(sig)((void) sig);
1916
1917 serverLogFromHandler(LL_WARNING3,"\n--- WATCHDOG TIMER EXPIRED ---");
1918#ifdef HAVE_BACKTRACE1
1919 logStackTrace(getMcontextEip(uc), 1);
1920#else
1921 serverLogFromHandler(LL_WARNING3,"Sorry: no support for backtrace().");
1922#endif
1923 serverLogFromHandler(LL_WARNING3,"--------\n");
1924}
1925
1926/* Schedule a SIGALRM delivery after the specified period in milliseconds.
1927 * If a timer is already scheduled, this function will re-schedule it to the
1928 * specified time. If period is 0 the current timer is disabled. */
1929void watchdogScheduleSignal(int period) {
1930 struct itimerval it;
1931
1932 /* Will stop the timer if period is 0. */
1933 it.it_value.tv_sec = period/1000;
1934 it.it_value.tv_usec = (period%1000)*1000;
1935 /* Don't automatically restart. */
1936 it.it_interval.tv_sec = 0;
1937 it.it_interval.tv_usec = 0;
1938 setitimer(ITIMER_REALITIMER_REAL, &it, NULL((void*)0));
1939}
1940
1941/* Enable the software watchdog with the specified period in milliseconds. */
1942void enableWatchdog(int period) {
1943 int min_period;
1944
1945 if (server.watchdog_period == 0) {
1946 struct sigaction act;
1947
1948 /* Watchdog was actually disabled, so we have to setup the signal
1949 * handler. */
1950 sigemptyset(&act.sa_mask);
1951 act.sa_flags = SA_SIGINFO4;
1952 act.sa_sigaction__sigaction_handler.sa_sigaction = watchdogSignalHandler;
1953 sigaction(SIGALRM14, &act, NULL((void*)0));
1954 }
1955 /* If the configured period is smaller than twice the timer period, it is
1956 * too short for the software watchdog to work reliably. Fix it now
1957 * if needed. */
1958 min_period = (1000/server.hz)*2;
1959 if (period < min_period) period = min_period;
1960 watchdogScheduleSignal(period); /* Adjust the current timer. */
1961 server.watchdog_period = period;
1962}
1963
1964/* Disable the software watchdog. */
1965void disableWatchdog(void) {
1966 struct sigaction act;
1967 if (server.watchdog_period == 0) return; /* Already disabled. */
1968 watchdogScheduleSignal(0); /* Stop the current timer. */
1969
1970 /* Set the signal handler to SIG_IGN, this will also remove pending
1971 * signals from the queue. */
1972 sigemptyset(&act.sa_mask);
1973 act.sa_flags = 0;
1974 act.sa_handler__sigaction_handler.sa_handler = SIG_IGN((__sighandler_t) 1);
1975 sigaction(SIGALRM14, &act, NULL((void*)0));
1976 server.watchdog_period = 0;
1977}
1978
1979/* Positive input is sleep time in microseconds. Negative input is fractions
1980 * of microseconds, i.e. -10 means 100 nanoseconds. */
1981void debugDelay(int usec) {
1982 /* Since even the shortest sleep results in context switch and system call,
1983 * the way we achive short sleeps is by statistically sleeping less often. */
1984 if (usec < 0) usec = (rand() % -usec) == 0 ? 1: 0;
1985 if (usec) usleep(usec);
1986}