e4d1a32f2e8a0fe7c7701bb43f1f93657437a493
[akaros.git] / user / parlib / debug.c
1 #include <parlib/common.h>
2 #include <parlib/assert.h>
3 #include <parlib/stdio.h>
4 #include <parlib/parlib.h>
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <parlib/spinlock.h>
8 #include <ros/common.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12
13 /* This is called from glibc in delicate places, like signal handlers.  We might
14  * as well just write any valid output to FD 2. */
15 int akaros_printf(const char *format, ...)
16 {
17         char buf[128];
18         va_list ap;
19         int ret;
20
21         va_start(ap, format);
22         ret = vsnprintf(buf, sizeof(buf), format, ap);
23         va_end(ap);
24         if (ret < 0)
25                 return ret;
26         write(2, buf, MIN(sizeof(buf), ret));
27         return ret;
28 }
29
30 /* Poor man's Ftrace, won't work well with concurrency. */
31 static const char *blacklist[] = {
32         "whatever",
33 };
34
35 static bool is_blacklisted(const char *s)
36 {
37         for (int i = 0; i < COUNT_OF(blacklist); i++) {
38                 if (!strcmp(blacklist[i], s))
39                         return TRUE;
40         }
41         return FALSE;
42 }
43
44 static int tab_depth = 0;
45 static bool print = TRUE;
46
47 void reset_print_func_depth(void)
48 {
49         tab_depth = 0;
50 }
51
52 void toggle_print_func(void)
53 {
54         print = !print;
55         printf("Func entry/exit printing is now %sabled\n", print ? "en" :
56                "dis");
57 }
58
59 static spinlock_t lock = {0};
60
61 void __print_func_entry(const char *func, const char *file)
62 {
63         if (!print)
64                 return;
65         if (is_blacklisted(func))
66                 return;
67         spinlock_lock(&lock);
68         printd("Vcore %2d", vcore_id()); /* helps with multicore output */
69         for (int i = 0; i < tab_depth; i++)
70                 printf("\t");
71         printf("%s() in %s\n", func, file);
72         spinlock_unlock(&lock);
73         tab_depth++;
74 }
75
76 void __print_func_exit(const char *func, const char *file)
77 {
78         if (!print)
79                 return;
80         if (is_blacklisted(func))
81                 return;
82         tab_depth--;
83         spinlock_lock(&lock);
84         printd("Vcore %2d", vcore_id());
85         for (int i = 0; i < tab_depth; i++)
86                 printf("\t");
87         printf("---- %s()\n", func);
88         spinlock_unlock(&lock);
89 }
90
91 static int kptrace;
92
93 static void trace_init(void *arg)
94 {
95         kptrace = open("#kprof/kptrace", O_WRITE);
96         if (kptrace < 0)
97                 perror("Unable to open kptrace!\n");
98 }
99
100 int trace_printf(const char *fmt, ...)
101 {
102         va_list args;
103         char buf[128];
104         int amt;
105         static parlib_once_t once = PARLIB_ONCE_INIT;
106
107         parlib_run_once(&once, trace_init, NULL);
108         if (kptrace < 0)
109                 return 0;
110         amt = snprintf(buf, sizeof(buf), "PID %d: ", getpid());
111         /* amt could be > sizeof, if we truncated. */
112         amt = MIN(amt, sizeof(buf));
113         va_start(args, fmt);
114         /* amt == sizeof is OK here */
115         amt += vsnprintf(buf + amt, sizeof(buf) - amt, fmt, args);
116         va_end(args);
117         amt = MIN(amt, sizeof(buf));
118         write(kptrace, buf, amt);
119         return amt;
120 }