]>
Commit | Line | Data |
---|---|---|
a4b75251 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause */ |
2 | /* Copyright 2014-2020, Intel Corporation */ | |
3 | ||
4 | /* | |
5 | * out.h -- definitions for "out" module | |
6 | */ | |
7 | ||
8 | #ifndef PMDK_OUT_H | |
9 | #define PMDK_OUT_H 1 | |
10 | ||
11 | #include <stdarg.h> | |
12 | #include <stddef.h> | |
13 | #include <stdlib.h> | |
14 | ||
15 | #include "util.h" | |
16 | ||
17 | #ifdef __cplusplus | |
18 | extern "C" { | |
19 | #endif | |
20 | ||
21 | /* | |
22 | * Suppress errors which are after appropriate ASSERT* macro for nondebug | |
23 | * builds. | |
24 | */ | |
25 | #if !defined(DEBUG) && (defined(__clang_analyzer__) || defined(__COVERITY__) ||\ | |
26 | defined(__KLOCWORK__)) | |
27 | #define OUT_FATAL_DISCARD_NORETURN __attribute__((noreturn)) | |
28 | #else | |
29 | #define OUT_FATAL_DISCARD_NORETURN | |
30 | #endif | |
31 | ||
32 | #ifndef EVALUATE_DBG_EXPRESSIONS | |
33 | #if defined(DEBUG) || defined(__clang_analyzer__) || defined(__COVERITY__) ||\ | |
34 | defined(__KLOCWORK__) | |
35 | #define EVALUATE_DBG_EXPRESSIONS 1 | |
36 | #else | |
37 | #define EVALUATE_DBG_EXPRESSIONS 0 | |
38 | #endif | |
39 | #endif | |
40 | ||
41 | #ifdef DEBUG | |
42 | ||
43 | #define OUT_LOG out_log | |
44 | #define OUT_NONL out_nonl | |
45 | #define OUT_FATAL out_fatal | |
46 | #define OUT_FATAL_ABORT out_fatal | |
47 | ||
48 | #else | |
49 | ||
50 | static __attribute__((always_inline)) inline void | |
51 | out_log_discard(const char *file, int line, const char *func, int level, | |
52 | const char *fmt, ...) | |
53 | { | |
54 | (void) file; | |
55 | (void) line; | |
56 | (void) func; | |
57 | (void) level; | |
58 | (void) fmt; | |
59 | } | |
60 | ||
61 | static __attribute__((always_inline)) inline void | |
62 | out_nonl_discard(int level, const char *fmt, ...) | |
63 | { | |
64 | (void) level; | |
65 | (void) fmt; | |
66 | } | |
67 | ||
68 | static __attribute__((always_inline)) OUT_FATAL_DISCARD_NORETURN inline void | |
69 | out_fatal_discard(const char *file, int line, const char *func, | |
70 | const char *fmt, ...) | |
71 | { | |
72 | (void) file; | |
73 | (void) line; | |
74 | (void) func; | |
75 | (void) fmt; | |
76 | } | |
77 | ||
78 | static __attribute__((always_inline)) NORETURN inline void | |
79 | out_fatal_abort(const char *file, int line, const char *func, | |
80 | const char *fmt, ...) | |
81 | { | |
82 | (void) file; | |
83 | (void) line; | |
84 | (void) func; | |
85 | (void) fmt; | |
86 | ||
87 | abort(); | |
88 | } | |
89 | ||
90 | #define OUT_LOG out_log_discard | |
91 | #define OUT_NONL out_nonl_discard | |
92 | #define OUT_FATAL out_fatal_discard | |
93 | #define OUT_FATAL_ABORT out_fatal_abort | |
94 | ||
95 | #endif | |
96 | ||
97 | #if defined(__KLOCWORK__) | |
98 | #define TEST_ALWAYS_TRUE_EXPR(cnd) | |
99 | #define TEST_ALWAYS_EQ_EXPR(cnd) | |
100 | #define TEST_ALWAYS_NE_EXPR(cnd) | |
101 | #else | |
102 | #define TEST_ALWAYS_TRUE_EXPR(cnd)\ | |
103 | if (__builtin_constant_p(cnd))\ | |
104 | ASSERT_COMPILE_ERROR_ON(cnd); | |
105 | #define TEST_ALWAYS_EQ_EXPR(lhs, rhs)\ | |
106 | if (__builtin_constant_p(lhs) && __builtin_constant_p(rhs))\ | |
107 | ASSERT_COMPILE_ERROR_ON((lhs) == (rhs)); | |
108 | #define TEST_ALWAYS_NE_EXPR(lhs, rhs)\ | |
109 | if (__builtin_constant_p(lhs) && __builtin_constant_p(rhs))\ | |
110 | ASSERT_COMPILE_ERROR_ON((lhs) != (rhs)); | |
111 | #endif | |
112 | ||
113 | /* produce debug/trace output */ | |
114 | #define LOG(level, ...) do { \ | |
115 | if (!EVALUATE_DBG_EXPRESSIONS) break;\ | |
116 | OUT_LOG(__FILE__, __LINE__, __func__, level, __VA_ARGS__);\ | |
117 | } while (0) | |
118 | ||
119 | /* produce debug/trace output without prefix and new line */ | |
120 | #define LOG_NONL(level, ...) do { \ | |
121 | if (!EVALUATE_DBG_EXPRESSIONS) break; \ | |
122 | OUT_NONL(level, __VA_ARGS__); \ | |
123 | } while (0) | |
124 | ||
125 | /* produce output and exit */ | |
126 | #define FATAL(...)\ | |
127 | OUT_FATAL_ABORT(__FILE__, __LINE__, __func__, __VA_ARGS__) | |
128 | ||
129 | /* assert a condition is true at runtime */ | |
130 | #define ASSERT_rt(cnd) do { \ | |
131 | if (!EVALUATE_DBG_EXPRESSIONS || (cnd)) break; \ | |
132 | OUT_FATAL(__FILE__, __LINE__, __func__, "assertion failure: %s", #cnd);\ | |
133 | } while (0) | |
134 | ||
135 | /* assertion with extra info printed if assertion fails at runtime */ | |
136 | #define ASSERTinfo_rt(cnd, info) do { \ | |
137 | if (!EVALUATE_DBG_EXPRESSIONS || (cnd)) break; \ | |
138 | OUT_FATAL(__FILE__, __LINE__, __func__, \ | |
139 | "assertion failure: %s (%s = %s)", #cnd, #info, info);\ | |
140 | } while (0) | |
141 | ||
142 | /* assert two integer values are equal at runtime */ | |
143 | #define ASSERTeq_rt(lhs, rhs) do { \ | |
144 | if (!EVALUATE_DBG_EXPRESSIONS || ((lhs) == (rhs))) break; \ | |
145 | OUT_FATAL(__FILE__, __LINE__, __func__,\ | |
146 | "assertion failure: %s (0x%llx) == %s (0x%llx)", #lhs,\ | |
147 | (unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)); \ | |
148 | } while (0) | |
149 | ||
150 | /* assert two integer values are not equal at runtime */ | |
151 | #define ASSERTne_rt(lhs, rhs) do { \ | |
152 | if (!EVALUATE_DBG_EXPRESSIONS || ((lhs) != (rhs))) break; \ | |
153 | OUT_FATAL(__FILE__, __LINE__, __func__,\ | |
154 | "assertion failure: %s (0x%llx) != %s (0x%llx)", #lhs,\ | |
155 | (unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)); \ | |
156 | } while (0) | |
157 | ||
158 | /* assert a condition is true */ | |
159 | #define ASSERT(cnd)\ | |
160 | do {\ | |
161 | /*\ | |
162 | * Detect useless asserts on always true expression. Please use\ | |
163 | * COMPILE_ERROR_ON(!cnd) or ASSERT_rt(cnd) in such cases.\ | |
164 | */\ | |
165 | TEST_ALWAYS_TRUE_EXPR(cnd);\ | |
166 | ASSERT_rt(cnd);\ | |
167 | } while (0) | |
168 | ||
169 | /* assertion with extra info printed if assertion fails */ | |
170 | #define ASSERTinfo(cnd, info)\ | |
171 | do {\ | |
172 | /* See comment in ASSERT. */\ | |
173 | TEST_ALWAYS_TRUE_EXPR(cnd);\ | |
174 | ASSERTinfo_rt(cnd, info);\ | |
175 | } while (0) | |
176 | ||
177 | /* assert two integer values are equal */ | |
178 | #define ASSERTeq(lhs, rhs)\ | |
179 | do {\ | |
180 | /* See comment in ASSERT. */\ | |
181 | TEST_ALWAYS_EQ_EXPR(lhs, rhs);\ | |
182 | ASSERTeq_rt(lhs, rhs);\ | |
183 | } while (0) | |
184 | ||
185 | /* assert two integer values are not equal */ | |
186 | #define ASSERTne(lhs, rhs)\ | |
187 | do {\ | |
188 | /* See comment in ASSERT. */\ | |
189 | TEST_ALWAYS_NE_EXPR(lhs, rhs);\ | |
190 | ASSERTne_rt(lhs, rhs);\ | |
191 | } while (0) | |
192 | ||
193 | #define ERR(...)\ | |
194 | out_err(__FILE__, __LINE__, __func__, __VA_ARGS__) | |
195 | ||
196 | void out_init(const char *log_prefix, const char *log_level_var, | |
197 | const char *log_file_var, int major_version, | |
198 | int minor_version); | |
199 | void out_fini(void); | |
200 | void out(const char *fmt, ...) FORMAT_PRINTF(1, 2); | |
201 | void out_nonl(int level, const char *fmt, ...) FORMAT_PRINTF(2, 3); | |
202 | void out_log(const char *file, int line, const char *func, int level, | |
203 | const char *fmt, ...) FORMAT_PRINTF(5, 6); | |
204 | void out_err(const char *file, int line, const char *func, | |
205 | const char *fmt, ...) FORMAT_PRINTF(4, 5); | |
206 | void NORETURN out_fatal(const char *file, int line, const char *func, | |
207 | const char *fmt, ...) FORMAT_PRINTF(4, 5); | |
208 | void out_set_print_func(void (*print_func)(const char *s)); | |
209 | void out_set_vsnprintf_func(int (*vsnprintf_func)(char *str, size_t size, | |
210 | const char *format, va_list ap)); | |
211 | ||
212 | #ifdef _WIN32 | |
213 | #ifndef PMDK_UTF8_API | |
214 | #define out_get_errormsg out_get_errormsgW | |
215 | #else | |
216 | #define out_get_errormsg out_get_errormsgU | |
217 | #endif | |
218 | #endif | |
219 | ||
220 | #ifndef _WIN32 | |
221 | const char *out_get_errormsg(void); | |
222 | #else | |
223 | const char *out_get_errormsgU(void); | |
224 | const wchar_t *out_get_errormsgW(void); | |
225 | #endif | |
226 | ||
227 | #ifdef __cplusplus | |
228 | } | |
229 | #endif | |
230 | ||
231 | #endif |