cregit-Linux how code gets into the kernel

Release 4.10 tools/perf/util/machine.c

Directory: tools/perf/util
#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 "vdso.h"
#include <stdbool.h>
#include <symbol/kallsyms.h>
#include "unwind.h"
#include "linux/hash.h"

static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock);


static void dsos__init(struct dsos *dsos) { INIT_LIST_HEAD(&dsos->head); dsos->root = RB_ROOT; pthread_rwlock_init(&dsos->lock, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo35100.00%2100.00%
Total35100.00%2100.00%


int machine__init(struct machine *machine, const char *root_dir, pid_t pid) { memset(machine, 0, sizeof(*machine)); map_groups__init(&machine->kmaps, machine); RB_CLEAR_NODE(&machine->rb_node); dsos__init(&machine->dsos); machine->threads = RB_ROOT; pthread_rwlock_init(&machine->threads_lock, NULL); machine->nr_threads = 0; INIT_LIST_HEAD(&machine->dead_threads); machine->last_match = NULL; machine->vdso_info = NULL; machine->env = NULL; machine->pid = pid; machine->id_hdr_size = 0; machine->kptr_restrict_warned = false; machine->comm_exec = false; machine->kernel_start = 0; memset(machine->vmlinux_maps, 0, sizeof(machine->vmlinux_maps)); 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, -1, pid); char comm[64]; if (thread == NULL) return -ENOMEM; snprintf(comm, sizeof(comm), "[guest/%d]", pid); thread__set_comm(thread, comm, 0); thread__put(thread); } machine->current_tid = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo18474.19%844.44%
adrian hunteradrian hunter2710.89%633.33%
masami hiramatsumasami hiramatsu166.45%15.56%
wang nanwang nan135.24%15.56%
jiri olsajiri olsa62.42%15.56%
frederic weisbeckerfrederic weisbecker20.81%15.56%
Total248100.00%18100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
david aherndavid ahern65100.00%1100.00%
Total65100.00%1100.00%


static void dsos__purge(struct dsos *dsos) { struct dso *pos, *n; pthread_rwlock_wrlock(&dsos->lock); list_for_each_entry_safe(pos, n, &dsos->head, node) { RB_CLEAR_NODE(&pos->rb_node); pos->root = NULL; list_del_init(&pos->node); dso__put(pos); } pthread_rwlock_unlock(&dsos->lock); }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo5878.38%350.00%
waiman longwaiman long1013.51%233.33%
adrian hunteradrian hunter68.11%116.67%
Total74100.00%6100.00%


static void dsos__exit(struct dsos *dsos) { dsos__purge(dsos); pthread_rwlock_destroy(&dsos->lock); }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo24100.00%3100.00%
Total24100.00%3100.00%


void machine__delete_threads(struct machine *machine) { struct rb_node *nd; pthread_rwlock_wrlock(&machine->threads_lock); nd = rb_first(&machine->threads); while (nd) { struct thread *t = rb_entry(nd, struct thread, rb_node); nd = rb_next(nd); __machine__remove_thread(machine, t, false); } pthread_rwlock_unlock(&machine->threads_lock); }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo78100.00%3100.00%
Total78100.00%3100.00%


void machine__exit(struct machine *machine) { machine__destroy_kernel_maps(machine); map_groups__exit(&machine->kmaps); dsos__exit(&machine->dsos); machine__exit_vdso(machine); zfree(&machine->root_dir); zfree(&machine->current_tid); pthread_rwlock_destroy(&machine->threads_lock); }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo4371.67%666.67%
adrian hunteradrian hunter1220.00%222.22%
masami hiramatsumasami hiramatsu58.33%111.11%
Total60100.00%9100.00%


void machine__delete(struct machine *machine) { if (machine) { machine__exit(machine); free(machine); } }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo26100.00%2100.00%
Total26100.00%2100.00%


void machines__init(struct machines *machines) { machine__init(&machines->host, "", HOST_KERNEL_ID); machines->guests = RB_ROOT; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo28100.00%1100.00%
Total28100.00%1100.00%


void machines__exit(struct machines *machines) { machine__exit(&machines->host); /* XXX exit guest */ }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo19100.00%1100.00%
Total19100.00%1100.00%


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; } 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; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo172100.00%2100.00%
Total172100.00%2100.00%


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; } }

Contributors

PersonTokensPropCommitsCommitProp
adrian hunteradrian hunter70100.00%1100.00%
Total70100.00%1100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo140100.00%2100.00%
Total140100.00%2100.00%


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(NULL, 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; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo174100.00%3100.00%
Total174100.00%3100.00%


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); } }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo67100.00%2100.00%
Total67100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo76100.00%1100.00%
Total76100.00%1100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo73100.00%2100.00%
Total73100.00%2100.00%


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) leader->mg = map_groups__new(machine); 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\n", th->pid_, th->tid); map_groups__put(th->mg); } th->mg = map_groups__get(leader->mg); out_put: thread__put(leader); return; out_err: pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid); goto out_put; }

Contributors

PersonTokensPropCommitsCommitProp
adrian hunteradrian hunter18392.42%120.00%
arnaldo carvalho de meloarnaldo carvalho de melo157.58%480.00%
Total198100.00%5100.00%

/* * Caller must eventually drop thread->refcnt returned with a successful * lookup/new thread inserted. */
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: */ th = machine->last_match; if (th != NULL) { if (th->tid == tid) { machine__update_thread_pid(machine, th, pid); return thread__get(th); } machine->last_match = NULL; } while (*p != NULL) { parent = *p; th = rb_entry(parent, struct thread, rb_node); if (th->tid == tid) { machine->last_match = th; machine__update_thread_pid(machine, th, pid); return thread__get(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); /* * 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. */ if (thread__init_map_groups(th, machine)) { rb_erase_init(&th->rb_node, &machine->threads); RB_CLEAR_NODE(&th->rb_node); thread__put(th); return NULL; } /* * It is now in the rbtree, get a ref */ thread__get(th); machine->last_match = th; ++machine->nr_threads; } return th; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo21172.76%753.85%
adrian hunteradrian hunter4816.55%430.77%
namhyung kimnamhyung kim186.21%17.69%
jiri olsajiri olsa134.48%17.69%
Total290100.00%13100.00%


struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid) { return ____machine__findnew_thread(machine, pid, tid, true); }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo2376.67%240.00%
adrian hunteradrian hunter723.33%360.00%
Total30100.00%5100.00%


struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid) { struct thread *th; pthread_rwlock_wrlock(&machine->threads_lock); th = __machine__findnew_thread(machine, pid, tid); pthread_rwlock_unlock(&machine->threads_lock); return th; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo53100.00%1100.00%
Total53100.00%1100.00%


struct thread *machine__find_thread(struct machine *machine, pid_t pid, pid_t tid) { struct thread *th; pthread_rwlock_rdlock(&machine->threads_lock); th = ____machine__findnew_thread(machine, pid, tid, false); pthread_rwlock_unlock(&machine->threads_lock); return th; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo4887.27%240.00%
jiri olsajiri olsa47.27%120.00%
adrian hunteradrian hunter35.45%240.00%
Total55100.00%5100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
adrian hunteradrian hunter36100.00%1100.00%
Total36100.00%1100.00%


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); bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC; int err = 0; if (exec) machine->comm_exec = true; if (dump_trace) perf_event__fprintf_comm(event, stdout); if (thread == NULL || __thread__set_comm(thread, event->comm.comm, sample->time, exec)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); err = -1; } thread__put(thread); return err; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo8368.03%233.33%
adrian hunteradrian hunter3024.59%350.00%
frederic weisbeckerfrederic weisbecker97.38%116.67%
Total122100.00%6100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo4086.96%150.00%
frederic weisbeckerfrederic weisbecker613.04%150.00%
Total46100.00%2100.00%


int machine__process_lost_samples_event(struct machine *machine __maybe_unused, union perf_event *event, struct perf_sample *sample) { dump_printf(": id:%" PRIu64 ": lost samples :%" PRIu64 "\n", sample->id, event->lost_samples.lost); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kan liangkan liang43100.00%1100.00%
Total43100.00%1100.00%


static struct dso *machine__findnew_module_dso(struct machine *machine, struct kmod_path *m, const char *filename) { struct dso *dso; pthread_rwlock_wrlock(&machine->dsos.lock); dso = __dsos__find(&machine->dsos, m->name, true); if (!dso) { dso = __dsos__addnew(&machine->dsos, m->name); if (dso == NULL) goto out_unlock; if (machine__is_host(machine)) dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; else dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; /* _KMODULE_COMP should be next to _KMODULE */ if (m->kmod && m->comp) dso->symtab_type++; dso__set_short_name(dso, strdup(m->name), true); dso__set_long_name(dso, strdup(filename), true); } dso__get(dso); out_unlock: pthread_rwlock_unlock(&machine->dsos.lock); return dso; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo9356.02%666.67%
jiri olsajiri olsa6337.95%222.22%
namhyung kimnamhyung kim106.02%111.11%
Total166100.00%9100.00%


int machine__process_aux_event(struct machine *machine __maybe_unused, union perf_event *event) { if (dump_trace) perf_event__fprintf_aux(event, stdout); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
adrian hunteradrian hunter30100.00%1100.00%
Total30100.00%1100.00%


int machine__process_itrace_start_event(struct machine *machine __maybe_unused, union perf_event *event) { if (dump_trace) perf_event__fprintf_itrace_start(event, stdout); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
adrian hunteradrian hunter30100.00%1100.00%
Total30100.00%1100.00%


int machine__process_switch_event(struct machine *machine __maybe_unused, union perf_event *event) { if (dump_trace) perf_event__fprintf_switch(event, stdout); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
adrian hunteradrian hunter30100.00%1100.00%
Total30100.00%1100.00%


static void dso__adjust_kmod_long_name(struct dso *dso, const char *filename) { const char *dup_filename; if (!filename || !dso || !dso->long_name) return; if (dso->long_name[0] != '[') return; if (!strchr(filename, '/')) return; dup_filename = strdup(filename); if (!dup_filename) return; dso__set_long_name(dso, dup_filename, true); }

Contributors

PersonTokensPropCommitsCommitProp
wang nanwang nan80100.00%2100.00%
Total80100.00%2100.00%


struct map *machine__findnew_module_map(struct machine *machine, u64 start, const char *filename) { struct map *map = NULL; struct dso *dso = NULL; struct kmod_path m; if (kmod_path__parse_name(&m, filename)) return NULL; map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION, m.name); if (map) { /* * If the map's dso is an offline module, give dso__load() * a chance to find the file path of that module by fixing * long_name. */ dso__adjust_kmod_long_name(map->dso, filename); goto out; } dso = machine__findnew_module_dso(machine, &m, filename); if (dso == NULL) goto out; map = map__new2(start, dso, MAP__FUNCTION); if (map == NULL