GCC Code Coverage Report


Directory: kernel/
File: kernel/src/util.c
Date: 2024-01-01 16:15:14
Exec Total Coverage
Lines: 135 243 55.6%
Functions: 9 13 69.2%
Branches: 82 183 44.8%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2022-2023, The Puppy RTOS Authors
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <puppy.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdarg.h>
11
12 static int _p_vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
13 static char _printk_buf[P_PRINTK_BUF_SIZE];
14
15 p_weak int p_hw_cons_getc(void)
16 {
17 return -1;
18 }
19
20 p_weak int p_hw_cons_output(const char *str, int len)
21 {
22 return 0;
23 }
24
25 arch_spinlock_t cons_lock = {0};
26
27 9575 int printk(const char *fmt, ...)
28 {
29 va_list args;
30 int n;
31
32 9575 va_start(args, fmt);
33 9575 n = _p_vsnprintf(_printk_buf, P_PRINTK_BUF_SIZE, fmt, args);
34 9575 va_end(args);
35
36 9575 p_hw_cons_output(_printk_buf, n);
37
38 9575 return 0;
39 }
40
41 #define ZEROPAD (1 << 0) /* pad with zero */
42 #define SIGN (1 << 1) /* unsigned/signed long */
43 #define PLUS (1 << 2) /* show plus */
44 #define SPACE (1 << 3) /* space if plus */
45 #define LEFT (1 << 4) /* left justified */
46 #define SPECIAL (1 << 5) /* 0x */
47 #define LARGE (1 << 6) /* use 'ABCDEF' instead of 'abcdef' */
48
49 #define _ISDIGIT(c) ((unsigned)((c) - '0') < 10)
50
51 4730 static inline int divide(long *n, int base)
52 {
53 int res;
54
55 4730 res = (int)(((unsigned long)*n) % base);
56 4730 *n = (long)(((unsigned long)*n) / base);
57
58 4730 return res;
59 }
60
61 8430 static inline int skip_atoi(const char **s)
62 {
63 8430 int i = 0;
64
2/2
✓ Branch 0 taken 8430 times.
✓ Branch 1 taken 8430 times.
16860 while (_ISDIGIT(**s))
65 8430 i = i * 10 + *((*s)++) - '0';
66
67 8430 return i;
68 }
69 8679 static char *print_number(char *buf,
70 char *end,
71 long num,
72 int base,
73 int s,
74 int precision,
75 int type)
76 {
77 char c, sign;
78 char tmp[32];
79 8679 int precision_bak = precision;
80 const char *digits;
81 static const char small_digits[] = "0123456789abcdef";
82 static const char large_digits[] = "0123456789ABCDEF";
83 int i, size;
84
85 8679 size = s;
86
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8679 times.
8679 digits = (type & LARGE) ? large_digits : small_digits;
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8679 times.
8679 if (type & LEFT)
89 type &= ~ZEROPAD;
90
91
2/2
✓ Branch 0 taken 8346 times.
✓ Branch 1 taken 333 times.
8679 c = (type & ZEROPAD) ? '0' : ' ';
92
93 /* get sign */
94 8679 sign = 0;
95
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 8346 times.
8679 if (type & SIGN)
96 {
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (num < 0)
98 {
99 sign = '-';
100 num = -num;
101 }
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 else if (type & PLUS)
103 sign = '+';
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 else if (type & SPACE)
105 sign = ' ';
106 }
107
108 8679 i = 0;
109
2/2
✓ Branch 0 taken 6296 times.
✓ Branch 1 taken 2383 times.
8679 if (num == 0)
110 6296 tmp[i++] = '0';
111 else
112 {
113
2/2
✓ Branch 0 taken 4730 times.
✓ Branch 1 taken 2383 times.
7113 while (num != 0)
114 4730 tmp[i++] = digits[divide(&num, base)];
115 }
116
117
1/2
✓ Branch 0 taken 8679 times.
✗ Branch 1 not taken.
8679 if (i > precision)
118 8679 precision = i;
119 8679 size -= precision;
120
121
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 8346 times.
8679 if (!(type & (ZEROPAD | LEFT)))
122 {
123
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
333 if ((sign) && (size > 0))
124 size--;
125
126
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 333 times.
339 while (size-- > 0)
127 {
128
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (buf < end)
129 6 *buf = ' ';
130 6 ++ buf;
131 }
132 }
133
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8679 times.
8679 if (sign)
135 {
136 if (buf < end)
137 {
138 *buf = sign;
139 }
140 -- size;
141 ++ buf;
142 }
143
144 /* no align to the left */
145
1/2
✓ Branch 0 taken 8679 times.
✗ Branch 1 not taken.
8679 if (!(type & LEFT))
146 {
147
2/2
✓ Branch 0 taken 9238 times.
✓ Branch 1 taken 8679 times.
17917 while (size-- > 0)
148 {
149
1/2
✓ Branch 0 taken 9238 times.
✗ Branch 1 not taken.
9238 if (buf < end)
150 9238 *buf = c;
151 9238 ++ buf;
152 }
153 }
154
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8679 times.
8679 while (i < precision--)
156 {
157 if (buf < end)
158 *buf = '0';
159 ++ buf;
160 }
161
162 /* put number in the temporary buffer */
163
3/4
✓ Branch 0 taken 11026 times.
✓ Branch 1 taken 8679 times.
✓ Branch 2 taken 11026 times.
✗ Branch 3 not taken.
19705 while (i-- > 0 && (precision_bak != 0))
164 {
165
1/2
✓ Branch 0 taken 11026 times.
✗ Branch 1 not taken.
11026 if (buf < end)
166 11026 *buf = tmp[i];
167 11026 ++ buf;
168 }
169
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8679 times.
8679 while (size-- > 0)
171 {
172 if (buf < end)
173 *buf = ' ';
174 ++ buf;
175 }
176
177 8679 return buf;
178 }
179
180 9575 static int _p_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
181 {
182 uint32_t num;
183 int i, len;
184 char *str, *end, c;
185 const char *s;
186
187 uint8_t base; /* the base of number */
188 uint8_t flags; /* flags to print number */
189 uint8_t qualifier; /* 'h', 'l', or 'L' for integer fields */
190 int32_t field_width; /* width of output field */
191 int precision; /* min. # of digits for integers and max for a string */
192
193 9575 str = buf;
194 9575 end = buf + size;
195
196 /* Make sure end is always >= buf */
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9575 times.
9575 if (end < buf)
198 {
199 end = ((char *) - 1);
200 size = end - buf;
201 }
202
203
2/2
✓ Branch 0 taken 23207 times.
✓ Branch 1 taken 9575 times.
32782 for (; *fmt ; ++fmt)
204 {
205
2/2
✓ Branch 0 taken 13842 times.
✓ Branch 1 taken 9365 times.
23207 if (*fmt != '%')
206 {
207
1/2
✓ Branch 0 taken 13842 times.
✗ Branch 1 not taken.
13842 if (str < end)
208 13842 *str = *fmt;
209 13842 ++ str;
210 13842 continue;
211 }
212
213 /* process flags */
214 9365 flags = 0;
215
216 while (1)
217 {
218 /* skips the first '%' also */
219 17711 ++ fmt;
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17711 times.
17711 if (*fmt == '-') flags |= LEFT;
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17711 times.
17711 else if (*fmt == '+') flags |= PLUS;
222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17711 times.
17711 else if (*fmt == ' ') flags |= SPACE;
223
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17711 times.
17711 else if (*fmt == '#') flags |= SPECIAL;
224
2/2
✓ Branch 0 taken 8346 times.
✓ Branch 1 taken 9365 times.
17711 else if (*fmt == '0') flags |= ZEROPAD;
225 9365 else break;
226 }
227
228 /* get field width */
229 9365 field_width = -1;
230
2/2
✓ Branch 0 taken 8430 times.
✓ Branch 1 taken 935 times.
9365 if (_ISDIGIT(*fmt)) field_width = skip_atoi(&fmt);
231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 935 times.
935 else if (*fmt == '*')
232 {
233 ++ fmt;
234 /* it's the next argument */
235 field_width = va_arg(args, int);
236 if (field_width < 0)
237 {
238 field_width = -field_width;
239 flags |= LEFT;
240 }
241 }
242
243 /* get the precision */
244 9365 precision = -1;
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9365 times.
9365 if (*fmt == '.')
246 {
247 ++ fmt;
248 if (_ISDIGIT(*fmt)) precision = skip_atoi(&fmt);
249 else if (*fmt == '*')
250 {
251 ++ fmt;
252 /* it's the next argument */
253 precision = va_arg(args, int);
254 }
255 if (precision < 0) precision = 0;
256 }
257 /* get the conversion qualifier */
258 9365 qualifier = 0;
259
2/4
✓ Branch 0 taken 9365 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9365 times.
9365 if (*fmt == 'h' || *fmt == 'l')
260 {
261 qualifier = *fmt;
262 ++ fmt;
263 }
264
265 /* the default base */
266 9365 base = 10;
267
268
3/11
✗ Branch 0 not taken.
✓ Branch 1 taken 686 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 8346 times.
✓ Branch 8 taken 333 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
9365 switch (*fmt)
269 {
270 case 'c':
271 if (!(flags & LEFT))
272 {
273 while (--field_width > 0)
274 {
275 if (str < end) *str = ' ';
276 ++ str;
277 }
278 }
279
280 /* get character */
281 c = (uint8_t)va_arg(args, int);
282 if (str < end) *str = c;
283 ++ str;
284
285 /* put width */
286 while (--field_width > 0)
287 {
288 if (str < end) *str = ' ';
289 ++ str;
290 }
291 continue;
292
293 686 case 's':
294 686 s = va_arg(args, char *);
295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 686 times.
686 if (!s) s = "(NULL)";
296
297
3/4
✓ Branch 0 taken 4665 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3979 times.
✓ Branch 3 taken 686 times.
4665 for (len = 0; (len != field_width) && (s[len] != '\0'); len++);
298
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 686 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
686 if (precision > 0 && len > precision) len = precision;
299
300
1/2
✓ Branch 0 taken 686 times.
✗ Branch 1 not taken.
686 if (!(flags & LEFT))
301 {
302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 686 times.
686 while (len < field_width--)
303 {
304 if (str < end) *str = ' ';
305 ++ str;
306 }
307 }
308
309
2/2
✓ Branch 0 taken 3979 times.
✓ Branch 1 taken 686 times.
4665 for (i = 0; i < len; ++i)
310 {
311
1/2
✓ Branch 0 taken 3979 times.
✗ Branch 1 not taken.
3979 if (str < end) *str = *s;
312 3979 ++ str;
313 3979 ++ s;
314 }
315
316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 686 times.
686 while (len < field_width--)
317 {
318 if (str < end) *str = ' ';
319 ++ str;
320 }
321 686 continue;
322
323 case 'p':
324 if (field_width == -1)
325 {
326 field_width = sizeof(void *) << 1;
327 flags |= ZEROPAD;
328 }
329 str = print_number(str, end,
330 (long)va_arg(args, void *),
331 16, field_width, precision, flags);
332 continue;
333
334 case '%':
335 if (str < end) *str = '%';
336 ++ str;
337 continue;
338
339 /* integer number formats - set up the flags and "break" */
340 case 'b':
341 base = 2;
342 break;
343 case 'o':
344 base = 8;
345 break;
346
347 case 'X':
348 flags |= LARGE;
349 8346 case 'x':
350 8346 base = 16;
351 8346 break;
352
353 333 case 'd':
354 case 'i':
355 333 flags |= SIGN;
356 333 case 'u':
357 333 break;
358
359 default:
360 if (str < end) *str = '%';
361 ++ str;
362
363 if (*fmt)
364 {
365 if (str < end) *str = *fmt;
366 ++ str;
367 }
368 else
369 {
370 -- fmt;
371 }
372 continue;
373 }
374
375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8679 times.
8679 if (qualifier == 'l')
376 {
377 num = va_arg(args, uint32_t);
378 if (flags & SIGN) num = (int32_t)num;
379 }
380
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8679 times.
8679 else if (qualifier == 'h')
381 {
382 num = (uint16_t)va_arg(args, int);
383 if (flags & SIGN) num = (int16_t)num;
384 }
385 else
386 {
387 8679 num = va_arg(args, uint32_t);
388
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 8346 times.
8679 if (flags & SIGN) num = (int32_t)num;
389 }
390 8679 str = print_number(str, end, num, base, field_width, precision, flags);
391 }
392
393
1/2
✓ Branch 0 taken 9575 times.
✗ Branch 1 not taken.
9575 if (size > 0)
394 {
395
1/2
✓ Branch 0 taken 9575 times.
✗ Branch 1 not taken.
9575 if (str < end) *str = '\0';
396 else
397 {
398 end[-1] = '\0';
399 }
400 }
401
402 /* the trailing null byte doesn't count towards the total
403 * ++str;
404 */
405 9575 return str - buf;
406 }
407
408 const P_SECTION_START_DEFINE(P_TC_SECTION, _tc_list_start);
409 const P_SECTION_END_DEFINE(P_TC_SECTION, _tc_list_end);
410 1 void tc_list(void)
411 {
412 struct p_ex_fn *ptr_begin, *ptr_end;
413 volatile struct p_ex_fn *tc;
414 1 ptr_begin = (struct p_ex_fn *)P_SECTION_START_ADDR(_tc_list_start);
415 1 ptr_end = (struct p_ex_fn *)P_SECTION_END_ADDR(_tc_list_end);
416
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (tc = ptr_begin; tc < ptr_end;)
417 {
418 4 printk("Get a testcase: %s\n", tc->name);
419 4 tc ++;
420 }
421 1 }
422
423 void tc_runall(bool verbose)
424 {
425 struct p_ex_fn *ptr_begin, *ptr_end;
426 ptr_begin = (struct p_ex_fn *)P_SECTION_START_ADDR(_tc_list_start);
427 ptr_end = (struct p_ex_fn *)P_SECTION_END_ADDR(_tc_list_end);
428 for (struct p_ex_fn *tc = ptr_begin; tc < ptr_end;)
429 {
430 printk("Start test: %s\n", tc->name);
431 tc->func();
432 printk("Test end\n");
433 tc ++;
434 }
435 }
436
437 4 void tc_run(char *name)
438 {
439 struct p_ex_fn *ptr_begin, *ptr_end;
440 4 ptr_begin = (struct p_ex_fn *)P_SECTION_START_ADDR(_tc_list_start);
441 4 ptr_end = (struct p_ex_fn *)P_SECTION_END_ADDR(_tc_list_end);
442
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
20 for (struct p_ex_fn *tc = ptr_begin; tc < ptr_end;)
443 {
444
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
16 if (!strcmp(tc->name, name))
445 {
446 4 printk("Start test: %s\n", tc->name);
447 4 tc->func();
448 4 printk("Test end\n");
449 }
450 16 tc ++;
451 }
452 4 }
453 static void print_help(void)
454 {
455 printk("useage: tc [options]\r\n");
456 printk("options: \r\n");
457 printk("\t -h \t: show help\r\n");
458 printk("\t -v \t: verbose mode\r\n");
459 printk("\t list \t: show all testcase\r\n");
460 printk("\t run <tcname> \t: run testcase\r\n");
461 printk("\t runall \t: run all testcase\r\n");
462 }
463 5 void shell_tc_cmd(char argc, char *argv)
464 {
465
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (argc > 1)
466 {
467
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (!strcmp("list", &argv[(uint16_t)argv[1]]))
468 {
469 1 tc_list();
470 }
471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 else if (!strcmp("runall", &argv[(uint16_t)argv[1]]))
472 {
473 tc_runall(true);
474 }
475
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 else if (!strcmp("run", &argv[(uint16_t)argv[1]]))
476 {
477 4 tc_run(&argv[(uint16_t)argv[2]]);
478 }
479 else if (!strcmp("-v", &argv[(uint16_t)argv[1]]))
480 {
481 printk("verbose mode not support\r\n");
482 }
483 else if (!strcmp("-h", &argv[(uint8_t)argv[1]]))
484 {
485 print_help();
486 }
487 }
488 else
489 {
490 print_help();
491 }
492 5 }
493 #ifdef ENABLE_NR_SHELL
494 #include <nr_micro_shell.h>
495 NR_SHELL_CMD_EXPORT(tc, shell_tc_cmd);
496 #endif
497
498 #if defined(ENABLE_GCOV) && defined(ENABLE_NR_SHELL)
499 #include "gcov_public.h"
500 #include <nr_micro_shell.h>
501 1 void shell_gcov_exit_cmd(char argc, char *argv)
502 {
503 1 __gcov_exit();
504 }
505 NR_SHELL_CMD_EXPORT(gcov_exit, shell_gcov_exit_cmd);
506 #endif
507