17d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng/* ANDROID_CHANGE_BEGIN */
27d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#ifdef __APPLE__
37d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#include "include/linux/types.h"
47d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#else
5097a574687b429a2f8ab7988308c7edb828156b6Andrew Hsieh/* Suppress kernel-name space pollution in <linux/types.h> below */
6097a574687b429a2f8ab7988308c7edb828156b6Andrew Hsieh#include <features.h>
7e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include <linux/types.h>
87d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#endif
97d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng/* ANDROID_CHANGE_END */
10e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "event.h"
11e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "debug.h"
12e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "session.h"
13e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "sort.h"
14e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "string.h"
15e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "strlist.h"
16e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "thread.h"
17e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#include "thread_map.h"
18e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
19e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic const char *perf_event__names[] = {
20e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[0]					= "TOTAL",
21e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_MMAP]			= "MMAP",
22e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_LOST]			= "LOST",
23e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_COMM]			= "COMM",
24e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_EXIT]			= "EXIT",
25e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_THROTTLE]			= "THROTTLE",
26e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_UNTHROTTLE]		= "UNTHROTTLE",
27e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_FORK]			= "FORK",
28e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_READ]			= "READ",
29e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_SAMPLE]			= "SAMPLE",
30e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_HEADER_ATTR]		= "ATTR",
31e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_HEADER_EVENT_TYPE]		= "EVENT_TYPE",
32e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_HEADER_TRACING_DATA]	= "TRACING_DATA",
33e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_HEADER_BUILD_ID]		= "BUILD_ID",
34e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	[PERF_RECORD_FINISHED_ROUND]		= "FINISHED_ROUND",
35e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng};
36e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
37e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengconst char *perf_event__name(unsigned int id)
38e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
39e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (id >= ARRAY_SIZE(perf_event__names))
40e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return "INVALID";
41e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (!perf_event__names[id])
42e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return "UNKNOWN";
43e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return perf_event__names[id];
44e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
45e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
46e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic struct perf_sample synth_sample = {
47e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	.pid	   = -1,
48e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	.tid	   = -1,
49e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	.time	   = -1,
50e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	.stream_id = -1,
51e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	.cpu	   = -1,
52e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	.period	   = 1,
53e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng};
54e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
55e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
56e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					 int full, perf_event__handler_t process,
57e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					 struct perf_session *session)
58e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
59e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char filename[PATH_MAX];
60e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char bf[BUFSIZ];
61e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	FILE *fp;
62e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	size_t size = 0;
63e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	DIR *tasks;
64e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct dirent dirent, *next;
65e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	pid_t tgid = 0;
66e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
67e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
68e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
69e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	fp = fopen(filename, "r");
70e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (fp == NULL) {
71e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout_race:
72e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/*
73e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * We raced with a task exiting - just return:
74e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 */
75e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		pr_debug("couldn't open %s\n", filename);
76e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return 0;
77e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
78e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
79e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	memset(&event->comm, 0, sizeof(event->comm));
80e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
81e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	while (!event->comm.comm[0] || !event->comm.pid) {
82e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (fgets(bf, sizeof(bf), fp) == NULL) {
83e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
84e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			goto out;
85e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
86e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
87e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (memcmp(bf, "Name:", 5) == 0) {
88e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			char *name = bf + 5;
89e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			while (*name && isspace(*name))
90e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				++name;
91e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			size = strlen(name) - 1;
92e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			memcpy(event->comm.comm, name, size++);
93e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		} else if (memcmp(bf, "Tgid:", 5) == 0) {
94e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			char *tgids = bf + 5;
95e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			while (*tgids && isspace(*tgids))
96e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				++tgids;
97e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			tgid = event->comm.pid = atoi(tgids);
98e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
99e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
100e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
101e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->comm.header.type = PERF_RECORD_COMM;
102e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng        /* ANDROID_CHANGE_BEGIN */
1037d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#if defined(__BIONIC__) || defined(__APPLE__)
104e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	size = KERNEL_ALIGN(size, sizeof(u64));
105e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#else
106e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	size = ALIGN(size, sizeof(u64));
107e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#endif
108e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng        /* ANDROID_CHANGE_END */
109e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	memset(event->comm.comm + size, 0, session->id_hdr_size);
110e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->comm.header.size = (sizeof(event->comm) -
111e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				(sizeof(event->comm.comm) - size) +
112e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				session->id_hdr_size);
113e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (!full) {
114e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->comm.tid = pid;
115e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
116e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		process(event, &synth_sample, session);
117e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out;
118e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
119e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
120e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
121e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
122e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	tasks = opendir(filename);
123e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (tasks == NULL)
124e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_race;
125e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
126e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	while (!readdir_r(tasks, &dirent, &next) && next) {
127e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		char *end;
128e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		pid = strtol(dirent.d_name, &end, 10);
129e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (*end)
130e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			continue;
131e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
132e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->comm.tid = pid;
133e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
134e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		process(event, &synth_sample, session);
135e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
136e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
137e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	closedir(tasks);
138e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout:
139e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	fclose(fp);
140e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
141e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return tgid;
142e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
143e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
144e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic int perf_event__synthesize_mmap_events(union perf_event *event,
145e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					      pid_t pid, pid_t tgid,
146e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					      perf_event__handler_t process,
147e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					      struct perf_session *session)
148e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
149e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char filename[PATH_MAX];
150e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	FILE *fp;
151e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
152e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
153e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
154e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	fp = fopen(filename, "r");
155e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (fp == NULL) {
156e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/*
157e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * We raced with a task exiting - just return:
158e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 */
159e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		pr_debug("couldn't open %s\n", filename);
160e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -1;
161e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
162e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
163e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->header.type = PERF_RECORD_MMAP;
164e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/*
165e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
166e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 */
167e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->header.misc = PERF_RECORD_MISC_USER;
168e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
169e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	while (1) {
170e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		char bf[BUFSIZ], *pbf = bf;
171e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		int n;
172e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		size_t size;
173e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (fgets(bf, sizeof(bf), fp) == NULL)
174e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			break;
175e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
176e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
177e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		n = hex2u64(pbf, &event->mmap.start);
178e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (n < 0)
179e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			continue;
180e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		pbf += n + 1;
181e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		n = hex2u64(pbf, &event->mmap.len);
182e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (n < 0)
183e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			continue;
184e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		pbf += n + 3;
185e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (*pbf == 'x') { /* vm_exec */
186e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			char *execname = strchr(bf, '/');
187e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
188e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			/* Catch VDSO */
189e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			if (execname == NULL)
190e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				execname = strstr(bf, "[vdso]");
191e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
192e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			if (execname == NULL)
193e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				continue;
194e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
195e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			pbf += 3;
196e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			n = hex2u64(pbf, &event->mmap.pgoff);
197e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
198e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			size = strlen(execname);
199e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			execname[size - 1] = '\0'; /* Remove \n */
200e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			memcpy(event->mmap.filename, execname, size);
201e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng                        /* ANDROID_CHANGE_BEGIN */
2027d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#if defined(__BIONIC__) || defined(__APPLE__)
203e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			size = KERNEL_ALIGN(size, sizeof(u64));
204e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#else
205e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			size = ALIGN(size, sizeof(u64));
206e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#endif
207e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng                        /* ANDROID_CHANGE_END */
208e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			event->mmap.len -= event->mmap.start;
209e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			event->mmap.header.size = (sizeof(event->mmap) -
210e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					        (sizeof(event->mmap.filename) - size));
211e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			memset(event->mmap.filename + size, 0, session->id_hdr_size);
212e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			event->mmap.header.size += session->id_hdr_size;
213e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			event->mmap.pid = tgid;
214e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			event->mmap.tid = pid;
215e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
216e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			process(event, &synth_sample, session);
217e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
218e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
219e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
220e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	fclose(fp);
221e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
222e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
223e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
224e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__synthesize_modules(perf_event__handler_t process,
225e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				   struct perf_session *session,
226e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				   struct machine *machine)
227e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
228e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct rb_node *nd;
229e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct map_groups *kmaps = &machine->kmaps;
230e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	union perf_event *event = zalloc((sizeof(event->mmap) +
231e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					  session->id_hdr_size));
232e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (event == NULL) {
233e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		pr_debug("Not enough memory synthesizing mmap event "
234e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			 "for kernel modules\n");
235e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -1;
236e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
237e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
238e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->header.type = PERF_RECORD_MMAP;
239e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
240e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/*
241e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * kernel uses 0 for user space maps, see kernel/perf_event.c
242e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * __perf_event_mmap
243e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 */
244e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (machine__is_host(machine))
245e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->header.misc = PERF_RECORD_MISC_KERNEL;
246e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	else
247e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
248e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
249e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
250e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	     nd; nd = rb_next(nd)) {
251e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		size_t size;
252e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		struct map *pos = rb_entry(nd, struct map, rb_node);
253e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
254e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (pos->dso->kernel)
255e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			continue;
256e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
257e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng                /* ANDROID_CHANGE_BEGIN */
2587d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#if defined(__BIONIC__) || defined(__APPLE__)
259e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		size = KERNEL_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
260e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#else
261e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
262e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#endif
263e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng                /* ANDROID_CHANGE_END */
264e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->mmap.header.type = PERF_RECORD_MMAP;
265e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->mmap.header.size = (sizeof(event->mmap) -
266e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				        (sizeof(event->mmap.filename) - size));
267e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		memset(event->mmap.filename + size, 0, session->id_hdr_size);
268e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->mmap.header.size += session->id_hdr_size;
269e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->mmap.start = pos->start;
270e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->mmap.len   = pos->end - pos->start;
271e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->mmap.pid   = machine->pid;
272e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
273e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		memcpy(event->mmap.filename, pos->dso->long_name,
274e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		       pos->dso->long_name_len + 1);
275e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		process(event, &synth_sample, session);
276e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
277e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
278e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	free(event);
279e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
280e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
281e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
282e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic int __event__synthesize_thread(union perf_event *comm_event,
283e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				      union perf_event *mmap_event,
284e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				      pid_t pid, perf_event__handler_t process,
285e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				      struct perf_session *session)
286e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
287e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process,
288e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					    session);
289e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (tgid == -1)
290e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -1;
291e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return perf_event__synthesize_mmap_events(mmap_event, pid, tgid,
292e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					     process, session);
293e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
294e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
295e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__synthesize_thread_map(struct thread_map *threads,
296e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				      perf_event__handler_t process,
297e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				      struct perf_session *session)
298e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
299e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	union perf_event *comm_event, *mmap_event;
300e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int err = -1, thread;
301e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
302e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
303e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (comm_event == NULL)
304e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out;
305e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
306e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
307e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (mmap_event == NULL)
308e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_free_comm;
309e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
310e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	err = 0;
311e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	for (thread = 0; thread < threads->nr; ++thread) {
312e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (__event__synthesize_thread(comm_event, mmap_event,
313e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					       threads->map[thread],
314e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					       process, session)) {
315e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			err = -1;
316e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			break;
317e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
318e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
319e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	free(mmap_event);
320e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout_free_comm:
321e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	free(comm_event);
322e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout:
323e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return err;
324e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
325e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
326e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__synthesize_threads(perf_event__handler_t process,
327e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				   struct perf_session *session)
328e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
329e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	DIR *proc;
330e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct dirent dirent, *next;
331e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	union perf_event *comm_event, *mmap_event;
332e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int err = -1;
333e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
334e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
335e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (comm_event == NULL)
336e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out;
337e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
338e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
339e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (mmap_event == NULL)
340e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_free_comm;
341e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
342e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	proc = opendir("/proc");
343e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (proc == NULL)
344e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_free_mmap;
345e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
346e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	while (!readdir_r(proc, &dirent, &next) && next) {
347e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		char *end;
348e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		pid_t pid = strtol(dirent.d_name, &end, 10);
349e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
350e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (*end) /* only interested in proper numerical dirents */
351e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			continue;
352e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
353e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		__event__synthesize_thread(comm_event, mmap_event, pid,
354e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					   process, session);
355e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
356e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
357e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	closedir(proc);
358e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	err = 0;
359e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout_free_mmap:
360e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	free(mmap_event);
361e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout_free_comm:
362e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	free(comm_event);
363e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout:
364e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return err;
365e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
366e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
367e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstruct process_symbol_args {
368e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	const char *name;
369e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	u64	   start;
370e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng};
371e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
372e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic int find_symbol_cb(void *arg, const char *name, char type,
373e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			  u64 start, u64 end __used)
374e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
375e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct process_symbol_args *args = arg;
376e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
377e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/*
378e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * Must be a function or at least an alias, as in PARISC64, where "_text" is
379e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * an 'A' to the same address as "_stext".
380e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 */
381e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
382e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	      type == 'A') || strcmp(name, args->name))
383e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return 0;
384e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
385e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	args->start = start;
386e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 1;
387e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
388e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
389e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
390e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				       struct perf_session *session,
391e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				       struct machine *machine,
392e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				       const char *symbol_name)
393e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
394e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	size_t size;
395e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	const char *filename, *mmap_name;
396e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char path[PATH_MAX];
397e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char name_buff[PATH_MAX];
398e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct map *map;
399e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int err;
400e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/*
401e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * We should get this from /sys/kernel/sections/.text, but till that is
402e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * available use this, and after it is use this as a fallback for older
403e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * kernels.
404e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 */
405e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct process_symbol_args args = { .name = symbol_name, };
406e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	union perf_event *event = zalloc((sizeof(event->mmap) +
407e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					  session->id_hdr_size));
408e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (event == NULL) {
409e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		pr_debug("Not enough memory synthesizing mmap event "
410e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			 "for kernel modules\n");
411e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -1;
412e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
413e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
414e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
415e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (machine__is_host(machine)) {
416e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/*
417e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * kernel uses PERF_RECORD_MISC_USER for user space maps,
418e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * see kernel/perf_event.c __perf_event_mmap
419e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 */
420e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->header.misc = PERF_RECORD_MISC_KERNEL;
421e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		filename = "/proc/kallsyms";
422e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	} else {
423e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
424e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (machine__is_default_guest(machine))
425e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			filename = (char *) symbol_conf.default_guest_kallsyms;
426e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		else {
427e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			sprintf(path, "%s/proc/kallsyms", machine->root_dir);
428e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			filename = path;
429e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
430e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
431e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
432e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
433e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -ENOENT;
434e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
435e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	map = machine->vmlinux_maps[MAP__FUNCTION];
436e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
437e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			"%s%s", mmap_name, symbol_name) + 1;
438e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng        /* ANDROID_CHANGE_BEGIN */
4397d82a4640abdcc3ffbd89c7971a11e4ac7953b7fBen Cheng#if defined(__BIONIC__) || defined(__APPLE__)
440e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	size = KERNEL_ALIGN(size, sizeof(u64));
441e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#else
442e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	size = ALIGN(size, sizeof(u64));
443e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#endif
444e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng        /* ANDROID_CHANGE_END */
445e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->mmap.header.type = PERF_RECORD_MMAP;
446e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->mmap.header.size = (sizeof(event->mmap) -
447e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			(sizeof(event->mmap.filename) - size) + session->id_hdr_size);
448e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->mmap.pgoff = args.start;
449e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->mmap.start = map->start;
450e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->mmap.len   = map->end - event->mmap.start;
451e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	event->mmap.pid   = machine->pid;
452e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
453e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	err = process(event, &synth_sample, session);
454e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	free(event);
455e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
456e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return err;
457e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
458e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
459e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__process_comm(union perf_event *event,
460e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			     struct perf_sample *sample __used,
461e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			     struct perf_session *session)
462e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
463e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct thread *thread = perf_session__findnew(session, event->comm.tid);
464e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
465e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid);
466e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
467e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
468e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
469e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -1;
470e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
471e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
472e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
473e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
474e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
475e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__process_lost(union perf_event *event,
476e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			     struct perf_sample *sample __used,
477e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			     struct perf_session *session)
478e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
479e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
480e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		    event->lost.id, event->lost.lost);
481e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	session->hists.stats.total_lost += event->lost.lost;
482e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
483e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
484e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
485e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic void perf_event__set_kernel_mmap_len(union perf_event *event,
486e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					    struct map **maps)
487e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
488e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	maps[MAP__FUNCTION]->start = event->mmap.start;
489e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	maps[MAP__FUNCTION]->end   = event->mmap.start + event->mmap.len;
490e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/*
491e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * Be a bit paranoid here, some perf.data file came with
492e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * a zero sized synthesized MMAP event for the kernel.
493e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 */
494e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (maps[MAP__FUNCTION]->end == 0)
495e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		maps[MAP__FUNCTION]->end = ~0ULL;
496e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
497e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
498e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengstatic int perf_event__process_kernel_mmap(union perf_event *event,
499e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					   struct perf_session *session)
500e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
501e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct map *map;
502e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	char kmmap_prefix[PATH_MAX];
503e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct machine *machine;
504e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	enum dso_kernel_type kernel_type;
505e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	bool is_kernel_mmap;
506e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
507e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	machine = perf_session__findnew_machine(session, event->mmap.pid);
508e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (!machine) {
509e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		pr_err("Can't find id %d's machine\n", event->mmap.pid);
510e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_problem;
511e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
512e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
513e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
514e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (machine__is_host(machine))
515e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		kernel_type = DSO_TYPE_KERNEL;
516e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	else
517e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		kernel_type = DSO_TYPE_GUEST_KERNEL;
518e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
519e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	is_kernel_mmap = memcmp(event->mmap.filename,
520e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				kmmap_prefix,
521e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				strlen(kmmap_prefix)) == 0;
522e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (event->mmap.filename[0] == '/' ||
523e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	    (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
524e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
525e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		char short_module_name[1024];
526e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		char *name, *dot;
527e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
528e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (event->mmap.filename[0] == '/') {
529e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			name = strrchr(event->mmap.filename, '/');
530e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			if (name == NULL)
531e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				goto out_problem;
532e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
533e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			++name; /* skip / */
534e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			dot = strrchr(name, '.');
535e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			if (dot == NULL)
536e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				goto out_problem;
537e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			snprintf(short_module_name, sizeof(short_module_name),
538e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					"[%.*s]", (int)(dot - name), name);
539e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			strxfrchar(short_module_name, '-', '_');
540e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		} else
541e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			strcpy(short_module_name, event->mmap.filename);
542e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
543e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		map = machine__new_module(machine, event->mmap.start,
544e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					  event->mmap.filename);
545e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (map == NULL)
546e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			goto out_problem;
547e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
548e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		name = strdup(short_module_name);
549e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (name == NULL)
550e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			goto out_problem;
551e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
552e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		map->dso->short_name = name;
553e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		map->dso->sname_alloc = 1;
554e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		map->end = map->start + event->mmap.len;
555e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	} else if (is_kernel_mmap) {
556e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		const char *symbol_name = (event->mmap.filename +
557e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				strlen(kmmap_prefix));
558e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/*
559e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * Should be there already, from the build-id table in
560e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * the header.
561e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 */
562e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
563e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng						     kmmap_prefix);
564e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (kernel == NULL)
565e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			goto out_problem;
566e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
567e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		kernel->kernel = kernel_type;
568e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (__machine__create_kernel_maps(machine, kernel) < 0)
569e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			goto out_problem;
570e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
571e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
572e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
573e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/*
574e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * Avoid using a zero address (kptr_restrict) for the ref reloc
575e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * symbol. Effectively having zero here means that at record
576e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * time /proc/sys/kernel/kptr_restrict was non zero.
577e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 */
578e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (event->mmap.pgoff != 0) {
579e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
580e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng								 symbol_name,
581e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng								 event->mmap.pgoff);
582e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
583e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
584e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (machine__is_default_guest(machine)) {
585e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			/*
586e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			 * preload dso of guest kernel and modules
587e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			 */
588e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
589e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				  NULL);
590e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
591e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
592e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
593e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout_problem:
594e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return -1;
595e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
596e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
597e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__process_mmap(union perf_event *event,
598e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			     struct perf_sample *sample __used,
599e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			     struct perf_session *session)
600e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
601e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct machine *machine;
602e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct thread *thread;
603e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct map *map;
604e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
605e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	int ret = 0;
606e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
607e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
608e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			event->mmap.pid, event->mmap.tid, event->mmap.start,
609e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			event->mmap.len, event->mmap.pgoff, event->mmap.filename);
610e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
611e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
612e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	    cpumode == PERF_RECORD_MISC_KERNEL) {
613e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		ret = perf_event__process_kernel_mmap(event, session);
614e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (ret < 0)
615e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			goto out_problem;
616e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return 0;
617e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
618e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
619e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	machine = perf_session__find_host_machine(session);
620e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (machine == NULL)
621e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_problem;
622e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	thread = perf_session__findnew(session, event->mmap.pid);
623e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (thread == NULL)
624e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_problem;
625e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	map = map__new(&machine->user_dsos, event->mmap.start,
626e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			event->mmap.len, event->mmap.pgoff,
627e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			event->mmap.pid, event->mmap.filename,
628e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			MAP__FUNCTION);
629e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (map == NULL)
630e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_problem;
631e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
632e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	thread__insert_map(thread, map);
633e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
634e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
635e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout_problem:
636e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
637e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
638e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
639e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
640e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__process_task(union perf_event *event,
641e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			     struct perf_sample *sample __used,
642e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			     struct perf_session *session)
643e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
644e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct thread *thread = perf_session__findnew(session, event->fork.tid);
645e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct thread *parent = perf_session__findnew(session, event->fork.ptid);
646e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
647e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
648e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		    event->fork.ppid, event->fork.ptid);
649e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
650e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (event->header.type == PERF_RECORD_EXIT) {
651e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		perf_session__remove_thread(session, thread);
652e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return 0;
653e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
654e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
655e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (thread == NULL || parent == NULL ||
656e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	    thread__fork(thread, parent) < 0) {
657e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
658e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -1;
659e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
660e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
661e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
662e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
663e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
664e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__process(union perf_event *event, struct perf_sample *sample,
665e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			struct perf_session *session)
666e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
667e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	switch (event->header.type) {
668e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	case PERF_RECORD_COMM:
669e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		perf_event__process_comm(event, sample, session);
670e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		break;
671e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	case PERF_RECORD_MMAP:
672e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		perf_event__process_mmap(event, sample, session);
673e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		break;
674e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	case PERF_RECORD_FORK:
675e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	case PERF_RECORD_EXIT:
676e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		perf_event__process_task(event, sample, session);
677e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		break;
678e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	case PERF_RECORD_LOST:
679e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		perf_event__process_lost(event, sample, session);
680e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	default:
681e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		break;
682e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
683e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
684e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
685e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
686e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
687e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengvoid thread__find_addr_map(struct thread *self,
688e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			   struct perf_session *session, u8 cpumode,
689e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			   enum map_type type, pid_t pid, u64 addr,
690e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			   struct addr_location *al)
691e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
692e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct map_groups *mg = &self->mg;
693e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct machine *machine = NULL;
694e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
695e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	al->thread = self;
696e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	al->addr = addr;
697e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	al->cpumode = cpumode;
698e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	al->filtered = false;
699e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
700e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
701e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		al->level = 'k';
702e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		machine = perf_session__find_host_machine(session);
703e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (machine == NULL) {
704e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			al->map = NULL;
705e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			return;
706e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
707e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		mg = &machine->kmaps;
708e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
709e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		al->level = '.';
710e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		machine = perf_session__find_host_machine(session);
711e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
712e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		al->level = 'g';
713e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		machine = perf_session__find_machine(session, pid);
714e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (machine == NULL) {
715e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			al->map = NULL;
716e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			return;
717e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
718e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		mg = &machine->kmaps;
719e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	} else {
720e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/*
721e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * 'u' means guest os user space.
722e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * TODO: We don't support guest user space. Might support late.
723e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 */
724e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
725e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			al->level = 'u';
726e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		else
727e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			al->level = 'H';
728e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		al->map = NULL;
729e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
730e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
731e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
732e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			!perf_guest)
733e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			al->filtered = true;
734e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if ((cpumode == PERF_RECORD_MISC_USER ||
735e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			cpumode == PERF_RECORD_MISC_KERNEL) &&
736e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			!perf_host)
737e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			al->filtered = true;
738e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
739e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return;
740e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
741e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengtry_again:
742e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	al->map = map_groups__find(mg, type, al->addr);
743e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (al->map == NULL) {
744e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		/*
745e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * If this is outside of all known maps, and is a negative
746e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * address, try to look it up in the kernel dso, as it might be
747e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * a vsyscall or vdso (which executes in user-mode).
748e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 *
749e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * XXX This is nasty, we should have a symbol list in the
750e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * "[vdso]" dso, but for now lets use the old trick of looking
751e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 * in the whole kernel symbol list.
752e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		 */
753e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if ((long long)al->addr < 0 &&
754e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		    cpumode == PERF_RECORD_MISC_USER &&
755e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		    machine && mg != &machine->kmaps) {
756e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			mg = &machine->kmaps;
757e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			goto try_again;
758e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		}
759e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	} else
760e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		al->addr = al->map->map_ip(al->map, al->addr);
761e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
762e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
763e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengvoid thread__find_addr_location(struct thread *self,
764e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				struct perf_session *session, u8 cpumode,
765e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				enum map_type type, pid_t pid, u64 addr,
766e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				struct addr_location *al,
767e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				symbol_filter_t filter)
768e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
769e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	thread__find_addr_map(self, session, cpumode, type, pid, addr, al);
770e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (al->map != NULL)
771e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		al->sym = map__find_symbol(al->map, al->addr, filter);
772e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	else
773e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		al->sym = NULL;
774e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
775e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
776e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengint perf_event__preprocess_sample(const union perf_event *event,
777e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				  struct perf_session *session,
778e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				  struct addr_location *al,
779e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				  struct perf_sample *sample,
780e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng				  symbol_filter_t filter)
781e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng{
782e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
783e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	struct thread *thread = perf_session__findnew(session, event->ip.pid);
784e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
785e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (thread == NULL)
786e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return -1;
787e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
788e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (symbol_conf.comm_list &&
789e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	    !strlist__has_entry(symbol_conf.comm_list, thread->comm))
790e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_filtered;
791e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
792e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
793e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	/*
794e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * Have we already created the kernel maps for the host machine?
795e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 *
796e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * This should have happened earlier, when we processed the kernel MMAP
797e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * events, but for older perf.data files there was no such thing, so do
798e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 * it now.
799e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	 */
800e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (cpumode == PERF_RECORD_MISC_KERNEL &&
801e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	    session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL)
802e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		machine__create_kernel_maps(&session->host_machine);
803e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
804e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
805e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			      event->ip.pid, event->ip.ip, al);
806e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	dump_printf(" ...... dso: %s\n",
807e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		    al->map ? al->map->dso->long_name :
808e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			al->level == 'H' ? "[hypervisor]" : "<not found>");
809e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	al->sym = NULL;
810e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	al->cpu = sample->cpu;
811e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
812e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (al->map) {
813e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if (symbol_conf.dso_list &&
814e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		    (!al->map || !al->map->dso ||
815e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		     !(strlist__has_entry(symbol_conf.dso_list,
816e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					  al->map->dso->short_name) ||
817e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		       (al->map->dso->short_name != al->map->dso->long_name &&
818e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			strlist__has_entry(symbol_conf.dso_list,
819e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng					   al->map->dso->long_name)))))
820e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			goto out_filtered;
821e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
822e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		al->sym = map__find_symbol(al->map, al->addr, filter);
823e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	}
824e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
825e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	if (symbol_conf.sym_list && al->sym &&
826e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	    !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
827e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		goto out_filtered;
828e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
829e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
830e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
831e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengout_filtered:
832e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	al->filtered = true;
833e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	return 0;
834e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng}
835