1 2 #include <unistd.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 #include <stdlib.h> 9 #include <linux/kernel.h> 10 11 #include "vdso.h" 12 #include "util.h" 13 #include "symbol.h" 14 #include "machine.h" 15 #include "linux/string.h" 16 #include "debug.h" 17 18 #define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX" 19 20 struct vdso_file { 21 bool found; 22 bool error; 23 char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)]; 24 const char *dso_name; 25 }; 26 27 struct vdso_info { 28 struct vdso_file vdso; 29 }; 30 31 static struct vdso_info *vdso_info__new(void) 32 { 33 static const struct vdso_info vdso_info_init = { 34 .vdso = { 35 .temp_file_name = VDSO__TEMP_FILE_NAME, 36 .dso_name = DSO__NAME_VDSO, 37 }, 38 }; 39 40 return memdup(&vdso_info_init, sizeof(vdso_info_init)); 41 } 42 43 static int find_vdso_map(void **start, void **end) 44 { 45 FILE *maps; 46 char line[128]; 47 int found = 0; 48 49 maps = fopen("/proc/self/maps", "r"); 50 if (!maps) { 51 pr_err("vdso: cannot open maps\n"); 52 return -1; 53 } 54 55 while (!found && fgets(line, sizeof(line), maps)) { 56 int m = -1; 57 58 /* We care only about private r-x mappings. */ 59 if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n", 60 start, end, &m)) 61 continue; 62 if (m < 0) 63 continue; 64 65 if (!strncmp(&line[m], VDSO__MAP_NAME, 66 sizeof(VDSO__MAP_NAME) - 1)) 67 found = 1; 68 } 69 70 fclose(maps); 71 return !found; 72 } 73 74 static char *get_file(struct vdso_file *vdso_file) 75 { 76 char *vdso = NULL; 77 char *buf = NULL; 78 void *start, *end; 79 size_t size; 80 int fd; 81 82 if (vdso_file->found) 83 return vdso_file->temp_file_name; 84 85 if (vdso_file->error || find_vdso_map(&start, &end)) 86 return NULL; 87 88 size = end - start; 89 90 buf = memdup(start, size); 91 if (!buf) 92 return NULL; 93 94 fd = mkstemp(vdso_file->temp_file_name); 95 if (fd < 0) 96 goto out; 97 98 if (size == (size_t) write(fd, buf, size)) 99 vdso = vdso_file->temp_file_name; 100 101 close(fd); 102 103 out: 104 free(buf); 105 106 vdso_file->found = (vdso != NULL); 107 vdso_file->error = !vdso_file->found; 108 return vdso; 109 } 110 111 void vdso__exit(struct machine *machine) 112 { 113 struct vdso_info *vdso_info = machine->vdso_info; 114 115 if (!vdso_info) 116 return; 117 118 if (vdso_info->vdso.found) 119 unlink(vdso_info->vdso.temp_file_name); 120 121 zfree(&machine->vdso_info); 122 } 123 124 static struct dso *vdso__new(struct machine *machine, const char *short_name, 125 const char *long_name) 126 { 127 struct dso *dso; 128 129 dso = dso__new(short_name); 130 if (dso != NULL) { 131 dsos__add(&machine->user_dsos, dso); 132 dso__set_long_name(dso, long_name, false); 133 } 134 135 return dso; 136 } 137 138 struct dso *vdso__dso_findnew(struct machine *machine, 139 struct thread *thread __maybe_unused) 140 { 141 struct vdso_info *vdso_info; 142 struct dso *dso; 143 144 if (!machine->vdso_info) 145 machine->vdso_info = vdso_info__new(); 146 147 vdso_info = machine->vdso_info; 148 if (!vdso_info) 149 return NULL; 150 151 dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true); 152 if (!dso) { 153 char *file; 154 155 file = get_file(&vdso_info->vdso); 156 if (!file) 157 return NULL; 158 159 dso = vdso__new(machine, DSO__NAME_VDSO, file); 160 } 161 162 return dso; 163 } 164 165 bool dso__is_vdso(struct dso *dso) 166 { 167 return !strcmp(dso->short_name, DSO__NAME_VDSO); 168 } 169