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