#include "callchain.h"#include "debug.h"#include "event.h"#include "evsel.h"#include "hist.h"#include "machine.h"#include "map.h"#include "sort.h"#include "strlist.h"#include "thread.h"#include <stdbool.h>#include "unwind.h" int machine__init(struct machine *machine, const char *root_dir, pid_t pid){ map_groups__init(&machine->kmaps); RB_CLEAR_NODE(&machine->rb_node); INIT_LIST_HEAD(&machine->user_dsos); INIT_LIST_HEAD(&machine->kernel_dsos); machine->threads = RB_ROOT; INIT_LIST_HEAD(&machine->dead_threads); machine->last_match = NULL; machine->kmaps.machine = machine; machine->pid = pid; machine->symbol_filter = NULL; machine->root_dir = strdup(root_dir); if (machine->root_dir == NULL) return -ENOMEM; if (pid != HOST_KERNEL_ID) { struct thread *thread = machine__findnew_thread(machine, 0, pid); char comm[64]; if (thread == NULL) return -ENOMEM; snprintf(comm, sizeof(comm), "[guest/%d]", pid); thread__set_comm(thread, comm, 0); } return 0;} 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;} static void dsos__delete(struct list_head *dsos){ struct dso *pos, *n; list_for_each_entry_safe(pos, n, dsos, node) { list_del(&pos->node); dso__delete(pos); }} 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); }} void machine__exit(struct machine *machine){ map_groups__exit(&machine->kmaps); dsos__delete(&machine->user_dsos); dsos__delete(&machine->kernel_dsos); free(machine->root_dir); machine->root_dir = NULL;} void machine__delete(struct machine *machine){ machine__exit(machine); free(machine);} void machines__init(struct machines *machines){ machine__init(&machines->host, "", HOST_KERNEL_ID); machines->guests = RB_ROOT; machines->symbol_filter = NULL;} void machines__exit(struct machines *machines){ machine__exit(&machines->host); /* XXX exit guest */} struct machine *machines__add(struct machines *machines, pid_t pid, const char *root_dir){ struct rb_node **p = &machines->guests.rb_node; 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; } machine->symbol_filter = machines->symbol_filter; 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); rb_insert_color(&machine->rb_node, &machines->guests); return machine;} 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; }} struct machine *machines__find(struct machines *machines, pid_t pid){ struct rb_node **p = &machines->guests.rb_node; struct rb_node *parent = NULL; struct machine *machine; struct machine *default_machine = NULL; if (pid == HOST_KERNEL_ID) return &machines->host; 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;} struct machine *machines__findnew(struct machines *machines, pid_t pid){ 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\n", path); strlist__add(seen, path); } machine = NULL; goto out; } root_dir = path; } machine = machines__add(machines, pid, root_dir);out: return machine;} void machines__process_guests(struct machines *machines, machine__process_t process, void *data){ struct rb_node *nd; for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { 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;} void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size){ struct rb_node *node; struct machine *machine; machines->host.id_hdr_size = id_hdr_size; for (node = rb_first(&machines->guests); node; node = rb_next(node)) { machine = rb_entry(node, struct machine, rb_node); machine->id_hdr_size = id_hdr_size; } return;} static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid, bool create){ struct rb_node **p = &machine->threads.rb_node; struct rb_node *parent = NULL; struct thread *th; /* * Front-end cache - TID lookups come in blocks, * so most of the time we dont have to look up * the full rbtree: */ if (machine->last_match && machine->last_match->tid == tid) { if (pid && pid != machine->last_match->pid_) machine->last_match->pid_ = pid; return machine->last_match; } while (*p != NULL) { parent = *p; th = rb_entry(parent, struct thread, rb_node); if (th->tid == tid) { machine->last_match = th; if (pid && pid != th->pid_) th->pid_ = pid; return th; } if (tid < th->tid) p = &(*p)->rb_left; else p = &(*p)->rb_right; } if (!create) return NULL; th = thread__new(pid, tid); if (th != NULL) { rb_link_node(&th->rb_node, parent, p); rb_insert_color(&th->rb_node, &machine->threads); machine->last_match = th; } return th;} struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid){ return __machine__findnew_thread(machine, pid, tid, true);} struct thread *machine__find_thread(struct machine *machine, pid_t tid){ return __machine__findnew_thread(machine, 0, tid, false);} int machine__process_comm_event(struct machine *machine, union perf_event *event, struct perf_sample *sample){ struct thread *thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid); if (dump_trace) perf_event__fprintf_comm(event, stdout); if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); return -1; } return 0;} int machine__process_lost_event(struct machine *machine __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused){ dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", event->lost.id, event->lost.lost); return 0;} 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); 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; map_groups__insert(&machine->kmaps, map); return map;} size_t machines__fprintf_dsos(struct machines *machines, FILE *fp){ struct rb_node *nd; size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) + __dsos__fprintf(&machines->host.user_dsos, fp); for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += __dsos__fprintf(&pos->kernel_dsos, fp); ret += __dsos__fprintf(&pos->user_dsos, fp); } return ret;} size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm){ return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) + __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);} size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm){ struct rb_node *nd; size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { 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\n", filename); } for (i = 0; i < vmlinux_path__nr_entries; ++i) printed += fprintf(fp, "[%d] %s\n", 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;}; static int symbol__in_kernel(void *arg, const char *name, char type __maybe_unused, u64 start){ struct process_args *args = arg; if (strchr(name, '[')) return 0; args->start = start; return 1;} /* Figure out the start address of kernel map from /proc/kallsyms */static u64 machine__get_kernel_start_addr(struct machine *machine){Lines 1–500 of 1408. Load more
#include "callchain.h" #include "debug.h" #include "event.h" #include "evsel.h" #include "hist.h" #include "machine.h" #include "map.h" #include "sort.h" #include "strlist.h" #include "thread.h" #include <stdbool.h> #include "unwind.h" int machine__init(struct machine *machine, const char *root_dir, pid_t pid) { map_groups__init(&machine->kmaps); RB_CLEAR_NODE(&machine->rb_node); INIT_LIST_HEAD(&machine->user_dsos); INIT_LIST_HEAD(&machine->kernel_dsos); machine->threads = RB_ROOT; INIT_LIST_HEAD(&machine->dead_threads); machine->last_match = NULL; machine->kmaps.machine = machine; machine->pid = pid; machine->symbol_filter = NULL; machine->root_dir = strdup(root_dir); if (machine->root_dir == NULL) return -ENOMEM; if (pid != HOST_KERNEL_ID) { struct thread *thread = machine__findnew_thread(machine, 0, pid); char comm[64]; if (thread == NULL) return -ENOMEM; snprintf(comm, sizeof(comm), "[guest/%d]", pid); thread__set_comm(thread, comm, 0); } return 0; } 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; } static void dsos__delete(struct list_head *dsos) { struct dso *pos, *n; list_for_each_entry_safe(pos, n, dsos, node) { list_del(&pos->node); dso__delete(pos); } } 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); } } void machine__exit(struct machine *machine) { map_groups__exit(&machine->kmaps); dsos__delete(&machine->user_dsos); dsos__delete(&machine->kernel_dsos); free(machine->root_dir); machine->root_dir = NULL; } void machine__delete(struct machine *machine) { machine__exit(machine); free(machine); } void machines__init(struct machines *machines) { machine__init(&machines->host, "", HOST_KERNEL_ID); machines->guests = RB_ROOT; machines->symbol_filter = NULL; } void machines__exit(struct machines *machines) { machine__exit(&machines->host); /* XXX exit guest */ } struct machine *machines__add(struct machines *machines, pid_t pid, const char *root_dir) { struct rb_node **p = &machines->guests.rb_node; 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; } machine->symbol_filter = machines->symbol_filter; 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); rb_insert_color(&machine->rb_node, &machines->guests); return machine; } 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; } } struct machine *machines__find(struct machines *machines, pid_t pid) { struct rb_node **p = &machines->guests.rb_node; struct rb_node *parent = NULL; struct machine *machine; struct machine *default_machine = NULL; if (pid == HOST_KERNEL_ID) return &machines->host; 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; } struct machine *machines__findnew(struct machines *machines, pid_t pid) { 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\n", path); strlist__add(seen, path); } machine = NULL; goto out; } root_dir = path; } machine = machines__add(machines, pid, root_dir); out: return machine; } void machines__process_guests(struct machines *machines, machine__process_t process, void *data) { struct rb_node *nd; for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { 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; } void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) { struct rb_node *node; struct machine *machine; machines->host.id_hdr_size = id_hdr_size; for (node = rb_first(&machines->guests); node; node = rb_next(node)) { machine = rb_entry(node, struct machine, rb_node); machine->id_hdr_size = id_hdr_size; } return; } static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid, bool create) { struct rb_node **p = &machine->threads.rb_node; struct rb_node *parent = NULL; struct thread *th; /* * Front-end cache - TID lookups come in blocks, * so most of the time we dont have to look up * the full rbtree: */ if (machine->last_match && machine->last_match->tid == tid) { if (pid && pid != machine->last_match->pid_) machine->last_match->pid_ = pid; return machine->last_match; } while (*p != NULL) { parent = *p; th = rb_entry(parent, struct thread, rb_node); if (th->tid == tid) { machine->last_match = th; if (pid && pid != th->pid_) th->pid_ = pid; return th; } if (tid < th->tid) p = &(*p)->rb_left; else p = &(*p)->rb_right; } if (!create) return NULL; th = thread__new(pid, tid); if (th != NULL) { rb_link_node(&th->rb_node, parent, p); rb_insert_color(&th->rb_node, &machine->threads); machine->last_match = th; } return th; } struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid) { return __machine__findnew_thread(machine, pid, tid, true); } struct thread *machine__find_thread(struct machine *machine, pid_t tid) { return __machine__findnew_thread(machine, 0, tid, false); } int machine__process_comm_event(struct machine *machine, union perf_event *event, struct perf_sample *sample) { struct thread *thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid); if (dump_trace) perf_event__fprintf_comm(event, stdout); if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); return -1; } return 0; } int machine__process_lost_event(struct machine *machine __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused) { dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", event->lost.id, event->lost.lost); return 0; } 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); 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; map_groups__insert(&machine->kmaps, map); return map; } size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) { struct rb_node *nd; size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) + __dsos__fprintf(&machines->host.user_dsos, fp); for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += __dsos__fprintf(&pos->kernel_dsos, fp); ret += __dsos__fprintf(&pos->user_dsos, fp); } return ret; } size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm) { return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) + __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); } size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm) { struct rb_node *nd; size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { 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\n", filename); } for (i = 0; i < vmlinux_path__nr_entries; ++i) printed += fprintf(fp, "[%d] %s\n", 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; }; static int symbol__in_kernel(void *arg, const char *name, char type __maybe_unused, u64 start) { struct process_args *args = arg; if (strchr(name, '[')) return 0; args->start = start; return 1; } /* Figure out the start address of kernel map from /proc/kallsyms */ static u64 machine__get_kernel_start_addr(struct machine *machine) {