xref: /linux/tools/perf/util/event.c (revision 273b281fa22c293963ee3e6eec418f5dda2dbc83)
1 #include <linux/types.h>
2 #include "event.h"
3 #include "debug.h"
4 #include "string.h"
5 #include "thread.h"
6 
7 static pid_t event__synthesize_comm(pid_t pid, int full,
8 				    int (*process)(event_t *event))
9 {
10 	event_t ev;
11 	char filename[PATH_MAX];
12 	char bf[BUFSIZ];
13 	FILE *fp;
14 	size_t size = 0;
15 	DIR *tasks;
16 	struct dirent dirent, *next;
17 	pid_t tgid = 0;
18 
19 	snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
20 
21 	fp = fopen(filename, "r");
22 	if (fp == NULL) {
23 out_race:
24 		/*
25 		 * We raced with a task exiting - just return:
26 		 */
27 		pr_debug("couldn't open %s\n", filename);
28 		return 0;
29 	}
30 
31 	memset(&ev.comm, 0, sizeof(ev.comm));
32 	while (!ev.comm.comm[0] || !ev.comm.pid) {
33 		if (fgets(bf, sizeof(bf), fp) == NULL)
34 			goto out_failure;
35 
36 		if (memcmp(bf, "Name:", 5) == 0) {
37 			char *name = bf + 5;
38 			while (*name && isspace(*name))
39 				++name;
40 			size = strlen(name) - 1;
41 			memcpy(ev.comm.comm, name, size++);
42 		} else if (memcmp(bf, "Tgid:", 5) == 0) {
43 			char *tgids = bf + 5;
44 			while (*tgids && isspace(*tgids))
45 				++tgids;
46 			tgid = ev.comm.pid = atoi(tgids);
47 		}
48 	}
49 
50 	ev.comm.header.type = PERF_RECORD_COMM;
51 	size = ALIGN(size, sizeof(u64));
52 	ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
53 
54 	if (!full) {
55 		ev.comm.tid = pid;
56 
57 		process(&ev);
58 		goto out_fclose;
59 	}
60 
61 	snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
62 
63 	tasks = opendir(filename);
64 	if (tasks == NULL)
65 		goto out_race;
66 
67 	while (!readdir_r(tasks, &dirent, &next) && next) {
68 		char *end;
69 		pid = strtol(dirent.d_name, &end, 10);
70 		if (*end)
71 			continue;
72 
73 		ev.comm.tid = pid;
74 
75 		process(&ev);
76 	}
77 	closedir(tasks);
78 
79 out_fclose:
80 	fclose(fp);
81 	return tgid;
82 
83 out_failure:
84 	pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
85 	return -1;
86 }
87 
88 static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
89 					 int (*process)(event_t *event))
90 {
91 	char filename[PATH_MAX];
92 	FILE *fp;
93 
94 	snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
95 
96 	fp = fopen(filename, "r");
97 	if (fp == NULL) {
98 		/*
99 		 * We raced with a task exiting - just return:
100 		 */
101 		pr_debug("couldn't open %s\n", filename);
102 		return -1;
103 	}
104 
105 	while (1) {
106 		char bf[BUFSIZ], *pbf = bf;
107 		event_t ev = {
108 			.header = { .type = PERF_RECORD_MMAP },
109 		};
110 		int n;
111 		size_t size;
112 		if (fgets(bf, sizeof(bf), fp) == NULL)
113 			break;
114 
115 		/* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
116 		n = hex2u64(pbf, &ev.mmap.start);
117 		if (n < 0)
118 			continue;
119 		pbf += n + 1;
120 		n = hex2u64(pbf, &ev.mmap.len);
121 		if (n < 0)
122 			continue;
123 		pbf += n + 3;
124 		if (*pbf == 'x') { /* vm_exec */
125 			char *execname = strchr(bf, '/');
126 
127 			/* Catch VDSO */
128 			if (execname == NULL)
129 				execname = strstr(bf, "[vdso]");
130 
131 			if (execname == NULL)
132 				continue;
133 
134 			size = strlen(execname);
135 			execname[size - 1] = '\0'; /* Remove \n */
136 			memcpy(ev.mmap.filename, execname, size);
137 			size = ALIGN(size, sizeof(u64));
138 			ev.mmap.len -= ev.mmap.start;
139 			ev.mmap.header.size = (sizeof(ev.mmap) -
140 					       (sizeof(ev.mmap.filename) - size));
141 			ev.mmap.pid = tgid;
142 			ev.mmap.tid = pid;
143 
144 			process(&ev);
145 		}
146 	}
147 
148 	fclose(fp);
149 	return 0;
150 }
151 
152 int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
153 {
154 	pid_t tgid = event__synthesize_comm(pid, 1, process);
155 	if (tgid == -1)
156 		return -1;
157 	return event__synthesize_mmap_events(pid, tgid, process);
158 }
159 
160 void event__synthesize_threads(int (*process)(event_t *event))
161 {
162 	DIR *proc;
163 	struct dirent dirent, *next;
164 
165 	proc = opendir("/proc");
166 
167 	while (!readdir_r(proc, &dirent, &next) && next) {
168 		char *end;
169 		pid_t pid = strtol(dirent.d_name, &end, 10);
170 
171 		if (*end) /* only interested in proper numerical dirents */
172 			continue;
173 
174 		event__synthesize_thread(pid, process);
175 	}
176 
177 	closedir(proc);
178 }
179 
180 char *event__cwd;
181 int  event__cwdlen;
182 
183 struct events_stats event__stats;
184 
185 int event__process_comm(event_t *self)
186 {
187 	struct thread *thread = threads__findnew(self->comm.pid);
188 
189 	dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
190 
191 	if (thread == NULL || thread__set_comm(thread, self->comm.comm)) {
192 		dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
193 		return -1;
194 	}
195 
196 	return 0;
197 }
198 
199 int event__process_lost(event_t *self)
200 {
201 	dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
202 	event__stats.lost += self->lost.lost;
203 	return 0;
204 }
205 
206 int event__process_mmap(event_t *self)
207 {
208 	struct thread *thread = threads__findnew(self->mmap.pid);
209 	struct map *map = map__new(&self->mmap, MAP__FUNCTION,
210 				   event__cwd, event__cwdlen);
211 
212 	dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
213 		    self->mmap.pid, self->mmap.tid,
214 		    (void *)(long)self->mmap.start,
215 		    (void *)(long)self->mmap.len,
216 		    (void *)(long)self->mmap.pgoff,
217 		    self->mmap.filename);
218 
219 	if (thread == NULL || map == NULL)
220 		dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
221 	else
222 		thread__insert_map(thread, map);
223 
224 	return 0;
225 }
226 
227 int event__process_task(event_t *self)
228 {
229 	struct thread *thread = threads__findnew(self->fork.pid);
230 	struct thread *parent = threads__findnew(self->fork.ppid);
231 
232 	dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
233 		    self->fork.ppid, self->fork.ptid);
234 	/*
235 	 * A thread clone will have the same PID for both parent and child.
236 	 */
237 	if (thread == parent)
238 		return 0;
239 
240 	if (self->header.type == PERF_RECORD_EXIT)
241 		return 0;
242 
243 	if (thread == NULL || parent == NULL ||
244 	    thread__fork(thread, parent) < 0) {
245 		dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
246 		return -1;
247 	}
248 
249 	return 0;
250 }
251 
252 void thread__find_addr_location(struct thread *self, u8 cpumode,
253 				enum map_type type, u64 addr,
254 				struct addr_location *al,
255 				symbol_filter_t filter)
256 {
257 	struct thread *thread = al->thread = self;
258 
259 	al->addr = addr;
260 
261 	if (cpumode & PERF_RECORD_MISC_KERNEL) {
262 		al->level = 'k';
263 		thread = kthread;
264 	} else if (cpumode & PERF_RECORD_MISC_USER)
265 		al->level = '.';
266 	else {
267 		al->level = 'H';
268 		al->map = NULL;
269 		al->sym = NULL;
270 		return;
271 	}
272 try_again:
273 	al->map = thread__find_map(thread, type, al->addr);
274 	if (al->map == NULL) {
275 		/*
276 		 * If this is outside of all known maps, and is a negative
277 		 * address, try to look it up in the kernel dso, as it might be
278 		 * a vsyscall or vdso (which executes in user-mode).
279 		 *
280 		 * XXX This is nasty, we should have a symbol list in the
281 		 * "[vdso]" dso, but for now lets use the old trick of looking
282 		 * in the whole kernel symbol list.
283 		 */
284 		if ((long long)al->addr < 0 && thread != kthread) {
285 			thread = kthread;
286 			goto try_again;
287 		}
288 		al->sym = NULL;
289 	} else {
290 		al->addr = al->map->map_ip(al->map, al->addr);
291 		al->sym = map__find_symbol(al->map, al->addr, filter);
292 	}
293 }
294 
295 int event__preprocess_sample(const event_t *self, struct addr_location *al,
296 			     symbol_filter_t filter)
297 {
298 	u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
299 	struct thread *thread = threads__findnew(self->ip.pid);
300 
301 	if (thread == NULL)
302 		return -1;
303 
304 	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
305 
306 	thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
307 				   self->ip.ip, al, filter);
308 	dump_printf(" ...... dso: %s\n",
309 		    al->map ? al->map->dso->long_name :
310 			al->level == 'H' ? "[hypervisor]" : "<not found>");
311 	return 0;
312 }
313 
314 int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
315 {
316 	u64 *array = event->sample.array;
317 
318 	if (type & PERF_SAMPLE_IP) {
319 		data->ip = event->ip.ip;
320 		array++;
321 	}
322 
323 	if (type & PERF_SAMPLE_TID) {
324 		u32 *p = (u32 *)array;
325 		data->pid = p[0];
326 		data->tid = p[1];
327 		array++;
328 	}
329 
330 	if (type & PERF_SAMPLE_TIME) {
331 		data->time = *array;
332 		array++;
333 	}
334 
335 	if (type & PERF_SAMPLE_ADDR) {
336 		data->addr = *array;
337 		array++;
338 	}
339 
340 	if (type & PERF_SAMPLE_ID) {
341 		data->id = *array;
342 		array++;
343 	}
344 
345 	if (type & PERF_SAMPLE_STREAM_ID) {
346 		data->stream_id = *array;
347 		array++;
348 	}
349 
350 	if (type & PERF_SAMPLE_CPU) {
351 		u32 *p = (u32 *)array;
352 		data->cpu = *p;
353 		array++;
354 	}
355 
356 	if (type & PERF_SAMPLE_PERIOD) {
357 		data->period = *array;
358 		array++;
359 	}
360 
361 	if (type & PERF_SAMPLE_READ) {
362 		pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
363 		return -1;
364 	}
365 
366 	if (type & PERF_SAMPLE_CALLCHAIN) {
367 		data->callchain = (struct ip_callchain *)array;
368 		array += 1 + data->callchain->nr;
369 	}
370 
371 	if (type & PERF_SAMPLE_RAW) {
372 		u32 *p = (u32 *)array;
373 		data->raw_size = *p;
374 		p++;
375 		data->raw_data = p;
376 	}
377 
378 	return 0;
379 }
380