|  | #include <parlib/common.h> | 
|  | #include <parlib/assert.h> | 
|  | #include <parlib/stdio.h> | 
|  | #include <parlib/parlib.h> | 
|  | #include <unistd.h> | 
|  | #include <parlib/spinlock.h> | 
|  | #include <ros/common.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <fcntl.h> | 
|  |  | 
|  | /* This is called from glibc in delicate places, like signal handlers.  We might | 
|  | * as well just write any valid output to FD 2. */ | 
|  | int akaros_printf(const char *format, ...) | 
|  | { | 
|  | char buf[128]; | 
|  | va_list ap; | 
|  | int ret; | 
|  |  | 
|  | va_start(ap, format); | 
|  | ret = vsnprintf(buf, sizeof(buf), format, ap); | 
|  | va_end(ap); | 
|  | if (ret < 0) | 
|  | return ret; | 
|  | write(2, buf, MIN(sizeof(buf), ret)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Poor man's Ftrace, won't work well with concurrency. */ | 
|  | static const char *blacklist[] = { | 
|  | "whatever", | 
|  | }; | 
|  |  | 
|  | static bool is_blacklisted(const char *s) | 
|  | { | 
|  | for (int i = 0; i < COUNT_OF(blacklist); i++) { | 
|  | if (!strcmp(blacklist[i], s)) | 
|  | return TRUE; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | static int tab_depth = 0; | 
|  | static bool print = TRUE; | 
|  |  | 
|  | void reset_print_func_depth(void) | 
|  | { | 
|  | tab_depth = 0; | 
|  | } | 
|  |  | 
|  | void toggle_print_func(void) | 
|  | { | 
|  | print = !print; | 
|  | printf("Func entry/exit printing is now %sabled\n", print ? "en" : | 
|  | "dis"); | 
|  | } | 
|  |  | 
|  | static spinlock_t lock = {0}; | 
|  |  | 
|  | void __print_func_entry(const char *func, const char *file) | 
|  | { | 
|  | if (!print) | 
|  | return; | 
|  | if (is_blacklisted(func)) | 
|  | return; | 
|  | spinlock_lock(&lock); | 
|  | printd("Vcore %2d", vcore_id()); /* helps with multicore output */ | 
|  | for (int i = 0; i < tab_depth; i++) | 
|  | printf("\t"); | 
|  | printf("%s() in %s\n", func, file); | 
|  | spinlock_unlock(&lock); | 
|  | tab_depth++; | 
|  | } | 
|  |  | 
|  | void __print_func_exit(const char *func, const char *file) | 
|  | { | 
|  | if (!print) | 
|  | return; | 
|  | if (is_blacklisted(func)) | 
|  | return; | 
|  | tab_depth--; | 
|  | spinlock_lock(&lock); | 
|  | printd("Vcore %2d", vcore_id()); | 
|  | for (int i = 0; i < tab_depth; i++) | 
|  | printf("\t"); | 
|  | printf("---- %s()\n", func); | 
|  | spinlock_unlock(&lock); | 
|  | } | 
|  |  | 
|  | static int kptrace; | 
|  |  | 
|  | static void trace_init(void *arg) | 
|  | { | 
|  | kptrace = open("#kprof/kptrace", O_WRITE); | 
|  | if (kptrace < 0) | 
|  | perror("Unable to open kptrace!\n"); | 
|  | } | 
|  |  | 
|  | int trace_printf(const char *fmt, ...) | 
|  | { | 
|  | va_list args; | 
|  | char buf[128]; | 
|  | int amt; | 
|  | static parlib_once_t once = PARLIB_ONCE_INIT; | 
|  |  | 
|  | parlib_run_once(&once, trace_init, NULL); | 
|  | if (kptrace < 0) | 
|  | return 0; | 
|  | amt = snprintf(buf, sizeof(buf), "PID %d: ", getpid()); | 
|  | /* amt could be > sizeof, if we truncated. */ | 
|  | amt = MIN(amt, sizeof(buf)); | 
|  | va_start(args, fmt); | 
|  | /* amt == sizeof is OK here */ | 
|  | amt += vsnprintf(buf + amt, sizeof(buf) - amt, fmt, args); | 
|  | va_end(args); | 
|  | amt = MIN(amt, sizeof(buf)); | 
|  | write(kptrace, buf, amt); | 
|  | return amt; | 
|  | } |