1 /* Copyright (c) 2016 Facebook 2 * 3 * This program is free software; you can redistribute it and/or 4 * modify it under the terms of version 2 of the GNU General Public 5 * License as published by the Free Software Foundation. 6 */ 7 #include <stdio.h> 8 #include <unistd.h> 9 #include <stdlib.h> 10 #include <signal.h> 11 #include <linux/bpf.h> 12 #include <string.h> 13 #include <linux/perf_event.h> 14 #include <errno.h> 15 #include <assert.h> 16 #include <stdbool.h> 17 #include <sys/resource.h> 18 #include "libbpf.h" 19 #include "bpf_load.h" 20 21 #define MAX_SYMS 300000 22 #define PRINT_RAW_ADDR 0 23 24 static struct ksym { 25 long addr; 26 char *name; 27 } syms[MAX_SYMS]; 28 static int sym_cnt; 29 30 static int ksym_cmp(const void *p1, const void *p2) 31 { 32 return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr; 33 } 34 35 static int load_kallsyms(void) 36 { 37 FILE *f = fopen("/proc/kallsyms", "r"); 38 char func[256], buf[256]; 39 char symbol; 40 void *addr; 41 int i = 0; 42 43 if (!f) 44 return -ENOENT; 45 46 while (!feof(f)) { 47 if (!fgets(buf, sizeof(buf), f)) 48 break; 49 if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3) 50 break; 51 if (!addr) 52 continue; 53 syms[i].addr = (long) addr; 54 syms[i].name = strdup(func); 55 i++; 56 } 57 sym_cnt = i; 58 qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp); 59 return 0; 60 } 61 62 static void *search(long key) 63 { 64 int start = 0, end = sym_cnt; 65 int result; 66 67 while (start < end) { 68 size_t mid = start + (end - start) / 2; 69 70 result = key - syms[mid].addr; 71 if (result < 0) 72 end = mid; 73 else if (result > 0) 74 start = mid + 1; 75 else 76 return &syms[mid]; 77 } 78 79 if (start >= 1 && syms[start - 1].addr < key && 80 key < syms[start].addr) 81 /* valid ksym */ 82 return &syms[start - 1]; 83 84 /* out of range. return _stext */ 85 return &syms[0]; 86 } 87 88 static void print_ksym(__u64 addr) 89 { 90 struct ksym *sym; 91 92 if (!addr) 93 return; 94 sym = search(addr); 95 if (PRINT_RAW_ADDR) 96 printf("%s/%llx;", sym->name, addr); 97 else 98 printf("%s;", sym->name); 99 } 100 101 #define TASK_COMM_LEN 16 102 103 struct key_t { 104 char waker[TASK_COMM_LEN]; 105 char target[TASK_COMM_LEN]; 106 __u32 wret; 107 __u32 tret; 108 }; 109 110 static void print_stack(struct key_t *key, __u64 count) 111 { 112 __u64 ip[PERF_MAX_STACK_DEPTH] = {}; 113 static bool warned; 114 int i; 115 116 printf("%s;", key->target); 117 if (bpf_lookup_elem(map_fd[3], &key->tret, ip) != 0) { 118 printf("---;"); 119 } else { 120 for (i = PERF_MAX_STACK_DEPTH - 1; i >= 0; i--) 121 print_ksym(ip[i]); 122 } 123 printf("-;"); 124 if (bpf_lookup_elem(map_fd[3], &key->wret, ip) != 0) { 125 printf("---;"); 126 } else { 127 for (i = 0; i < PERF_MAX_STACK_DEPTH; i++) 128 print_ksym(ip[i]); 129 } 130 printf(";%s %lld\n", key->waker, count); 131 132 if ((key->tret == -EEXIST || key->wret == -EEXIST) && !warned) { 133 printf("stackmap collisions seen. Consider increasing size\n"); 134 warned = true; 135 } else if (((int)(key->tret) < 0 || (int)(key->wret) < 0)) { 136 printf("err stackid %d %d\n", key->tret, key->wret); 137 } 138 } 139 140 static void print_stacks(int fd) 141 { 142 struct key_t key = {}, next_key; 143 __u64 value; 144 145 while (bpf_get_next_key(fd, &key, &next_key) == 0) { 146 bpf_lookup_elem(fd, &next_key, &value); 147 print_stack(&next_key, value); 148 key = next_key; 149 } 150 } 151 152 static void int_exit(int sig) 153 { 154 print_stacks(map_fd[0]); 155 exit(0); 156 } 157 158 int main(int argc, char **argv) 159 { 160 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 161 char filename[256]; 162 int delay = 1; 163 164 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 165 setrlimit(RLIMIT_MEMLOCK, &r); 166 167 signal(SIGINT, int_exit); 168 169 if (load_kallsyms()) { 170 printf("failed to process /proc/kallsyms\n"); 171 return 2; 172 } 173 174 if (load_bpf_file(filename)) { 175 printf("%s", bpf_log_buf); 176 return 1; 177 } 178 179 if (argc > 1) 180 delay = atoi(argv[1]); 181 sleep(delay); 182 print_stacks(map_fd[0]); 183 184 return 0; 185 } 186