Example #1
0
int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
				       perf_event__handler_t process,
				       struct machine *machine)
{
	size_t size;
	const char *mmap_name;
	char name_buff[PATH_MAX];
	struct map *map = machine__kernel_map(machine);
	struct kmap *kmap;
	int err;
	union perf_event *event;

	if (symbol_conf.kptr_restrict)
		return -1;
	if (map == NULL)
		return -1;

	/*
	 * We should get this from /sys/kernel/sections/.text, but till that is
	 * available use this, and after it is use this as a fallback for older
	 * kernels.
	 */
	event = zalloc((sizeof(event->mmap) + machine->id_hdr_size));
	if (event == NULL) {
		pr_debug("Not enough memory synthesizing mmap event "
			 "for kernel modules\n");
		return -1;
	}

	mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
	if (machine__is_host(machine)) {
		/*
		 * kernel uses PERF_RECORD_MISC_USER for user space maps,
		 * see kernel/perf_event.c __perf_event_mmap
		 */
		event->header.misc = PERF_RECORD_MISC_KERNEL;
	} else {
		event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
	}

	kmap = map__kmap(map);
	size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
			"%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1;
	size = PERF_ALIGN(size, sizeof(u64));
	event->mmap.header.type = PERF_RECORD_MMAP;
	event->mmap.header.size = (sizeof(event->mmap) -
			(sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
	event->mmap.pgoff = kmap->ref_reloc_sym->addr;
	event->mmap.start = map->start;
	event->mmap.len   = map->end - event->mmap.start;
	event->mmap.pid   = machine->pid;

	err = perf_tool__process_synth_event(tool, event, machine, process);
	free(event);

	return err;
}
Example #2
0
int event__synthesize_kernel_mmap(event__handler_t process,
				  struct perf_session *session,
				  struct machine *machine,
				  const char *symbol_name)
{
	size_t size;
	const char *filename, *mmap_name;
	char path[PATH_MAX];
	char name_buff[PATH_MAX];
	struct map *map;

	event_t ev = {
		.header = {
			.type = PERF_RECORD_MMAP,
		},
	};
	/*
	 * We should get this from /sys/kernel/sections/.text, but till that is
	 * available use this, and after it is use this as a fallback for older
	 * kernels.
	 */
	struct process_symbol_args args = { .name = symbol_name, };

	mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
	if (machine__is_host(machine)) {
		/*
		 * kernel uses PERF_RECORD_MISC_USER for user space maps,
		 * see kernel/perf_event.c __perf_event_mmap
		 */
		ev.header.misc = PERF_RECORD_MISC_KERNEL;
		filename = "/proc/kallsyms";
	} else {
		ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
		if (machine__is_default_guest(machine))
			filename = (char *) symbol_conf.default_guest_kallsyms;
		else {
			sprintf(path, "%s/proc/kallsyms", machine->root_dir);
			filename = path;
		}
	}

	if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
		return -ENOENT;

	map = machine->vmlinux_maps[MAP__FUNCTION];
	size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
			"%s%s", mmap_name, symbol_name) + 1;
	size = ALIGN(size, sizeof(u64));
	ev.mmap.header.size = (sizeof(ev.mmap) -
			(sizeof(ev.mmap.filename) - size));
	ev.mmap.pgoff = args.start;
	ev.mmap.start = map->start;
	ev.mmap.len   = map->end - ev.mmap.start;
	ev.mmap.pid   = machine->pid;

	return process(&ev, session);
}
Example #3
0
int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
                                       struct perf_session *session,
                                       struct machine *machine,
                                       const char *symbol_name)
{
    size_t size;
    const char *filename, *mmap_name;
    char path[PATH_MAX];
    char name_buff[PATH_MAX];
    struct map *map;
    int err;
    /*
     * We should get this from /sys/kernel/sections/.text, but till that is
     * available use this, and after it is use this as a fallback for older
     * kernels.
     */
    struct process_symbol_args args = { .name = symbol_name, };
    union perf_event *event = zalloc((sizeof(event->mmap) +
                                          session->id_hdr_size));
    if (event == NULL) {
        pr_debug("Not enough memory synthesizing mmap event "
                 "for kernel modules\n");
        return -1;
    }

    mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
    if (machine__is_host(machine)) {
        /*
         * kernel uses PERF_RECORD_MISC_USER for user space maps,
         * see kernel/perf_event.c __perf_event_mmap
         */
        event->header.misc = PERF_RECORD_MISC_KERNEL;
        filename = "/proc/kallsyms";
    } else {
        event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
        if (machine__is_default_guest(machine))
            filename = (char *) symbol_conf.default_guest_kallsyms;
        else {
            sprintf(path, "%s/proc/kallsyms", machine->root_dir);
            filename = path;
        }
    }

    if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
        return -ENOENT;

    map = machine->vmlinux_maps[MAP__FUNCTION];
    size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
                    "%s%s", mmap_name, symbol_name) + 1;
    size = ALIGN(size, sizeof(u64));
    event->mmap.header.type = PERF_RECORD_MMAP;
    event->mmap.header.size = (sizeof(event->mmap) -
                               (sizeof(event->mmap.filename) - size) + session->id_hdr_size);
    event->mmap.pgoff = args.start;
    event->mmap.start = map->start;
    event->mmap.len   = map->end - event->mmap.start;
    event->mmap.pid   = machine->pid;

    err = process(event, &synth_sample, session);
    free(event);

    return err;
}
Example #4
0
static int event__process_kernel_mmap(event_t *self,
			struct perf_session *session)
{
	struct map *map;
	char kmmap_prefix[PATH_MAX];
	struct machine *machine;
	enum dso_kernel_type kernel_type;
	bool is_kernel_mmap;

	machine = perf_session__findnew_machine(session, self->mmap.pid);
	if (!machine) {
		pr_err("Can't find id %d's machine\n", self->mmap.pid);
		goto out_problem;
	}

	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(self->mmap.filename,
				kmmap_prefix,
				strlen(kmmap_prefix)) == 0;
	if (self->mmap.filename[0] == '/' ||
	    (!is_kernel_mmap && self->mmap.filename[0] == '[')) {

		char short_module_name[1024];
		char *name, *dot;

		if (self->mmap.filename[0] == '/') {
			name = strrchr(self->mmap.filename, '/');
			if (name == NULL)
				goto out_problem;

			++name; /* skip / */
			dot = strrchr(name, '.');
			if (dot == NULL)
				goto out_problem;
			snprintf(short_module_name, sizeof(short_module_name),
					"[%.*s]", (int)(dot - name), name);
			strxfrchar(short_module_name, '-', '_');
		} else
			strcpy(short_module_name, self->mmap.filename);

		map = machine__new_module(machine, self->mmap.start,
					  self->mmap.filename);
		if (map == NULL)
			goto out_problem;

		name = strdup(short_module_name);
		if (name == NULL)
			goto out_problem;

		map->dso->short_name = name;
		map->end = map->start + self->mmap.len;
	} else if (is_kernel_mmap) {
		const char *symbol_name = (self->mmap.filename +
				strlen(kmmap_prefix));
		/*
		 * Should be there already, from the build-id table in
		 * the header.
		 */
		struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
						     kmmap_prefix);
		if (kernel == NULL)
			goto out_problem;

		kernel->kernel = kernel_type;
		if (__machine__create_kernel_maps(machine, kernel) < 0)
			goto out_problem;

		event_set_kernel_mmap_len(machine->vmlinux_maps, self);
		perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
							 symbol_name,
							 self->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;
}