1 /* Copyright (c) 2021 Apple Inc. All rights reserved. */
2
3 #include <kern/clock.h>
4 #include <libkern/libkern.h>
5 #include <machine/machine_routines.h>
6 #include <os/system_event_log.h>
7
8 static const char *
convert_subsystem_to_string(uint8_t subsystem)9 convert_subsystem_to_string(uint8_t subsystem)
10 {
11 switch (subsystem) {
12 case SYSTEM_EVENT_SUBSYSTEM_LAUNCHD:
13 return "launchd";
14 case SYSTEM_EVENT_SUBSYSTEM_TEST:
15 return "test";
16 case SYSTEM_EVENT_SUBSYSTEM_NVRAM:
17 return "nvram";
18 case SYSTEM_EVENT_SUBSYSTEM_PROCESS:
19 return "process";
20 default:
21 break;
22 }
23 return "UNKNOWN";
24 }
25
26 static const char *
convert_type_to_string(uint8_t type)27 convert_type_to_string(uint8_t type)
28 {
29 switch (type) {
30 case SYSTEM_EVENT_TYPE_INFO:
31 return "INFO";
32 case SYSTEM_EVENT_TYPE_ERROR:
33 return "ERROR";
34 default:
35 break;
36 }
37 return "UNKNOWN";
38 }
39
40 /* We don't want to interfere with critical tasks.
41 * Skip recording this event if:
42 * 1. Interrupts are disabled.
43 * 2. We are not in a panic.
44 * A suggested improvement is adding events to an MPSC queue to log later on (rdar://84678724).
45 */
46 static bool
is_recording_allowed(void)47 is_recording_allowed(void)
48 {
49 return ml_get_interrupts_enabled() || panic_active();
50 }
51
52 static void
_record_system_event_internal(uint8_t type,uint8_t subsystem,const char * event,const char * payload)53 _record_system_event_internal(uint8_t type, uint8_t subsystem, const char *event, const char *payload)
54 {
55 const char *type_string = convert_type_to_string(type);
56 const char *subsystem_string = convert_subsystem_to_string(subsystem);
57
58 uint64_t nanosecs;
59 const uint64_t timestamp = mach_continuous_time();
60 absolutetime_to_nanoseconds(timestamp, &nanosecs);
61
62 printf("[System Event] [%llu] [%s] [Subsystem: %s] [Event: %.*s] %s\n", timestamp, type_string, subsystem_string, SYSTEM_EVENT_EVENT_MAX, event, payload);
63 }
64
65 void
record_system_event(uint8_t type,uint8_t subsystem,const char * event,const char * format,...)66 record_system_event(uint8_t type, uint8_t subsystem, const char *event, const char *format, ...)
67 {
68 if (!is_recording_allowed()) {
69 return;
70 }
71
72 va_list args;
73 va_start(args, format);
74 char payload[SYSTEM_EVENT_PAYLOAD_MAX];
75
76 vsnprintf(payload, sizeof(payload), format, args);
77 va_end(args);
78
79 _record_system_event_internal(type, subsystem, event, payload);
80 }
81
82 void
record_system_event_no_varargs(uint8_t type,uint8_t subsystem,const char * event,const char * payload)83 record_system_event_no_varargs(uint8_t type, uint8_t subsystem, const char *event, const char *payload)
84 {
85 if (!is_recording_allowed()) {
86 return;
87 }
88
89 _record_system_event_internal(type, subsystem, event, payload);
90 }
91