diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 284 |
1 files changed, 243 insertions, 41 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8a0bca55106f..6c9aa16ee51f 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1,8 +1,12 @@ | |||
1 | #define _FILE_OFFSET_BITS 64 | ||
2 | |||
1 | #include <sys/types.h> | 3 | #include <sys/types.h> |
4 | #include <byteswap.h> | ||
2 | #include <unistd.h> | 5 | #include <unistd.h> |
3 | #include <stdio.h> | 6 | #include <stdio.h> |
4 | #include <stdlib.h> | 7 | #include <stdlib.h> |
5 | #include <linux/list.h> | 8 | #include <linux/list.h> |
9 | #include <linux/kernel.h> | ||
6 | 10 | ||
7 | #include "util.h" | 11 | #include "util.h" |
8 | #include "header.h" | 12 | #include "header.h" |
@@ -105,24 +109,28 @@ struct perf_trace_event_type { | |||
105 | static int event_count; | 109 | static int event_count; |
106 | static struct perf_trace_event_type *events; | 110 | static struct perf_trace_event_type *events; |
107 | 111 | ||
108 | void perf_header__push_event(u64 id, const char *name) | 112 | int perf_header__push_event(u64 id, const char *name) |
109 | { | 113 | { |
110 | if (strlen(name) > MAX_EVENT_NAME) | 114 | if (strlen(name) > MAX_EVENT_NAME) |
111 | pr_warning("Event %s will be truncated\n", name); | 115 | pr_warning("Event %s will be truncated\n", name); |
112 | 116 | ||
113 | if (!events) { | 117 | if (!events) { |
114 | events = malloc(sizeof(struct perf_trace_event_type)); | 118 | events = malloc(sizeof(struct perf_trace_event_type)); |
115 | if (!events) | 119 | if (events == NULL) |
116 | die("nomem"); | 120 | return -ENOMEM; |
117 | } else { | 121 | } else { |
118 | events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); | 122 | struct perf_trace_event_type *nevents; |
119 | if (!events) | 123 | |
120 | die("nomem"); | 124 | nevents = realloc(events, (event_count + 1) * sizeof(*events)); |
125 | if (nevents == NULL) | ||
126 | return -ENOMEM; | ||
127 | events = nevents; | ||
121 | } | 128 | } |
122 | memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); | 129 | memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); |
123 | events[event_count].event_id = id; | 130 | events[event_count].event_id = id; |
124 | strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); | 131 | strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); |
125 | event_count++; | 132 | event_count++; |
133 | return 0; | ||
126 | } | 134 | } |
127 | 135 | ||
128 | char *perf_header__find_event(u64 id) | 136 | char *perf_header__find_event(u64 id) |
@@ -169,31 +177,48 @@ static int do_write(int fd, const void *buf, size_t size) | |||
169 | return 0; | 177 | return 0; |
170 | } | 178 | } |
171 | 179 | ||
172 | static int __dsos__write_buildid_table(struct list_head *head, int fd) | 180 | #define NAME_ALIGN 64 |
181 | |||
182 | static int write_padded(int fd, const void *bf, size_t count, | ||
183 | size_t count_aligned) | ||
173 | { | 184 | { |
174 | #define NAME_ALIGN 64 | ||
175 | struct dso *pos; | ||
176 | static const char zero_buf[NAME_ALIGN]; | 185 | static const char zero_buf[NAME_ALIGN]; |
186 | int err = do_write(fd, bf, count); | ||
187 | |||
188 | if (!err) | ||
189 | err = do_write(fd, zero_buf, count_aligned - count); | ||
190 | |||
191 | return err; | ||
192 | } | ||
177 | 193 | ||
178 | list_for_each_entry(pos, head, node) { | 194 | #define dsos__for_each_with_build_id(pos, head) \ |
195 | list_for_each_entry(pos, head, node) \ | ||
196 | if (!pos->has_build_id) \ | ||
197 | continue; \ | ||
198 | else | ||
199 | |||
200 | static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd) | ||
201 | { | ||
202 | struct dso *pos; | ||
203 | |||
204 | dsos__for_each_with_build_id(pos, head) { | ||
179 | int err; | 205 | int err; |
180 | struct build_id_event b; | 206 | struct build_id_event b; |
181 | size_t len; | 207 | size_t len; |
182 | 208 | ||
183 | if (!pos->has_build_id) | 209 | if (!pos->hit) |
184 | continue; | 210 | continue; |
185 | len = pos->long_name_len + 1; | 211 | len = pos->long_name_len + 1; |
186 | len = ALIGN(len, NAME_ALIGN); | 212 | len = ALIGN(len, NAME_ALIGN); |
187 | memset(&b, 0, sizeof(b)); | 213 | memset(&b, 0, sizeof(b)); |
188 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); | 214 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); |
215 | b.header.misc = misc; | ||
189 | b.header.size = sizeof(b) + len; | 216 | b.header.size = sizeof(b) + len; |
190 | err = do_write(fd, &b, sizeof(b)); | 217 | err = do_write(fd, &b, sizeof(b)); |
191 | if (err < 0) | 218 | if (err < 0) |
192 | return err; | 219 | return err; |
193 | err = do_write(fd, pos->long_name, pos->long_name_len + 1); | 220 | err = write_padded(fd, pos->long_name, |
194 | if (err < 0) | 221 | pos->long_name_len + 1, len); |
195 | return err; | ||
196 | err = do_write(fd, zero_buf, len - pos->long_name_len - 1); | ||
197 | if (err < 0) | 222 | if (err < 0) |
198 | return err; | 223 | return err; |
199 | } | 224 | } |
@@ -203,12 +228,143 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd) | |||
203 | 228 | ||
204 | static int dsos__write_buildid_table(int fd) | 229 | static int dsos__write_buildid_table(int fd) |
205 | { | 230 | { |
206 | int err = __dsos__write_buildid_table(&dsos__kernel, fd); | 231 | int err = __dsos__write_buildid_table(&dsos__kernel, |
232 | PERF_RECORD_MISC_KERNEL, fd); | ||
207 | if (err == 0) | 233 | if (err == 0) |
208 | err = __dsos__write_buildid_table(&dsos__user, fd); | 234 | err = __dsos__write_buildid_table(&dsos__user, |
235 | PERF_RECORD_MISC_USER, fd); | ||
209 | return err; | 236 | return err; |
210 | } | 237 | } |
211 | 238 | ||
239 | int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | ||
240 | const char *name, bool is_kallsyms) | ||
241 | { | ||
242 | const size_t size = PATH_MAX; | ||
243 | char *filename = malloc(size), | ||
244 | *linkname = malloc(size), *targetname; | ||
245 | int len, err = -1; | ||
246 | |||
247 | if (filename == NULL || linkname == NULL) | ||
248 | goto out_free; | ||
249 | |||
250 | len = snprintf(filename, size, "%s%s%s", | ||
251 | debugdir, is_kallsyms ? "/" : "", name); | ||
252 | if (mkdir_p(filename, 0755)) | ||
253 | goto out_free; | ||
254 | |||
255 | snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id); | ||
256 | |||
257 | if (access(filename, F_OK)) { | ||
258 | if (is_kallsyms) { | ||
259 | if (copyfile("/proc/kallsyms", filename)) | ||
260 | goto out_free; | ||
261 | } else if (link(name, filename) && copyfile(name, filename)) | ||
262 | goto out_free; | ||
263 | } | ||
264 | |||
265 | len = snprintf(linkname, size, "%s/.build-id/%.2s", | ||
266 | debugdir, sbuild_id); | ||
267 | |||
268 | if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) | ||
269 | goto out_free; | ||
270 | |||
271 | snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); | ||
272 | targetname = filename + strlen(debugdir) - 5; | ||
273 | memcpy(targetname, "../..", 5); | ||
274 | |||
275 | if (symlink(targetname, linkname) == 0) | ||
276 | err = 0; | ||
277 | out_free: | ||
278 | free(filename); | ||
279 | free(linkname); | ||
280 | return err; | ||
281 | } | ||
282 | |||
283 | static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, | ||
284 | const char *name, const char *debugdir, | ||
285 | bool is_kallsyms) | ||
286 | { | ||
287 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
288 | |||
289 | build_id__sprintf(build_id, build_id_size, sbuild_id); | ||
290 | |||
291 | return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms); | ||
292 | } | ||
293 | |||
294 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) | ||
295 | { | ||
296 | const size_t size = PATH_MAX; | ||
297 | char *filename = malloc(size), | ||
298 | *linkname = malloc(size); | ||
299 | int err = -1; | ||
300 | |||
301 | if (filename == NULL || linkname == NULL) | ||
302 | goto out_free; | ||
303 | |||
304 | snprintf(linkname, size, "%s/.build-id/%.2s/%s", | ||
305 | debugdir, sbuild_id, sbuild_id + 2); | ||
306 | |||
307 | if (access(linkname, F_OK)) | ||
308 | goto out_free; | ||
309 | |||
310 | if (readlink(linkname, filename, size) < 0) | ||
311 | goto out_free; | ||
312 | |||
313 | if (unlink(linkname)) | ||
314 | goto out_free; | ||
315 | |||
316 | /* | ||
317 | * Since the link is relative, we must make it absolute: | ||
318 | */ | ||
319 | snprintf(linkname, size, "%s/.build-id/%.2s/%s", | ||
320 | debugdir, sbuild_id, filename); | ||
321 | |||
322 | if (unlink(linkname)) | ||
323 | goto out_free; | ||
324 | |||
325 | err = 0; | ||
326 | out_free: | ||
327 | free(filename); | ||
328 | free(linkname); | ||
329 | return err; | ||
330 | } | ||
331 | |||
332 | static int dso__cache_build_id(struct dso *self, const char *debugdir) | ||
333 | { | ||
334 | bool is_kallsyms = self->kernel && self->long_name[0] != '/'; | ||
335 | |||
336 | return build_id_cache__add_b(self->build_id, sizeof(self->build_id), | ||
337 | self->long_name, debugdir, is_kallsyms); | ||
338 | } | ||
339 | |||
340 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | ||
341 | { | ||
342 | struct dso *pos; | ||
343 | int err = 0; | ||
344 | |||
345 | dsos__for_each_with_build_id(pos, head) | ||
346 | if (dso__cache_build_id(pos, debugdir)) | ||
347 | err = -1; | ||
348 | |||
349 | return err; | ||
350 | } | ||
351 | |||
352 | static int dsos__cache_build_ids(void) | ||
353 | { | ||
354 | int err_kernel, err_user; | ||
355 | char debugdir[PATH_MAX]; | ||
356 | |||
357 | snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), | ||
358 | DEBUG_CACHE_DIR); | ||
359 | |||
360 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | ||
361 | return -1; | ||
362 | |||
363 | err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir); | ||
364 | err_user = __dsos__cache_build_ids(&dsos__user, debugdir); | ||
365 | return err_kernel || err_user ? -1 : 0; | ||
366 | } | ||
367 | |||
212 | static int perf_header__adds_write(struct perf_header *self, int fd) | 368 | static int perf_header__adds_write(struct perf_header *self, int fd) |
213 | { | 369 | { |
214 | int nr_sections; | 370 | int nr_sections; |
@@ -217,7 +373,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
217 | u64 sec_start; | 373 | u64 sec_start; |
218 | int idx = 0, err; | 374 | int idx = 0, err; |
219 | 375 | ||
220 | if (dsos__read_build_ids()) | 376 | if (dsos__read_build_ids(true)) |
221 | perf_header__set_feat(self, HEADER_BUILD_ID); | 377 | perf_header__set_feat(self, HEADER_BUILD_ID); |
222 | 378 | ||
223 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 379 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); |
@@ -257,7 +413,9 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
257 | pr_debug("failed to write buildid table\n"); | 413 | pr_debug("failed to write buildid table\n"); |
258 | goto out_free; | 414 | goto out_free; |
259 | } | 415 | } |
260 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; | 416 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - |
417 | buildid_sec->offset; | ||
418 | dsos__cache_build_ids(); | ||
261 | } | 419 | } |
262 | 420 | ||
263 | lseek(fd, sec_start, SEEK_SET); | 421 | lseek(fd, sec_start, SEEK_SET); |
@@ -360,30 +518,43 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) | |||
360 | return 0; | 518 | return 0; |
361 | } | 519 | } |
362 | 520 | ||
363 | static void do_read(int fd, void *buf, size_t size) | 521 | static int do_read(int fd, void *buf, size_t size) |
364 | { | 522 | { |
365 | while (size) { | 523 | while (size) { |
366 | int ret = read(fd, buf, size); | 524 | int ret = read(fd, buf, size); |
367 | 525 | ||
368 | if (ret < 0) | 526 | if (ret <= 0) |
369 | die("failed to read"); | 527 | return -1; |
370 | if (ret == 0) | ||
371 | die("failed to read: missing data"); | ||
372 | 528 | ||
373 | size -= ret; | 529 | size -= ret; |
374 | buf += ret; | 530 | buf += ret; |
375 | } | 531 | } |
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static int perf_header__getbuffer64(struct perf_header *self, | ||
537 | int fd, void *buf, size_t size) | ||
538 | { | ||
539 | if (do_read(fd, buf, size)) | ||
540 | return -1; | ||
541 | |||
542 | if (self->needs_swap) | ||
543 | mem_bswap_64(buf, size); | ||
544 | |||
545 | return 0; | ||
376 | } | 546 | } |
377 | 547 | ||
378 | int perf_header__process_sections(struct perf_header *self, int fd, | 548 | int perf_header__process_sections(struct perf_header *self, int fd, |
379 | int (*process)(struct perf_file_section *self, | 549 | int (*process)(struct perf_file_section *self, |
550 | struct perf_header *ph, | ||
380 | int feat, int fd)) | 551 | int feat, int fd)) |
381 | { | 552 | { |
382 | struct perf_file_section *feat_sec; | 553 | struct perf_file_section *feat_sec; |
383 | int nr_sections; | 554 | int nr_sections; |
384 | int sec_size; | 555 | int sec_size; |
385 | int idx = 0; | 556 | int idx = 0; |
386 | int err = 0, feat = 1; | 557 | int err = -1, feat = 1; |
387 | 558 | ||
388 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 559 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); |
389 | if (!nr_sections) | 560 | if (!nr_sections) |
@@ -397,33 +568,45 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
397 | 568 | ||
398 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 569 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); |
399 | 570 | ||
400 | do_read(fd, feat_sec, sec_size); | 571 | if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) |
572 | goto out_free; | ||
401 | 573 | ||
574 | err = 0; | ||
402 | while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { | 575 | while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { |
403 | if (perf_header__has_feat(self, feat)) { | 576 | if (perf_header__has_feat(self, feat)) { |
404 | struct perf_file_section *sec = &feat_sec[idx++]; | 577 | struct perf_file_section *sec = &feat_sec[idx++]; |
405 | 578 | ||
406 | err = process(sec, feat, fd); | 579 | err = process(sec, self, feat, fd); |
407 | if (err < 0) | 580 | if (err < 0) |
408 | break; | 581 | break; |
409 | } | 582 | } |
410 | ++feat; | 583 | ++feat; |
411 | } | 584 | } |
412 | 585 | out_free: | |
413 | free(feat_sec); | 586 | free(feat_sec); |
414 | return err; | 587 | return err; |
415 | }; | 588 | } |
416 | 589 | ||
417 | int perf_file_header__read(struct perf_file_header *self, | 590 | int perf_file_header__read(struct perf_file_header *self, |
418 | struct perf_header *ph, int fd) | 591 | struct perf_header *ph, int fd) |
419 | { | 592 | { |
420 | lseek(fd, 0, SEEK_SET); | 593 | lseek(fd, 0, SEEK_SET); |
421 | do_read(fd, self, sizeof(*self)); | ||
422 | 594 | ||
423 | if (self->magic != PERF_MAGIC || | 595 | if (do_read(fd, self, sizeof(*self)) || |
424 | self->attr_size != sizeof(struct perf_file_attr)) | 596 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) |
425 | return -1; | 597 | return -1; |
426 | 598 | ||
599 | if (self->attr_size != sizeof(struct perf_file_attr)) { | ||
600 | u64 attr_size = bswap_64(self->attr_size); | ||
601 | |||
602 | if (attr_size != sizeof(struct perf_file_attr)) | ||
603 | return -1; | ||
604 | |||
605 | mem_bswap_64(self, offsetof(struct perf_file_header, | ||
606 | adds_features)); | ||
607 | ph->needs_swap = true; | ||
608 | } | ||
609 | |||
427 | if (self->size != sizeof(*self)) { | 610 | if (self->size != sizeof(*self)) { |
428 | /* Support the previous format */ | 611 | /* Support the previous format */ |
429 | if (self->size == offsetof(typeof(*self), adds_features)) | 612 | if (self->size == offsetof(typeof(*self), adds_features)) |
@@ -433,19 +616,31 @@ int perf_file_header__read(struct perf_file_header *self, | |||
433 | } | 616 | } |
434 | 617 | ||
435 | memcpy(&ph->adds_features, &self->adds_features, | 618 | memcpy(&ph->adds_features, &self->adds_features, |
436 | sizeof(self->adds_features)); | 619 | sizeof(ph->adds_features)); |
620 | /* | ||
621 | * FIXME: hack that assumes that if we need swap the perf.data file | ||
622 | * may be coming from an arch with a different word-size, ergo different | ||
623 | * DEFINE_BITMAP format, investigate more later, but for now its mostly | ||
624 | * safe to assume that we have a build-id section. Trace files probably | ||
625 | * have several other issues in this realm anyway... | ||
626 | */ | ||
627 | if (ph->needs_swap) { | ||
628 | memset(&ph->adds_features, 0, sizeof(ph->adds_features)); | ||
629 | perf_header__set_feat(ph, HEADER_BUILD_ID); | ||
630 | } | ||
437 | 631 | ||
438 | ph->event_offset = self->event_types.offset; | 632 | ph->event_offset = self->event_types.offset; |
439 | ph->event_size = self->event_types.size; | 633 | ph->event_size = self->event_types.size; |
440 | ph->data_offset = self->data.offset; | 634 | ph->data_offset = self->data.offset; |
441 | ph->data_size = self->data.size; | 635 | ph->data_size = self->data.size; |
442 | return 0; | 636 | return 0; |
443 | } | 637 | } |
444 | 638 | ||
445 | static int perf_file_section__process(struct perf_file_section *self, | 639 | static int perf_file_section__process(struct perf_file_section *self, |
640 | struct perf_header *ph, | ||
446 | int feat, int fd) | 641 | int feat, int fd) |
447 | { | 642 | { |
448 | if (lseek(fd, self->offset, SEEK_SET) < 0) { | 643 | if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) { |
449 | pr_debug("Failed to lseek to %Ld offset for feature %d, " | 644 | pr_debug("Failed to lseek to %Ld offset for feature %d, " |
450 | "continuing...\n", self->offset, feat); | 645 | "continuing...\n", self->offset, feat); |
451 | return 0; | 646 | return 0; |
@@ -457,7 +652,7 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
457 | break; | 652 | break; |
458 | 653 | ||
459 | case HEADER_BUILD_ID: | 654 | case HEADER_BUILD_ID: |
460 | if (perf_header__read_build_ids(fd, self->offset, self->size)) | 655 | if (perf_header__read_build_ids(ph, fd, self->offset, self->size)) |
461 | pr_debug("Failed to read buildids, continuing...\n"); | 656 | pr_debug("Failed to read buildids, continuing...\n"); |
462 | break; | 657 | break; |
463 | default: | 658 | default: |
@@ -469,7 +664,7 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
469 | 664 | ||
470 | int perf_header__read(struct perf_header *self, int fd) | 665 | int perf_header__read(struct perf_header *self, int fd) |
471 | { | 666 | { |
472 | struct perf_file_header f_header; | 667 | struct perf_file_header f_header; |
473 | struct perf_file_attr f_attr; | 668 | struct perf_file_attr f_attr; |
474 | u64 f_id; | 669 | u64 f_id; |
475 | int nr_attrs, nr_ids, i, j; | 670 | int nr_attrs, nr_ids, i, j; |
@@ -486,7 +681,9 @@ int perf_header__read(struct perf_header *self, int fd) | |||
486 | struct perf_header_attr *attr; | 681 | struct perf_header_attr *attr; |
487 | off_t tmp; | 682 | off_t tmp; |
488 | 683 | ||
489 | do_read(fd, &f_attr, sizeof(f_attr)); | 684 | if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) |
685 | goto out_errno; | ||
686 | |||
490 | tmp = lseek(fd, 0, SEEK_CUR); | 687 | tmp = lseek(fd, 0, SEEK_CUR); |
491 | 688 | ||
492 | attr = perf_header_attr__new(&f_attr.attr); | 689 | attr = perf_header_attr__new(&f_attr.attr); |
@@ -497,7 +694,8 @@ int perf_header__read(struct perf_header *self, int fd) | |||
497 | lseek(fd, f_attr.ids.offset, SEEK_SET); | 694 | lseek(fd, f_attr.ids.offset, SEEK_SET); |
498 | 695 | ||
499 | for (j = 0; j < nr_ids; j++) { | 696 | for (j = 0; j < nr_ids; j++) { |
500 | do_read(fd, &f_id, sizeof(f_id)); | 697 | if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) |
698 | goto out_errno; | ||
501 | 699 | ||
502 | if (perf_header_attr__add_id(attr, f_id) < 0) { | 700 | if (perf_header_attr__add_id(attr, f_id) < 0) { |
503 | perf_header_attr__delete(attr); | 701 | perf_header_attr__delete(attr); |
@@ -517,7 +715,9 @@ int perf_header__read(struct perf_header *self, int fd) | |||
517 | events = malloc(f_header.event_types.size); | 715 | events = malloc(f_header.event_types.size); |
518 | if (events == NULL) | 716 | if (events == NULL) |
519 | return -ENOMEM; | 717 | return -ENOMEM; |
520 | do_read(fd, events, f_header.event_types.size); | 718 | if (perf_header__getbuffer64(self, fd, events, |
719 | f_header.event_types.size)) | ||
720 | goto out_errno; | ||
521 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | 721 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); |
522 | } | 722 | } |
523 | 723 | ||
@@ -527,6 +727,8 @@ int perf_header__read(struct perf_header *self, int fd) | |||
527 | 727 | ||
528 | self->frozen = 1; | 728 | self->frozen = 1; |
529 | return 0; | 729 | return 0; |
730 | out_errno: | ||
731 | return -errno; | ||
530 | } | 732 | } |
531 | 733 | ||
532 | u64 perf_header__sample_type(struct perf_header *header) | 734 | u64 perf_header__sample_type(struct perf_header *header) |