Software APIs
log.h
Go to the documentation of this file.
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #ifndef OPENTITAN_SW_DEVICE_LIB_RUNTIME_LOG_H_
6 #define OPENTITAN_SW_DEVICE_LIB_RUNTIME_LOG_H_
7 
8 #include <stdbool.h>
9 #include <stdint.h>
10 
13 
14 /**
15  * @file
16  * @brief Generic logging APIs
17  *
18  * The logging APIs below take a format string with a variable number of
19  * arguments for the type specifiers. The APIs are designed to provide a way
20  * for attaching the log severity, file name, and line number
21  * information along with the message to provide an easier path to debug.
22  * These parameters form a log prefix, which is prepended to the actual
23  * message being printed. The following is a brief description of these:
24  *
25  * log_type: Severity of the message: info, warning, error or fatal
26  *
27  * file name: Name of the file using __FILE__
28  *
29  * line number: Line where the print originated using __LINE__
30  *
31  * Log macros support OpenTitan formatting specifiers; see print.h for
32  * details the subset of C specifier syntax supported.
33  *
34  * The precise mechanism for logging is dependent on the target device. On core
35  * devices, like Verilator, logs are printed using whatever `stdout` is set to
36  * in print.h. DV testbenches may use an alternative, more efficient mechanism.
37  *
38  * In DV mode, some format specifiers may be unsupported, such as %s.
39  */
40 
41 /**
42  * Log severities available.
43  *
44  * Additional log severities can be added as necessary.
45  */
46 typedef enum log_severity {
47  kLogSeverityInfo,
48  kLogSeverityWarn,
49  kLogSeverityError,
50  kLogSeverityFatal,
52 
53 /**
54  * Represents log metadata used to format a log line.
55  *
56  * Any modification to this struct must be made with caution due to external
57  * assumptions. A post-processing script parses the ELF file and extracts the
58  * log fields. The said script uses 20-byte size as the delimiter to collect the
59  * log fields. Any changes to this struct must be accompanied with the updates
60  * to the script, located here:
61  * util/device_sw_utils/extract_sw_logs.py.
62  */
63 typedef struct log_fields {
64  /**
65  * Indicates the severity of the LOG.
66  */
68  /**
69  * Name of the file at which a LOG line occurs, e.g. `__FILE__`. There
70  * are no requirements for this string, other than that it be some kind of
71  * UNIX-like pathname.
72  */
73  const char *file_name;
74  /**
75  * Indicates the line number at which the LOG line occurs, e.g., `__LINE__`.
76  */
77  uint32_t line;
78  /**
79  * Indicates the number of arguments passed to the format string.
80  *
81  * This value used only in DV mode, and is ignored by non-DV logging.
82  */
83  uint32_t nargs;
84  /**
85  * The actual format string.
86  */
87  const char *format;
88 } log_fields_t;
89 
90 // Internal functions exposed only for access by macros. Their
91 // real doxygen can be found in log.c.
92 /**
93  * Implementation detail.
94  */
95 void base_log_internal_core(const log_fields_t *log, ...);
96 /**
97  * Implementation detail.
98  */
99 void base_log_internal_dv(const log_fields_t *log, uint32_t nargs, ...);
100 
101 /**
102  * A macro that wraps the `OT_FAIL_IF_64_BIT` macro, providing the name
103  * of the LOG macro for better error messages.
104  *
105  * @param arg an arg/expression to check
106  */
107 #define OT_FAIL_IF_64_BIT_LOG(arg) OT_FAIL_IF_64_BIT(arg, LOG)
108 
109 /**
110  * A macro that checks the variable arguments of the `LOG` function are valid
111  * at compile time, by asserting that each of the argument is not a standard
112  * C integer type with a width of 64 bits. Any such invalid argument will
113  * cause a relevant error via a static assertion.
114  *
115  * @param ... the variable args list
116  */
117 #define OT_CHECK_VALID_LOG_ARGS(...) \
118  OT_VA_FOR_EACH(OT_FAIL_IF_64_BIT_LOG, ##__VA_ARGS__)
119 
120 /**
121  * Basic logging macro that all other logging macros delegate to.
122  *
123  * Prefer to use a LOG function with a specified severity, instead.
124  *
125  * @param severity a severity of type `log_severity_t`.
126  * @param format a format string, as described in print.h. This must be a
127  * string literal.
128  * @param ... format parameters matching the format string.
129  */
130 #define LOG(severity, format, ...) \
131  do { \
132  OT_CHECK_VALID_LOG_ARGS(__VA_ARGS__); \
133  if (kDeviceLogBypassUartAddress != 0) { \
134  /* clang-format off */ \
135  /* Put DV-only log constants in .logs.* sections, which
136  * the linker will dutifully discard.
137  * Unfortunately, clang-format really mangles these
138  * declarations, so we format them manually. */ \
139  __attribute__((section(".logs.fields"))) \
140  static const log_fields_t kLogFields = \
141  LOG_MAKE_FIELDS_(severity, format, ##__VA_ARGS__); \
142  base_log_internal_dv(&kLogFields, \
143  OT_VA_ARGS_COUNT(format, ##__VA_ARGS__), \
144  ##__VA_ARGS__); /* clang-format on */ \
145  } else { \
146  static const log_fields_t log_fields = \
147  LOG_MAKE_FIELDS_(severity, format, ##__VA_ARGS__); \
148  base_log_internal_core(&log_fields, ##__VA_ARGS__); \
149  } \
150  } while (false)
151 
152 /**
153  * Implementation detail of `LOG`.
154  */
155 #define LOG_MAKE_FIELDS_(_severity, _format, ...) \
156  { \
157  .severity = _severity, .file_name = "" __FILE__ "", .line = __LINE__, \
158  .nargs = OT_VA_ARGS_COUNT(_format, ##__VA_ARGS__), .format = _format, \
159  }
160 
161 /**
162  * Log an informational message.
163  *
164  * @param severity a severity of type `log_severity_t`.
165  * @param format a format string, as described in print.h. This must be a string
166  * literal.
167  * @param ... format parameters matching the format string.
168  */
169 #define LOG_INFO(...) LOG(kLogSeverityInfo, __VA_ARGS__)
170 
171 /**
172  * Log a warning
173  *
174  * @param severity a severity of type `log_severity_t`.
175  * @param format a format string, as described in print.h. This must be a string
176  * literal.
177  * @param ... format parameters matching the format string.
178  */
179 #define LOG_WARNING(...) LOG(kLogSeverityWarn, __VA_ARGS__)
180 
181 /**
182  * Log a non-fatal error.
183  *
184  * @param severity a severity of type `log_severity_t`.
185  * @param format a format string, as described in print.h. This must be a string
186  * literal.
187  * @param ... format parameters matching the format string.
188  */
189 #define LOG_ERROR(...) LOG(kLogSeverityError, __VA_ARGS__)
190 
191 /**
192  * Log a fatal error.
193  *
194  * @param severity a severity of type `log_severity_t`.
195  * @param format a format string, as described in print.h. This must be a string
196  * literal.
197  * @param ... format parameters matching the format string.
198  *
199  * It is the user's responsibility to follow this up with a call to `abort()` to
200  * immediately stop the execution.
201  */
202 #define LOG_FATAL(...) LOG(kLogSeverityFatal, __VA_ARGS__)
203 
204 #endif // OPENTITAN_SW_DEVICE_LIB_RUNTIME_LOG_H_