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 case SYSTEM_EVENT_SUBSYSTEM_PMRD:
21 return "iopmrd";
22 default:
23 break;
24 }
25 return "UNKNOWN";
26 }
27
28 static const char *
convert_type_to_string(uint8_t type)29 convert_type_to_string(uint8_t type)
30 {
31 switch (type) {
32 case SYSTEM_EVENT_TYPE_INFO:
33 return "INFO";
34 case SYSTEM_EVENT_TYPE_ERROR:
35 return "ERROR";
36 default:
37 break;
38 }
39 return "UNKNOWN";
40 }
41
42 /* We don't want to interfere with critical tasks.
43 * Skip recording this event if:
44 * 1. Interrupts are disabled.
45 * 2. We are not in a panic.
46 * A suggested improvement is adding events to an MPSC queue to log later on (rdar://84678724).
47 */
48 static bool
is_recording_allowed(void)49 is_recording_allowed(void)
50 {
51 return ml_get_interrupts_enabled() || panic_active();
52 }
53
54 static void
_record_system_event_internal(uint8_t type,uint8_t subsystem,const char * event,const char * payload)55 _record_system_event_internal(uint8_t type, uint8_t subsystem, const char *event, const char *payload)
56 {
57 const char *type_string = convert_type_to_string(type);
58 const char *subsystem_string = convert_subsystem_to_string(subsystem);
59
60 uint64_t nanosecs;
61 const uint64_t timestamp = mach_continuous_time();
62 absolutetime_to_nanoseconds(timestamp, &nanosecs);
63
64 printf("[System Event] [%llu] [%s] [Subsystem: %s] [Event: %.*s] %s\n", timestamp, type_string, subsystem_string, SYSTEM_EVENT_EVENT_MAX, event, payload);
65 }
66
67 void
record_system_event(uint8_t type,uint8_t subsystem,const char * event,const char * format,...)68 record_system_event(uint8_t type, uint8_t subsystem, const char *event, const char *format, ...)
69 {
70 if (!is_recording_allowed()) {
71 return;
72 }
73
74 va_list args;
75 va_start(args, format);
76 char payload[SYSTEM_EVENT_PAYLOAD_MAX];
77
78 vsnprintf(payload, sizeof(payload), format, args);
79 va_end(args);
80
81 _record_system_event_internal(type, subsystem, event, payload);
82 }
83
84 void
record_system_event_no_varargs(uint8_t type,uint8_t subsystem,const char * event,const char * payload)85 record_system_event_no_varargs(uint8_t type, uint8_t subsystem, const char *event, const char *payload)
86 {
87 if (!is_recording_allowed()) {
88 return;
89 }
90
91 _record_system_event_internal(type, subsystem, event, payload);
92 }
93