brintos

brintos / linux-shallow public Read only

0
0
Text · 7.4 KiB · c12f5d8 Raw
370 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <errno.h>3#include <unistd.h>4#include <stdio.h>5#include <string.h>6#include <sys/types.h>7#include <sys/stat.h>8#include <fcntl.h>9#include <stdlib.h>10#include <linux/kernel.h>11 12#include "vdso.h"13#include "dso.h"14#include <internal/lib.h>15#include "map.h"16#include "symbol.h"17#include "machine.h"18#include "thread.h"19#include "linux/string.h"20#include <linux/zalloc.h>21#include "debug.h"22 23/*24 * Include definition of find_map() also used in perf-read-vdso.c for25 * building perf-read-vdso32 and perf-read-vdsox32.26 */27#include "find-map.c"28 29#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"30 31struct vdso_file {32	bool found;33	bool error;34	char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];35	const char *dso_name;36	const char *read_prog;37};38 39struct vdso_info {40	struct vdso_file vdso;41#if BITS_PER_LONG == 6442	struct vdso_file vdso32;43	struct vdso_file vdsox32;44#endif45};46 47static struct vdso_info *vdso_info__new(void)48{49	static const struct vdso_info vdso_info_init = {50		.vdso    = {51			.temp_file_name = VDSO__TEMP_FILE_NAME,52			.dso_name = DSO__NAME_VDSO,53		},54#if BITS_PER_LONG == 6455		.vdso32  = {56			.temp_file_name = VDSO__TEMP_FILE_NAME,57			.dso_name = DSO__NAME_VDSO32,58			.read_prog = "perf-read-vdso32",59		},60		.vdsox32  = {61			.temp_file_name = VDSO__TEMP_FILE_NAME,62			.dso_name = DSO__NAME_VDSOX32,63			.read_prog = "perf-read-vdsox32",64		},65#endif66	};67 68	return memdup(&vdso_info_init, sizeof(vdso_info_init));69}70 71static char *get_file(struct vdso_file *vdso_file)72{73	char *vdso = NULL;74	char *buf = NULL;75	void *start, *end;76	size_t size;77	int fd;78 79	if (vdso_file->found)80		return vdso_file->temp_file_name;81 82	if (vdso_file->error || find_map(&start, &end, VDSO__MAP_NAME))83		return NULL;84 85	size = end - start;86 87	buf = memdup(start, size);88	if (!buf)89		return NULL;90 91	fd = mkstemp(vdso_file->temp_file_name);92	if (fd < 0)93		goto out;94 95	if (size == (size_t) write(fd, buf, size))96		vdso = vdso_file->temp_file_name;97 98	close(fd);99 100 out:101	free(buf);102 103	vdso_file->found = (vdso != NULL);104	vdso_file->error = !vdso_file->found;105	return vdso;106}107 108void machine__exit_vdso(struct machine *machine)109{110	struct vdso_info *vdso_info = machine->vdso_info;111 112	if (!vdso_info)113		return;114 115	if (vdso_info->vdso.found)116		unlink(vdso_info->vdso.temp_file_name);117#if BITS_PER_LONG == 64118	if (vdso_info->vdso32.found)119		unlink(vdso_info->vdso32.temp_file_name);120	if (vdso_info->vdsox32.found)121		unlink(vdso_info->vdsox32.temp_file_name);122#endif123 124	zfree(&machine->vdso_info);125}126 127static struct dso *__machine__addnew_vdso(struct machine *machine, const char *short_name,128					  const char *long_name)129{130	struct dso *dso;131 132	dso = dso__new(short_name);133	if (dso != NULL) {134		__dsos__add(&machine->dsos, dso);135		dso__set_long_name(dso, long_name, false);136	}137 138	return dso;139}140 141struct machine__thread_dso_type_maps_cb_args {142	struct machine *machine;143	enum dso_type dso_type;144};145 146static int machine__thread_dso_type_maps_cb(struct map *map, void *data)147{148	struct machine__thread_dso_type_maps_cb_args *args = data;149	struct dso *dso = map__dso(map);150 151	if (!dso || dso__long_name(dso)[0] != '/')152		return 0;153 154	args->dso_type = dso__type(dso, args->machine);155	return (args->dso_type != DSO__TYPE_UNKNOWN) ? 1 : 0;156}157 158static enum dso_type machine__thread_dso_type(struct machine *machine,159					      struct thread *thread)160{161	struct machine__thread_dso_type_maps_cb_args args = {162		.machine = machine,163		.dso_type = DSO__TYPE_UNKNOWN,164	};165 166	maps__for_each_map(thread__maps(thread), machine__thread_dso_type_maps_cb, &args);167 168	return args.dso_type;169}170 171#if BITS_PER_LONG == 64172 173static int vdso__do_copy_compat(FILE *f, int fd)174{175	char buf[4096];176	size_t count;177 178	while (1) {179		count = fread(buf, 1, sizeof(buf), f);180		if (ferror(f))181			return -errno;182		if (feof(f))183			break;184		if (count && writen(fd, buf, count) != (ssize_t)count)185			return -errno;186	}187 188	return 0;189}190 191static int vdso__copy_compat(const char *prog, int fd)192{193	FILE *f;194	int err;195 196	f = popen(prog, "r");197	if (!f)198		return -errno;199 200	err = vdso__do_copy_compat(f, fd);201 202	if (pclose(f) == -1)203		return -errno;204 205	return err;206}207 208static int vdso__create_compat_file(const char *prog, char *temp_name)209{210	int fd, err;211 212	fd = mkstemp(temp_name);213	if (fd < 0)214		return -errno;215 216	err = vdso__copy_compat(prog, fd);217 218	if (close(fd) == -1)219		return -errno;220 221	return err;222}223 224static const char *vdso__get_compat_file(struct vdso_file *vdso_file)225{226	int err;227 228	if (vdso_file->found)229		return vdso_file->temp_file_name;230 231	if (vdso_file->error)232		return NULL;233 234	err = vdso__create_compat_file(vdso_file->read_prog,235				       vdso_file->temp_file_name);236	if (err) {237		pr_err("%s failed, error %d\n", vdso_file->read_prog, err);238		vdso_file->error = true;239		return NULL;240	}241 242	vdso_file->found = true;243 244	return vdso_file->temp_file_name;245}246 247static struct dso *__machine__findnew_compat(struct machine *machine,248					     struct vdso_file *vdso_file)249{250	const char *file_name;251	struct dso *dso;252 253	dso = dsos__find(&machine->dsos, vdso_file->dso_name, true);254	if (dso)255		return dso;256 257	file_name = vdso__get_compat_file(vdso_file);258	if (!file_name)259		return NULL;260 261	return __machine__addnew_vdso(machine, vdso_file->dso_name, file_name);262}263 264static int __machine__findnew_vdso_compat(struct machine *machine,265					  struct thread *thread,266					  struct vdso_info *vdso_info,267					  struct dso **dso)268{269	enum dso_type dso_type;270 271	dso_type = machine__thread_dso_type(machine, thread);272 273#ifndef HAVE_PERF_READ_VDSO32274	if (dso_type == DSO__TYPE_32BIT)275		return 0;276#endif277#ifndef HAVE_PERF_READ_VDSOX32278	if (dso_type == DSO__TYPE_X32BIT)279		return 0;280#endif281 282	switch (dso_type) {283	case DSO__TYPE_32BIT:284		*dso = __machine__findnew_compat(machine, &vdso_info->vdso32);285		return 1;286	case DSO__TYPE_X32BIT:287		*dso = __machine__findnew_compat(machine, &vdso_info->vdsox32);288		return 1;289	case DSO__TYPE_UNKNOWN:290	case DSO__TYPE_64BIT:291	default:292		return 0;293	}294}295 296#endif297 298static struct dso *machine__find_vdso(struct machine *machine,299				      struct thread *thread)300{301	struct dso *dso = NULL;302	enum dso_type dso_type;303 304	dso_type = machine__thread_dso_type(machine, thread);305	switch (dso_type) {306	case DSO__TYPE_32BIT:307		dso = dsos__find(&machine->dsos, DSO__NAME_VDSO32, true);308		if (!dso) {309			dso = dsos__find(&machine->dsos, DSO__NAME_VDSO,310					 true);311			if (dso && dso_type != dso__type(dso, machine)) {312				dso__put(dso);313				dso = NULL;314			}315		}316		break;317	case DSO__TYPE_X32BIT:318		dso = dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true);319		break;320	case DSO__TYPE_64BIT:321	case DSO__TYPE_UNKNOWN:322	default:323		dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true);324		break;325	}326 327	return dso;328}329 330struct dso *machine__findnew_vdso(struct machine *machine,331				  struct thread *thread)332{333	struct vdso_info *vdso_info;334	struct dso *dso = NULL;335	char *file;336 337	if (!machine->vdso_info)338		machine->vdso_info = vdso_info__new();339 340	vdso_info = machine->vdso_info;341	if (!vdso_info)342		return NULL;343 344	dso = machine__find_vdso(machine, thread);345	if (dso)346		return dso;347 348#if BITS_PER_LONG == 64349	if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso))350		return dso;351#endif352 353	dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true);354	if (dso)355		return dso;356 357	file = get_file(&vdso_info->vdso);358	if (!file)359		return NULL;360 361	return __machine__addnew_vdso(machine, DSO__NAME_VDSO, file);362}363 364bool dso__is_vdso(struct dso *dso)365{366	return !strcmp(dso__short_name(dso), DSO__NAME_VDSO) ||367	       !strcmp(dso__short_name(dso), DSO__NAME_VDSO32) ||368	       !strcmp(dso__short_name(dso), DSO__NAME_VDSOX32);369}370