Add parlib/common.h
[akaros.git] / user / parlib / debug.c
1 // Implementation of cprintf console output for user processes,
2 // based on printfmt() and the sys_cputs() system call.
3 //
4 // cprintf is a debugging statement, not a generic output statement.
5 // It is very important that it always go to the console, especially when
6 // debugging file descriptor code!
7
8 #include <parlib/common.h>
9 #include <parlib/parlib.h>
10 #include <stdio.h>
11 #include <parlib/spinlock.h>
12
13 // Collect up to BUF_SIZE characters into a buffer
14 // and perform ONE system call to print all of them,
15 // in order to make the lines output to the console atomic
16 // and prevent interrupts from causing context switches
17 // in the middle of a console output line and such.
18 #define BUF_SIZE 256
19 typedef struct debugbuf {
20         size_t  idx;    // current buffer index
21         size_t  cnt;    // total bytes printed so far
22         uint8_t buf[BUF_SIZE];
23 } debugbuf_t;
24
25
26 static void putch(int ch, debugbuf_t **b)
27 {
28         (*b)->buf[(*b)->idx++] = ch;
29         if ((*b)->idx == BUF_SIZE) {
30                 sys_cputs((*b)->buf, (*b)->idx);
31                 (*b)->idx = 0;
32         }
33         (*b)->cnt++;
34 }
35
36 int ros_vdebug(const char *fmt, va_list ap)
37 {
38         debugbuf_t b;
39         debugbuf_t *bp = &b;
40
41         b.idx = 0;
42         b.cnt = 0;
43         ros_vdebugfmt((void*)putch, (void*)&bp, fmt, ap);
44         sys_cputs(b.buf, b.idx);
45
46         return b.cnt;
47 }
48
49 int ros_debug(const char *fmt, ...)
50 {
51         va_list ap;
52         int cnt;
53
54         va_start(ap, fmt);
55         cnt = ros_vdebug(fmt, ap);
56         va_end(ap);
57
58         return cnt;
59 }
60
61 /* Poor man's Ftrace, won't work well with concurrency. */
62 static const char *blacklist[] = {
63         "whatever",
64 };
65
66 static bool is_blacklisted(const char *s)
67 {
68         #define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0]))
69         for (int i = 0; i < ARRAY_SIZE(blacklist); i++) {
70                 if (!strcmp(blacklist[i], s))
71                         return TRUE;
72         }
73         return FALSE;
74 }
75
76 static int tab_depth = 0;
77 static bool print = TRUE;
78
79 void reset_print_func_depth(void)
80 {
81         tab_depth = 0;
82 }
83
84 void toggle_print_func(void)
85 {
86         print = !print;
87         printf("Func entry/exit printing is now %sabled\n", print ? "en" : "dis");
88 }
89
90 static spinlock_t lock = {0};
91
92 void __print_func_entry(const char *func, const char *file)
93 {
94         if (!print)
95                 return;
96         if (is_blacklisted(func))
97                 return;
98         spinlock_lock(&lock);
99         printd("Vcore %2d", vcore_id());        /* helps with multicore output */
100         for (int i = 0; i < tab_depth; i++)
101                 printf("\t");
102         printf("%s() in %s\n", func, file);
103         spinlock_unlock(&lock);
104         tab_depth++;
105 }
106
107 void __print_func_exit(const char *func, const char *file)
108 {
109         if (!print)
110                 return;
111         if (is_blacklisted(func))
112                 return;
113         tab_depth--;
114         spinlock_lock(&lock);
115         printd("Vcore %2d", vcore_id());
116         for (int i = 0; i < tab_depth; i++)
117                 printf("\t");
118         printf("---- %s()\n", func);
119         spinlock_unlock(&lock);
120 }