9 int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
11 map_groups__init(&machine->kmaps);
12 RB_CLEAR_NODE(&machine->rb_node);
13 INIT_LIST_HEAD(&machine->user_dsos);
14 INIT_LIST_HEAD(&machine->kernel_dsos);
16 machine->threads = RB_ROOT;
17 INIT_LIST_HEAD(&machine->dead_threads);
18 machine->last_match = NULL;
20 machine->kmaps.machine = machine;
23 machine->root_dir = strdup(root_dir);
24 if (machine->root_dir == NULL)
27 if (pid != HOST_KERNEL_ID) {
28 struct thread *thread = machine__findnew_thread(machine, pid);
34 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
35 thread__set_comm(thread, comm);
41 static void dsos__delete(struct list_head *dsos)
45 list_for_each_entry_safe(pos, n, dsos, node) {
51 void machine__exit(struct machine *machine)
53 map_groups__exit(&machine->kmaps);
54 dsos__delete(&machine->user_dsos);
55 dsos__delete(&machine->kernel_dsos);
56 free(machine->root_dir);
57 machine->root_dir = NULL;
60 void machine__delete(struct machine *machine)
62 machine__exit(machine);
66 struct machine *machines__add(struct rb_root *machines, pid_t pid,
69 struct rb_node **p = &machines->rb_node;
70 struct rb_node *parent = NULL;
71 struct machine *pos, *machine = malloc(sizeof(*machine));
76 if (machine__init(machine, root_dir, pid) != 0) {
83 pos = rb_entry(parent, struct machine, rb_node);
90 rb_link_node(&machine->rb_node, parent, p);
91 rb_insert_color(&machine->rb_node, machines);
96 struct machine *machines__find(struct rb_root *machines, pid_t pid)
98 struct rb_node **p = &machines->rb_node;
99 struct rb_node *parent = NULL;
100 struct machine *machine;
101 struct machine *default_machine = NULL;
105 machine = rb_entry(parent, struct machine, rb_node);
106 if (pid < machine->pid)
108 else if (pid > machine->pid)
113 default_machine = machine;
116 return default_machine;
119 struct machine *machines__findnew(struct rb_root *machines, pid_t pid)
122 const char *root_dir = "";
123 struct machine *machine = machines__find(machines, pid);
125 if (machine && (machine->pid == pid))
128 if ((pid != HOST_KERNEL_ID) &&
129 (pid != DEFAULT_GUEST_KERNEL_ID) &&
130 (symbol_conf.guestmount)) {
131 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
132 if (access(path, R_OK)) {
133 static struct strlist *seen;
136 seen = strlist__new(true, NULL);
138 if (!strlist__has_entry(seen, path)) {
139 pr_err("Can't access file %s\n", path);
140 strlist__add(seen, path);
148 machine = machines__add(machines, pid, root_dir);
153 void machines__process(struct rb_root *machines,
154 machine__process_t process, void *data)
158 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
159 struct machine *pos = rb_entry(nd, struct machine, rb_node);
164 char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
166 if (machine__is_host(machine))
167 snprintf(bf, size, "[%s]", "kernel.kallsyms");
168 else if (machine__is_default_guest(machine))
169 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
171 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms",
178 void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
180 struct rb_node *node;
181 struct machine *machine;
183 for (node = rb_first(machines); node; node = rb_next(node)) {
184 machine = rb_entry(node, struct machine, rb_node);
185 machine->id_hdr_size = id_hdr_size;
191 static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid,
194 struct rb_node **p = &machine->threads.rb_node;
195 struct rb_node *parent = NULL;
199 * Font-end cache - PID lookups come in blocks,
200 * so most of the time we dont have to look up
203 if (machine->last_match && machine->last_match->pid == pid)
204 return machine->last_match;
208 th = rb_entry(parent, struct thread, rb_node);
210 if (th->pid == pid) {
211 machine->last_match = th;
224 th = thread__new(pid);
226 rb_link_node(&th->rb_node, parent, p);
227 rb_insert_color(&th->rb_node, &machine->threads);
228 machine->last_match = th;
234 struct thread *machine__findnew_thread(struct machine *machine, pid_t pid)
236 return __machine__findnew_thread(machine, pid, true);
239 struct thread *machine__find_thread(struct machine *machine, pid_t pid)
241 return __machine__findnew_thread(machine, pid, false);
244 int machine__process_comm_event(struct machine *machine, union perf_event *event)
246 struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
249 perf_event__fprintf_comm(event, stdout);
251 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
252 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
259 int machine__process_lost_event(struct machine *machine __maybe_unused,
260 union perf_event *event)
262 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
263 event->lost.id, event->lost.lost);
267 static void machine__set_kernel_mmap_len(struct machine *machine,
268 union perf_event *event)
272 for (i = 0; i < MAP__NR_TYPES; i++) {
273 machine->vmlinux_maps[i]->start = event->mmap.start;
274 machine->vmlinux_maps[i]->end = (event->mmap.start +
277 * Be a bit paranoid here, some perf.data file came with
278 * a zero sized synthesized MMAP event for the kernel.
280 if (machine->vmlinux_maps[i]->end == 0)
281 machine->vmlinux_maps[i]->end = ~0ULL;
285 static int machine__process_kernel_mmap_event(struct machine *machine,
286 union perf_event *event)
289 char kmmap_prefix[PATH_MAX];
290 enum dso_kernel_type kernel_type;
293 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
294 if (machine__is_host(machine))
295 kernel_type = DSO_TYPE_KERNEL;
297 kernel_type = DSO_TYPE_GUEST_KERNEL;
299 is_kernel_mmap = memcmp(event->mmap.filename,
301 strlen(kmmap_prefix) - 1) == 0;
302 if (event->mmap.filename[0] == '/' ||
303 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
305 char short_module_name[1024];
308 if (event->mmap.filename[0] == '/') {
309 name = strrchr(event->mmap.filename, '/');
314 dot = strrchr(name, '.');
317 snprintf(short_module_name, sizeof(short_module_name),
318 "[%.*s]", (int)(dot - name), name);
319 strxfrchar(short_module_name, '-', '_');
321 strcpy(short_module_name, event->mmap.filename);
323 map = machine__new_module(machine, event->mmap.start,
324 event->mmap.filename);
328 name = strdup(short_module_name);
332 map->dso->short_name = name;
333 map->dso->sname_alloc = 1;
334 map->end = map->start + event->mmap.len;
335 } else if (is_kernel_mmap) {
336 const char *symbol_name = (event->mmap.filename +
337 strlen(kmmap_prefix));
339 * Should be there already, from the build-id table in
342 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
347 kernel->kernel = kernel_type;
348 if (__machine__create_kernel_maps(machine, kernel) < 0)
351 machine__set_kernel_mmap_len(machine, event);
354 * Avoid using a zero address (kptr_restrict) for the ref reloc
355 * symbol. Effectively having zero here means that at record
356 * time /proc/sys/kernel/kptr_restrict was non zero.
358 if (event->mmap.pgoff != 0) {
359 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
364 if (machine__is_default_guest(machine)) {
366 * preload dso of guest kernel and modules
368 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
377 int machine__process_mmap_event(struct machine *machine, union perf_event *event)
379 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
380 struct thread *thread;
385 perf_event__fprintf_mmap(event, stdout);
387 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
388 cpumode == PERF_RECORD_MISC_KERNEL) {
389 ret = machine__process_kernel_mmap_event(machine, event);
395 thread = machine__findnew_thread(machine, event->mmap.pid);
398 map = map__new(&machine->user_dsos, event->mmap.start,
399 event->mmap.len, event->mmap.pgoff,
400 event->mmap.pid, event->mmap.filename,
405 thread__insert_map(thread, map);
409 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
413 int machine__process_fork_event(struct machine *machine, union perf_event *event)
415 struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
416 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
419 perf_event__fprintf_task(event, stdout);
421 if (thread == NULL || parent == NULL ||
422 thread__fork(thread, parent) < 0) {
423 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
430 int machine__process_exit_event(struct machine *machine, union perf_event *event)
432 struct thread *thread = machine__find_thread(machine, event->fork.tid);
435 perf_event__fprintf_task(event, stdout);
438 machine__remove_thread(machine, thread);
443 int machine__process_event(struct machine *machine, union perf_event *event)
447 switch (event->header.type) {
448 case PERF_RECORD_COMM:
449 ret = machine__process_comm_event(machine, event); break;
450 case PERF_RECORD_MMAP:
451 ret = machine__process_mmap_event(machine, event); break;
452 case PERF_RECORD_FORK:
453 ret = machine__process_fork_event(machine, event); break;
454 case PERF_RECORD_EXIT:
455 ret = machine__process_exit_event(machine, event); break;
456 case PERF_RECORD_LOST:
457 ret = machine__process_lost_event(machine, event); break;