]>
Commit | Line | Data |
---|---|---|
016e92fb FW |
1 | #include "data_map.h" |
2 | #include "symbol.h" | |
3 | #include "util.h" | |
4 | #include "debug.h" | |
5 | ||
6 | ||
7 | static struct perf_file_handler *curr_handler; | |
8 | static unsigned long mmap_window = 32; | |
9 | static char __cwd[PATH_MAX]; | |
10 | ||
11 | static int | |
12 | process_event_stub(event_t *event __used, | |
13 | unsigned long offset __used, | |
14 | unsigned long head __used) | |
15 | { | |
16 | return 0; | |
17 | } | |
18 | ||
19 | void register_perf_file_handler(struct perf_file_handler *handler) | |
20 | { | |
21 | if (!handler->process_sample_event) | |
22 | handler->process_sample_event = process_event_stub; | |
23 | if (!handler->process_mmap_event) | |
24 | handler->process_mmap_event = process_event_stub; | |
25 | if (!handler->process_comm_event) | |
26 | handler->process_comm_event = process_event_stub; | |
27 | if (!handler->process_fork_event) | |
28 | handler->process_fork_event = process_event_stub; | |
29 | if (!handler->process_exit_event) | |
30 | handler->process_exit_event = process_event_stub; | |
31 | if (!handler->process_lost_event) | |
32 | handler->process_lost_event = process_event_stub; | |
33 | if (!handler->process_read_event) | |
34 | handler->process_read_event = process_event_stub; | |
35 | if (!handler->process_throttle_event) | |
36 | handler->process_throttle_event = process_event_stub; | |
37 | if (!handler->process_unthrottle_event) | |
38 | handler->process_unthrottle_event = process_event_stub; | |
39 | ||
40 | curr_handler = handler; | |
41 | } | |
42 | ||
43 | static int | |
44 | process_event(event_t *event, unsigned long offset, unsigned long head) | |
45 | { | |
46 | trace_event(event); | |
47 | ||
48 | switch (event->header.type) { | |
49 | case PERF_RECORD_SAMPLE: | |
50 | return curr_handler->process_sample_event(event, offset, head); | |
51 | case PERF_RECORD_MMAP: | |
52 | return curr_handler->process_mmap_event(event, offset, head); | |
53 | case PERF_RECORD_COMM: | |
54 | return curr_handler->process_comm_event(event, offset, head); | |
55 | case PERF_RECORD_FORK: | |
56 | return curr_handler->process_fork_event(event, offset, head); | |
57 | case PERF_RECORD_EXIT: | |
58 | return curr_handler->process_exit_event(event, offset, head); | |
59 | case PERF_RECORD_LOST: | |
60 | return curr_handler->process_lost_event(event, offset, head); | |
61 | case PERF_RECORD_READ: | |
62 | return curr_handler->process_read_event(event, offset, head); | |
63 | case PERF_RECORD_THROTTLE: | |
64 | return curr_handler->process_throttle_event(event, offset, head); | |
65 | case PERF_RECORD_UNTHROTTLE: | |
66 | return curr_handler->process_unthrottle_event(event, offset, head); | |
67 | default: | |
68 | curr_handler->total_unknown++; | |
69 | return -1; | |
70 | } | |
71 | } | |
72 | ||
84fe8488 | 73 | int perf_header__read_build_ids(int input, off_t offset, off_t size) |
8d06367f | 74 | { |
8d06367f ACM |
75 | struct build_id_event bev; |
76 | char filename[PATH_MAX]; | |
9e827dd0 | 77 | off_t limit = offset + size; |
8d06367f ACM |
78 | int err = -1; |
79 | ||
9e827dd0 | 80 | while (offset < limit) { |
8d06367f ACM |
81 | struct dso *dso; |
82 | ssize_t len; | |
83 | ||
84 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | |
85 | goto out; | |
86 | ||
87 | len = bev.header.size - sizeof(bev); | |
88 | if (read(input, filename, len) != len) | |
89 | goto out; | |
90 | ||
91 | dso = dsos__findnew(filename); | |
92 | if (dso != NULL) | |
93 | dso__set_build_id(dso, &bev.build_id); | |
94 | ||
95 | offset += bev.header.size; | |
96 | } | |
97 | err = 0; | |
98 | out: | |
99 | return err; | |
100 | } | |
101 | ||
016e92fb FW |
102 | int mmap_dispatch_perf_file(struct perf_header **pheader, |
103 | const char *input_name, | |
104 | int force, | |
105 | int full_paths, | |
106 | int *cwdlen, | |
107 | char **cwd) | |
108 | { | |
6b0cb5f9 | 109 | int err; |
016e92fb FW |
110 | struct perf_header *header; |
111 | unsigned long head, shift; | |
112 | unsigned long offset = 0; | |
113 | struct stat input_stat; | |
114 | size_t page_size; | |
115 | u64 sample_type; | |
116 | event_t *event; | |
117 | uint32_t size; | |
118 | int input; | |
119 | char *buf; | |
120 | ||
6b0cb5f9 ACM |
121 | if (curr_handler == NULL) { |
122 | pr_debug("Forgot to register perf file handler\n"); | |
123 | return -EINVAL; | |
124 | } | |
016e92fb FW |
125 | |
126 | page_size = getpagesize(); | |
127 | ||
128 | input = open(input_name, O_RDONLY); | |
129 | if (input < 0) { | |
6b0cb5f9 | 130 | pr_err("Failed to open file: %s", input_name); |
016e92fb | 131 | if (!strcmp(input_name, "perf.data")) |
6b0cb5f9 ACM |
132 | pr_err(" (try 'perf record' first)"); |
133 | pr_err("\n"); | |
134 | return -errno; | |
016e92fb FW |
135 | } |
136 | ||
6b0cb5f9 ACM |
137 | if (fstat(input, &input_stat) < 0) { |
138 | pr_err("failed to stat file"); | |
139 | err = -errno; | |
140 | goto out_close; | |
016e92fb FW |
141 | } |
142 | ||
6b0cb5f9 | 143 | err = -EACCES; |
016e92fb | 144 | if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { |
6b0cb5f9 | 145 | pr_err("file: %s not owned by current user or root\n", |
016e92fb | 146 | input_name); |
6b0cb5f9 | 147 | goto out_close; |
016e92fb FW |
148 | } |
149 | ||
6b0cb5f9 ACM |
150 | if (input_stat.st_size == 0) { |
151 | pr_info("zero-sized file, nothing to do!\n"); | |
152 | goto done; | |
016e92fb FW |
153 | } |
154 | ||
6b0cb5f9 | 155 | err = -ENOMEM; |
4dc0a04b ACM |
156 | header = perf_header__new(); |
157 | if (header == NULL) | |
6b0cb5f9 | 158 | goto out_close; |
4dc0a04b ACM |
159 | |
160 | err = perf_header__read(header, input); | |
6b0cb5f9 ACM |
161 | if (err < 0) |
162 | goto out_delete; | |
4dc0a04b | 163 | *pheader = header; |
016e92fb FW |
164 | head = header->data_offset; |
165 | ||
166 | sample_type = perf_header__sample_type(header); | |
167 | ||
6b0cb5f9 ACM |
168 | err = -EINVAL; |
169 | if (curr_handler->sample_type_check && | |
170 | curr_handler->sample_type_check(sample_type) < 0) | |
171 | goto out_delete; | |
016e92fb | 172 | |
016e92fb FW |
173 | if (!full_paths) { |
174 | if (getcwd(__cwd, sizeof(__cwd)) == NULL) { | |
6b0cb5f9 ACM |
175 | pr_err("failed to get the current directory\n"); |
176 | err = -errno; | |
177 | goto out_delete; | |
016e92fb FW |
178 | } |
179 | *cwd = __cwd; | |
180 | *cwdlen = strlen(*cwd); | |
181 | } else { | |
182 | *cwd = NULL; | |
183 | *cwdlen = 0; | |
184 | } | |
185 | ||
186 | shift = page_size * (head / page_size); | |
187 | offset += shift; | |
188 | head -= shift; | |
189 | ||
190 | remap: | |
6b0cb5f9 ACM |
191 | buf = mmap(NULL, page_size * mmap_window, PROT_READ, |
192 | MAP_SHARED, input, offset); | |
016e92fb | 193 | if (buf == MAP_FAILED) { |
6b0cb5f9 ACM |
194 | pr_err("failed to mmap file\n"); |
195 | err = -errno; | |
196 | goto out_delete; | |
016e92fb FW |
197 | } |
198 | ||
199 | more: | |
200 | event = (event_t *)(buf + head); | |
201 | ||
202 | size = event->header.size; | |
203 | if (!size) | |
204 | size = 8; | |
205 | ||
206 | if (head + event->header.size >= page_size * mmap_window) { | |
207 | int munmap_ret; | |
208 | ||
209 | shift = page_size * (head / page_size); | |
210 | ||
211 | munmap_ret = munmap(buf, page_size * mmap_window); | |
212 | assert(munmap_ret == 0); | |
213 | ||
214 | offset += shift; | |
215 | head -= shift; | |
216 | goto remap; | |
217 | } | |
218 | ||
219 | size = event->header.size; | |
220 | ||
221 | dump_printf("\n%p [%p]: event: %d\n", | |
222 | (void *)(offset + head), | |
223 | (void *)(long)event->header.size, | |
224 | event->header.type); | |
225 | ||
226 | if (!size || process_event(event, offset, head) < 0) { | |
227 | ||
228 | dump_printf("%p [%p]: skipping unknown header type: %d\n", | |
229 | (void *)(offset + head), | |
230 | (void *)(long)(event->header.size), | |
231 | event->header.type); | |
232 | ||
233 | /* | |
234 | * assume we lost track of the stream, check alignment, and | |
235 | * increment a single u64 in the hope to catch on again 'soon'. | |
236 | */ | |
237 | ||
238 | if (unlikely(head & 7)) | |
239 | head &= ~7ULL; | |
240 | ||
241 | size = 8; | |
242 | } | |
243 | ||
244 | head += size; | |
245 | ||
246 | if (offset + head >= header->data_offset + header->data_size) | |
247 | goto done; | |
248 | ||
249 | if (offset + head < (unsigned long)input_stat.st_size) | |
250 | goto more; | |
251 | ||
252 | done: | |
6b0cb5f9 ACM |
253 | err = 0; |
254 | out_close: | |
016e92fb FW |
255 | close(input); |
256 | ||
6b0cb5f9 ACM |
257 | return err; |
258 | out_delete: | |
259 | perf_header__delete(header); | |
260 | goto out_close; | |
016e92fb | 261 | } |