1408 lines · 33.3 KB · C
RawDownload
#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.