1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
/*
* Copyright Internet Systems Consortium, Inc. ("ISC")
* Copyright Internet Software Consortium.
* Copyright the NTPsec project contributors
* SPDX-License-Identifier: ISC
*/
/*! \file */
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include "ntp.h"
#include "ntp_debug.h"
#include "ntp_syslog.h"
#include "ntp_assert.h"
#include "isc_result.h"
#ifdef USEBACKTRACE
/*
* Getting a back trace of a running process is tricky and highly platform
* dependent. Our current approach is as follows:
* 1. If the system library supports the "backtrace()" function, use it.
* OS X support this starting at with SDK 10.5. glibc since version 2.1
* 2. Otherwise, if unwind.h exists then use the __Unwind_Backtrace() function.
* This function is available on Linux, OS X, and FreeBSD. It is defined
* in Linux Standard Base since version 4.1
* 3. Otherwise, tough luck.
*/
/*
* The maximum number of stack frames to dump on assertion failure.
*/
#ifndef BACKTRACE_MAXFRAME
#define BACKTRACE_MAXFRAME 128
#endif
# ifdef HAVE_BACKTRACE_SYMBOLS_FD
#include <execinfo.h>
void
backtrace_log(void) {
int nptrs;
void *buffer[BACKTRACE_MAXFRAME];
char **strings;
nptrs = backtrace(buffer, BACKTRACE_MAXFRAME);
strings = backtrace_symbols(buffer, nptrs);
msyslog(LOG_ERR, "ERR: Stack trace:\n");
if (strings) {
/* skip trace of this shim function */
for (int j = 1; j < nptrs; j++)
msyslog(LOG_ERR, "ERR: %s\n", strings[j]);
free(strings);
}
}
# elif defined(HAVE__UNWIND_BACKTRACE)
#include <unwind.h>
typedef struct {
void **result;
int max_depth;
int skip_count;
int count;
} trace_arg_t;
static _Unwind_Reason_Code
btcallback(struct _Unwind_Context *uc, void *opq) {
trace_arg_t *arg = (trace_arg_t *)opq;
if (arg->skip_count > 0)
arg->skip_count--;
else
arg->result[arg->count++] = (void *)_Unwind_GetIP(uc);
if (arg->count == arg->max_depth)
return (5); /* _URC_END_OF_STACK */
return (0); /* _URC_NO_REASON */
}
void
backtrace_log(void) {
trace_arg_t arg;
void *buffer[BACKTRACE_MAXFRAME];
arg.skip_count = 1;
arg.result = buffer;
arg.max_depth = BACKTRACE_MAXFRAME;
arg.count = 0;
_Unwind_Backtrace(btcallback, &arg);
msyslog(LOG_ERR, "ERR: Stack trace:\n");
/* skip trace of this shim function */
for (int i = 1; i < arg.count; i++) {
msyslog(LOG_ERR, "ERR: #%d %p in ??\n", i, buffer[i]);
}
}
#endif /* HAVE__UNWIND_BACKTRACE */
#endif /* USEBACKTRACE */
/*% Type to Text */
static const char *
assertion_typetotext(assertiontype_t type) {
const char *result;
/*
* These strings have purposefully not been internationalized
* because they are considered to essentially be keywords of
* the ISC development environment.
*/
switch (type) {
case assertiontype_require:
result = "REQUIRE";
break;
case assertiontype_ensure:
result = "ENSURE";
break;
case assertiontype_insist:
result = "INSIST";
break;
case assertiontype_invariant:
result = "INVARIANT";
break;
default:
result = "(null)";
}
return (result);
}
/*
* assertion_failed - Redirect assertion failed output to msyslog().
*/
void
assertion_failed(
const char *file,
int line,
assertiontype_t type,
const char *cond
)
{
/* Is recursion an issue? */
termlogit = true; /* insist log to terminal */
msyslog(LOG_ERR, "ERR: %s:%d: %s(%s) failed",
file, line, assertion_typetotext(type), cond);
#ifndef BACKTRACE_DISABLED
backtrace_log();
#endif
msyslog(LOG_ERR, "ERR: exiting (due to assertion failure)");
abort();
}
|