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 * |
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 * |
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 |
49 | is_recording_allowed(void) |
50 | { |
51 | return ml_get_interrupts_enabled() || panic_active(); |
52 | } |
53 | |
54 | static void |
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(abstime: timestamp, result: &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 |
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 |
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 | |