1 #include <linux/kernel.h> 2 3 #include <unistd.h> 4 #include <sys/types.h> 5 6 #include "session.h" 7 #include "sort.h" 8 #include "util.h" 9 10 static int perf_session__open(struct perf_session *self, bool force) 11 { 12 struct stat input_stat; 13 14 self->fd = open(self->filename, O_RDONLY); 15 if (self->fd < 0) { 16 pr_err("failed to open file: %s", self->filename); 17 if (!strcmp(self->filename, "perf.data")) 18 pr_err(" (try 'perf record' first)"); 19 pr_err("\n"); 20 return -errno; 21 } 22 23 if (fstat(self->fd, &input_stat) < 0) 24 goto out_close; 25 26 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { 27 pr_err("file %s not owned by current user or root\n", 28 self->filename); 29 goto out_close; 30 } 31 32 if (!input_stat.st_size) { 33 pr_info("zero-sized file (%s), nothing to do!\n", 34 self->filename); 35 goto out_close; 36 } 37 38 if (perf_header__read(&self->header, self->fd) < 0) { 39 pr_err("incompatible file format"); 40 goto out_close; 41 } 42 43 self->size = input_stat.st_size; 44 return 0; 45 46 out_close: 47 close(self->fd); 48 self->fd = -1; 49 return -1; 50 } 51 52 struct perf_session *perf_session__new(const char *filename, int mode, 53 bool force, struct symbol_conf *conf) 54 { 55 size_t len = filename ? strlen(filename) + 1 : 0; 56 struct perf_session *self = zalloc(sizeof(*self) + len); 57 58 if (self == NULL) 59 goto out; 60 61 if (perf_header__init(&self->header) < 0) 62 goto out_free; 63 64 memcpy(self->filename, filename, len); 65 self->threads = RB_ROOT; 66 self->last_match = NULL; 67 self->mmap_window = 32; 68 self->cwd = NULL; 69 self->cwdlen = 0; 70 map_groups__init(&self->kmaps); 71 72 if (perf_session__create_kernel_maps(self, conf) < 0) 73 goto out_delete; 74 75 if (mode == O_RDONLY && perf_session__open(self, force) < 0) 76 goto out_delete; 77 out: 78 return self; 79 out_free: 80 free(self); 81 return NULL; 82 out_delete: 83 perf_session__delete(self); 84 return NULL; 85 } 86 87 void perf_session__delete(struct perf_session *self) 88 { 89 perf_header__exit(&self->header); 90 close(self->fd); 91 free(self->cwd); 92 free(self); 93 } 94 95 static bool symbol__match_parent_regex(struct symbol *sym) 96 { 97 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 98 return 1; 99 100 return 0; 101 } 102 103 struct symbol **perf_session__resolve_callchain(struct perf_session *self, 104 struct thread *thread, 105 struct ip_callchain *chain, 106 struct symbol **parent) 107 { 108 u8 cpumode = PERF_RECORD_MISC_USER; 109 struct symbol **syms = NULL; 110 unsigned int i; 111 112 if (self->use_callchain) { 113 syms = calloc(chain->nr, sizeof(*syms)); 114 if (!syms) { 115 fprintf(stderr, "Can't allocate memory for symbols\n"); 116 exit(-1); 117 } 118 } 119 120 for (i = 0; i < chain->nr; i++) { 121 u64 ip = chain->ips[i]; 122 struct addr_location al; 123 124 if (ip >= PERF_CONTEXT_MAX) { 125 switch (ip) { 126 case PERF_CONTEXT_HV: 127 cpumode = PERF_RECORD_MISC_HYPERVISOR; break; 128 case PERF_CONTEXT_KERNEL: 129 cpumode = PERF_RECORD_MISC_KERNEL; break; 130 case PERF_CONTEXT_USER: 131 cpumode = PERF_RECORD_MISC_USER; break; 132 default: 133 break; 134 } 135 continue; 136 } 137 138 thread__find_addr_location(thread, self, cpumode, 139 MAP__FUNCTION, ip, &al, NULL); 140 if (al.sym != NULL) { 141 if (sort__has_parent && !*parent && 142 symbol__match_parent_regex(al.sym)) 143 *parent = al.sym; 144 if (!self->use_callchain) 145 break; 146 syms[i] = al.sym; 147 } 148 } 149 150 return syms; 151 } 152