Blame view

tools/perf/util/machine.c 41.3 KB
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1
  #include "callchain.h"
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
2
3
  #include "debug.h"
  #include "event.h"
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
4
5
  #include "evsel.h"
  #include "hist.h"
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
6
7
  #include "machine.h"
  #include "map.h"
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
8
  #include "sort.h"
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
9
  #include "strlist.h"
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
10
  #include "thread.h"
d027b6400   Adrian Hunter   perf machine: Fix...
11
  #include "vdso.h"
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
12
  #include <stdbool.h>
c506c96b6   Arnaldo Carvalho de Melo   tools lib symbol:...
13
  #include <symbol/kallsyms.h>
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
14
  #include "unwind.h"
8b7bad58e   Andi Kleen   perf callchain: S...
15
  #include "linux/hash.h"
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
16

e167f995e   Arnaldo Carvalho de Melo   perf machine: Add...
17
18
19
20
21
  static void dsos__init(struct dsos *dsos)
  {
  	INIT_LIST_HEAD(&dsos->head);
  	dsos->root = RB_ROOT;
  }
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
22
23
  int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
  {
11246c708   Arnaldo Carvalho de Melo   perf tools: Set t...
24
  	map_groups__init(&machine->kmaps, machine);
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
25
  	RB_CLEAR_NODE(&machine->rb_node);
e167f995e   Arnaldo Carvalho de Melo   perf machine: Add...
26
27
  	dsos__init(&machine->user_dsos);
  	dsos__init(&machine->kernel_dsos);
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
28
29
30
31
  
  	machine->threads = RB_ROOT;
  	INIT_LIST_HEAD(&machine->dead_threads);
  	machine->last_match = NULL;
d027b6400   Adrian Hunter   perf machine: Fix...
32
  	machine->vdso_info = NULL;
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
33
  	machine->pid = pid;
611a5ce8a   Adrian Hunter   perf machine: Add...
34
  	machine->symbol_filter = NULL;
14bd6d20f   Jiri Olsa   perf machine: Fix...
35
  	machine->id_hdr_size = 0;
cfe1c4140   Adrian Hunter   perf machine: Add...
36
  	machine->comm_exec = false;
fbe2af45f   Adrian Hunter   perf tools: Add m...
37
  	machine->kernel_start = 0;
611a5ce8a   Adrian Hunter   perf machine: Add...
38

69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
39
40
41
42
43
  	machine->root_dir = strdup(root_dir);
  	if (machine->root_dir == NULL)
  		return -ENOMEM;
  
  	if (pid != HOST_KERNEL_ID) {
1fcb87686   Adrian Hunter   perf machine: Fix...
44
  		struct thread *thread = machine__findnew_thread(machine, -1,
314add6b1   Adrian Hunter   perf tools: chang...
45
  								pid);
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
46
47
48
49
50
51
  		char comm[64];
  
  		if (thread == NULL)
  			return -ENOMEM;
  
  		snprintf(comm, sizeof(comm), "[guest/%d]", pid);
162f0befd   Frederic Weisbecker   perf tools: Add t...
52
  		thread__set_comm(thread, comm, 0);
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
53
  	}
b9d266baa   Adrian Hunter   perf machine: Add...
54
  	machine->current_tid = NULL;
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
55
56
  	return 0;
  }
8fb598e5a   David Ahern   perf trace: Fix c...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  struct machine *machine__new_host(void)
  {
  	struct machine *machine = malloc(sizeof(*machine));
  
  	if (machine != NULL) {
  		machine__init(machine, "", HOST_KERNEL_ID);
  
  		if (machine__create_kernel_maps(machine) < 0)
  			goto out_delete;
  	}
  
  	return machine;
  out_delete:
  	free(machine);
  	return NULL;
  }
8fa7d87f9   Waiman Long   perf symbols: Enc...
73
  static void dsos__delete(struct dsos *dsos)
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
74
75
  {
  	struct dso *pos, *n;
8fa7d87f9   Waiman Long   perf symbols: Enc...
76
  	list_for_each_entry_safe(pos, n, &dsos->head, node) {
4598a0a6d   Waiman Long   perf symbols: Imp...
77
  		RB_CLEAR_NODE(&pos->rb_node);
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
78
79
80
81
  		list_del(&pos->node);
  		dso__delete(pos);
  	}
  }
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  void machine__delete_dead_threads(struct machine *machine)
  {
  	struct thread *n, *t;
  
  	list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
  		list_del(&t->node);
  		thread__delete(t);
  	}
  }
  
  void machine__delete_threads(struct machine *machine)
  {
  	struct rb_node *nd = rb_first(&machine->threads);
  
  	while (nd) {
  		struct thread *t = rb_entry(nd, struct thread, rb_node);
  
  		rb_erase(&t->rb_node, &machine->threads);
  		nd = rb_next(nd);
  		thread__delete(t);
  	}
  }
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
104
105
106
107
108
  void machine__exit(struct machine *machine)
  {
  	map_groups__exit(&machine->kmaps);
  	dsos__delete(&machine->user_dsos);
  	dsos__delete(&machine->kernel_dsos);
d027b6400   Adrian Hunter   perf machine: Fix...
109
  	vdso__exit(machine);
046625231   Arnaldo Carvalho de Melo   perf tools: Intro...
110
  	zfree(&machine->root_dir);
b9d266baa   Adrian Hunter   perf machine: Add...
111
  	zfree(&machine->current_tid);
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
112
113
114
115
116
117
118
  }
  
  void machine__delete(struct machine *machine)
  {
  	machine__exit(machine);
  	free(machine);
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
119
120
121
122
  void machines__init(struct machines *machines)
  {
  	machine__init(&machines->host, "", HOST_KERNEL_ID);
  	machines->guests = RB_ROOT;
611a5ce8a   Adrian Hunter   perf machine: Add...
123
  	machines->symbol_filter = NULL;
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
124
125
126
127
128
129
130
131
132
  }
  
  void machines__exit(struct machines *machines)
  {
  	machine__exit(&machines->host);
  	/* XXX exit guest */
  }
  
  struct machine *machines__add(struct machines *machines, pid_t pid,
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
133
134
  			      const char *root_dir)
  {
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
135
  	struct rb_node **p = &machines->guests.rb_node;
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
136
137
138
139
140
141
142
143
144
145
  	struct rb_node *parent = NULL;
  	struct machine *pos, *machine = malloc(sizeof(*machine));
  
  	if (machine == NULL)
  		return NULL;
  
  	if (machine__init(machine, root_dir, pid) != 0) {
  		free(machine);
  		return NULL;
  	}
611a5ce8a   Adrian Hunter   perf machine: Add...
146
  	machine->symbol_filter = machines->symbol_filter;
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
147
148
149
150
151
152
153
154
155
156
  	while (*p != NULL) {
  		parent = *p;
  		pos = rb_entry(parent, struct machine, rb_node);
  		if (pid < pos->pid)
  			p = &(*p)->rb_left;
  		else
  			p = &(*p)->rb_right;
  	}
  
  	rb_link_node(&machine->rb_node, parent, p);
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
157
  	rb_insert_color(&machine->rb_node, &machines->guests);
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
158
159
160
  
  	return machine;
  }
611a5ce8a   Adrian Hunter   perf machine: Add...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  void machines__set_symbol_filter(struct machines *machines,
  				 symbol_filter_t symbol_filter)
  {
  	struct rb_node *nd;
  
  	machines->symbol_filter = symbol_filter;
  	machines->host.symbol_filter = symbol_filter;
  
  	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
  		struct machine *machine = rb_entry(nd, struct machine, rb_node);
  
  		machine->symbol_filter = symbol_filter;
  	}
  }
cfe1c4140   Adrian Hunter   perf machine: Add...
175
176
177
178
179
180
181
182
183
184
185
186
  void machines__set_comm_exec(struct machines *machines, bool comm_exec)
  {
  	struct rb_node *nd;
  
  	machines->host.comm_exec = comm_exec;
  
  	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
  		struct machine *machine = rb_entry(nd, struct machine, rb_node);
  
  		machine->comm_exec = comm_exec;
  	}
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
187
  struct machine *machines__find(struct machines *machines, pid_t pid)
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
188
  {
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
189
  	struct rb_node **p = &machines->guests.rb_node;
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
190
191
192
  	struct rb_node *parent = NULL;
  	struct machine *machine;
  	struct machine *default_machine = NULL;
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
193
194
  	if (pid == HOST_KERNEL_ID)
  		return &machines->host;
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  	while (*p != NULL) {
  		parent = *p;
  		machine = rb_entry(parent, struct machine, rb_node);
  		if (pid < machine->pid)
  			p = &(*p)->rb_left;
  		else if (pid > machine->pid)
  			p = &(*p)->rb_right;
  		else
  			return machine;
  		if (!machine->pid)
  			default_machine = machine;
  	}
  
  	return default_machine;
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
210
  struct machine *machines__findnew(struct machines *machines, pid_t pid)
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  {
  	char path[PATH_MAX];
  	const char *root_dir = "";
  	struct machine *machine = machines__find(machines, pid);
  
  	if (machine && (machine->pid == pid))
  		goto out;
  
  	if ((pid != HOST_KERNEL_ID) &&
  	    (pid != DEFAULT_GUEST_KERNEL_ID) &&
  	    (symbol_conf.guestmount)) {
  		sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
  		if (access(path, R_OK)) {
  			static struct strlist *seen;
  
  			if (!seen)
  				seen = strlist__new(true, NULL);
  
  			if (!strlist__has_entry(seen, path)) {
  				pr_err("Can't access file %s
  ", path);
  				strlist__add(seen, path);
  			}
  			machine = NULL;
  			goto out;
  		}
  		root_dir = path;
  	}
  
  	machine = machines__add(machines, pid, root_dir);
  out:
  	return machine;
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
244
245
  void machines__process_guests(struct machines *machines,
  			      machine__process_t process, void *data)
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
246
247
  {
  	struct rb_node *nd;
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
248
  	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  		struct machine *pos = rb_entry(nd, struct machine, rb_node);
  		process(pos, data);
  	}
  }
  
  char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
  {
  	if (machine__is_host(machine))
  		snprintf(bf, size, "[%s]", "kernel.kallsyms");
  	else if (machine__is_default_guest(machine))
  		snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
  	else {
  		snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms",
  			 machine->pid);
  	}
  
  	return bf;
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
267
  void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
268
269
270
  {
  	struct rb_node *node;
  	struct machine *machine;
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
271
272
273
  	machines->host.id_hdr_size = id_hdr_size;
  
  	for (node = rb_first(&machines->guests); node; node = rb_next(node)) {
69d2591a8   Arnaldo Carvalho de Melo   perf machine: Mov...
274
275
276
277
278
279
  		machine = rb_entry(node, struct machine, rb_node);
  		machine->id_hdr_size = id_hdr_size;
  	}
  
  	return;
  }
29ce36121   Adrian Hunter   perf machine: Fix...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  static void machine__update_thread_pid(struct machine *machine,
  				       struct thread *th, pid_t pid)
  {
  	struct thread *leader;
  
  	if (pid == th->pid_ || pid == -1 || th->pid_ != -1)
  		return;
  
  	th->pid_ = pid;
  
  	if (th->pid_ == th->tid)
  		return;
  
  	leader = machine__findnew_thread(machine, th->pid_, th->pid_);
  	if (!leader)
  		goto out_err;
  
  	if (!leader->mg)
11246c708   Arnaldo Carvalho de Melo   perf tools: Set t...
298
  		leader->mg = map_groups__new(machine);
29ce36121   Adrian Hunter   perf machine: Fix...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  
  	if (!leader->mg)
  		goto out_err;
  
  	if (th->mg == leader->mg)
  		return;
  
  	if (th->mg) {
  		/*
  		 * Maps are created from MMAP events which provide the pid and
  		 * tid.  Consequently there never should be any maps on a thread
  		 * with an unknown pid.  Just print an error if there are.
  		 */
  		if (!map_groups__empty(th->mg))
  			pr_err("Discarding thread maps for %d:%d
  ",
  			       th->pid_, th->tid);
  		map_groups__delete(th->mg);
  	}
  
  	th->mg = map_groups__get(leader->mg);
  
  	return;
  
  out_err:
  	pr_err("Failed to join map groups for %d:%d
  ", th->pid_, th->tid);
  }
99d725fc6   Adrian Hunter   perf tools: Add p...
327
328
  static struct thread *__machine__findnew_thread(struct machine *machine,
  						pid_t pid, pid_t tid,
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
329
330
331
332
333
334
335
  						bool create)
  {
  	struct rb_node **p = &machine->threads.rb_node;
  	struct rb_node *parent = NULL;
  	struct thread *th;
  
  	/*
380512345   Adrian Hunter   perf tools: struc...
336
  	 * Front-end cache - TID lookups come in blocks,
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
337
338
339
  	 * so most of the time we dont have to look up
  	 * the full rbtree:
  	 */
29ce36121   Adrian Hunter   perf machine: Fix...
340
341
342
343
  	th = machine->last_match;
  	if (th && th->tid == tid) {
  		machine__update_thread_pid(machine, th, pid);
  		return th;
99d725fc6   Adrian Hunter   perf tools: Add p...
344
  	}
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
345
346
347
348
  
  	while (*p != NULL) {
  		parent = *p;
  		th = rb_entry(parent, struct thread, rb_node);
380512345   Adrian Hunter   perf tools: struc...
349
  		if (th->tid == tid) {
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
350
  			machine->last_match = th;
29ce36121   Adrian Hunter   perf machine: Fix...
351
  			machine__update_thread_pid(machine, th, pid);
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
352
353
  			return th;
  		}
380512345   Adrian Hunter   perf tools: struc...
354
  		if (tid < th->tid)
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
355
356
357
358
359
360
361
  			p = &(*p)->rb_left;
  		else
  			p = &(*p)->rb_right;
  	}
  
  	if (!create)
  		return NULL;
99d725fc6   Adrian Hunter   perf tools: Add p...
362
  	th = thread__new(pid, tid);
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
363
364
365
  	if (th != NULL) {
  		rb_link_node(&th->rb_node, parent, p);
  		rb_insert_color(&th->rb_node, &machine->threads);
cddcef607   Jiri Olsa   perf tools: Share...
366
367
368
369
370
371
372
373
374
  
  		/*
  		 * We have to initialize map_groups separately
  		 * after rb tree is updated.
  		 *
  		 * The reason is that we call machine__findnew_thread
  		 * within thread__init_map_groups to find the thread
  		 * leader and that would screwed the rb tree.
  		 */
418029b73   Adrian Hunter   perf machine: Fix...
375
  		if (thread__init_map_groups(th, machine)) {
260d819e3   Namhyung Kim   perf machine: Fix...
376
  			rb_erase(&th->rb_node, &machine->threads);
418029b73   Adrian Hunter   perf machine: Fix...
377
  			thread__delete(th);
cddcef607   Jiri Olsa   perf tools: Share...
378
  			return NULL;
418029b73   Adrian Hunter   perf machine: Fix...
379
  		}
260d819e3   Namhyung Kim   perf machine: Fix...
380
381
  
  		machine->last_match = th;
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
382
383
384
385
  	}
  
  	return th;
  }
314add6b1   Adrian Hunter   perf tools: chang...
386
387
  struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
  				       pid_t tid)
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
388
  {
314add6b1   Adrian Hunter   perf tools: chang...
389
  	return __machine__findnew_thread(machine, pid, tid, true);
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
390
  }
d75e6097e   Jiri Olsa   perf machine: Fac...
391
392
  struct thread *machine__find_thread(struct machine *machine, pid_t pid,
  				    pid_t tid)
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
393
  {
d75e6097e   Jiri Olsa   perf machine: Fac...
394
  	return __machine__findnew_thread(machine, pid, tid, false);
9d2f8e22f   Arnaldo Carvalho de Melo   perf machine: Int...
395
  }
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
396

cfe1c4140   Adrian Hunter   perf machine: Add...
397
398
399
400
401
402
403
404
  struct comm *machine__thread_exec_comm(struct machine *machine,
  				       struct thread *thread)
  {
  	if (machine->comm_exec)
  		return thread__exec_comm(thread);
  	else
  		return thread__comm(thread);
  }
162f0befd   Frederic Weisbecker   perf tools: Add t...
405
406
  int machine__process_comm_event(struct machine *machine, union perf_event *event,
  				struct perf_sample *sample)
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
407
  {
314add6b1   Adrian Hunter   perf tools: chang...
408
409
410
  	struct thread *thread = machine__findnew_thread(machine,
  							event->comm.pid,
  							event->comm.tid);
65de51f93   Adrian Hunter   perf tools: Ident...
411
  	bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
412

cfe1c4140   Adrian Hunter   perf machine: Add...
413
414
  	if (exec)
  		machine->comm_exec = true;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
415
416
  	if (dump_trace)
  		perf_event__fprintf_comm(event, stdout);
65de51f93   Adrian Hunter   perf tools: Ident...
417
418
  	if (thread == NULL ||
  	    __thread__set_comm(thread, event->comm.comm, sample->time, exec)) {
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
419
420
421
422
423
424
425
426
427
  		dump_printf("problem processing PERF_RECORD_COMM, skipping event.
  ");
  		return -1;
  	}
  
  	return 0;
  }
  
  int machine__process_lost_event(struct machine *machine __maybe_unused,
162f0befd   Frederic Weisbecker   perf tools: Add t...
428
  				union perf_event *event, struct perf_sample *sample __maybe_unused)
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
429
430
431
432
433
434
  {
  	dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "
  ",
  		    event->lost.id, event->lost.lost);
  	return 0;
  }
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
435
436
437
438
439
  struct map *machine__new_module(struct machine *machine, u64 start,
  				const char *filename)
  {
  	struct map *map;
  	struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
c00c48fc6   Namhyung Kim   perf symbols: Pre...
440
  	bool compressed;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
441
442
443
444
445
446
447
448
449
450
451
452
  
  	if (dso == NULL)
  		return NULL;
  
  	map = map__new2(start, dso, MAP__FUNCTION);
  	if (map == NULL)
  		return NULL;
  
  	if (machine__is_host(machine))
  		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
  	else
  		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
c00c48fc6   Namhyung Kim   perf symbols: Pre...
453
454
455
456
  
  	/* _KMODULE_COMP should be next to _KMODULE */
  	if (is_kernel_module(filename, &compressed) && compressed)
  		dso->symtab_type++;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
457
458
459
  	map_groups__insert(&machine->kmaps, map);
  	return map;
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
460
  size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
461
462
  {
  	struct rb_node *nd;
8fa7d87f9   Waiman Long   perf symbols: Enc...
463
464
  	size_t ret = __dsos__fprintf(&machines->host.kernel_dsos.head, fp) +
  		     __dsos__fprintf(&machines->host.user_dsos.head, fp);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
465

876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
466
  	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
467
  		struct machine *pos = rb_entry(nd, struct machine, rb_node);
8fa7d87f9   Waiman Long   perf symbols: Enc...
468
469
  		ret += __dsos__fprintf(&pos->kernel_dsos.head, fp);
  		ret += __dsos__fprintf(&pos->user_dsos.head, fp);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
470
471
472
473
  	}
  
  	return ret;
  }
8fa7d87f9   Waiman Long   perf symbols: Enc...
474
  size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp,
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
475
476
  				     bool (skip)(struct dso *dso, int parm), int parm)
  {
8fa7d87f9   Waiman Long   perf symbols: Enc...
477
478
  	return __dsos__fprintf_buildid(&m->kernel_dsos.head, fp, skip, parm) +
  	       __dsos__fprintf_buildid(&m->user_dsos.head, fp, skip, parm);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
479
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
480
  size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
481
482
483
  				     bool (skip)(struct dso *dso, int parm), int parm)
  {
  	struct rb_node *nd;
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
484
  	size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
485

876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
486
  	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
  		struct machine *pos = rb_entry(nd, struct machine, rb_node);
  		ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
  	}
  	return ret;
  }
  
  size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
  {
  	int i;
  	size_t printed = 0;
  	struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
  
  	if (kdso->has_build_id) {
  		char filename[PATH_MAX];
  		if (dso__build_id_filename(kdso, filename, sizeof(filename)))
  			printed += fprintf(fp, "[0] %s
  ", filename);
  	}
  
  	for (i = 0; i < vmlinux_path__nr_entries; ++i)
  		printed += fprintf(fp, "[%d] %s
  ",
  				   i + kdso->has_build_id, vmlinux_path[i]);
  
  	return printed;
  }
  
  size_t machine__fprintf(struct machine *machine, FILE *fp)
  {
  	size_t ret = 0;
  	struct rb_node *nd;
  
  	for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
  		struct thread *pos = rb_entry(nd, struct thread, rb_node);
  
  		ret += thread__fprintf(pos, fp);
  	}
  
  	return ret;
  }
  
  static struct dso *machine__get_kernel(struct machine *machine)
  {
  	const char *vmlinux_name = NULL;
  	struct dso *kernel;
  
  	if (machine__is_host(machine)) {
  		vmlinux_name = symbol_conf.vmlinux_name;
  		if (!vmlinux_name)
  			vmlinux_name = "[kernel.kallsyms]";
  
  		kernel = dso__kernel_findnew(machine, vmlinux_name,
  					     "[kernel]",
  					     DSO_TYPE_KERNEL);
  	} else {
  		char bf[PATH_MAX];
  
  		if (machine__is_default_guest(machine))
  			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
  		if (!vmlinux_name)
  			vmlinux_name = machine__mmap_name(machine, bf,
  							  sizeof(bf));
  
  		kernel = dso__kernel_findnew(machine, vmlinux_name,
  					     "[guest.kernel]",
  					     DSO_TYPE_GUEST_KERNEL);
  	}
  
  	if (kernel != NULL && (!kernel->has_build_id))
  		dso__read_running_kernel_build_id(kernel, machine);
  
  	return kernel;
  }
  
  struct process_args {
  	u64 start;
  };
15a0a8706   Adrian Hunter   perf machine: Add...
564
565
566
567
568
569
570
571
  static void machine__get_kallsyms_filename(struct machine *machine, char *buf,
  					   size_t bufsz)
  {
  	if (machine__is_default_guest(machine))
  		scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms);
  	else
  		scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir);
  }
a93f0e551   Simon Que   perf symbols: Get...
572
573
574
575
576
577
  const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
  
  /* Figure out the start address of kernel map from /proc/kallsyms.
   * Returns the name of the start symbol in *symbol_name. Pass in NULL as
   * symbol_name if it's not that important.
   */
4b99375b3   Adrian Hunter   perf machine: Ren...
578
579
  static u64 machine__get_running_kernel_start(struct machine *machine,
  					     const char **symbol_name)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
580
  {
15a0a8706   Adrian Hunter   perf machine: Add...
581
  	char filename[PATH_MAX];
a93f0e551   Simon Que   perf symbols: Get...
582
583
584
  	int i;
  	const char *name;
  	u64 addr = 0;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
585

15a0a8706   Adrian Hunter   perf machine: Add...
586
  	machine__get_kallsyms_filename(machine, filename, PATH_MAX);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
587
588
589
  
  	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
  		return 0;
a93f0e551   Simon Que   perf symbols: Get...
590
591
592
593
594
595
596
597
  	for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
  		addr = kallsyms__get_function_start(filename, name);
  		if (addr)
  			break;
  	}
  
  	if (symbol_name)
  		*symbol_name = name;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
598

a93f0e551   Simon Que   perf symbols: Get...
599
  	return addr;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
600
601
602
603
604
  }
  
  int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
  {
  	enum map_type type;
4b99375b3   Adrian Hunter   perf machine: Ren...
605
  	u64 start = machine__get_running_kernel_start(machine, NULL);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
  
  	for (type = 0; type < MAP__NR_TYPES; ++type) {
  		struct kmap *kmap;
  
  		machine->vmlinux_maps[type] = map__new2(start, kernel, type);
  		if (machine->vmlinux_maps[type] == NULL)
  			return -1;
  
  		machine->vmlinux_maps[type]->map_ip =
  			machine->vmlinux_maps[type]->unmap_ip =
  				identity__map_ip;
  		kmap = map__kmap(machine->vmlinux_maps[type]);
  		kmap->kmaps = &machine->kmaps;
  		map_groups__insert(&machine->kmaps,
  				   machine->vmlinux_maps[type]);
  	}
  
  	return 0;
  }
  
  void machine__destroy_kernel_maps(struct machine *machine)
  {
  	enum map_type type;
  
  	for (type = 0; type < MAP__NR_TYPES; ++type) {
  		struct kmap *kmap;
  
  		if (machine->vmlinux_maps[type] == NULL)
  			continue;
  
  		kmap = map__kmap(machine->vmlinux_maps[type]);
  		map_groups__remove(&machine->kmaps,
  				   machine->vmlinux_maps[type]);
  		if (kmap->ref_reloc_sym) {
  			/*
  			 * ref_reloc_sym is shared among all maps, so free just
  			 * on one of them.
  			 */
  			if (type == MAP__FUNCTION) {
046625231   Arnaldo Carvalho de Melo   perf tools: Intro...
645
646
647
648
  				zfree((char **)&kmap->ref_reloc_sym->name);
  				zfree(&kmap->ref_reloc_sym);
  			} else
  				kmap->ref_reloc_sym = NULL;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
649
650
651
652
653
654
  		}
  
  		map__delete(machine->vmlinux_maps[type]);
  		machine->vmlinux_maps[type] = NULL;
  	}
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
655
  int machines__create_guest_kernel_maps(struct machines *machines)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
  {
  	int ret = 0;
  	struct dirent **namelist = NULL;
  	int i, items = 0;
  	char path[PATH_MAX];
  	pid_t pid;
  	char *endp;
  
  	if (symbol_conf.default_guest_vmlinux_name ||
  	    symbol_conf.default_guest_modules ||
  	    symbol_conf.default_guest_kallsyms) {
  		machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
  	}
  
  	if (symbol_conf.guestmount) {
  		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
  		if (items <= 0)
  			return -ENOENT;
  		for (i = 0; i < items; i++) {
  			if (!isdigit(namelist[i]->d_name[0])) {
  				/* Filter out . and .. */
  				continue;
  			}
  			pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
  			if ((*endp != '\0') ||
  			    (endp == namelist[i]->d_name) ||
  			    (errno == ERANGE)) {
  				pr_debug("invalid directory (%s). Skipping.
  ",
  					 namelist[i]->d_name);
  				continue;
  			}
  			sprintf(path, "%s/%s/proc/kallsyms",
  				symbol_conf.guestmount,
  				namelist[i]->d_name);
  			ret = access(path, R_OK);
  			if (ret) {
  				pr_debug("Can't access file %s
  ", path);
  				goto failure;
  			}
  			machines__create_kernel_maps(machines, pid);
  		}
  failure:
  		free(namelist);
  	}
  
  	return ret;
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
705
  void machines__destroy_kernel_maps(struct machines *machines)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
706
  {
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
707
708
709
  	struct rb_node *next = rb_first(&machines->guests);
  
  	machine__destroy_kernel_maps(&machines->host);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
710
711
712
713
714
  
  	while (next) {
  		struct machine *pos = rb_entry(next, struct machine, rb_node);
  
  		next = rb_next(&pos->rb_node);
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
715
  		rb_erase(&pos->rb_node, &machines->guests);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
716
717
718
  		machine__delete(pos);
  	}
  }
876650e6c   Arnaldo Carvalho de Melo   perf machine: Int...
719
  int machines__create_kernel_maps(struct machines *machines, pid_t pid)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
  {
  	struct machine *machine = machines__findnew(machines, pid);
  
  	if (machine == NULL)
  		return -1;
  
  	return machine__create_kernel_maps(machine);
  }
  
  int machine__load_kallsyms(struct machine *machine, const char *filename,
  			   enum map_type type, symbol_filter_t filter)
  {
  	struct map *map = machine->vmlinux_maps[type];
  	int ret = dso__load_kallsyms(map->dso, filename, map, filter);
  
  	if (ret > 0) {
  		dso__set_loaded(map->dso, type);
  		/*
  		 * Since /proc/kallsyms will have multiple sessions for the
  		 * kernel, with modules between them, fixup the end of all
  		 * sections.
  		 */
  		__map_groups__fixup_end(&machine->kmaps, type);
  	}
  
  	return ret;
  }
  
  int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
  			       symbol_filter_t filter)
  {
  	struct map *map = machine->vmlinux_maps[type];
  	int ret = dso__load_vmlinux_path(map->dso, map, filter);
39b12f781   Adrian Hunter   perf tools: Make ...
753
  	if (ret > 0)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
754
  		dso__set_loaded(map->dso, type);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
  
  	return ret;
  }
  
  static void map_groups__fixup_end(struct map_groups *mg)
  {
  	int i;
  	for (i = 0; i < MAP__NR_TYPES; ++i)
  		__map_groups__fixup_end(mg, i);
  }
  
  static char *get_kernel_version(const char *root_dir)
  {
  	char version[PATH_MAX];
  	FILE *file;
  	char *name, *tmp;
  	const char *prefix = "Linux version ";
  
  	sprintf(version, "%s/proc/version", root_dir);
  	file = fopen(version, "r");
  	if (!file)
  		return NULL;
  
  	version[0] = '\0';
  	tmp = fgets(version, sizeof(version), file);
  	fclose(file);
  
  	name = strstr(version, prefix);
  	if (!name)
  		return NULL;
  	name += strlen(prefix);
  	tmp = strchr(name, ' ');
  	if (tmp)
  		*tmp = '\0';
  
  	return strdup(name);
  }
  
  static int map_groups__set_modules_path_dir(struct map_groups *mg,
61d4290cc   Richard Yao   perf machine: Sea...
794
  				const char *dir_name, int depth)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  {
  	struct dirent *dent;
  	DIR *dir = opendir(dir_name);
  	int ret = 0;
  
  	if (!dir) {
  		pr_debug("%s: cannot open %s dir
  ", __func__, dir_name);
  		return -1;
  	}
  
  	while ((dent = readdir(dir)) != NULL) {
  		char path[PATH_MAX];
  		struct stat st;
  
  		/*sshfs might return bad dent->d_type, so we have to stat*/
  		snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
  		if (stat(path, &st))
  			continue;
  
  		if (S_ISDIR(st.st_mode)) {
  			if (!strcmp(dent->d_name, ".") ||
  			    !strcmp(dent->d_name, ".."))
  				continue;
61d4290cc   Richard Yao   perf machine: Sea...
819
820
821
822
823
824
825
826
827
  			/* Do not follow top-level source and build symlinks */
  			if (depth == 0) {
  				if (!strcmp(dent->d_name, "source") ||
  				    !strcmp(dent->d_name, "build"))
  					continue;
  			}
  
  			ret = map_groups__set_modules_path_dir(mg, path,
  							       depth + 1);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
828
829
830
831
832
833
834
  			if (ret < 0)
  				goto out;
  		} else {
  			char *dot = strrchr(dent->d_name, '.'),
  			     dso_name[PATH_MAX];
  			struct map *map;
  			char *long_name;
c00c48fc6   Namhyung Kim   perf symbols: Pre...
835
  			if (dot == NULL)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
836
  				continue;
c00c48fc6   Namhyung Kim   perf symbols: Pre...
837
838
839
840
841
  
  			/* On some system, modules are compressed like .ko.gz */
  			if (is_supported_compression(dot + 1) &&
  			    is_kmodule_extension(dot - 2))
  				dot -= 3;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
842
843
844
845
846
847
848
849
850
851
852
853
854
855
  			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
  				 (int)(dot - dent->d_name), dent->d_name);
  
  			strxfrchar(dso_name, '-', '_');
  			map = map_groups__find_by_name(mg, MAP__FUNCTION,
  						       dso_name);
  			if (map == NULL)
  				continue;
  
  			long_name = strdup(path);
  			if (long_name == NULL) {
  				ret = -1;
  				goto out;
  			}
7e155d4d5   Arnaldo Carvalho de Melo   perf symbols: Rem...
856
  			dso__set_long_name(map->dso, long_name, true);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  			dso__kernel_module_get_build_id(map->dso, "");
  		}
  	}
  
  out:
  	closedir(dir);
  	return ret;
  }
  
  static int machine__set_modules_path(struct machine *machine)
  {
  	char *version;
  	char modules_path[PATH_MAX];
  
  	version = get_kernel_version(machine->root_dir);
  	if (!version)
  		return -1;
61d4290cc   Richard Yao   perf machine: Sea...
874
  	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s",
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
875
876
  		 machine->root_dir, version);
  	free(version);
61d4290cc   Richard Yao   perf machine: Sea...
877
  	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
878
  }
316d70d6d   Adrian Hunter   perf symbols: Mak...
879
  static int machine__create_module(void *arg, const char *name, u64 start)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
880
  {
316d70d6d   Adrian Hunter   perf symbols: Mak...
881
  	struct machine *machine = arg;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
882
  	struct map *map;
316d70d6d   Adrian Hunter   perf symbols: Mak...
883
884
885
886
887
888
889
890
891
892
893
894
  
  	map = machine__new_module(machine, start, name);
  	if (map == NULL)
  		return -1;
  
  	dso__kernel_module_get_build_id(map->dso, machine->root_dir);
  
  	return 0;
  }
  
  static int machine__create_modules(struct machine *machine)
  {
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
895
896
  	const char *modules;
  	char path[PATH_MAX];
f4be904d2   Adrian Hunter   perf machine: Use...
897
  	if (machine__is_default_guest(machine)) {
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
898
  		modules = symbol_conf.default_guest_modules;
f4be904d2   Adrian Hunter   perf machine: Use...
899
900
  	} else {
  		snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
901
902
  		modules = path;
  	}
aa7fe3b0c   Adrian Hunter   perf machine: Fix...
903
  	if (symbol__restricted_filename(modules, "/proc/modules"))
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
904
  		return -1;
316d70d6d   Adrian Hunter   perf symbols: Mak...
905
  	if (modules__parse(modules, machine, machine__create_module))
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
906
  		return -1;
316d70d6d   Adrian Hunter   perf symbols: Mak...
907
908
  	if (!machine__set_modules_path(machine))
  		return 0;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
909

316d70d6d   Adrian Hunter   perf symbols: Mak...
910
911
  	pr_debug("Problems setting modules path maps, continuing anyway...
  ");
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
912

8f76fcd90   Jason Wessel   perf machine: Do ...
913
  	return 0;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
914
915
916
917
918
  }
  
  int machine__create_kernel_maps(struct machine *machine)
  {
  	struct dso *kernel = machine__get_kernel(machine);
5512cf24b   Adrian Hunter   perf machine: Set...
919
  	const char *name;
4b99375b3   Adrian Hunter   perf machine: Ren...
920
  	u64 addr = machine__get_running_kernel_start(machine, &name);
5512cf24b   Adrian Hunter   perf machine: Set...
921
922
  	if (!addr)
  		return -1;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
  
  	if (kernel == NULL ||
  	    __machine__create_kernel_maps(machine, kernel) < 0)
  		return -1;
  
  	if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
  		if (machine__is_host(machine))
  			pr_debug("Problems creating module maps, "
  				 "continuing anyway...
  ");
  		else
  			pr_debug("Problems creating module maps for guest %d, "
  				 "continuing anyway...
  ", machine->pid);
  	}
  
  	/*
  	 * Now that we have all the maps created, just set the ->end of them:
  	 */
  	map_groups__fixup_end(&machine->kmaps);
5512cf24b   Adrian Hunter   perf machine: Set...
943
944
945
946
947
948
  
  	if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name,
  					     addr)) {
  		machine__destroy_kernel_maps(machine);
  		return -1;
  	}
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
949
950
  	return 0;
  }
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
951
952
953
  static void machine__set_kernel_mmap_len(struct machine *machine,
  					 union perf_event *event)
  {
4552cf0f7   Namhyung Kim   perf machine: Set...
954
955
956
957
958
959
960
961
962
963
964
965
966
  	int i;
  
  	for (i = 0; i < MAP__NR_TYPES; i++) {
  		machine->vmlinux_maps[i]->start = event->mmap.start;
  		machine->vmlinux_maps[i]->end   = (event->mmap.start +
  						   event->mmap.len);
  		/*
  		 * Be a bit paranoid here, some perf.data file came with
  		 * a zero sized synthesized MMAP event for the kernel.
  		 */
  		if (machine->vmlinux_maps[i]->end == 0)
  			machine->vmlinux_maps[i]->end = ~0ULL;
  	}
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
967
  }
8e0cf965f   Adrian Hunter   perf symbols: Add...
968
969
970
  static bool machine__uses_kcore(struct machine *machine)
  {
  	struct dso *dso;
8fa7d87f9   Waiman Long   perf symbols: Enc...
971
  	list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
8e0cf965f   Adrian Hunter   perf symbols: Add...
972
973
974
975
976
977
  		if (dso__is_kcore(dso))
  			return true;
  	}
  
  	return false;
  }
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
978
979
980
981
982
983
984
  static int machine__process_kernel_mmap_event(struct machine *machine,
  					      union perf_event *event)
  {
  	struct map *map;
  	char kmmap_prefix[PATH_MAX];
  	enum dso_kernel_type kernel_type;
  	bool is_kernel_mmap;
8e0cf965f   Adrian Hunter   perf symbols: Add...
985
986
987
  	/* If we have maps from kcore then we do not need or want any others */
  	if (machine__uses_kcore(machine))
  		return 0;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  	machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
  	if (machine__is_host(machine))
  		kernel_type = DSO_TYPE_KERNEL;
  	else
  		kernel_type = DSO_TYPE_GUEST_KERNEL;
  
  	is_kernel_mmap = memcmp(event->mmap.filename,
  				kmmap_prefix,
  				strlen(kmmap_prefix) - 1) == 0;
  	if (event->mmap.filename[0] == '/' ||
  	    (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
  
  		char short_module_name[1024];
  		char *name, *dot;
  
  		if (event->mmap.filename[0] == '/') {
  			name = strrchr(event->mmap.filename, '/');
  			if (name == NULL)
  				goto out_problem;
  
  			++name; /* skip / */
  			dot = strrchr(name, '.');
  			if (dot == NULL)
  				goto out_problem;
c00c48fc6   Namhyung Kim   perf symbols: Pre...
1012
1013
1014
1015
1016
  			/* On some system, modules are compressed like .ko.gz */
  			if (is_supported_compression(dot + 1))
  				dot -= 3;
  			if (!is_kmodule_extension(dot + 1))
  				goto out_problem;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
  			snprintf(short_module_name, sizeof(short_module_name),
  					"[%.*s]", (int)(dot - name), name);
  			strxfrchar(short_module_name, '-', '_');
  		} else
  			strcpy(short_module_name, event->mmap.filename);
  
  		map = machine__new_module(machine, event->mmap.start,
  					  event->mmap.filename);
  		if (map == NULL)
  			goto out_problem;
  
  		name = strdup(short_module_name);
  		if (name == NULL)
  			goto out_problem;
58a98c9cc   Adrian Hunter   perf symbols: Rem...
1031
  		dso__set_short_name(map->dso, name, true);
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1032
1033
1034
1035
1036
1037
1038
1039
  		map->end = map->start + event->mmap.len;
  	} else if (is_kernel_mmap) {
  		const char *symbol_name = (event->mmap.filename +
  				strlen(kmmap_prefix));
  		/*
  		 * Should be there already, from the build-id table in
  		 * the header.
  		 */
b837a8bdc   Namhyung Kim   perf tools: Fix b...
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
  		struct dso *kernel = NULL;
  		struct dso *dso;
  
  		list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
  			if (is_kernel_module(dso->long_name, NULL))
  				continue;
  
  			kernel = dso;
  			break;
  		}
  
  		if (kernel == NULL)
  			kernel = __dsos__findnew(&machine->kernel_dsos,
  						 kmmap_prefix);
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1054
1055
1056
1057
1058
1059
  		if (kernel == NULL)
  			goto out_problem;
  
  		kernel->kernel = kernel_type;
  		if (__machine__create_kernel_maps(machine, kernel) < 0)
  			goto out_problem;
330dfa224   Namhyung Kim   perf tools: Fix s...
1060
1061
  		if (strstr(kernel->long_name, "vmlinux"))
  			dso__set_short_name(kernel, "[kernel.vmlinux]", false);
96d78059d   Namhyung Kim   perf tools: Make ...
1062

b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
  		machine__set_kernel_mmap_len(machine, event);
  
  		/*
  		 * Avoid using a zero address (kptr_restrict) for the ref reloc
  		 * symbol. Effectively having zero here means that at record
  		 * time /proc/sys/kernel/kptr_restrict was non zero.
  		 */
  		if (event->mmap.pgoff != 0) {
  			maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
  							 symbol_name,
  							 event->mmap.pgoff);
  		}
  
  		if (machine__is_default_guest(machine)) {
  			/*
  			 * preload dso of guest kernel and modules
  			 */
  			dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
  				  NULL);
  		}
  	}
  	return 0;
  out_problem:
  	return -1;
  }
5c5e854bc   Stephane Eranian   perf tools: Add a...
1088
  int machine__process_mmap2_event(struct machine *machine,
162f0befd   Frederic Weisbecker   perf tools: Add t...
1089
1090
  				 union perf_event *event,
  				 struct perf_sample *sample __maybe_unused)
5c5e854bc   Stephane Eranian   perf tools: Add a...
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
  {
  	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
  	struct thread *thread;
  	struct map *map;
  	enum map_type type;
  	int ret = 0;
  
  	if (dump_trace)
  		perf_event__fprintf_mmap2(event, stdout);
  
  	if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
  	    cpumode == PERF_RECORD_MISC_KERNEL) {
  		ret = machine__process_kernel_mmap_event(machine, event);
  		if (ret < 0)
  			goto out_problem;
  		return 0;
  	}
  
  	thread = machine__findnew_thread(machine, event->mmap2.pid,
11c9abf22   Don Zickus   perf tools: Use t...
1110
  					event->mmap2.tid);
5c5e854bc   Stephane Eranian   perf tools: Add a...
1111
1112
1113
1114
1115
1116
1117
  	if (thread == NULL)
  		goto out_problem;
  
  	if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
  		type = MAP__VARIABLE;
  	else
  		type = MAP__FUNCTION;
2a03068c5   Adrian Hunter   perf tools: Pass ...
1118
  	map = map__new(machine, event->mmap2.start,
5c5e854bc   Stephane Eranian   perf tools: Add a...
1119
1120
1121
1122
  			event->mmap2.len, event->mmap2.pgoff,
  			event->mmap2.pid, event->mmap2.maj,
  			event->mmap2.min, event->mmap2.ino,
  			event->mmap2.ino_generation,
7ef807034   Don Zickus   perf tools: Updat...
1123
1124
  			event->mmap2.prot,
  			event->mmap2.flags,
5835eddab   Adrian Hunter   perf tools: Add t...
1125
  			event->mmap2.filename, type, thread);
5c5e854bc   Stephane Eranian   perf tools: Add a...
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  
  	if (map == NULL)
  		goto out_problem;
  
  	thread__insert_map(thread, map);
  	return 0;
  
  out_problem:
  	dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.
  ");
  	return 0;
  }
162f0befd   Frederic Weisbecker   perf tools: Add t...
1138
1139
  int machine__process_mmap_event(struct machine *machine, union perf_event *event,
  				struct perf_sample *sample __maybe_unused)
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1140
1141
1142
1143
  {
  	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
  	struct thread *thread;
  	struct map *map;
bad409179   Stephane Eranian   perf machine: Det...
1144
  	enum map_type type;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
  	int ret = 0;
  
  	if (dump_trace)
  		perf_event__fprintf_mmap(event, stdout);
  
  	if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
  	    cpumode == PERF_RECORD_MISC_KERNEL) {
  		ret = machine__process_kernel_mmap_event(machine, event);
  		if (ret < 0)
  			goto out_problem;
  		return 0;
  	}
314add6b1   Adrian Hunter   perf tools: chang...
1157
  	thread = machine__findnew_thread(machine, event->mmap.pid,
11c9abf22   Don Zickus   perf tools: Use t...
1158
  					 event->mmap.tid);
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1159
1160
  	if (thread == NULL)
  		goto out_problem;
bad409179   Stephane Eranian   perf machine: Det...
1161
1162
1163
1164
1165
  
  	if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
  		type = MAP__VARIABLE;
  	else
  		type = MAP__FUNCTION;
2a03068c5   Adrian Hunter   perf tools: Pass ...
1166
  	map = map__new(machine, event->mmap.start,
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1167
  			event->mmap.len, event->mmap.pgoff,
7ef807034   Don Zickus   perf tools: Updat...
1168
  			event->mmap.pid, 0, 0, 0, 0, 0, 0,
5c5e854bc   Stephane Eranian   perf tools: Add a...
1169
  			event->mmap.filename,
5835eddab   Adrian Hunter   perf tools: Add t...
1170
  			type, thread);
bad409179   Stephane Eranian   perf machine: Det...
1171

b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
  	if (map == NULL)
  		goto out_problem;
  
  	thread__insert_map(thread, map);
  	return 0;
  
  out_problem:
  	dump_printf("problem processing PERF_RECORD_MMAP, skipping event.
  ");
  	return 0;
  }
236a3bbd5   David Ahern   perf tools: Sampl...
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
  static void machine__remove_thread(struct machine *machine, struct thread *th)
  {
  	machine->last_match = NULL;
  	rb_erase(&th->rb_node, &machine->threads);
  	/*
  	 * We may have references to this thread, for instance in some hist_entry
  	 * instances, so just move them to a separate list.
  	 */
  	list_add_tail(&th->node, &machine->dead_threads);
  }
162f0befd   Frederic Weisbecker   perf tools: Add t...
1193
1194
  int machine__process_fork_event(struct machine *machine, union perf_event *event,
  				struct perf_sample *sample)
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1195
  {
d75e6097e   Jiri Olsa   perf machine: Fac...
1196
1197
1198
  	struct thread *thread = machine__find_thread(machine,
  						     event->fork.pid,
  						     event->fork.tid);
314add6b1   Adrian Hunter   perf tools: chang...
1199
1200
1201
  	struct thread *parent = machine__findnew_thread(machine,
  							event->fork.ppid,
  							event->fork.ptid);
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1202

236a3bbd5   David Ahern   perf tools: Sampl...
1203
1204
1205
  	/* if a thread currently exists for the thread id remove it */
  	if (thread != NULL)
  		machine__remove_thread(machine, thread);
314add6b1   Adrian Hunter   perf tools: chang...
1206
1207
  	thread = machine__findnew_thread(machine, event->fork.pid,
  					 event->fork.tid);
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1208
1209
1210
1211
  	if (dump_trace)
  		perf_event__fprintf_task(event, stdout);
  
  	if (thread == NULL || parent == NULL ||
162f0befd   Frederic Weisbecker   perf tools: Add t...
1212
  	    thread__fork(thread, parent, sample->time) < 0) {
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1213
1214
1215
1216
1217
1218
1219
  		dump_printf("problem processing PERF_RECORD_FORK, skipping event.
  ");
  		return -1;
  	}
  
  	return 0;
  }
162f0befd   Frederic Weisbecker   perf tools: Add t...
1220
1221
  int machine__process_exit_event(struct machine *machine, union perf_event *event,
  				struct perf_sample *sample __maybe_unused)
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1222
  {
d75e6097e   Jiri Olsa   perf machine: Fac...
1223
1224
1225
  	struct thread *thread = machine__find_thread(machine,
  						     event->fork.pid,
  						     event->fork.tid);
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1226
1227
1228
1229
1230
  
  	if (dump_trace)
  		perf_event__fprintf_task(event, stdout);
  
  	if (thread != NULL)
236a3bbd5   David Ahern   perf tools: Sampl...
1231
  		thread__exited(thread);
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1232
1233
1234
  
  	return 0;
  }
162f0befd   Frederic Weisbecker   perf tools: Add t...
1235
1236
  int machine__process_event(struct machine *machine, union perf_event *event,
  			   struct perf_sample *sample)
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1237
1238
1239
1240
1241
  {
  	int ret;
  
  	switch (event->header.type) {
  	case PERF_RECORD_COMM:
162f0befd   Frederic Weisbecker   perf tools: Add t...
1242
  		ret = machine__process_comm_event(machine, event, sample); break;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1243
  	case PERF_RECORD_MMAP:
162f0befd   Frederic Weisbecker   perf tools: Add t...
1244
  		ret = machine__process_mmap_event(machine, event, sample); break;
5c5e854bc   Stephane Eranian   perf tools: Add a...
1245
  	case PERF_RECORD_MMAP2:
162f0befd   Frederic Weisbecker   perf tools: Add t...
1246
  		ret = machine__process_mmap2_event(machine, event, sample); break;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1247
  	case PERF_RECORD_FORK:
162f0befd   Frederic Weisbecker   perf tools: Add t...
1248
  		ret = machine__process_fork_event(machine, event, sample); break;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1249
  	case PERF_RECORD_EXIT:
162f0befd   Frederic Weisbecker   perf tools: Add t...
1250
  		ret = machine__process_exit_event(machine, event, sample); break;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1251
  	case PERF_RECORD_LOST:
162f0befd   Frederic Weisbecker   perf tools: Add t...
1252
  		ret = machine__process_lost_event(machine, event, sample); break;
b0a7d1a0c   Arnaldo Carvalho de Melo   perf machine: Car...
1253
1254
1255
1256
1257
1258
1259
  	default:
  		ret = -1;
  		break;
  	}
  
  	return ret;
  }
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1260

b21484f1a   Greg Price   perf report/top: ...
1261
  static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1262
  {
b21484f1a   Greg Price   perf report/top: ...
1263
  	if (sym->name && !regexec(regex, sym->name, 0, NULL, 0))
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1264
  		return 1;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1265
1266
  	return 0;
  }
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1267
  static void ip__resolve_ams(struct thread *thread,
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1268
1269
1270
1271
  			    struct addr_map_symbol *ams,
  			    u64 ip)
  {
  	struct addr_location al;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1272
1273
  
  	memset(&al, 0, sizeof(al));
52a3cb8cf   Arnaldo Carvalho de Melo   perf symbols: Int...
1274
1275
1276
1277
1278
1279
1280
  	/*
  	 * We cannot use the header.misc hint to determine whether a
  	 * branch stack address is user, kernel, guest, hypervisor.
  	 * Branches may straddle the kernel/user/hypervisor boundaries.
  	 * Thus, we have to try consecutively until we find a match
  	 * or else, the symbol is unknown
  	 */
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1281
  	thread__find_cpumode_addr_location(thread, MAP__FUNCTION, ip, &al);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1282

3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1283
1284
1285
1286
1287
  	ams->addr = ip;
  	ams->al_addr = al.addr;
  	ams->sym = al.sym;
  	ams->map = al.map;
  }
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1288
  static void ip__resolve_data(struct thread *thread,
98a3b32c9   Stephane Eranian   perf tools: Add m...
1289
1290
1291
1292
1293
  			     u8 m, struct addr_map_symbol *ams, u64 addr)
  {
  	struct addr_location al;
  
  	memset(&al, 0, sizeof(al));
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1294
  	thread__find_addr_location(thread, m, MAP__VARIABLE, addr, &al);
06b2afc0b   Don Zickus   perf machine: Fal...
1295
1296
1297
1298
1299
1300
  	if (al.map == NULL) {
  		/*
  		 * some shared data regions have execute bit set which puts
  		 * their mapping in the MAP__FUNCTION type array.
  		 * Check there as a fallback option before dropping the sample.
  		 */
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1301
  		thread__find_addr_location(thread, m, MAP__FUNCTION, addr, &al);
06b2afc0b   Don Zickus   perf machine: Fal...
1302
  	}
98a3b32c9   Stephane Eranian   perf tools: Add m...
1303
1304
1305
1306
1307
  	ams->addr = addr;
  	ams->al_addr = al.addr;
  	ams->sym = al.sym;
  	ams->map = al.map;
  }
e80faac04   Arnaldo Carvalho de Melo   perf tools: Short...
1308
1309
  struct mem_info *sample__resolve_mem(struct perf_sample *sample,
  				     struct addr_location *al)
98a3b32c9   Stephane Eranian   perf tools: Add m...
1310
1311
1312
1313
1314
  {
  	struct mem_info *mi = zalloc(sizeof(*mi));
  
  	if (!mi)
  		return NULL;
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1315
1316
  	ip__resolve_ams(al->thread, &mi->iaddr, sample->ip);
  	ip__resolve_data(al->thread, al->cpumode, &mi->daddr, sample->addr);
98a3b32c9   Stephane Eranian   perf tools: Add m...
1317
1318
1319
1320
  	mi->data_src.val = sample->data_src;
  
  	return mi;
  }
37592b8af   Andi Kleen   perf callchain: F...
1321
1322
1323
  static int add_callchain_ip(struct thread *thread,
  			    struct symbol **parent,
  			    struct addr_location *root_al,
2e77784bb   Kan Liang   perf callchain: M...
1324
  			    bool branch_history,
37592b8af   Andi Kleen   perf callchain: F...
1325
1326
1327
1328
1329
1330
  			    u64 ip)
  {
  	struct addr_location al;
  
  	al.filtered = 0;
  	al.sym = NULL;
2e77784bb   Kan Liang   perf callchain: M...
1331
  	if (branch_history)
8b7bad58e   Andi Kleen   perf callchain: S...
1332
1333
  		thread__find_cpumode_addr_location(thread, MAP__FUNCTION,
  						   ip, &al);
2e77784bb   Kan Liang   perf callchain: M...
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
  	else {
  		u8 cpumode = PERF_RECORD_MISC_USER;
  
  		if (ip >= PERF_CONTEXT_MAX) {
  			switch (ip) {
  			case PERF_CONTEXT_HV:
  				cpumode = PERF_RECORD_MISC_HYPERVISOR;
  				break;
  			case PERF_CONTEXT_KERNEL:
  				cpumode = PERF_RECORD_MISC_KERNEL;
  				break;
  			case PERF_CONTEXT_USER:
  				cpumode = PERF_RECORD_MISC_USER;
  				break;
  			default:
  				pr_debug("invalid callchain context: "
  					 "%"PRId64"
  ", (s64) ip);
  				/*
  				 * It seems the callchain is corrupted.
  				 * Discard all.
  				 */
  				callchain_cursor_reset(&callchain_cursor);
  				return 1;
  			}
  			return 0;
  		}
8b7bad58e   Andi Kleen   perf callchain: S...
1361
  		thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
37592b8af   Andi Kleen   perf callchain: F...
1362
  				   ip, &al);
2e77784bb   Kan Liang   perf callchain: M...
1363
  	}
37592b8af   Andi Kleen   perf callchain: F...
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
  	if (al.sym != NULL) {
  		if (sort__has_parent && !*parent &&
  		    symbol__match_regex(al.sym, &parent_regex))
  			*parent = al.sym;
  		else if (have_ignore_callees && root_al &&
  		  symbol__match_regex(al.sym, &ignore_callees_regex)) {
  			/* Treat this symbol as the root,
  			   forgetting its callees. */
  			*root_al = al;
  			callchain_cursor_reset(&callchain_cursor);
  		}
  	}
5550171b2   Andi Kleen   perf callchain: U...
1376
  	return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym);
37592b8af   Andi Kleen   perf callchain: F...
1377
  }
644f2df29   Arnaldo Carvalho de Melo   perf tools: Short...
1378
1379
  struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
  					   struct addr_location *al)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1380
  {
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1381
  	unsigned int i;
644f2df29   Arnaldo Carvalho de Melo   perf tools: Short...
1382
1383
  	const struct branch_stack *bs = sample->branch_stack;
  	struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info));
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1384

3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1385
1386
1387
1388
  	if (!bi)
  		return NULL;
  
  	for (i = 0; i < bs->nr; i++) {
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1389
1390
  		ip__resolve_ams(al->thread, &bi[i].to, bs->entries[i].to);
  		ip__resolve_ams(al->thread, &bi[i].from, bs->entries[i].from);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1391
1392
1393
1394
  		bi[i].flags = bs->entries[i].flags;
  	}
  	return bi;
  }
8b7bad58e   Andi Kleen   perf callchain: S...
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
  #define CHASHSZ 127
  #define CHASHBITS 7
  #define NO_ENTRY 0xff
  
  #define PERF_MAX_BRANCH_DEPTH 127
  
  /* Remove loops. */
  static int remove_loops(struct branch_entry *l, int nr)
  {
  	int i, j, off;
  	unsigned char chash[CHASHSZ];
  
  	memset(chash, NO_ENTRY, sizeof(chash));
  
  	BUG_ON(PERF_MAX_BRANCH_DEPTH > 255);
  
  	for (i = 0; i < nr; i++) {
  		int h = hash_64(l[i].from, CHASHBITS) % CHASHSZ;
  
  		/* no collision handling for now */
  		if (chash[h] == NO_ENTRY) {
  			chash[h] = i;
  		} else if (l[chash[h]].from == l[i].from) {
  			bool is_loop = true;
  			/* check if it is a real loop */
  			off = 0;
  			for (j = chash[h]; j < i && i + off < nr; j++, off++)
  				if (l[j].from != l[i + off].from) {
  					is_loop = false;
  					break;
  				}
  			if (is_loop) {
  				memmove(l + i, l + i + off,
  					(nr - (i + off)) * sizeof(*l));
  				nr -= off;
  			}
  		}
  	}
  	return nr;
  }
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1435
  static int thread__resolve_callchain_sample(struct thread *thread,
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1436
  					     struct ip_callchain *chain,
8b7bad58e   Andi Kleen   perf callchain: S...
1437
  					     struct branch_stack *branch,
b21484f1a   Greg Price   perf report/top: ...
1438
  					     struct symbol **parent,
91e956174   Waiman Long   perf report: Add ...
1439
1440
  					     struct addr_location *root_al,
  					     int max_stack)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1441
  {
91e956174   Waiman Long   perf report: Add ...
1442
  	int chain_nr = min(max_stack, (int)chain->nr);
2e77784bb   Kan Liang   perf callchain: M...
1443
  	int i, j, err;
8b7bad58e   Andi Kleen   perf callchain: S...
1444
1445
1446
1447
1448
1449
1450
1451
1452
  	int skip_idx = -1;
  	int first_call = 0;
  
  	/*
  	 * Based on DWARF debug information, some architectures skip
  	 * a callchain entry saved by the kernel.
  	 */
  	if (chain->nr < PERF_MAX_STACK_DEPTH)
  		skip_idx = arch_skip_callchain_idx(thread, chain);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1453
1454
  
  	callchain_cursor_reset(&callchain_cursor);
8b7bad58e   Andi Kleen   perf callchain: S...
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
  	/*
  	 * Add branches to call stack for easier browsing. This gives
  	 * more context for a sample than just the callers.
  	 *
  	 * This uses individual histograms of paths compared to the
  	 * aggregated histograms the normal LBR mode uses.
  	 *
  	 * Limitations for now:
  	 * - No extra filters
  	 * - No annotations (should annotate somehow)
  	 */
  
  	if (branch && callchain_param.branch_callstack) {
  		int nr = min(max_stack, (int)branch->nr);
  		struct branch_entry be[nr];
  
  		if (branch->nr > PERF_MAX_BRANCH_DEPTH) {
  			pr_warning("corrupted branch chain. skipping...
  ");
  			goto check_calls;
  		}
  
  		for (i = 0; i < nr; i++) {
  			if (callchain_param.order == ORDER_CALLEE) {
  				be[i] = branch->entries[i];
  				/*
  				 * Check for overlap into the callchain.
  				 * The return address is one off compared to
  				 * the branch entry. To adjust for this
  				 * assume the calling instruction is not longer
  				 * than 8 bytes.
  				 */
  				if (i == skip_idx ||
  				    chain->ips[first_call] >= PERF_CONTEXT_MAX)
  					first_call++;
  				else if (be[i].from < chain->ips[first_call] &&
  				    be[i].from >= chain->ips[first_call] - 8)
  					first_call++;
  			} else
  				be[i] = branch->entries[branch->nr - i - 1];
  		}
  
  		nr = remove_loops(be, nr);
  
  		for (i = 0; i < nr; i++) {
  			err = add_callchain_ip(thread, parent, root_al,
2e77784bb   Kan Liang   perf callchain: M...
1501
  					       true, be[i].to);
8b7bad58e   Andi Kleen   perf callchain: S...
1502
1503
  			if (!err)
  				err = add_callchain_ip(thread, parent, root_al,
2e77784bb   Kan Liang   perf callchain: M...
1504
  						       true, be[i].from);
8b7bad58e   Andi Kleen   perf callchain: S...
1505
1506
1507
1508
1509
1510
1511
1512
1513
  			if (err == -EINVAL)
  				break;
  			if (err)
  				return err;
  		}
  		chain_nr -= nr;
  	}
  
  check_calls:
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1514
1515
1516
1517
1518
  	if (chain->nr > PERF_MAX_STACK_DEPTH) {
  		pr_warning("corrupted callchain. skipping...
  ");
  		return 0;
  	}
8b7bad58e   Andi Kleen   perf callchain: S...
1519
  	for (i = first_call; i < chain_nr; i++) {
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1520
  		u64 ip;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1521
1522
  
  		if (callchain_param.order == ORDER_CALLEE)
a60335ba3   Sukadev Bhattiprolu   perf tools powerp...
1523
  			j = i;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1524
  		else
a60335ba3   Sukadev Bhattiprolu   perf tools powerp...
1525
1526
1527
1528
1529
1530
1531
  			j = chain->nr - i - 1;
  
  #ifdef HAVE_SKIP_CALLCHAIN_IDX
  		if (j == skip_idx)
  			continue;
  #endif
  		ip = chain->ips[j];
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1532

2e77784bb   Kan Liang   perf callchain: M...
1533
  		err = add_callchain_ip(thread, parent, root_al, false, ip);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1534

3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1535
  		if (err)
2e77784bb   Kan Liang   perf callchain: M...
1536
  			return (err < 0) ? err : 0;
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
  	}
  
  	return 0;
  }
  
  static int unwind_entry(struct unwind_entry *entry, void *arg)
  {
  	struct callchain_cursor *cursor = arg;
  	return callchain_cursor_append(cursor, entry->ip,
  				       entry->map, entry->sym);
  }
cc8b7c2bf   Arnaldo Carvalho de Melo   perf thread: Adop...
1548
1549
1550
1551
1552
1553
  int thread__resolve_callchain(struct thread *thread,
  			      struct perf_evsel *evsel,
  			      struct perf_sample *sample,
  			      struct symbol **parent,
  			      struct addr_location *root_al,
  			      int max_stack)
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1554
  {
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1555
  	int ret = thread__resolve_callchain_sample(thread, sample->callchain,
8b7bad58e   Andi Kleen   perf callchain: S...
1556
  						   sample->branch_stack,
bb871a9c8   Arnaldo Carvalho de Melo   perf tools: A thr...
1557
  						   parent, root_al, max_stack);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
  	if (ret)
  		return ret;
  
  	/* Can we do dwarf post unwind? */
  	if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
  	      (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
  		return 0;
  
  	/* Bail out if nothing was captured. */
  	if ((!sample->user_regs.regs) ||
  	    (!sample->user_stack.size))
  		return 0;
dd8c17a5f   Arnaldo Carvalho de Melo   perf callchains: ...
1570
  	return unwind__get_entries(unwind_entry, &callchain_cursor,
352ea45a7   Jiri Olsa   perf callchain: A...
1571
  				   thread, sample, max_stack);
3f067dcab   Arnaldo Carvalho de Melo   perf machine: Mov...
1572
1573
  
  }
35feee19f   David Ahern   perf machine: Add...
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
  
  int machine__for_each_thread(struct machine *machine,
  			     int (*fn)(struct thread *thread, void *p),
  			     void *priv)
  {
  	struct rb_node *nd;
  	struct thread *thread;
  	int rc = 0;
  
  	for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
  		thread = rb_entry(nd, struct thread, rb_node);
  		rc = fn(thread, priv);
  		if (rc != 0)
  			return rc;
  	}
  
  	list_for_each_entry(thread, &machine->dead_threads, node) {
  		rc = fn(thread, priv);
  		if (rc != 0)
  			return rc;
  	}
  	return rc;
  }
58d925dce   Arnaldo Carvalho de Melo   perf machine: Int...
1597

a33fbd56e   Arnaldo Carvalho de Melo   perf machine: Sim...
1598
  int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
602ad878d   Arnaldo Carvalho de Melo   perf target: Shor...
1599
  				  struct target *target, struct thread_map *threads,
a33fbd56e   Arnaldo Carvalho de Melo   perf machine: Sim...
1600
  				  perf_event__handler_t process, bool data_mmap)
58d925dce   Arnaldo Carvalho de Melo   perf machine: Int...
1601
  {
602ad878d   Arnaldo Carvalho de Melo   perf target: Shor...
1602
  	if (target__has_task(target))
58d925dce   Arnaldo Carvalho de Melo   perf machine: Int...
1603
  		return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap);
602ad878d   Arnaldo Carvalho de Melo   perf target: Shor...
1604
  	else if (target__has_cpu(target))
58d925dce   Arnaldo Carvalho de Melo   perf machine: Int...
1605
1606
1607
1608
  		return perf_event__synthesize_threads(tool, process, machine, data_mmap);
  	/* command specified */
  	return 0;
  }
b9d266baa   Adrian Hunter   perf machine: Add...
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
  
  pid_t machine__get_current_tid(struct machine *machine, int cpu)
  {
  	if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid)
  		return -1;
  
  	return machine->current_tid[cpu];
  }
  
  int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
  			     pid_t tid)
  {
  	struct thread *thread;
  
  	if (cpu < 0)
  		return -EINVAL;
  
  	if (!machine->current_tid) {
  		int i;
  
  		machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t));
  		if (!machine->current_tid)
  			return -ENOMEM;
  		for (i = 0; i < MAX_NR_CPUS; i++)
  			machine->current_tid[i] = -1;
  	}
  
  	if (cpu >= MAX_NR_CPUS) {
  		pr_err("Requested CPU %d too large. ", cpu);
  		pr_err("Consider raising MAX_NR_CPUS
  ");
  		return -EINVAL;
  	}
  
  	machine->current_tid[cpu] = tid;
  
  	thread = machine__findnew_thread(machine, pid, tid);
  	if (!thread)
  		return -ENOMEM;
  
  	thread->cpu = cpu;
  
  	return 0;
  }
fbe2af45f   Adrian Hunter   perf tools: Add m...
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
  
  int machine__get_kernel_start(struct machine *machine)
  {
  	struct map *map = machine__kernel_map(machine, MAP__FUNCTION);
  	int err = 0;
  
  	/*
  	 * The only addresses above 2^63 are kernel addresses of a 64-bit
  	 * kernel.  Note that addresses are unsigned so that on a 32-bit system
  	 * all addresses including kernel addresses are less than 2^32.  In
  	 * that case (32-bit system), if the kernel mapping is unknown, all
  	 * addresses will be assumed to be in user space - see
  	 * machine__kernel_ip().
  	 */
  	machine->kernel_start = 1ULL << 63;
  	if (map) {
  		err = map__load(map, machine->symbol_filter);
  		if (map->start)
  			machine->kernel_start = map->start;
  	}
  	return err;
  }