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 exit(0); 47 } 48 49 char *func = NULL; 50 using xtt = tuple<time_t, string, string>; 51 static map<int, xtt> pids; 52 int process_event(char *base, unsigned long long size, unsigned long long offset) { 53 struct perf_event_header* p = NULL; 54 int pid, i; 55 unsigned long long abi, addr, arg1, arg2, arg3, arg4; 56 offset%=size; 57 // assuming the header would fit within size 58 p = (struct perf_event_header*) (base+offset); 59 offset+=sizeof(*p); if (offset>=size) offset-=size; 60 if (p->type == PERF_RECORD_SAMPLE) { 61 pid = *(int*)(base+offset); offset+=8; if (offset>=size) offset-=size; 62 time_t ctime = time(NULL); 63 if (pids.count(pid)==0 || ctime-get<0>(pids[pid]) > 1000) { 64 char b[128]; 65 char comm[128]; 66 char host[128]; 67 sprintf(b, "/proc/%d/comm", pid); 68 FILE* fp; 69 size_t i=0; 70 fp = fopen(b, "r"); if (fp) { 71 comm[0]=0; fgets(comm, sizeof(comm), fp); 72 while(i<sizeof(comm)&&comm[i]!=0&&comm[i]!='\n'&&comm[i]!='\r') i++; 73 comm[i]=0; 74 fclose(fp); 75 } 76 if (i<1) strcpy(comm, "unknown-command"); 77 sprintf(b, "/proc/%d/root/etc/hostname", pid); 78 i=0; fp = fopen(b, "r"); if (fp) { 79 host[0]=0; fgets(host, sizeof(host), fp); 80 while(i<sizeof(host)&&host[i]!=0&&host[i]!='\n'&&host[i]!='\r') i++; 81 host[i]=0; 82 fclose(fp); 83 } 84 if (i<1) strcpy(host, "unknown-host"); 85 pids[pid] = make_tuple(ctime, string(comm), string(host)); 86 } 87 abi = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; 88 if (abi == PERF_SAMPLE_REGS_ABI_64) { 89 addr = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //rax 90 arg3 = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //rdx 91 arg2 = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //rsi 92 arg1 = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //rdi 93 arg4 = *(unsigned long long*)(base+offset); offset+=8; if (offset>=size) offset-=size; //r10 94 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); 95 } 96 } 97 return p->size; 98 } 99 100 101 #define MAXCPU 1024 102 struct pollfd polls[MAXCPU]; 103 int main(int argc, char *argv[]) { 104 int i, k, type; 105 // start perf event 106 if (argc<2) { printf("Need kprobe function name, e.g. %s do_sys_open\n", argv[0]); return 1; } 107 func = argv[1]; 108 psize = sysconf(_SC_PAGE_SIZE); // getpagesize(); 109 int cpu_num = sysconf(_SC_NPROCESSORS_ONLN); 110 struct perf_event_attr attr; 111 memset(&attr, 0, sizeof(attr)); 112 // /sys/bus/event_source/devices/kprobe/type 113 FILE *fp = fopen("/sys/bus/event_source/devices/kprobe/type", "r"); 114 if (fp == NULL) { printf("fail to find type for kprobe\n"); return 1; } 115 type = 0; 116 fscanf(fp, "%d", &type); 117 fclose(fp); 118 if (type <= 0) { printf("unexpected type %d\n", type); return 1; } 119 attr.type = type; 120 attr.size = sizeof(attr); 121 attr.config = 0; // (1<<0) for kreprobe 122 attr.sample_period = 1; 123 attr.wakeup_events = 1; 124 attr.sample_type = PERF_SAMPLE_TID|PERF_SAMPLE_REGS_INTR; 125 // ffffffff92ea9240 t bprm_execve 126 attr.kprobe_func = (__u64)func; // "do_sys_open"; // "bprm_execve"; 127 attr.probe_offset = 0; 128 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)| 129 (1<<PERF_REG_X86_R8)|(1<<PERF_REG_X86_R9); 130 int fd, cgroup_fd; 131 for (i=0, k=0; i<cpu_num&&i<MAXCPU; i++) { 132 printf("attaching cpu %d\n", i); 133 fd = perf_event_open(&attr, -1, i, -1, PERF_FLAG_FD_CLOEXEC); 134 if (fd<0) { perror("fail to open perf event"); continue; } 135 addr = mmap(NULL, (1+MAXN)*psize, PROT_READ, MAP_SHARED, fd, 0); 136 if (addr == MAP_FAILED) { perror("mmap failed"); close(fd); continue; } 137 res[fd] = make_pair(addr, 0); 138 polls[k].fd = fd; 139 polls[k].events = POLLIN; 140 polls[k].revents = 0; 141 k++; 142 } 143 if (k==0) { printf("no cpu event attached at all\n"); return 1; } 144 145 signal(SIGINT, int_exit); 146 signal(SIGTERM, int_exit); 147 148 unsigned long long head; 149 struct perf_event_mmap_page *mp; 150 while (poll(polls, k, -1)>0) { 151 for (i=0; i<k; i++) { 152 if (!alive) break; 153 if ((polls[i].revents&POLLIN)==0) continue; 154 fd = polls[i].fd; 155 addr = res[fd].first; 156 mp = (struct perf_event_mmap_page *)addr; 157 head = res[fd].second; 158 if (head==mp->data_head) continue; 159 ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 1); 160 head = mp->data_head-((mp->data_head-head)%mp->data_size); 161 while(head<mp->data_head) head+=process_event((char*)addr+mp->data_offset, mp->data_size, head); 162 ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, 0); 163 res[fd].second = mp->data_head; 164 } 165 } 166 int_exit(0); 167 return 0; 168 } 169