@cryptotaxi247 / netdata-1 / commits / d686b5372

daemon status file 17 (#19869)

* cleanup thread name to avoid reporting duplicate events * ensure there is a stack trace message in all cases * keep separate hashes for sentry and netdata * fixes * signal code now renders signo and si_code independently as decimal numbers; it also supports the common SI_* codes on all signals * prevent sentry from looping signals back to us * allow the chained handler to run and use on_crash to disable the crash * cleanup * fix codacy warnings * fix for missing signals on freebsd * fix for missing signals on macos

Costa Tsaousis committed Mar 15, 2025 at 14:51 UTC d686b537218a59d1b2482c7da51ad2056801ee90
11 files changed +377 -123
src/daemon/daemon-status-file.c
+80 -37
@@ -9,7 +9,7 @@
9 #include <openssl/pem.h>
10 #include <openssl/err.h>
11
12 -#define STATUS_FILE_VERSION 16
12 +#define STATUS_FILE_VERSION 17
13
14 #define STATUS_FILENAME "status-netdata.json"
15
@@ -59,6 +59,30 @@ static void daemon_status_file_out_of_memory(void);
59 #define dsf_acquire(ds) __atomic_load_n(&(ds).v, __ATOMIC_ACQUIRE)
60 #define dsf_release(ds) __atomic_store_n(&(ds).v, (ds).v, __ATOMIC_RELEASE)
61
62 +static void copy_and_clean_thread_name_if_empty(DAEMON_STATUS_FILE *ds, const char *name) {
63 + if(ds->fatal.thread[0] && strcmp(ds->fatal.thread, "NO_NAME") != 0)
64 + return;
65 +
66 + if(!name || !*name) name = "NO_NAME";
67 +
68 + strncpyz(ds->fatal.thread, name, sizeof(ds->fatal.thread) - 1);
69 +
70 + // remove the variable part from the thread by removing [XXX] from it
71 + unsigned char *p = (unsigned char *)strchr(ds->fatal.thread, '[');
72 + if(p && isdigit(p[1]) && (isdigit(p[2]) || p[2] == ']'))
73 + *p = '\0';
74 +}
75 +
76 +#define STACK_TRACE_INFO_PREFIX "info: "
77 +static bool stack_trace_is_empty(DAEMON_STATUS_FILE *ds) {
78 + return !ds->fatal.stack_trace[0] || strncmp(ds->fatal.stack_trace, STACK_TRACE_INFO_PREFIX, strlen(STACK_TRACE_INFO_PREFIX)) == 0;
79 +}
80 +
81 +static void set_stack_trace_message_if_empty(DAEMON_STATUS_FILE *ds, const char *msg) {
82 + if(stack_trace_is_empty(ds))
83 + strncpyz(ds->fatal.stack_trace, msg, sizeof(ds->fatal.stack_trace) - 1);
84 +}
85 +
86 // --------------------------------------------------------------------------------------------------------------------
87 // json generation
88
@@ -237,6 +261,7 @@ static void daemon_status_file_to_json(BUFFER *wb, DAEMON_STATUS_FILE *ds) {
261 {
262 buffer_json_member_add_datetime_rfc3339(wb, "@timestamp", ds->dedup.slot[i].timestamp_ut, true); // custom
263 buffer_json_member_add_uint64(wb, "hash", ds->dedup.slot[i].hash); // custom
264 + buffer_json_member_add_boolean(wb, "sentry", ds->dedup.slot[i].sentry); // custom
265 }
266 buffer_json_object_close(wb);
267 }
@@ -268,6 +293,7 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
293 bool required_v10 = version >= 10 ? strict : false;
294 bool required_v14 = version >= 14 ? strict : false;
295 bool required_v16 = version >= 16 ? strict : false;
296 + bool required_v17 = version >= 17 ? strict : false;
297
298 // Parse timestamp
299 JSONC_PARSE_TXT2CHAR_OR_ERROR_AND_RETURN(jobj, path, "@timestamp", datetime, error, required_v1);
@@ -390,8 +416,8 @@ static bool daemon_status_file_from_json(json_object *jobj, void *data, BUFFER *
416 if (datetime[0])
417 ds->dedup.slot[i].timestamp_ut = rfc3339_parse_ut(datetime, NULL);
418
393 - JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(
394 - jobj, path, "hash", ds->dedup.slot[i].hash, error, required_v4);
419 + JSONC_PARSE_UINT64_OR_ERROR_AND_RETURN(jobj, path, "hash", ds->dedup.slot[i].hash, error, required_v4);
420 + JSONC_PARSE_BOOL_OR_ERROR_AND_RETURN(jobj, path, "sentry", ds->dedup.slot[i].sentry, error, required_v17);
421 }
422 });
423 });
@@ -788,7 +814,7 @@ static void daemon_status_file_save(BUFFER *wb, DAEMON_STATUS_FILE *ds, bool log
814 // --------------------------------------------------------------------------------------------------------------------
815 // deduplication hashes management
816
791 -static bool dedup_already_posted(DAEMON_STATUS_FILE *ds, uint64_t hash) {
817 +static bool dedup_already_posted(DAEMON_STATUS_FILE *ds, uint64_t hash, bool sentry) {
818 usec_t now_ut = now_realtime_usec();
819
820 for(size_t i = 0; i < _countof(ds->dedup.slot); i++) {
@@ -796,6 +822,7 @@ static bool dedup_already_posted(DAEMON_STATUS_FILE *ds, uint64_t hash) {
822 continue;
823
824 if(hash == ds->dedup.slot[i].hash &&
825 + sentry == ds->dedup.slot[i].sentry &&
826 now_ut - ds->dedup.slot[i].timestamp_ut < 86400 * USEC_PER_SEC) {
827 // we have already posted this crash
828 return true;
@@ -805,11 +832,12 @@ static bool dedup_already_posted(DAEMON_STATUS_FILE *ds, uint64_t hash) {
832 return false;
833 }
834
808 -static void dedup_keep_hash(DAEMON_STATUS_FILE *ds, uint64_t hash) {
835 +static void dedup_keep_hash(DAEMON_STATUS_FILE *ds, uint64_t hash, bool sentry) {
836 // find the same hash
837 for(size_t i = 0; i < _countof(ds->dedup.slot); i++) {
811 - if(ds->dedup.slot[i].hash == hash) {
838 + if(ds->dedup.slot[i].hash == hash && ds->dedup.slot[i].sentry == sentry) {
839 ds->dedup.slot[i].hash = hash;
840 + ds->dedup.slot[i].sentry = sentry;
841 ds->dedup.slot[i].timestamp_ut = now_realtime_usec();
842 return;
843 }
@@ -819,6 +847,7 @@ static void dedup_keep_hash(DAEMON_STATUS_FILE *ds, uint64_t hash) {
847 for(size_t i = 0; i < _countof(ds->dedup.slot); i++) {
848 if(!ds->dedup.slot[i].hash) {
849 ds->dedup.slot[i].hash = hash;
850 + ds->dedup.slot[i].sentry = sentry;
851 ds->dedup.slot[i].timestamp_ut = now_realtime_usec();
852 return;
853 }
@@ -832,6 +861,7 @@ static void dedup_keep_hash(DAEMON_STATUS_FILE *ds, uint64_t hash) {
861 }
862
863 ds->dedup.slot[store_at_slot].hash = hash;
864 + ds->dedup.slot[store_at_slot].sentry = sentry;
865 ds->dedup.slot[store_at_slot].timestamp_ut = now_realtime_usec();
866 }
867
@@ -872,7 +902,7 @@ void post_status_file(struct post_status_file_thread_data *d) {
902 CURLcode rc = curl_easy_perform(curl);
903 if(rc == CURLE_OK) {
904 uint64_t hash = daemon_status_file_hash(d->status, d->msg, d->cause);
875 - dedup_keep_hash(&session_status, hash);
905 + dedup_keep_hash(&session_status, hash, false);
906 daemon_status_file_save(wb, &session_status, true);
907 }
908
@@ -1135,7 +1165,7 @@ void daemon_status_file_check_crash(void) {
1165 (last_session_status.restarts >= 10 || !is_ci()) &&
1166
1167 // we have not already reported this
1138 - !dedup_already_posted(&session_status, daemon_status_file_hash(&last_session_status, msg, cause))
1168 + !dedup_already_posted(&session_status, daemon_status_file_hash(&last_session_status, msg, cause), false)
1169
1170 ) {
1171 netdata_conf_ssl();
@@ -1154,19 +1184,28 @@ void daemon_status_file_check_crash(void) {
1184 }
1185 }
1186
1157 -static void daemon_status_file_save_again_if_we_can_get_stack_trace(void) {
1158 - if(!session_status.fatal.stack_trace[0]) {
1159 - buffer_flush(static_save_buffer);
1160 - capture_stack_trace(static_save_buffer);
1187 +static void daemon_status_file_save_twice_if_we_can_get_stack_trace(BUFFER *wb, DAEMON_STATUS_FILE *ds, bool force) {
1188 + if(capture_stack_trace_available())
1189 + set_stack_trace_message_if_empty(&session_status, STACK_TRACE_INFO_PREFIX "will now attempt to get stack trace - if you see this message, we couldn't get it.");
1190 + else
1191 + set_stack_trace_message_if_empty(&session_status, STACK_TRACE_INFO_PREFIX "no stack trace backend available");
1192
1162 - if(buffer_strlen(static_save_buffer) > 0) {
1163 - strncpyz(
1164 - session_status.fatal.stack_trace,
1165 - buffer_tostring(static_save_buffer),
1166 - sizeof(session_status.fatal.stack_trace) - 1);
1193 + // save it without a stack trace to be sure we will have the event
1194 + daemon_status_file_save(wb, ds, false);
1195
1168 - daemon_status_file_save(static_save_buffer, &session_status, false);
1169 - }
1196 + if(!stack_trace_is_empty(ds) && !force)
1197 + return;
1198 +
1199 + buffer_flush(wb);
1200 + capture_stack_trace(wb);
1201 +
1202 + if(buffer_strlen(wb) > 0) {
1203 + strncpyz(
1204 + ds->fatal.stack_trace,
1205 + buffer_tostring(wb),
1206 + sizeof(ds->fatal.stack_trace) - 1);
1207 +
1208 + daemon_status_file_save(wb, ds, false);
1209 }
1210 }
1211
@@ -1180,7 +1219,8 @@ void daemon_status_file_register_fatal(const char *filename, const char *functio
1219 spinlock_lock(&session_status.fatal.spinlock);
1220
1221 exit_initiated_add(EXIT_REASON_FATAL);
1183 - strncpyz(session_status.fatal.thread, nd_thread_tag(), sizeof(session_status.fatal.thread) - 1);
1222 +
1223 + copy_and_clean_thread_name_if_empty(&session_status, nd_thread_tag());
1224
1225 if(!session_status.fatal.filename[0] && filename)
1226 strncpyz(session_status.fatal.filename, filename, sizeof(session_status.fatal.filename) - 1);
@@ -1194,7 +1234,7 @@ void daemon_status_file_register_fatal(const char *filename, const char *functio
1234 if(!session_status.fatal.errno_str[0] && errno_str)
1235 strncpyz(session_status.fatal.errno_str, errno_str, sizeof(session_status.fatal.errno_str) - 1);
1236
1197 - if(!session_status.fatal.stack_trace[0] && stack_trace)
1237 + if(stack_trace_is_empty(&session_status) && stack_trace)
1238 strncpyz(session_status.fatal.stack_trace, stack_trace, sizeof(session_status.fatal.stack_trace) - 1);
1239
1240 if(!session_status.fatal.line)
@@ -1204,15 +1244,13 @@ void daemon_status_file_register_fatal(const char *filename, const char *functio
1244 dsf_release(session_status);
1245
1246 CLEAN_BUFFER *wb = buffer_create(0, NULL);
1207 - daemon_status_file_save(wb, &session_status, false);
1247 + daemon_status_file_save_twice_if_we_can_get_stack_trace(wb, &session_status, false);
1248
1249 freez((void *)filename);
1250 freez((void *)function);
1251 freez((void *)message);
1252 freez((void *)errno_str);
1253 freez((void *)stack_trace);
1214 -
1215 - daemon_status_file_save_again_if_we_can_get_stack_trace();
1254 }
1255
1256 // --------------------------------------------------------------------------------------------------------------------
@@ -1235,10 +1273,10 @@ static void daemon_status_file_out_of_memory(void) {
1273
1274 dsf_acquire(session_status);
1275 session_status.exit_reason = exit_initiated;
1276 +
1277 dsf_release(session_status);
1278
1240 - daemon_status_file_save(static_save_buffer, &session_status, false);
1241 - daemon_status_file_save_again_if_we_can_get_stack_trace();
1279 + daemon_status_file_save_twice_if_we_can_get_stack_trace(static_save_buffer, &session_status, true);
1280 }
1281
1282 bool daemon_status_file_deadly_signal_received(EXIT_REASON reason, SIGNAL_CODE code, bool chained_handler) {
@@ -1254,32 +1292,37 @@ bool daemon_status_file_deadly_signal_received(EXIT_REASON reason, SIGNAL_CODE c
1292 if(code)
1293 session_status.fatal.signal_code = code;
1294
1257 - if(!session_status.fatal.thread[0])
1258 - strncpyz(session_status.fatal.thread, nd_thread_tag_async_safe(), sizeof(session_status.fatal.thread) - 1);
1295 + copy_and_clean_thread_name_if_empty(&session_status, nd_thread_tag_async_safe());
1296
1297 dsf_release(session_status);
1298
1299 // the buffer should already be allocated, so this should normally do nothing
1300 static_save_buffer_init();
1301
1265 - // save what we know already
1266 - daemon_status_file_save(static_save_buffer, &session_status, false);
1267 -
1302 // deduplicate the crash for sentry
1303 bool duplicate = false;
1304 if(chained_handler) {
1305 uint64_t hash = daemon_status_file_hash(&session_status, NULL, NULL);
1272 - duplicate = dedup_already_posted(&session_status, hash);
1306 + duplicate = dedup_already_posted(&session_status, hash, true);
1307 if (!duplicate) {
1308 // save this hash, so that we won't post it again to sentry
1275 - dedup_keep_hash(&session_status, hash);
1276 - daemon_status_file_save(static_save_buffer, &session_status, false);
1309 + dedup_keep_hash(&session_status, hash, true);
1310 }
1311 }
1312
1280 - if((!chained_handler || duplicate) && (reason != EXIT_REASON_SIGABRT || capture_stack_trace_is_async_signal_safe())) {
1281 - // no sentry, try to get the stack trace
1282 - daemon_status_file_save_again_if_we_can_get_stack_trace();
1313 + bool safe_to_get_stack_trace = reason != EXIT_REASON_SIGABRT || capture_stack_trace_is_async_signal_safe();
1314 + bool get_stack_trace = capture_stack_trace_available() && safe_to_get_stack_trace && stack_trace_is_empty(&session_status);
1315 +
1316 + // save it
1317 + if(get_stack_trace)
1318 + daemon_status_file_save_twice_if_we_can_get_stack_trace(static_save_buffer, &session_status, true);
1319 + else {
1320 + if (!capture_stack_trace_available())
1321 + set_stack_trace_message_if_empty(&session_status, STACK_TRACE_INFO_PREFIX "no stack trace backend available");
1322 + else
1323 + set_stack_trace_message_if_empty(&session_status, STACK_TRACE_INFO_PREFIX "not safe to get a stack trace for this signal using this backend");
1324 +
1325 + daemon_status_file_save(static_save_buffer, &session_status, false);
1326 }
1327
1328 return duplicate;
src/daemon/daemon-status-file.h
+2 -1
@@ -86,9 +86,10 @@ typedef struct daemon_status_file {
86
87 struct {
88 struct {
89 + bool sentry;
90 uint64_t hash;
91 usec_t timestamp_ut;
91 - } slot[10];
92 + } slot[15];
93 } dedup;
94 } DAEMON_STATUS_FILE;
95
src/daemon/main.c
+1
@@ -989,6 +989,7 @@ int netdata_main(int argc, char **argv) {
989 // ----------------------------------------------------------------------------------------------------------------
990 delta_startup_time("sentry");
991
992 + nd_cleanup_fatal_signals(); // avoid sentry looping deadly signals back to us
993 nd_sentry_init();
994 nd_initialize_signals(true);
995 #endif
src/daemon/sentry-native/sentry-native.c
+47
@@ -5,6 +5,40 @@
5
6 #include "sentry.h"
7
8 +bool nd_sentry_crash_report_enabled = true;
9 +
10 +void nd_sentry_crash_report(bool enable) {
11 + nd_sentry_crash_report_enabled = enable;
12 +}
13 +
14 +static sentry_value_t nd_sentry_on_crash(
15 + const sentry_ucontext_t *uctx __maybe_unused, // provides the user-space context of the crash
16 + sentry_value_t event, // used the same way as in `before_send`
17 + void *closure __maybe_unused // user-data that you can provide at configuration time
18 +) {
19 + // IMPORTANT: this function is called from a signal handler
20 +
21 + if (!nd_sentry_crash_report_enabled) {
22 + sentry_value_decref(event);
23 + return sentry_value_new_null();
24 + }
25 +
26 + return event;
27 +}
28 +
29 +static sentry_value_t nd_sentry_before_send(
30 + sentry_value_t event,
31 + void *hint __maybe_unused,
32 + void *closure __maybe_unused) {
33 +
34 + if (!nd_sentry_crash_report_enabled) {
35 + sentry_value_decref(event);
36 + return sentry_value_new_null();
37 + }
38 +
39 + return event;
40 +}
41 +
42 void nd_sentry_init(void)
43 {
44 if (!analytics_check_enabled())
@@ -29,6 +63,19 @@ void nd_sentry_init(void)
63 sentry_options_set_debug(options, 1);
64 #endif
65
66 + CLEAN_BUFFER *profile = buffer_create(0, NULL);
67 + ND_PROFILE_2buffer(profile, nd_profile_detect_and_configure(false), " ");
68 + sentry_set_tag("profile", buffer_tostring(profile));
69 +
70 + sentry_set_tag("db_mode", rrd_memory_mode_name(default_rrd_memory_mode));
71 +
72 + char tiers[UINT64_MAX_LENGTH];
73 + print_uint64(tiers, nd_profile.storage_tiers);
74 + sentry_set_tag("db_tiers", tiers);
75 +
76 + sentry_options_set_on_crash(options, nd_sentry_on_crash, NULL);
77 + sentry_options_set_before_send(options, nd_sentry_before_send, NULL);
78 +
79 sentry_init(options);
80 }
81
src/daemon/sentry-native/sentry-native.h
+4
@@ -3,10 +3,14 @@
3 #ifndef ND_SENTRY_H
4 #define ND_SENTRY_H
5
6 +#include "libnetdata/common.h"
7 +
8 void nd_sentry_init(void);
9 void nd_sentry_fini(void);
10
11 void nd_sentry_set_user(const char *guid);
12 void nd_sentry_add_breadcrumb(const char *message);
13
14 +void nd_sentry_crash_report(bool enable);
15 +
16 #endif /* ND_SENTRY_H */
src/daemon/signal-handler.c
+31 -1
@@ -3,6 +3,10 @@
3 #include "common.h"
4 #include "daemon/daemon-status-file.h"
5
6 +#ifdef ENABLE_SENTRY
7 +#include "sentry-native/sentry-native.h"
8 +#endif
9 +
10 typedef enum signal_action {
11 NETDATA_SIGNAL_IGNORE,
12 NETDATA_SIGNAL_EXIT_CLEANLY,
@@ -63,7 +67,11 @@ void nd_signal_handler(int signo, siginfo_t *info, void *context __maybe_unused)
67 SIGNAL_CODE sc = info ? signal_code(signo, info->si_code) : 0;
68 if(daemon_status_file_deadly_signal_received(signals_waiting[i].reason, sc, chained_handler)) {
69 // this is a duplicate event, do not send it to sentry
70 +#ifdef ENABLE_SENTRY
71 + nd_sentry_crash_report(false);
72 +#else
73 chained_handler = false;
74 +#endif
75 }
76
77 // log it
@@ -71,8 +79,11 @@ void nd_signal_handler(int signo, siginfo_t *info, void *context __maybe_unused)
79 strncpyz(b, "SIGNAL HANDLER: received deadly signal: ", sizeof(b) - 1);
80 strcat(b, signals_waiting[i].name);
81 if(sc) {
82 + char buf[128];
83 + SIGNAL_CODE_2str_h(sc, buf, sizeof(buf));
84 +
85 strcat(b, " (");
75 - strcat(b, SIGNAL_CODE_2str(sc));
86 + strcat(b, buf);
87 strcat(b, ")");
88 }
89 strcat(b, " in thread ");
@@ -127,6 +138,25 @@ static void posix_unmask_my_signals(void) {
138 netdata_log_error("SIGNAL: cannot unmask netdata signals");
139 }
140
141 +void nd_cleanup_fatal_signals(void) {
142 + struct sigaction act;
143 + memset(&act, 0, sizeof(struct sigaction));
144 +
145 + // ignore all signals while we run in a signal handler
146 + sigfillset(&act.sa_mask);
147 +
148 + for (size_t i = 0; i < _countof(signals_waiting); i++) {
149 + if(signals_waiting[i].action != NETDATA_SIGNAL_DEADLY)
150 + continue;
151 +
152 + act.sa_flags = 0;
153 + act.sa_handler = SIG_DFL;
154 +
155 + if (sigaction(signals_waiting[i].signo, &act, NULL) == -1)
156 + netdata_log_error("SIGNAL: Failed to cleanup signal handler for: %s", signals_waiting[i].name);
157 + }
158 +}
159 +
160 void nd_initialize_signals(bool chain_existing) {
161 signals_block_all_except_deadly();
162
src/daemon/signal-handler.h
+1
@@ -3,6 +3,7 @@
3 #ifndef NETDATA_SIGNAL_HANDLER_H
4 #define NETDATA_SIGNAL_HANDLER_H 1
5
6 +void nd_cleanup_fatal_signals(void);
7 void nd_initialize_signals(bool chain_existing);
8 void nd_process_signals(void) NORETURN;
9
src/libnetdata/log/nd_log-stacktrace.c
+12
@@ -28,6 +28,10 @@ bool capture_stack_trace_is_async_signal_safe(void) {
28 #endif
29 }
30
31 +bool capture_stack_trace_available(void) {
32 + return true;
33 +}
34 +
35 void capture_stack_trace(BUFFER *wb) {
36 // this function is async-signal-safe, if the buffer has enough space to hold the stack trace
37
@@ -76,6 +80,10 @@ void capture_stack_trace(BUFFER *wb) {
80
81 #elif defined(HAVE_BACKTRACE)
82
83 +bool capture_stack_trace_available(void) {
84 + return true;
85 +}
86 +
87 void capture_stack_trace_init(void) {
88 ;
89 }
@@ -143,6 +151,10 @@ void capture_stack_trace(BUFFER *wb) {
151
152 #else
153
154 +bool capture_stack_trace_available(void) {
155 + return false;
156 +}
157 +
158 void capture_stack_trace_init(void) {
159 ;
160 }
src/libnetdata/log/nd_log.h
+1
@@ -36,6 +36,7 @@ ND_UUID nd_log_get_invocation_id(void);
36 void capture_stack_trace(BUFFER *wb);
37 void capture_stack_trace_init(void);
38 void capture_stack_trace_flush(void);
39 +bool capture_stack_trace_available(void);
40 bool capture_stack_trace_is_async_signal_safe(void);
41
42 typedef void (*log_event_t)(const char *filename, const char *function, const char *message, const char *errno_str, const char *stack_trace, long line);
src/libnetdata/signals/signal-code.c
+197 -81
@@ -3,150 +3,266 @@
3 #include "signal-code.h"
4 #include "libnetdata/libnetdata.h"
5
6 +#define SIG_NOT_FOUND 0xFFFFFFF
7 +
8 +// --------------------------------------------------------------------------------------------------------------------
9 +
10 +typedef int SIGNAL_NUM;
11 +
12 +ENUM_STR_MAP_DEFINE(SIGNAL_NUM) = {
13 + { SIGHUP, "SIGHUP" }, // 1 Hangup.
14 + { SIGINT, "SIGINT" }, // 2 Interactive attention signal.
15 + { SIGQUIT, "SIGQUIT" }, // 3 Quit.
16 + { SIGILL, "SIGILL" }, // 4 Illegal instruction.
17 + { SIGTRAP, "SIGTRAP" }, // 5 Trace/breakpoint trap.
18 + { SIGABRT, "SIGABRT" }, // 6 Abnormal termination.
19 + { SIGBUS, "SIGBUS" }, // 7 Bus error.
20 + { SIGFPE, "SIGFPE" }, // 8 Erroneous arithmetic operation.
21 + { SIGKILL, "SIGKILL" }, // 9 Killed.
22 + { SIGUSR1, "SIGUSR1" }, // 10 User-defined signal 1.
23 + { SIGSEGV, "SIGSEGV" }, // 11 Invalid access to storage.
24 + { SIGUSR2, "SIGUSR2" }, // 12 User-defined signal 2.
25 + { SIGPIPE, "SIGPIPE" }, // 13 Broken pipe.
26 + { SIGALRM, "SIGALRM" }, // 14 Alarm clock.
27 + { SIGTERM, "SIGTERM" }, // 15 Termination request.
28 +#ifdef SIGSTKFLT
29 + { SIGSTKFLT, "SIGSTKFLT" }, // 16 Stack fault (obsolete).
30 +#endif
31 + { SIGCHLD, "SIGCHLD" }, // 17 Child terminated or stopped.
32 + { SIGCONT, "SIGCONT" }, // 18 Continue.
33 + { SIGSTOP, "SIGSTOP" }, // 19 Stop, unblockable.
34 + { SIGTSTP, "SIGTSTP" }, // 20 Keyboard stop.
35 + { SIGTTIN, "SIGTTIN" }, // 21 Background read from control terminal.
36 + { SIGTTOU, "SIGTTOU" }, // 22 Background write to control terminal.
37 + { SIGURG, "SIGURG" }, // 23 Urgent data is available at a socket.
38 + { SIGXCPU, "SIGXCPU" }, // 24 CPU time limit exceeded.
39 + { SIGXFSZ, "SIGXFSZ" }, // 25 File size limit exceeded.
40 + { SIGVTALRM, "SIGVTALRM" }, // 26 Virtual timer expired.
41 + { SIGPROF, "SIGPROF" }, // 27 Profiling timer expired.
42 + { SIGWINCH, "SIGWINCH" }, // 28 Window size change (4.3 BSD, Sun).
43 +#ifdef SIGPOLL
44 + { SIGPOLL, "SIGPOLL" }, // 29 Pollable event occurred (System V).
45 +#endif
46 +#ifdef SIGPWR
47 + { SIGPWR, "SIGPWR" }, // 30 Power failure imminent.
48 +#endif
49 + { SIGSYS, "SIGSYS" }, // 31 Bad system call.
50 +
51 + // Terminator
52 + { 0, NULL },
53 +};
54 +
55 +// IMPORTANT: These function return invalid values when the signal is not found - always use a function wrapper
56 +ENUM_STR_DEFINE_FUNCTIONS(SIGNAL_NUM, SIG_NOT_FOUND, NULL);
57 +
58 +// --------------------------------------------------------------------------------------------------------------------
59 +
60 +typedef int SI_CODE;
61 +
62 +ENUM_STR_MAP_DEFINE(SI_CODE) = {
63 +#ifdef SI_ASYNCNL
64 + { SI_ASYNCNL, "SI_ASYNCNL" },
65 +#endif
66 +#ifdef SI_DETHREAD
67 + { SI_DETHREAD, "SI_DETHREAD" },
68 +#endif
69 +#ifdef SI_TKILL
70 + { SI_TKILL, "SI_TKILL" },
71 +#endif
72 +#ifdef SI_SIGIO
73 + { SI_SIGIO, "SI_SIGIO" },
74 +#endif
75 + { SI_ASYNCIO, "SI_ASYNCIO" },
76 + { SI_MESGQ, "SI_MESGQ" },
77 + { SI_TIMER, "SI_TIMER" },
78 + { SI_QUEUE, "SI_QUEUE" },
79 + { SI_USER, "SI_USER" },
80 +#ifdef SI_KERNEL
81 + { SI_KERNEL, "SI_KERNEL" },
82 +#endif
83 +
84 + // Terminator
85 + {0, NULL},
86 +};
87 +
88 +// IMPORTANT: These function return invalid values when the signal is not found - always use a function wrapper
89 +ENUM_STR_DEFINE_FUNCTIONS(SI_CODE, SIG_NOT_FOUND, NULL);
90 +
91 +// --------------------------------------------------------------------------------------------------------------------
92 +
93 // Helper macro to create a SIGNAL_CODE value
94 #define SIGNAL_CODE_CREATE(signo, si_code) (((uint64_t)(signo) << 32) | (uint32_t)(si_code))
95
9 -// Function to create a SIGNAL_CODE from signal number and signal code
10 -SIGNAL_CODE signal_code(int signo, int si_code) {
11 - return SIGNAL_CODE_CREATE(signo, si_code);
12 -}
13 -
96 // Define mapping from SIGNAL_CODE to string representation
97 ENUM_STR_MAP_DEFINE(SIGNAL_CODE) = {
98 // SIGILL codes
17 - { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLOPC), "SIGILL/ILL_ILLOPC" }, // Illegal opcode
18 - { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLOPN), "SIGILL/ILL_ILLOPN" }, // Illegal operand
19 - { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLADR), "SIGILL/ILL_ILLADR" }, // Illegal addressing mode
20 - { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLTRP), "SIGILL/ILL_ILLTRP" }, // Illegal trap
21 - { SIGNAL_CODE_CREATE(SIGILL, ILL_PRVOPC), "SIGILL/ILL_PRVOPC" }, // Privileged opcode
22 - { SIGNAL_CODE_CREATE(SIGILL, ILL_PRVREG), "SIGILL/ILL_PRVREG" }, // Privileged register
23 - { SIGNAL_CODE_CREATE(SIGILL, ILL_COPROC), "SIGILL/ILL_COPROC" }, // Coprocessor error
24 - { SIGNAL_CODE_CREATE(SIGILL, ILL_BADSTK), "SIGILL/ILL_BADSTK" }, // Internal stack error
99 + { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLOPC), "ILL_ILLOPC" }, // Illegal opcode
100 + { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLOPN), "ILL_ILLOPN" }, // Illegal operand
101 + { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLADR), "ILL_ILLADR" }, // Illegal addressing mode
102 + { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLTRP), "ILL_ILLTRP" }, // Illegal trap
103 + { SIGNAL_CODE_CREATE(SIGILL, ILL_PRVOPC), "ILL_PRVOPC" }, // Privileged opcode
104 + { SIGNAL_CODE_CREATE(SIGILL, ILL_PRVREG), "ILL_PRVREG" }, // Privileged register
105 + { SIGNAL_CODE_CREATE(SIGILL, ILL_COPROC), "ILL_COPROC" }, // Coprocessor error
106 + { SIGNAL_CODE_CREATE(SIGILL, ILL_BADSTK), "ILL_BADSTK" }, // Internal stack error
107 #ifdef ILL_BADIADDR
26 - { SIGNAL_CODE_CREATE(SIGILL, ILL_BADIADDR), "SIGILL/ILL_BADIADDR" }, // Unimplemented instruction address
108 + { SIGNAL_CODE_CREATE(SIGILL, ILL_BADIADDR), "ILL_BADIADDR" }, // Unimplemented instruction address
109 #endif
110
111 // SIGFPE codes
30 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_INTDIV), "SIGFPE/FPE_INTDIV" }, // Integer divide by zero
31 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_INTOVF), "SIGFPE/FPE_INTOVF" }, // Integer overflow
32 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTDIV), "SIGFPE/FPE_FLTDIV" }, // Floating point divide by zero
33 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTOVF), "SIGFPE/FPE_FLTOVF" }, // Floating point overflow
34 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTUND), "SIGFPE/FPE_FLTUND" }, // Floating point underflow
35 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTRES), "SIGFPE/FPE_FLTRES" }, // Floating point inexact result
36 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTINV), "SIGFPE/FPE_FLTINV" }, // Floating point invalid operation
37 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTSUB), "SIGFPE/FPE_FLTSUB" }, // Subscript out of range
112 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_INTDIV), "FPE_INTDIV" }, // Integer divide by zero
113 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_INTOVF), "FPE_INTOVF" }, // Integer overflow
114 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTDIV), "FPE_FLTDIV" }, // Floating point divide by zero
115 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTOVF), "FPE_FLTOVF" }, // Floating point overflow
116 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTUND), "FPE_FLTUND" }, // Floating point underflow
117 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTRES), "FPE_FLTRES" }, // Floating point inexact result
118 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTINV), "FPE_FLTINV" }, // Floating point invalid operation
119 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTSUB), "FPE_FLTSUB" }, // Subscript out of range
120 #ifdef FPE_FLTUNK
39 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTUNK), "SIGFPE/FPE_FLTUNK" }, // Undiagnosed floating-point exception
121 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTUNK), "FPE_FLTUNK" }, // Undiagnosed floating-point exception
122 #endif
123 #ifdef FPE_CONDTRAP
42 - { SIGNAL_CODE_CREATE(SIGFPE, FPE_CONDTRAP), "SIGFPE/FPE_CONDTRAP" }, // Trap on condition
124 + { SIGNAL_CODE_CREATE(SIGFPE, FPE_CONDTRAP), "FPE_CONDTRAP" }, // Trap on condition
125 #endif
126
127 // SIGSEGV codes
46 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_MAPERR), "SIGSEGV/SEGV_MAPERR" }, // Address not mapped to object
47 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ACCERR), "SIGSEGV/SEGV_ACCERR" }, // Invalid permissions for mapped object
128 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_MAPERR), "SEGV_MAPERR" }, // Address not mapped to object
129 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ACCERR), "SEGV_ACCERR" }, // Invalid permissions for mapped object
130 #ifdef SEGV_BNDERR
49 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_BNDERR), "SIGSEGV/SEGV_BNDERR" }, // Bounds checking failure
131 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_BNDERR), "SEGV_BNDERR" }, // Bounds checking failure
132 #endif
133 #ifdef SEGV_PKUERR
52 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_PKUERR), "SIGSEGV/SEGV_PKUERR" }, // Protection key checking failure
134 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_PKUERR), "SEGV_PKUERR" }, // Protection key checking failure
135 #endif
136 #ifdef SEGV_ACCADI
55 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ACCADI), "SIGSEGV/SEGV_ACCADI" }, // ADI not enabled for mapped object
137 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ACCADI), "SEGV_ACCADI" }, // ADI not enabled for mapped object
138 #endif
139 #ifdef SEGV_ADIDERR
58 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ADIDERR), "SIGSEGV/SEGV_ADIDERR" }, // Disrupting MCD error
140 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ADIDERR), "SEGV_ADIDERR" }, // Disrupting MCD error
141 #endif
142 #ifdef SEGV_ADIPERR
61 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ADIPERR), "SIGSEGV/SEGV_ADIPERR" }, // Precise MCD exception
143 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ADIPERR), "SEGV_ADIPERR" }, // Precise MCD exception
144 #endif
145 #ifdef SEGV_MTEAERR
64 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_MTEAERR), "SIGSEGV/SEGV_MTEAERR" }, // Asynchronous ARM MTE error
146 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_MTEAERR), "SEGV_MTEAERR" }, // Asynchronous ARM MTE error
147 #endif
148 #ifdef SEGV_MTESERR
67 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_MTESERR), "SIGSEGV/SEGV_MTESERR" }, // Synchronous ARM MTE exception
149 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_MTESERR), "SEGV_MTESERR" }, // Synchronous ARM MTE exception
150 #endif
151 #ifdef SEGV_CPERR
70 - { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_CPERR), "SIGSEGV/SEGV_CPERR" }, // Control protection fault
152 + { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_CPERR), "SEGV_CPERR" }, // Control protection fault
153 #endif
154
155 // SIGBUS codes
74 - { SIGNAL_CODE_CREATE(SIGBUS, BUS_ADRALN), "SIGBUS/BUS_ADRALN" }, // Invalid address alignment
75 - { SIGNAL_CODE_CREATE(SIGBUS, BUS_ADRERR), "SIGBUS/BUS_ADRERR" }, // Non-existent physical address
76 - { SIGNAL_CODE_CREATE(SIGBUS, BUS_OBJERR), "SIGBUS/BUS_OBJERR" }, // Object specific hardware error
156 + { SIGNAL_CODE_CREATE(SIGBUS, BUS_ADRALN), "BUS_ADRALN" }, // Invalid address alignment
157 + { SIGNAL_CODE_CREATE(SIGBUS, BUS_ADRERR), "BUS_ADRERR" }, // Non-existent physical address
158 + { SIGNAL_CODE_CREATE(SIGBUS, BUS_OBJERR), "BUS_OBJERR" }, // Object specific hardware error
159 #ifdef BUS_MCEERR_AR
78 - { SIGNAL_CODE_CREATE(SIGBUS, BUS_MCEERR_AR), "SIGBUS/BUS_MCEERR_AR" }, // Hardware memory error: action required
160 + { SIGNAL_CODE_CREATE(SIGBUS, BUS_MCEERR_AR), "BUS_MCEERR_AR" }, // Hardware memory error: action required
161 #endif
162 #ifdef BUS_MCEERR_AO
81 - { SIGNAL_CODE_CREATE(SIGBUS, BUS_MCEERR_AO), "SIGBUS/BUS_MCEERR_AO" }, // Hardware memory error: action optional
163 + { SIGNAL_CODE_CREATE(SIGBUS, BUS_MCEERR_AO), "BUS_MCEERR_AO" }, // Hardware memory error: action optional
164 #endif
165
166 // SIGTRAP codes
167 #ifdef TRAP_BRKPT
86 - { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_BRKPT), "SIGTRAP/TRAP_BRKPT" }, // Process breakpoint
168 + { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_BRKPT), "TRAP_BRKPT" }, // Process breakpoint
169 #endif
170 #ifdef TRAP_TRACE
89 - { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_TRACE), "SIGTRAP/TRAP_TRACE" }, // Process trace trap
171 + { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_TRACE), "TRAP_TRACE" }, // Process trace trap
172 #endif
173 #ifdef TRAP_BRANCH
92 - { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_BRANCH), "SIGTRAP/TRAP_BRANCH" }, // Process taken branch trap
174 + { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_BRANCH), "TRAP_BRANCH" }, // Process taken branch trap
175 #endif
176 #ifdef TRAP_HWBKPT
95 - { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_HWBKPT), "SIGTRAP/TRAP_HWBKPT" }, // Hardware breakpoint/watchpoint
177 + { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_HWBKPT), "TRAP_HWBKPT" }, // Hardware breakpoint/watchpoint
178 #endif
179 #ifdef TRAP_UNK
98 - { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_UNK), "SIGTRAP/TRAP_UNK" }, // Undiagnosed trap
99 -#endif
100 -
101 - // Add entries for standard signals
102 - { SIGNAL_CODE_CREATE(SIGINT, 0), "SIGINT" },
103 - { SIGNAL_CODE_CREATE(SIGILL, 0), "SIGILL" },
104 - { SIGNAL_CODE_CREATE(SIGABRT, 0), "SIGABRT" },
105 - { SIGNAL_CODE_CREATE(SIGFPE, 0), "SIGFPE" },
106 - { SIGNAL_CODE_CREATE(SIGSEGV, 0), "SIGSEGV" },
107 - { SIGNAL_CODE_CREATE(SIGTERM, 0), "SIGTERM" },
108 - { SIGNAL_CODE_CREATE(SIGHUP, 0), "SIGHUP" },
109 - { SIGNAL_CODE_CREATE(SIGQUIT, 0), "SIGQUIT" },
110 - { SIGNAL_CODE_CREATE(SIGTRAP, 0), "SIGTRAP" },
111 - { SIGNAL_CODE_CREATE(SIGKILL, 0), "SIGKILL" },
112 - { SIGNAL_CODE_CREATE(SIGPIPE, 0), "SIGPIPE" },
113 - { SIGNAL_CODE_CREATE(SIGALRM, 0), "SIGALRM" },
114 - { SIGNAL_CODE_CREATE(SIGCHLD, 0), "SIGCHLD" },
115 -
116 - { SIGNAL_CODE_CREATE(SIGUSR1, 0), "SIGUSR1" },
117 - { SIGNAL_CODE_CREATE(SIGUSR2, 0), "SIGUSR2" },
180 + { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_UNK), "TRAP_UNK" }, // Undiagnosed trap
181 +#endif
182
183 // Terminator
184 { 0, NULL },
185 };
186
123 -// Define string conversion functions for SIGNAL_CODE type
124 -ENUM_STR_DEFINE_FUNCTIONS(SIGNAL_CODE, 0, "");
187 +// IMPORTANT: These function return invalid values when the signal is not found - always use a function wrapper
188 +ENUM_STR_DEFINE_FUNCTIONS(SIGNAL_CODE, SIG_NOT_FOUND, NULL);
189
126 -void SIGNAL_CODE_2str_h(SIGNAL_CODE code, char *buf, size_t len) {
127 - if(!buf || !len) return;
128 - if(len < 3) {
190 +// --------------------------------------------------------------------------------------------------------------------
191 +
192 +void SIGNAL_CODE_2str_h(SIGNAL_CODE code, char *buf, size_t size) {
193 + if(!buf || !size) return;
194 + if(size < 3 || code == 0) {
195 buf[0] = '\0';
196 return;
197 }
198
133 - if(code) {
134 - const char *s = SIGNAL_CODE_2str(code);
135 - if (!*s) {
136 - char b[UINT64_MAX_LENGTH + 2];
137 - print_uint64_hex(b, code);
138 - strncpyz(buf, b, len - 1);
199 + char b1[UINT64_MAX_LENGTH];
200 + char b2[UINT64_MAX_LENGTH];
201 +
202 + int signo = SIGNAL_CODE_GET_SIGNO(code);
203 + int si_code = SIGNAL_CODE_GET_SI_CODE(code);
204 +
205 + // find the string for the signal
206 + const char *signo_str = SIGNAL_NUM_2str(signo);
207 + if(!signo_str || !*signo_str) {
208 + print_int64(b1, signo);
209 + signo_str = b1;
210 + }
211 +
212 + // find the string for the si_code
213 + const char *si_code_str = SIGNAL_CODE_2str(code);
214 + if(!si_code_str || !*si_code_str) {
215 + si_code_str = SI_CODE_2str(si_code);
216 + if(!si_code_str || !*si_code_str) {
217 + print_int64(b2, si_code);
218 + si_code_str = b2;
219 }
140 - else
141 - strncpyz(buf, s, len - 1);
220 }
143 - else
144 - buf[0] = '\0';
221 +
222 + // now we have to concatenate the two strings
223 + // with a slash in between
224 +
225 + strncpyz(buf, signo_str, size - 1);
226 + size_t len = strlen(buf);
227 +
228 + if(size - 1 > len)
229 + buf[len++] = '/';
230 +
231 + if(size -1 > len)
232 + strncpyz(&buf[len], si_code_str, size - 1 - len);
233 +
234 + buf[size - 1] = '\0';
235 }
236
237 SIGNAL_CODE SIGNAL_CODE_2id_h(const char *str) {
148 - if(strncmp(str, "0x", 2) == 0)
149 - return strtoull(str + 2, NULL, 16);
238 + if(!str || !*str) return 0;
239 +
240 + char buf[strlen(str) + 1];
241 + memcpy(buf, str, strlen(str) + 1);
242 +
243 + char *si_code_str = strchr(buf, '/');
244 + if(si_code_str) {
245 + *si_code_str = '\0';
246 + si_code_str++;
247 + }
248 +
249 + int signo = SIGNAL_NUM_2id(buf);
250 + if(signo == SIG_NOT_FOUND)
251 + signo = str2i(buf);
252 +
253 + SIGNAL_CODE code = si_code_str ? SIGNAL_CODE_2id(si_code_str) : SIG_NOT_FOUND;
254 + if(code != SIG_NOT_FOUND)
255 + // this has both signo and si_code in it
256 + return code;
257 +
258 + int si_code = si_code_str ? SI_CODE_2id(si_code_str) : SIG_NOT_FOUND;
259 + if(si_code == SIG_NOT_FOUND)
260 + si_code = si_code_str ? str2i(si_code_str) : 0;
261
151 - return SIGNAL_CODE_2id(str);
262 + return SIGNAL_CODE_CREATE(signo, si_code);
263 +}
264 +
265 +// Function to create a SIGNAL_CODE from signal number and signal code
266 +SIGNAL_CODE signal_code(int signo, int si_code) {
267 + return SIGNAL_CODE_CREATE(signo, si_code);
268 }
src/libnetdata/signals/signal-code.h
+1 -3
@@ -18,10 +18,8 @@ SIGNAL_CODE signal_code(int signo, int si_code);
18 // Extract the signal code from a SIGNAL_CODE
19 #define SIGNAL_CODE_GET_SI_CODE(code) ((int)((code) & 0xFFFFFFFF))
20
21 -ENUM_STR_DEFINE_FUNCTIONS_EXTERN(SIGNAL_CODE);
22 -
21 // convert a signal code to string, by name or hex (if no name is available)
24 -void SIGNAL_CODE_2str_h(SIGNAL_CODE code, char *buf, size_t len);
22 +void SIGNAL_CODE_2str_h(SIGNAL_CODE code, char *buf, size_t size);
23
24 // parse a signal code from a string, by name or hex
25 SIGNAL_CODE SIGNAL_CODE_2id_h(const char *str);