1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <unistd.h> 4 #include <string.h> 5 #include <sys/ioctl.h> 6 #include <linux/perf_event.h> 7 #include <asm/unistd.h> 8 #include <sys/mman.h> 9 #include <sys/stat.h> 10 #include <poll.h> 11 #include <signal.h> 12 #include <fcntl.h> 13 #include <asm/perf_regs.h> 14 15 16 #include <map> 17 #include <unordered_set> 18 #include <unordered_map> 19 #include <queue> 20 using namespace std; 21 22 23 #define error(msg) do { perror(msg); exit(1); } while(0) 24 #define MAXN 128 25 26 // refer to https://lkml.kernel.org/netdev/D0757E13-27E8-4392-972A-399D6E132111@fb.com/t/ 27 // 28 // 29 // 30 static long perf_event_open(struct perf_event_attr *perf_event, pid_t pid, int cpu, int group_fd, unsigned long flags) { 31 return syscall(__NR_perf_event_open, perf_event, pid, cpu, group_fd, flags); 32 } 33 static void *addr = NULL; 34 static long long psize; 35 map<int, pair<void*, long long>> res; 36 static int alive=1; 37 void int_exit(int s) { 38 for (auto x: res) { 39 auto y = x.second; 40 void* addr = y.first; 41 munmap(addr, (1+MAXN)*psize); 42 close(x.first); 43 } 44 res.clear(); 45 alive=0; 46 } 47 48 char *func = NULL; 49 using xtt = tuple<time_t, string, string>; 50 static map<int, xtt> pids; 51 int process_event(char *base, unsigned long long size, unsigned long long offset) { 52 struct perf_event_header* p = NULL; 53 int pid, i; 54 unsigned long long abi, addr, arg1, arg2, arg3, arg4; 55 offset%=size; 56 // assuming the header would fit within size 57 p = (struct perf_event_header*) (base+offset); 58 offset+=sizeof(*p); if (offset>=size) offset-=size; 59 if (p->type == PERF_RECORD_SAMPLE) { 60 pid = *(int*)(base+offset); offset+=8; if (offset>=size) offset-=size; 61 time_t ctime = time(NULL); 62 if (pids.count(pid)==0 || ctime-get<0>(pids[pid]) > 1000) { 63 char b[128]; 64 char comm[128]; 65 char host[128]; 66 sprintf(b, "/proc/%d/comm", pid); 67 FILE* fp; 68 size_t i=0; 69 fp = fopen(b, "r"); if (fp) { 70 comm[0]=0; fgets(comm, sizeof(comm), fp); 71 while(i<sizeof(comm)&&comm[i]!=0&&comm[i]!='\n'&&comm[i]!='\r') i++; 72 comm[i]=0; 73 fclose(fp); 74 } 75 if (i<1) strcpy(comm, "unknown-command"); 76 sprintf(b, "/proc/%d/root/etc/hostname", pid); 77 i=0; fp = fopen(b, "r"); if (fp) { 78 host[0]=0; fgets(host, sizeof(host), fp); 79 while(i<sizeof(host)&&host[i]!=0&&host[i]!='\n'&&host[i]!='\r') i++; 80 host[i]=0; 81 fclose(fp); 82 } 83 if (i<1) strcpy(host, "unknown-host"); 84 pids[pid] = make_tuple(ctime, string(comm), string(host)); 85 } 86 abi = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; 87 if (abi == PERF_SAMPLE_REGS_ABI_64) { 88 addr = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //rax 89 arg3 = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //rdx 90 arg2 = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //rsi 91 arg1 = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //rdi 92 arg4 = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //r10 93 printf("%s@%s[%d] %s(0x%llx,0x%llx,0x%llx,0x%llx)\n", get<1>(pids[pid]).c_str(), get<2>(pids[pid]).c_str(), pid, func, arg1, arg2, arg3, arg4); 94 } 95 } 96 return p->size; 97 } 98 99 100 #define MAXCPU 1024 101 struct pollfd polls[MAXCPU]; 102 int main(int argc, char *argv[]) { 103 int i, k, type; 104 // start perf event 105 if (argc<2) { printf("Need kprobe function name, e.g. %s do_sys_open\n", argv[0]); return 1; } 106 func = argv[1]; 107 psize = sysconf(_SC_PAGE_SIZE); // getpagesize(); 108 int cpu_num = sysconf(_SC_NPROCESSORS_ONLN); 109 struct perf_event_attr attr; 110 memset(&attr, 0, sizeof(attr)); 111 // /sys/bus/event_source/devices/kprobe/type 112 FILE *fp = fopen("/sys/bus/event_source/devices/kprobe/type", "r"); 113 if (fp == NULL) { printf("fail to find type for kprobe\n"); return 1; } 114 type = 0; 115 fscanf(fp, "%d", &type); 116 fclose(fp); 117 if (type <= 0) { printf("unexpected type %d\n", type); return 1; } 118 attr.type = type; 119 attr.size = sizeof(attr); 120 attr.config = 0; // (1<<0) for kreprobe 121 attr.sample_period = 1; 122 attr.wakeup_events = 1; 123 attr.sample_type = PERF_SAMPLE_TID|PERF_SAMPLE_REGS_INTR; 124 // ffffffff92ea9240 t bprm_execve 125 attr.kprobe_func = (__u64)func; // "do_sys_open"; // "bprm_execve"; 126 attr.probe_offset = 0; 127 attr.sample_regs_intr = (1<<PERF_REG_X86_AX)|(1<<PERF_REG_X86_DI)|(1<<PERF_REG_X86_SI)|(1<<PERF_REG_X86_DX)|(1<<PERF_REG_X86_R10)| 128 (1<<PERF_REG_X86_R8)|(1<<PERF_REG_X86_R9); 129 int fd, cgroup_fd; 130 for (i=0, k=0; i<cpu_num&&i<MAXCPU; i++) { 131 printf("attaching cpu %d\n", i); 132 fd = perf_event_open(&attr, -1, i, -1, PERF_FLAG_FD_CLOEXEC); 133 if (fd<0) { perror("fail to open perf event"); continue; } 134 addr = mmap(NULL, (1+MAXN)*psize, PROT_READ, MAP_SHARED, fd, 0); 135 if (addr == MAP_FAILED) { perror("mmap failed"); close(fd); continue; } 136 res[fd] = make_pair(addr, 0); 137 polls[k].fd = fd; 138 polls[k].events = POLLIN; 139 polls[k].revents = 0; 140 k++; 141 } 142 if (k==0) { printf("no cpu event attached at all\n"); return 1; } 143 144 signal(SIGINT, int_exit); 145 signal(SIGTERM, int_exit); 146 147 unsigned long long head; 148 struct perf_event_mmap_page *mp; 149 while (poll(polls, k, -1)>0) { 150 if (!alive) break; 151 for (i=0; i<k; i++) { 152 if ((polls[i].revents&POLLIN)==0) continue; 153 fd = polls[i].fd; 154 addr = res[fd].first; 155 mp = (struct perf_event_mmap_page *)addr; 156 head = res[fd].second; 157 if (head==mp->data_head) continue; 158 ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 1); 159 head = mp->data_head-((mp->data_head-head)%mp->data_size); 160 while(head<mp->data_head) head+=process_event((char*)addr+mp->data_offset, mp->data_size, head); 161 ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 0); 162 res[fd].second = mp->data_head; 163 } 164 } 165 int_exit(0); 166 return 0; 167 } 168