github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/tools/fops_probe/fops_probe.cc (about) 1 // Copyright 2019 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 // fops_probe utility helps to understand what file_operations callbacks 5 // are attached to a particular file. Requries KCOV and KALLSYMS. 6 // Build with: 7 // g++ tools/fops_probe/fops_probe.cc -Wall -static -o fops_probe 8 // Then copy the binary to target machine and run as: 9 // ./fops_probe /dev/fb0 10 // You should see output similar to: 11 // 12 // ffffffff81bcccb9 vfs_read 13 // ................ 14 // ffffffff83af85c3 fb_read 15 // ffffffff83b52af5 cirrusfb_sync 16 // 17 // ffffffff81bcd219 vfs_write 18 // ................ 19 // ffffffff83af7fe2 fb_write 20 // ffffffff83b52af5 cirrusfb_sync 21 // 22 // ffffffff81c1b745 do_vfs_ioctl 23 // ffffffff83af7ea9 fb_ioctl 24 // 25 // ffffffff81a4ea44 do_mmap 26 // ................ 27 // ffffffff83af716c fb_mmap 28 // 29 // which allows to understand what callbacks are associated with /dev/fb0. 30 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <stdarg.h> 34 #include <stddef.h> 35 #include <stdint.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include <linux/kcov.h> 42 #include <sys/ioctl.h> 43 #include <sys/mman.h> 44 #include <sys/stat.h> 45 #include <sys/types.h> 46 47 #include <functional> 48 #include <map> 49 #include <set> 50 #include <string> 51 52 #define COVER_SIZE (1 << 20) 53 54 typedef std::map<long long, std::string> kallsyms_map_t; 55 56 static __attribute__((noreturn)) __attribute__((format(printf, 1, 2))) void failf(const char* msg, ...); 57 static kallsyms_map_t read_kallsyms(); 58 static bool should_skip(const std::string& sym); 59 static void probe_callback(uint64_t* cover, const kallsyms_map_t& kallsyms, 60 const std::string& start_sym, std::function<void(void)> fn); 61 62 int main(int argc, char** argv) 63 { 64 if (argc != 2) 65 failf("usage: fops_probe file"); 66 int fd = open(argv[1], O_RDWR); 67 if (fd == -1) { 68 fd = open(argv[1], O_RDONLY); 69 if (fd == -1) 70 failf("failed to open %s", argv[1]); 71 } 72 const kallsyms_map_t kallsyms = read_kallsyms(); 73 int kcov = open("/sys/kernel/debug/kcov", O_RDWR); 74 if (kcov == -1) 75 failf("failed to open /sys/kernel/debug/kcov"); 76 if (ioctl(kcov, KCOV_INIT_TRACE, COVER_SIZE)) 77 failf("KCOV_INIT_TRACE failed"); 78 uint64_t* cover = (uint64_t*)mmap(NULL, COVER_SIZE * 8, PROT_READ | PROT_WRITE, MAP_SHARED, kcov, 0); 79 if (cover == MAP_FAILED) 80 failf("cover mmap failed"); 81 if (ioctl(kcov, KCOV_ENABLE, KCOV_TRACE_PC)) 82 failf("KCOV_ENABLE failed"); 83 probe_callback(cover, kallsyms, "do_vfs_ioctl", [&]() { ioctl(fd, 0, 0); }); 84 probe_callback(cover, kallsyms, "do_mmap", [&]() { mmap(0, 4096, PROT_READ, MAP_PRIVATE, fd, 0); }); 85 probe_callback(cover, kallsyms, "vfs_write", [&]() { write(fd, 0, 0); }); 86 probe_callback(cover, kallsyms, "vfs_read", [&]() { read(fd, 0, 0); }); 87 return 0; 88 } 89 90 void probe_callback(uint64_t* cover, const kallsyms_map_t& kallsyms, 91 const std::string& start_sym, std::function<void(void)> fn) 92 { 93 __atomic_store_n(&cover[0], 0, __ATOMIC_SEQ_CST); 94 fn(); 95 uint64_t ncover = __atomic_load_n(&cover[0], __ATOMIC_SEQ_CST); 96 bool started = false; 97 std::set<std::string> seen; 98 for (uint64_t i = 0; i < ncover; i++) { 99 long long pc = cover[i + 1]; 100 auto it = kallsyms.lower_bound(pc - 1); 101 const std::string& sym = it == kallsyms.begin() ? "" : (--it)->second; 102 if (!started && sym != start_sym) 103 continue; 104 started = true; 105 if (!seen.insert(sym).second || should_skip(sym)) 106 continue; 107 printf("%0llx %s\n", pc, sym.c_str()); 108 } 109 printf("\n"); 110 } 111 112 bool should_skip(const std::string& sym) 113 { 114 static const char* skip[] = { 115 "security", 116 "tomoyo", 117 "selinux", 118 "apparmor", 119 "smack", 120 "policy", 121 "stack_trace", 122 "should_fail", 123 "debug", 124 "trace", 125 "snprintf", 126 "vsnprintf", 127 }; 128 for (size_t i = 0; i < sizeof(skip) / sizeof(skip[0]); i++) { 129 if (!strncmp(sym.c_str(), skip[i], strlen(skip[i]))) 130 return true; 131 } 132 return false; 133 } 134 135 kallsyms_map_t read_kallsyms() 136 { 137 kallsyms_map_t kallsyms; 138 FILE* f = fopen("/proc/kallsyms", "r"); 139 if (f == NULL) 140 failf("failed to open /proc/kallsyms"); 141 size_t n = 0; 142 char* line = NULL; 143 for (;;) { 144 ssize_t len = getline(&line, &n, f); 145 if (len < 0) 146 break; 147 long long pc; 148 char typ; 149 char sym[1024]; 150 if (sscanf(line, "%016llx %c %s\n", &pc, &typ, sym) != 3) 151 failf("bad line in kallsyms: %s", line); 152 if (typ != 't' && typ != 'T') 153 continue; 154 kallsyms[pc] = sym; 155 } 156 free(line); 157 fclose(f); 158 return kallsyms; 159 } 160 161 void failf(const char* msg, ...) 162 { 163 int e = errno; 164 va_list args; 165 va_start(args, msg); 166 vfprintf(stderr, msg, args); 167 va_end(args); 168 fprintf(stderr, " (errno: %s)\n", strerror(e)); 169 exit(1); 170 }