1 /*
2  * Copyright (C) 2019-2020 Alibaba Group Holding Limited
3  */
4 
5 #ifndef OSAL_DEBUG_H
6 #define OSAL_DEBUG_H
7 
8 #include <stdio.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <ulog/ulog.h>
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 #define SHORT_FILE __FUNCTION__
18 
19 #ifdef CONFIG_DEBUG
20 #define debug_print_assert(A, B, C, D, E, F)                                                       \
21     do {                                                                                           \
22         printf("!!!assert: %s: %d, %s\r\n", D, E, F);                                              \
23         while (1)                                                                                  \
24             ;                                                                                      \
25     } while (0)
26 #else
27 #define debug_print_assert(A, B, C, D, E, F)
28 #endif
29 
30 #if (!defined(unlikely))
31 #define unlikely(EXPRESSSION) !!(EXPRESSSION)
32 #endif
33 
34 #ifdef CONFIG_DEBUG
35 
36 #define aos_assert(X)                                                                              \
37     do {                                                                                           \
38         if (unlikely(!(X))) {                                                                      \
39             debug_print_assert(0, #X, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);            \
40         }                                                                                          \
41     } while (0)
42 
43 #define except_process(err) aos_except_process(errno, SHORT_FILE, __LINE__,                  \
44                                 __PRETTY_FUNCTION__,  __builtin_return_address(0))
45 
46 #else
47 
48 #define aos_assert(X)
49 #define except_process(err) aos_except_process(errno, NULL, 0, NULL,                   \
50                                __builtin_return_address(0))
51 #endif
52 
53 #ifndef CHECK_PARAM
54 #define CHECK_PARAM(x, ret) \
55 	do { \
56 		if (!(x)) { \
57 			return ret; \
58 		}\
59 	} while (0)
60 #endif
61 
62 #ifndef CHECK_RET_WITH_GOTO
63 #define CHECK_RET_WITH_GOTO(x, label) \
64 	do { \
65 		if (!(x)) { \
66 			printf("%s, %d fail.\n", __FUNCTION__, __LINE__); \
67 			goto label; \
68 		}\
69 	} while (0)
70 #endif
71 
72 #ifndef CHECK_RET_WITH_RET
73 #define CHECK_RET_WITH_RET(x, ret) \
74 	do { \
75 		if (!(x)) { \
76 			printf("%s, %d fail.\n", __FUNCTION__, __LINE__); \
77 			return ret; \
78 		}\
79 	} while (0)
80 #endif
81 
82 #ifndef CHECK_RET_TAG_WITH_GOTO
83 #define CHECK_RET_TAG_WITH_GOTO(x, label) \
84 	do { \
85 		if (!(x)) { \
86 			LOGE(TAG, "%s, %d fail", __FUNCTION__, __LINE__); \
87 			goto label; \
88 		}\
89 	} while (0)
90 #endif
91 
92 #ifndef CHECK_RET_TAG_WITH_RET
93 #define CHECK_RET_TAG_WITH_RET(x, ret) \
94 	do { \
95 		if (!(x)) { \
96 			LOGE(TAG, "%s, %d fail", __FUNCTION__, __LINE__); \
97 			return ret; \
98 		}\
99 	} while (0)
100 #endif
101 
102 /*
103  * Check that an expression is true (non-zero).
104  * If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
105  * function name, etc.) using the default debugging output method.
106  *
107  * @param[in]  X  expression to be evaluated.
108  */
109 
110 #if (!defined(aos_check))
111 #define aos_check(X, errno)                                                                        \
112     do {                                                                                           \
113         if (unlikely(!(X)))                                                                        \
114             except_process(errno);                                                                 \
115     } while (0)
116 #endif
117 
118 #if (!defined(aos_check_param))
119 #define aos_check_param(X) aos_check(X, EINVAL)
120 #endif
121 
122 #if (!defined(aos_check_mem))
123 #define aos_check_mem(X) aos_check(X, ENOMEM)
124 #endif
125 
126 #if (!defined(aos_check_return_val))
127 #define aos_check_return_val(X, ret)                                                               \
128     do {                                                                                           \
129         if (unlikely(!(X))) {                                                                      \
130             except_process(errno);                                                                 \
131             return ret;                                                                            \
132         }                                                                                          \
133     } while (0)
134 #endif
135 
136 #if (!defined(aos_check_return_einval))
137 #define aos_check_return_einval(X) aos_check_return_val(X, -EINVAL)
138 #endif
139 
140 #if (!defined(aos_check_return_null))
141 #define aos_check_return_null(X) aos_check_return_val(X, NULL)
142 #endif
143 
144 #if (!defined(aos_check_return_enomem))
145 #define aos_check_return_enomem(X) aos_check_return_val(X, -ENOMEM)
146 #endif
147 
148 #if (!defined(aos_check_return))
149 #define aos_check_return(X)                                                                        \
150     do {                                                                                           \
151         if (unlikely(!(X))) {                                                                      \
152             except_process(errno);                                                                 \
153             return;                                                                                \
154         }                                                                                          \
155     } while (0)
156 #endif
157 
158 //////////////////////////////////////////////////////////////////////
159 
160 #if (!defined(check))
161 #define check(X)                                                                                   \
162     do {                                                                                           \
163         if (unlikely(!(X)))                                                                        \
164             except_process(0);                                                                     \
165     } while (0)
166 #endif
167 /*
168  * Check that an expression is true (non-zero) with an explanation.
169  * If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
170  * function name, etc.) using the default debugging output method.
171  *
172  * @param[in]  X       expression to be evaluated.
173  * @param[in]  STR     If the expression evaluate to false, custom string to print.
174  */
175 #if (!defined(check_string))
176 #define check_string(X, STR)                                                                       \
177     do {                                                                                           \
178         if (unlikely(!(X))) {                                                                      \
179             debug_print_assert(0, #X, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);             \
180             AOS_ASSERTION_FAIL_ACTION();                                                           \
181         }                                                                                          \
182     } while (1 == 0)
183 #endif
184 
185 /*
186  * Requires that an expression evaluate to true.
187  * If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
188  * function name, etc.) using the default debugging output method then jumps to a label.
189  *
190  * @param[in]  X      expression to be evalulated.
191  * @param[in]  LABEL  if expression evaluate to false,jumps to the LABEL.
192  */
193 #if (!defined(require))
194 #define require(X, LABEL)                                                                          \
195     do {                                                                                           \
196         if (unlikely(!(X))) {                                                                      \
197             debug_print_assert(0, #X, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);            \
198             goto LABEL;                                                                            \
199         }                                                                                          \
200     } while (1 == 0)
201 #endif
202 
203 /*
204  * Requires that an expression evaluate to true with an explanation.
205  * If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
206  * function name, etc.) and a custom explanation string using the default debugging output method then jumps to a label.
207  *
208  * @param[in]  X      expression to be evalulated.
209  * @param[in]  LABEL  if expression evaluate to false,jumps to the LABEL.
210  * @param[in]  STR    if expression evaluate to false,custom explanation string to print.
211  */
212 #if (!defined(require_string))
213 #define require_string(X, LABEL, STR)                                                              \
214     do {                                                                                           \
215         if (unlikely(!(X))) {                                                                      \
216             debug_print_assert(0, #X, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);             \
217             goto LABEL;                                                                            \
218         }                                                                                          \
219     } while (1 == 0)
220 #endif
221 
222 /*
223  * Requires that an expression evaluate to true.
224  * If expression evalulates to false, this jumps to a label. No debugging information is printed.
225  *
226  * @param[in]  X      expression to be evalulated
227  * @param[in]  LABEL  if expression evaluate to false,jumps to the LABEL.
228  */
229 #if (!defined(require_quiet))
230 #define require_quiet(X, LABEL)                                                                    \
231     do {                                                                                           \
232         if (unlikely(!(X))) {                                                                      \
233             goto LABEL;                                                                            \
234         }                                                                                          \
235     } while (1 == 0)
236 #endif
237 
238 /*
239  * Require that an error code is noErr (0).
240  * If the error code is non-0, this prints debugging information (actual expression string, file, line number,
241  * function name, etc.) using the default debugging output method then jumps to a label.
242  *
243  * @param[in]  ERR    error to be evaluated
244  * @param[in]  LABEL  If the error code is non-0,jumps to the LABEL.
245  */
246 #if (!defined(require_noerr))
247 #define require_noerr(ERR, LABEL)                                                                  \
248     do {                                                                                           \
249         int localErr;                                                                              \
250                                                                                                    \
251         localErr = (int)(ERR);                                                                     \
252         if (unlikely(localErr != 0)) {                                                             \
253             debug_print_assert(localErr, NULL, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);   \
254             goto LABEL;                                                                            \
255         }                                                                                          \
256                                                                                                    \
257     } while (1 == 0)
258 #endif
259 
260 /*
261  * Require that an error code is noErr (0) with an explanation.
262  * If the error code is non-0, this prints debugging information (actual expression string, file, line number,
263  * function name, etc.), and a custom explanation string using the default debugging output method using the
264  * default debugging output method then jumps to a label.
265  *
266  * @param[in]  ERR    error to be evaluated
267  * @param[in]  LABEL  If the error code is non-0, jumps to the LABEL.
268  * @param[in]  STR    If the error code is non-0, custom explanation string to print
269  */
270 #if (!defined(require_noerr_string))
271 #define require_noerr_string(ERR, LABEL, STR)                                                      \
272     do {                                                                                           \
273         int localErr;                                                                              \
274                                                                                                    \
275         localErr = (int)(ERR);                                                                     \
276         if (unlikely(localErr != 0)) {                                                             \
277             debug_print_assert(localErr, NULL, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);    \
278             goto LABEL;                                                                            \
279         }                                                                                          \
280     } while (1 == 0)
281 #endif
282 
283 /*
284  * Require that an error code is noErr (0)  with an explanation and action to execute otherwise.
285  * If the error code is non-0, this prints debugging information (actual expression string, file, line number,
286  * function name, etc.), and a custom explanation string using the default debugging output method using the
287  * default debugging output method then executes an action and jumps to a label.
288  *
289  * @param[in]  ERR     error to be evaluated.
290  * @param[in]  LABEL   If the error code is non-0, jumps to the LABEL.
291  * @param[in]  ACTION  If the error code is non-0, custom code to executes.
292  * @param[in]  STR     If the error code is non-0, custom explanation string to print.
293  */
294 #if (!defined(require_noerr_action_string))
295 #define require_noerr_action_string(ERR, LABEL, ACTION, STR)                                       \
296     do {                                                                                           \
297         int localErr;                                                                              \
298                                                                                                    \
299         localErr = (int)(ERR);                                                                     \
300         if (unlikely(localErr != 0)) {                                                             \
301             debug_print_assert(localErr, NULL, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);    \
302             {                                                                                      \
303                 ACTION;                                                                            \
304             }                                                                                      \
305             goto LABEL;                                                                            \
306         }                                                                                          \
307     } while (1 == 0)
308 #endif
309 
310 /*
311  * Require that an error code is noErr (0).
312  * If the error code is non-0, this jumps to a label. No debugging information is printed.
313  *
314  * @param[in]  ERR    error to be evaluated.
315  * @param[in]  LABEL  If the error code is non-0, jumps to the LABEL.
316  */
317 #if (!defined(require_noerr_quiet))
318 #define require_noerr_quiet(ERR, LABEL)                                                            \
319     do {                                                                                           \
320         if (unlikely((ERR) != 0)) {                                                                \
321             goto LABEL;                                                                            \
322         }                                                                                          \
323     } while (1 == 0)
324 #endif
325 
326 /*
327  * Require that an error code is noErr (0) with an action to execute otherwise.
328  * If the error code is non-0, this prints debugging information (actual expression string, file, line number,
329  * function name, etc.) using the default debugging output method then executes an action and jumps to a label.
330  *
331  * @param[in]  ERR     error to be evaluated.
332  * @param[in]  LABEL   If the error code is non-0, jumps to the LABEL.
333  * @param[in]  ACTION  If the error code is non-0, custom code to executes.
334  */
335 #if (!defined(require_noerr_action))
336 #define require_noerr_action(ERR, LABEL, ACTION)                                                   \
337     do {                                                                                           \
338         int localErr;                                                                              \
339                                                                                                    \
340         localErr = (int)(ERR);                                                                     \
341         if (unlikely(localErr != 0)) {                                                             \
342             debug_print_assert(localErr, NULL, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);   \
343             {                                                                                      \
344                 ACTION;                                                                            \
345             }                                                                                      \
346             goto LABEL;                                                                            \
347         }                                                                                          \
348     } while (1 == 0)
349 #endif
350 
351 /*
352  * Require that an error code is noErr (0) with an action to execute otherwise.
353  * If the error code is non-0, this executes an action and jumps to a label. No debugging information is printed.
354  *
355  * @param[in]  ERR     error to be evaluated.
356  * @param[in]  LABEL   If the error code is non-0, jumps to the LABEL.
357  * @param[in]  ACTION  If the error code is non-0, custom code to executes.
358  */
359 #if (!defined(require_noerr_action_quiet))
360 #define require_noerr_action_quiet(ERR, LABEL, ACTION)                                             \
361     do {                                                                                           \
362         if (unlikely((ERR) != 0)) {                                                                \
363             {                                                                                      \
364                 ACTION;                                                                            \
365             }                                                                                      \
366             goto LABEL;                                                                            \
367         }                                                                                          \
368     } while (1 == 0)
369 #endif
370 
371 /*
372  * Requires that an expression evaluate to true with an action to execute otherwise.
373  * If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
374  * function name, etc.) using the default debugging output method then executes an action and jumps to a label.
375  *
376  * @param[in]  X       expression to be evaluated.
377  * @param[in]  LABEL   If the expression evaluate to false, jumps to the LABEL.
378  * @param[in]  ACTION  If the expression evaluate to false, custom code to executes.
379  */
380 #if (!defined(require_action))
381 #define require_action(X, LABEL, ACTION)                                                           \
382     do {                                                                                           \
383         if (unlikely(!(X))) {                                                                      \
384             debug_print_assert(0, #X, NULL, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);            \
385             {                                                                                      \
386                 ACTION;                                                                            \
387             }                                                                                      \
388             goto LABEL;                                                                            \
389         }                                                                                          \
390     } while (1 == 0)
391 #endif
392 
393 /*
394  * Requires that an expression evaluate to true with an explanation and action to execute otherwise.
395  * If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
396  * function name, etc.) and a custom explanation string using the default debugging output method then executes an
397  * action and jumps to a label.
398  *
399  * @param[in]  X       expression to be evaluated.
400  * @param[in]  LABEL   If the expression evaluate to false, jumps to the LABEL.
401  * @param[in]  ACTION  If the expression evaluate to false, custom code to executes.
402  * @param[in]  STR     If the expression evaluate to false, custom string to print.
403  */
404 #if (!defined(require_action_string))
405 #define require_action_string(X, LABEL, ACTION, STR)                                               \
406     do {                                                                                           \
407         if (unlikely(!(X))) {                                                                      \
408             debug_print_assert(0, #X, STR, SHORT_FILE, __LINE__, __PRETTY_FUNCTION__);             \
409             {                                                                                      \
410                 ACTION;                                                                            \
411             }                                                                                      \
412             goto LABEL;                                                                            \
413         }                                                                                          \
414     } while (1 == 0)
415 #endif
416 
417 /*
418  * Requires that an expression evaluate to true with an action to execute otherwise.
419  * If expression evalulates to false, this executes an action and jumps to a label.
420  * No debugging information is printed.
421  *
422  * @param[in]  X       expression to be evaluated.
423  * @param[in]  LABEL   If the expression evaluate to false, jumps to the LABEL.
424  * @param[in]  ACTION  If the expression evaluate to false, custom code to executes.
425  */
426 #if (!defined(require_action_quiet))
427 #define require_action_quiet(X, LABEL, ACTION)                                                     \
428     do {                                                                                           \
429         if (unlikely(!(X))) {                                                                      \
430             {                                                                                      \
431                 ACTION;                                                                            \
432             }                                                                                      \
433             goto LABEL;                                                                            \
434         }                                                                                          \
435                                                                                                    \
436     } while (1 == 0)
437 #endif
438 
439 #ifdef __cplusplus
440 }
441 #endif
442 
443 void aos_except_process(int errno, const char *file, int line, const char *func_name, void *caller);
444 
445 #endif /* OSAL_DEBUG_H */
446