1 #include <sys/types.h> 2 #include <unistd.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <linux/list.h> 6 7 #include "util.h" 8 #include "header.h" 9 #include "../perf.h" 10 #include "trace-event.h" 11 #include "symbol.h" 12 #include "data_map.h" 13 #include "debug.h" 14 15 /* 16 * Create new perf.data header attribute: 17 */ 18 struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) 19 { 20 struct perf_header_attr *self = malloc(sizeof(*self)); 21 22 if (self != NULL) { 23 self->attr = *attr; 24 self->ids = 0; 25 self->size = 1; 26 self->id = malloc(sizeof(u64)); 27 if (self->id == NULL) { 28 free(self); 29 self = NULL; 30 } 31 } 32 33 return self; 34 } 35 36 void perf_header_attr__delete(struct perf_header_attr *self) 37 { 38 free(self->id); 39 free(self); 40 } 41 42 int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) 43 { 44 int pos = self->ids; 45 46 self->ids++; 47 if (self->ids > self->size) { 48 int nsize = self->size * 2; 49 u64 *nid = realloc(self->id, nsize * sizeof(u64)); 50 51 if (nid == NULL) 52 return -1; 53 54 self->size = nsize; 55 self->id = nid; 56 } 57 self->id[pos] = id; 58 return 0; 59 } 60 61 /* 62 * Create new perf.data header: 63 */ 64 struct perf_header *perf_header__new(void) 65 { 66 struct perf_header *self = zalloc(sizeof(*self)); 67 68 if (self != NULL) { 69 self->size = 1; 70 self->attr = malloc(sizeof(void *)); 71 72 if (self->attr == NULL) { 73 free(self); 74 self = NULL; 75 } 76 } 77 78 return self; 79 } 80 81 void perf_header__delete(struct perf_header *self) 82 { 83 int i; 84 85 for (i = 0; i < self->attrs; ++i) 86 perf_header_attr__delete(self->attr[i]); 87 88 free(self->attr); 89 free(self); 90 } 91 92 int perf_header__add_attr(struct perf_header *self, 93 struct perf_header_attr *attr) 94 { 95 if (self->frozen) 96 return -1; 97 98 if (self->attrs == self->size) { 99 int nsize = self->size * 2; 100 struct perf_header_attr **nattr; 101 102 nattr = realloc(self->attr, nsize * sizeof(void *)); 103 if (nattr == NULL) 104 return -1; 105 106 self->size = nsize; 107 self->attr = nattr; 108 } 109 110 self->attr[self->attrs++] = attr; 111 return 0; 112 } 113 114 #define MAX_EVENT_NAME 64 115 116 struct perf_trace_event_type { 117 u64 event_id; 118 char name[MAX_EVENT_NAME]; 119 }; 120 121 static int event_count; 122 static struct perf_trace_event_type *events; 123 124 void perf_header__push_event(u64 id, const char *name) 125 { 126 if (strlen(name) > MAX_EVENT_NAME) 127 pr_warning("Event %s will be truncated\n", name); 128 129 if (!events) { 130 events = malloc(sizeof(struct perf_trace_event_type)); 131 if (!events) 132 die("nomem"); 133 } else { 134 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 135 if (!events) 136 die("nomem"); 137 } 138 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 139 events[event_count].event_id = id; 140 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 141 event_count++; 142 } 143 144 char *perf_header__find_event(u64 id) 145 { 146 int i; 147 for (i = 0 ; i < event_count; i++) { 148 if (events[i].event_id == id) 149 return events[i].name; 150 } 151 return NULL; 152 } 153 154 static const char *__perf_magic = "PERFFILE"; 155 156 #define PERF_MAGIC (*(u64 *)__perf_magic) 157 158 struct perf_file_attr { 159 struct perf_event_attr attr; 160 struct perf_file_section ids; 161 }; 162 163 void perf_header__set_feat(struct perf_header *self, int feat) 164 { 165 set_bit(feat, self->adds_features); 166 } 167 168 bool perf_header__has_feat(const struct perf_header *self, int feat) 169 { 170 return test_bit(feat, self->adds_features); 171 } 172 173 static int do_write(int fd, const void *buf, size_t size) 174 { 175 while (size) { 176 int ret = write(fd, buf, size); 177 178 if (ret < 0) 179 return -errno; 180 181 size -= ret; 182 buf += ret; 183 } 184 185 return 0; 186 } 187 188 static int __dsos__write_buildid_table(struct list_head *head, int fd) 189 { 190 struct dso *pos; 191 192 list_for_each_entry(pos, head, node) { 193 int err; 194 struct build_id_event b; 195 size_t len; 196 197 if (!pos->has_build_id) 198 continue; 199 len = pos->long_name_len + 1; 200 len = ALIGN(len, 64); 201 memset(&b, 0, sizeof(b)); 202 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 203 b.header.size = sizeof(b) + len; 204 err = do_write(fd, &b, sizeof(b)); 205 if (err < 0) 206 return err; 207 err = do_write(fd, pos->long_name, len); 208 if (err < 0) 209 return err; 210 } 211 212 return 0; 213 } 214 215 static int dsos__write_buildid_table(int fd) 216 { 217 int err = __dsos__write_buildid_table(&dsos__kernel, fd); 218 if (err == 0) 219 err = __dsos__write_buildid_table(&dsos__user, fd); 220 return err; 221 } 222 223 static int perf_header__adds_write(struct perf_header *self, int fd) 224 { 225 int nr_sections; 226 struct perf_file_section *feat_sec; 227 int sec_size; 228 u64 sec_start; 229 int idx = 0, err; 230 231 if (dsos__read_build_ids()) 232 perf_header__set_feat(self, HEADER_BUILD_ID); 233 234 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 235 if (!nr_sections) 236 return 0; 237 238 feat_sec = calloc(sizeof(*feat_sec), nr_sections); 239 if (feat_sec == NULL) 240 return -ENOMEM; 241 242 sec_size = sizeof(*feat_sec) * nr_sections; 243 244 sec_start = self->data_offset + self->data_size; 245 lseek(fd, sec_start + sec_size, SEEK_SET); 246 247 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { 248 struct perf_file_section *trace_sec; 249 250 trace_sec = &feat_sec[idx++]; 251 252 /* Write trace info */ 253 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 254 read_tracing_data(fd, attrs, nr_counters); 255 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 256 } 257 258 259 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 260 struct perf_file_section *buildid_sec; 261 262 buildid_sec = &feat_sec[idx++]; 263 264 /* Write build-ids */ 265 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 266 err = dsos__write_buildid_table(fd); 267 if (err < 0) { 268 pr_debug("failed to write buildid table\n"); 269 goto out_free; 270 } 271 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 272 } 273 274 lseek(fd, sec_start, SEEK_SET); 275 err = do_write(fd, feat_sec, sec_size); 276 if (err < 0) 277 pr_debug("failed to write feature section\n"); 278 out_free: 279 free(feat_sec); 280 return err; 281 } 282 283 int perf_header__write(struct perf_header *self, int fd, bool at_exit) 284 { 285 struct perf_file_header f_header; 286 struct perf_file_attr f_attr; 287 struct perf_header_attr *attr; 288 int i, err; 289 290 lseek(fd, sizeof(f_header), SEEK_SET); 291 292 293 for (i = 0; i < self->attrs; i++) { 294 attr = self->attr[i]; 295 296 attr->id_offset = lseek(fd, 0, SEEK_CUR); 297 err = do_write(fd, attr->id, attr->ids * sizeof(u64)); 298 if (err < 0) { 299 pr_debug("failed to write perf header\n"); 300 return err; 301 } 302 } 303 304 305 self->attr_offset = lseek(fd, 0, SEEK_CUR); 306 307 for (i = 0; i < self->attrs; i++) { 308 attr = self->attr[i]; 309 310 f_attr = (struct perf_file_attr){ 311 .attr = attr->attr, 312 .ids = { 313 .offset = attr->id_offset, 314 .size = attr->ids * sizeof(u64), 315 } 316 }; 317 err = do_write(fd, &f_attr, sizeof(f_attr)); 318 if (err < 0) { 319 pr_debug("failed to write perf header attribute\n"); 320 return err; 321 } 322 } 323 324 self->event_offset = lseek(fd, 0, SEEK_CUR); 325 self->event_size = event_count * sizeof(struct perf_trace_event_type); 326 if (events) { 327 err = do_write(fd, events, self->event_size); 328 if (err < 0) { 329 pr_debug("failed to write perf header events\n"); 330 return err; 331 } 332 } 333 334 self->data_offset = lseek(fd, 0, SEEK_CUR); 335 336 if (at_exit) { 337 err = perf_header__adds_write(self, fd); 338 if (err < 0) 339 return err; 340 } 341 342 f_header = (struct perf_file_header){ 343 .magic = PERF_MAGIC, 344 .size = sizeof(f_header), 345 .attr_size = sizeof(f_attr), 346 .attrs = { 347 .offset = self->attr_offset, 348 .size = self->attrs * sizeof(f_attr), 349 }, 350 .data = { 351 .offset = self->data_offset, 352 .size = self->data_size, 353 }, 354 .event_types = { 355 .offset = self->event_offset, 356 .size = self->event_size, 357 }, 358 }; 359 360 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); 361 362 lseek(fd, 0, SEEK_SET); 363 err = do_write(fd, &f_header, sizeof(f_header)); 364 if (err < 0) { 365 pr_debug("failed to write perf header\n"); 366 return err; 367 } 368 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 369 370 self->frozen = 1; 371 return 0; 372 } 373 374 static void do_read(int fd, void *buf, size_t size) 375 { 376 while (size) { 377 int ret = read(fd, buf, size); 378 379 if (ret < 0) 380 die("failed to read"); 381 if (ret == 0) 382 die("failed to read: missing data"); 383 384 size -= ret; 385 buf += ret; 386 } 387 } 388 389 int perf_header__process_sections(struct perf_header *self, int fd, 390 int (*process)(struct perf_file_section *self, 391 int feat, int fd)) 392 { 393 struct perf_file_section *feat_sec; 394 int nr_sections; 395 int sec_size; 396 int idx = 0; 397 int err = 0, feat = 1; 398 399 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 400 if (!nr_sections) 401 return 0; 402 403 feat_sec = calloc(sizeof(*feat_sec), nr_sections); 404 if (!feat_sec) 405 return -1; 406 407 sec_size = sizeof(*feat_sec) * nr_sections; 408 409 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 410 411 do_read(fd, feat_sec, sec_size); 412 413 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 414 if (perf_header__has_feat(self, feat)) { 415 struct perf_file_section *sec = &feat_sec[idx++]; 416 417 err = process(sec, feat, fd); 418 if (err < 0) 419 break; 420 } 421 ++feat; 422 } 423 424 free(feat_sec); 425 return err; 426 }; 427 428 int perf_file_header__read(struct perf_file_header *self, 429 struct perf_header *ph, int fd) 430 { 431 lseek(fd, 0, SEEK_SET); 432 do_read(fd, self, sizeof(*self)); 433 434 if (self->magic != PERF_MAGIC || 435 self->attr_size != sizeof(struct perf_file_attr)) 436 return -1; 437 438 if (self->size != sizeof(*self)) { 439 /* Support the previous format */ 440 if (self->size == offsetof(typeof(*self), adds_features)) 441 bitmap_zero(self->adds_features, HEADER_FEAT_BITS); 442 else 443 return -1; 444 } 445 446 memcpy(&ph->adds_features, &self->adds_features, 447 sizeof(self->adds_features)); 448 449 ph->event_offset = self->event_types.offset; 450 ph->event_size = self->event_types.size; 451 ph->data_offset = self->data.offset; 452 ph->data_size = self->data.size; 453 return 0; 454 } 455 456 static int perf_file_section__process(struct perf_file_section *self, 457 int feat, int fd) 458 { 459 if (lseek(fd, self->offset, SEEK_SET) < 0) { 460 pr_debug("Failed to lseek to %Ld offset for feature %d, " 461 "continuing...\n", self->offset, feat); 462 return 0; 463 } 464 465 switch (feat) { 466 case HEADER_TRACE_INFO: 467 trace_report(fd); 468 break; 469 470 case HEADER_BUILD_ID: 471 if (perf_header__read_build_ids(fd, self->offset, self->size)) 472 pr_debug("Failed to read buildids, continuing...\n"); 473 break; 474 default: 475 pr_debug("unknown feature %d, continuing...\n", feat); 476 } 477 478 return 0; 479 } 480 481 int perf_header__read(struct perf_header *self, int fd) 482 { 483 struct perf_file_header f_header; 484 struct perf_file_attr f_attr; 485 u64 f_id; 486 int nr_attrs, nr_ids, i, j; 487 488 if (perf_file_header__read(&f_header, self, fd) < 0) { 489 pr_debug("incompatible file format\n"); 490 return -EINVAL; 491 } 492 493 nr_attrs = f_header.attrs.size / sizeof(f_attr); 494 lseek(fd, f_header.attrs.offset, SEEK_SET); 495 496 for (i = 0; i < nr_attrs; i++) { 497 struct perf_header_attr *attr; 498 off_t tmp; 499 500 do_read(fd, &f_attr, sizeof(f_attr)); 501 tmp = lseek(fd, 0, SEEK_CUR); 502 503 attr = perf_header_attr__new(&f_attr.attr); 504 if (attr == NULL) 505 return -ENOMEM; 506 507 nr_ids = f_attr.ids.size / sizeof(u64); 508 lseek(fd, f_attr.ids.offset, SEEK_SET); 509 510 for (j = 0; j < nr_ids; j++) { 511 do_read(fd, &f_id, sizeof(f_id)); 512 513 if (perf_header_attr__add_id(attr, f_id) < 0) { 514 perf_header_attr__delete(attr); 515 return -ENOMEM; 516 } 517 } 518 if (perf_header__add_attr(self, attr) < 0) { 519 perf_header_attr__delete(attr); 520 return -ENOMEM; 521 } 522 523 lseek(fd, tmp, SEEK_SET); 524 } 525 526 if (f_header.event_types.size) { 527 lseek(fd, f_header.event_types.offset, SEEK_SET); 528 events = malloc(f_header.event_types.size); 529 if (events == NULL) 530 return -ENOMEM; 531 do_read(fd, events, f_header.event_types.size); 532 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 533 } 534 535 perf_header__process_sections(self, fd, perf_file_section__process); 536 537 lseek(fd, self->data_offset, SEEK_SET); 538 539 self->frozen = 1; 540 return 0; 541 } 542 543 u64 perf_header__sample_type(struct perf_header *header) 544 { 545 u64 type = 0; 546 int i; 547 548 for (i = 0; i < header->attrs; i++) { 549 struct perf_header_attr *attr = header->attr[i]; 550 551 if (!type) 552 type = attr->attr.sample_type; 553 else if (type != attr->attr.sample_type) 554 die("non matching sample_type"); 555 } 556 557 return type; 558 } 559 560 struct perf_event_attr * 561 perf_header__find_attr(u64 id, struct perf_header *header) 562 { 563 int i; 564 565 for (i = 0; i < header->attrs; i++) { 566 struct perf_header_attr *attr = header->attr[i]; 567 int j; 568 569 for (j = 0; j < attr->ids; j++) { 570 if (attr->id[j] == id) 571 return &attr->attr; 572 } 573 } 574 575 return NULL; 576 } 577