header.c 14.2 KB
Newer Older
1 2 3 4
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
5
#include <linux/list.h>
6 7 8

#include "util.h"
#include "header.h"
9 10
#include "../perf.h"
#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 21
{
	struct perf_header_attr *self = malloc(sizeof(*self));

22 23 24 25 26 27 28 29 30 31
	if (self != NULL) {
		self->attr = *attr;
		self->ids  = 0;
		self->size = 1;
		self->id   = malloc(sizeof(u64));
		if (self->id == NULL) {
			free(self);
			self = NULL;
		}
	}
32 33 34 35

	return self;
}

36 37 38 39 40 41
void perf_header_attr__delete(struct perf_header_attr *self)
{
	free(self->id);
	free(self);
}

42
int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
43 44 45 46 47
{
	int pos = self->ids;

	self->ids++;
	if (self->ids > self->size) {
48 49 50 51 52 53 54 55
		int nsize = self->size * 2;
		u64 *nid = realloc(self->id, nsize * sizeof(u64));

		if (nid == NULL)
			return -1;

		self->size = nsize;
		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 64 65
	self->size = 1;
	self->attr = malloc(sizeof(void *));
	return self->attr == NULL ? -ENOMEM : 0;
66 67
}

68
void perf_header__exit(struct perf_header *self)
69 70 71
{
	int i;
	for (i = 0; i < self->attrs; ++i)
72
                perf_header_attr__delete(self->attr[i]);
73 74 75
	free(self->attr);
}

76 77
int perf_header__add_attr(struct perf_header *self,
			  struct perf_header_attr *attr)
78 79
{
	if (self->frozen)
80
		return -1;
81

82
	if (self->attrs == self->size) {
83 84 85 86 87 88 89 90 91
		int nsize = self->size * 2;
		struct perf_header_attr **nattr;

		nattr = realloc(self->attr, nsize * sizeof(void *));
		if (nattr == NULL)
			return -1;

		self->size = nsize;
		self->attr = nattr;
92
	}
93 94

	self->attr[self->attrs++] = attr;
95
	return 0;
96 97
}

98 99
#define MAX_EVENT_NAME 64

100 101
struct perf_trace_event_type {
	u64	event_id;
102
	char	name[MAX_EVENT_NAME];
103 104 105 106 107
};

static int event_count;
static struct perf_trace_event_type *events;

108
int 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 114

	if (!events) {
		events = malloc(sizeof(struct perf_trace_event_type));
115 116
		if (events == NULL)
			return -ENOMEM;
117
	} else {
118 119 120 121 122 123
		struct perf_trace_event_type *nevents;

		nevents = realloc(events, (event_count + 1) * sizeof(*events));
		if (nevents == NULL)
			return -ENOMEM;
		events = nevents;
124 125 126
	}
	memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
	events[event_count].event_id = id;
127
	strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
128
	event_count++;
129
	return 0;
130 131 132 133 134 135 136 137 138 139 140 141
}

char *perf_header__find_event(u64 id)
{
	int i;
	for (i = 0 ; i < event_count; i++) {
		if (events[i].event_id == id)
			return events[i].name;
	}
	return NULL;
}

142 143 144 145 146
static const char *__perf_magic = "PERFFILE";

#define PERF_MAGIC	(*(u64 *)__perf_magic)

struct perf_file_attr {
147
	struct perf_event_attr	attr;
148 149 150
	struct perf_file_section	ids;
};

151 152 153 154 155 156 157 158 159 160
void perf_header__set_feat(struct perf_header *self, int feat)
{
	set_bit(feat, self->adds_features);
}

bool perf_header__has_feat(const struct perf_header *self, int feat)
{
	return test_bit(feat, self->adds_features);
}

161
static int do_write(int fd, const void *buf, size_t size)
162 163 164 165 166
{
	while (size) {
		int ret = write(fd, buf, size);

		if (ret < 0)
167
			return -errno;
168 169 170 171

		size -= ret;
		buf += ret;
	}
172 173

	return 0;
174 175
}

176 177 178 179 180 181 182 183 184 185 186 187 188 189
#define NAME_ALIGN 64

static int write_padded(int fd, const void *bf, size_t count,
			size_t count_aligned)
{
	static const char zero_buf[NAME_ALIGN];
	int err = do_write(fd, bf, count);

	if (!err)
		err = do_write(fd, zero_buf, count_aligned - count);

	return err;
}

190 191 192 193 194 195
#define dsos__for_each_with_build_id(pos, head)	\
	list_for_each_entry(pos, head, node)	\
		if (!pos->has_build_id)		\
			continue;		\
		else

196
static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
197
{
198 199
	struct dso *pos;

200
	dsos__for_each_with_build_id(pos, head) {
201
		int err;
202
		struct build_id_event b;
203
		size_t len = pos->long_name_len + 1;
204

O
OGAWA Hirofumi 已提交
205
		len = ALIGN(len, NAME_ALIGN);
206 207
		memset(&b, 0, sizeof(b));
		memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
208
		b.header.misc = misc;
209
		b.header.size = sizeof(b) + len;
210 211 212
		err = do_write(fd, &b, sizeof(b));
		if (err < 0)
			return err;
213 214
		err = write_padded(fd, pos->long_name,
				   pos->long_name_len + 1, len);
215 216
		if (err < 0)
			return err;
217
	}
218 219

	return 0;
220 221
}

222 223
static int dsos__write_buildid_table(int fd)
{
224 225
	int err = __dsos__write_buildid_table(&dsos__kernel,
					      PERF_RECORD_MISC_KERNEL, fd);
226
	if (err == 0)
227 228
		err = __dsos__write_buildid_table(&dsos__user,
						  PERF_RECORD_MISC_USER, fd);
229 230 231
	return err;
}

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
static int dso__cache_build_id(struct dso *self, const char *debugdir)
{
	const size_t size = PATH_MAX;
	char *filename = malloc(size),
	     *linkname = malloc(size), *targetname, *sbuild_id;
	int len, err = -1;

	if (filename == NULL || linkname == NULL)
		goto out_free;

	len = snprintf(filename, size, "%s%s", debugdir, self->long_name);
	if (mkdir_p(filename, 0755))
		goto out_free;

	len += snprintf(filename + len, sizeof(filename) - len, "/");
	sbuild_id = filename + len;
	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);

	if (access(filename, F_OK) && link(self->long_name, filename) &&
	    copyfile(self->long_name, filename))
		goto out_free;

	len = snprintf(linkname, size, "%s/.build-id/%.2s",
		       debugdir, sbuild_id);

	if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
		goto out_free;

	snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
	targetname = filename + strlen(debugdir) - 5;
	memcpy(targetname, "../..", 5);

	if (symlink(targetname, linkname) == 0)
		err = 0;
out_free:
	free(filename);
	free(linkname);
	return err;
}

static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
{
	struct dso *pos;
	int err = 0;

	dsos__for_each_with_build_id(pos, head)
		if (dso__cache_build_id(pos, debugdir))
			err = -1;

	return err;
}

static int dsos__cache_build_ids(void)
{
	int err_kernel, err_user;
	char debugdir[PATH_MAX];

	snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
		 DEBUG_CACHE_DIR);

	if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
		return -1;

	err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
	err_user   = __dsos__cache_build_ids(&dsos__user, debugdir);
	return err_kernel || err_user ? -1 : 0;
}

300
static int perf_header__adds_write(struct perf_header *self, int fd)
301
{
302 303 304 305
	int nr_sections;
	struct perf_file_section *feat_sec;
	int sec_size;
	u64 sec_start;
306
	int idx = 0, err;
307

308
	if (dsos__read_build_ids())
309 310 311 312
		perf_header__set_feat(self, HEADER_BUILD_ID);

	nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
	if (!nr_sections)
313
		return 0;
314 315

	feat_sec = calloc(sizeof(*feat_sec), nr_sections);
316 317
	if (feat_sec == NULL)
		return -ENOMEM;
318 319 320 321 322

	sec_size = sizeof(*feat_sec) * nr_sections;

	sec_start = self->data_offset + self->data_size;
	lseek(fd, sec_start + sec_size, SEEK_SET);
323

324
	if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
325 326 327 328
		struct perf_file_section *trace_sec;

		trace_sec = &feat_sec[idx++];

329
		/* Write trace info */
330
		trace_sec->offset = lseek(fd, 0, SEEK_CUR);
331
		read_tracing_data(fd, attrs, nr_counters);
332
		trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
333
	}
334

335

336 337 338 339 340 341 342
	if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
		struct perf_file_section *buildid_sec;

		buildid_sec = &feat_sec[idx++];

		/* Write build-ids */
		buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
343 344 345 346 347
		err = dsos__write_buildid_table(fd);
		if (err < 0) {
			pr_debug("failed to write buildid table\n");
			goto out_free;
		}
348
		buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
349
		dsos__cache_build_ids();
350
	}
351 352

	lseek(fd, sec_start, SEEK_SET);
353 354 355 356
	err = do_write(fd, feat_sec, sec_size);
	if (err < 0)
		pr_debug("failed to write feature section\n");
out_free:
357
	free(feat_sec);
358
	return err;
359
}
360

361
int perf_header__write(struct perf_header *self, int fd, bool at_exit)
362 363 364 365
{
	struct perf_file_header f_header;
	struct perf_file_attr   f_attr;
	struct perf_header_attr	*attr;
366
	int i, err;
367 368 369 370 371 372 373 374

	lseek(fd, sizeof(f_header), SEEK_SET);


	for (i = 0; i < self->attrs; i++) {
		attr = self->attr[i];

		attr->id_offset = lseek(fd, 0, SEEK_CUR);
375 376 377 378 379
		err = do_write(fd, attr->id, attr->ids * sizeof(u64));
		if (err < 0) {
			pr_debug("failed to write perf header\n");
			return err;
		}
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
	}


	self->attr_offset = lseek(fd, 0, SEEK_CUR);

	for (i = 0; i < self->attrs; i++) {
		attr = self->attr[i];

		f_attr = (struct perf_file_attr){
			.attr = attr->attr,
			.ids  = {
				.offset = attr->id_offset,
				.size   = attr->ids * sizeof(u64),
			}
		};
395 396 397 398 399
		err = do_write(fd, &f_attr, sizeof(f_attr));
		if (err < 0) {
			pr_debug("failed to write perf header attribute\n");
			return err;
		}
400 401
	}

402 403
	self->event_offset = lseek(fd, 0, SEEK_CUR);
	self->event_size = event_count * sizeof(struct perf_trace_event_type);
404 405 406 407 408 409 410
	if (events) {
		err = do_write(fd, events, self->event_size);
		if (err < 0) {
			pr_debug("failed to write perf header events\n");
			return err;
		}
	}
411

412 413
	self->data_offset = lseek(fd, 0, SEEK_CUR);

414 415 416 417 418
	if (at_exit) {
		err = perf_header__adds_write(self, fd);
		if (err < 0)
			return err;
	}
419

420 421 422 423 424 425 426 427 428 429 430 431
	f_header = (struct perf_file_header){
		.magic	   = PERF_MAGIC,
		.size	   = sizeof(f_header),
		.attr_size = sizeof(f_attr),
		.attrs = {
			.offset = self->attr_offset,
			.size   = self->attrs * sizeof(f_attr),
		},
		.data = {
			.offset = self->data_offset,
			.size	= self->data_size,
		},
432 433 434 435
		.event_types = {
			.offset = self->event_offset,
			.size	= self->event_size,
		},
436 437
	};

438
	memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
439

440
	lseek(fd, 0, SEEK_SET);
441 442 443 444 445
	err = do_write(fd, &f_header, sizeof(f_header));
	if (err < 0) {
		pr_debug("failed to write perf header\n");
		return err;
	}
446 447 448
	lseek(fd, self->data_offset + self->data_size, SEEK_SET);

	self->frozen = 1;
449
	return 0;
450 451
}

452
static int do_read(int fd, void *buf, size_t size)
453 454 455 456
{
	while (size) {
		int ret = read(fd, buf, size);

457 458
		if (ret <= 0)
			return -1;
459 460 461 462

		size -= ret;
		buf += ret;
	}
463 464

	return 0;
465 466
}

467 468 469
int perf_header__process_sections(struct perf_header *self, int fd,
				  int (*process)(struct perf_file_section *self,
						 int feat, int fd))
470
{
471 472 473 474
	struct perf_file_section *feat_sec;
	int nr_sections;
	int sec_size;
	int idx = 0;
475
	int err = -1, feat = 1;
476 477 478

	nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
	if (!nr_sections)
479
		return 0;
480 481 482

	feat_sec = calloc(sizeof(*feat_sec), nr_sections);
	if (!feat_sec)
483
		return -1;
484 485 486 487 488

	sec_size = sizeof(*feat_sec) * nr_sections;

	lseek(fd, self->data_offset + self->data_size, SEEK_SET);

489 490
	if (do_read(fd, feat_sec, sec_size))
		goto out_free;
491

492
	err = 0;
493 494 495
	while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
		if (perf_header__has_feat(self, feat)) {
			struct perf_file_section *sec = &feat_sec[idx++];
496

497 498 499 500 501
			err = process(sec, feat, fd);
			if (err < 0)
				break;
		}
		++feat;
502
	}
503
out_free:
504 505
	free(feat_sec);
	return err;
506
}
507

508 509 510 511 512
int perf_file_header__read(struct perf_file_header *self,
			   struct perf_header *ph, int fd)
{
	lseek(fd, 0, SEEK_SET);

513 514
	if (do_read(fd, self, sizeof(*self)) ||
	    self->magic     != PERF_MAGIC ||
515 516 517 518 519 520 521 522 523
	    self->attr_size != sizeof(struct perf_file_attr))
		return -1;

	if (self->size != sizeof(*self)) {
		/* Support the previous format */
		if (self->size == offsetof(typeof(*self), adds_features))
			bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
		else
			return -1;
524
	}
525

526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
	memcpy(&ph->adds_features, &self->adds_features,
	       sizeof(self->adds_features));

	ph->event_offset = self->event_types.offset;
	ph->event_size	 = self->event_types.size;
	ph->data_offset	 = self->data.offset;
	ph->data_size	 = self->data.size;
	return 0;
}

static int perf_file_section__process(struct perf_file_section *self,
				      int feat, int fd)
{
	if (lseek(fd, self->offset, SEEK_SET) < 0) {
		pr_debug("Failed to lseek to %Ld offset for feature %d, "
			 "continuing...\n", self->offset, feat);
		return 0;
	}

	switch (feat) {
	case HEADER_TRACE_INFO:
		trace_report(fd);
		break;

	case HEADER_BUILD_ID:
		if (perf_header__read_build_ids(fd, self->offset, self->size))
			pr_debug("Failed to read buildids, continuing...\n");
		break;
	default:
		pr_debug("unknown feature %d, continuing...\n", feat);
	}

	return 0;
}
560

561
int perf_header__read(struct perf_header *self, int fd)
562 563 564 565 566 567
{
	struct perf_file_header f_header;
	struct perf_file_attr	f_attr;
	u64			f_id;
	int nr_attrs, nr_ids, i, j;

568 569 570 571
	if (perf_file_header__read(&f_header, self, fd) < 0) {
		pr_debug("incompatible file format\n");
		return -EINVAL;
	}
572 573 574 575 576 577

	nr_attrs = f_header.attrs.size / sizeof(f_attr);
	lseek(fd, f_header.attrs.offset, SEEK_SET);

	for (i = 0; i < nr_attrs; i++) {
		struct perf_header_attr *attr;
578
		off_t tmp;
579

580 581
		if (do_read(fd, &f_attr, sizeof(f_attr)))
			goto out_errno;
582
		tmp = lseek(fd, 0, SEEK_CUR);
583 584

		attr = perf_header_attr__new(&f_attr.attr);
585
		if (attr == NULL)
586
			 return -ENOMEM;
587 588 589 590 591

		nr_ids = f_attr.ids.size / sizeof(u64);
		lseek(fd, f_attr.ids.offset, SEEK_SET);

		for (j = 0; j < nr_ids; j++) {
592 593
			if (do_read(fd, &f_id, sizeof(f_id)))
				goto out_errno;
594

595 596 597 598 599 600 601 602
			if (perf_header_attr__add_id(attr, f_id) < 0) {
				perf_header_attr__delete(attr);
				return -ENOMEM;
			}
		}
		if (perf_header__add_attr(self, attr) < 0) {
			perf_header_attr__delete(attr);
			return -ENOMEM;
603
		}
604

605 606 607
		lseek(fd, tmp, SEEK_SET);
	}

608 609 610
	if (f_header.event_types.size) {
		lseek(fd, f_header.event_types.offset, SEEK_SET);
		events = malloc(f_header.event_types.size);
611 612
		if (events == NULL)
			return -ENOMEM;
613 614
		if (do_read(fd, events, f_header.event_types.size))
			goto out_errno;
615 616
		event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
	}
617

618
	perf_header__process_sections(self, fd, perf_file_section__process);
619

620
	lseek(fd, self->data_offset, SEEK_SET);
621 622

	self->frozen = 1;
623
	return 0;
624 625
out_errno:
	return -errno;
626
}
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644

u64 perf_header__sample_type(struct perf_header *header)
{
	u64 type = 0;
	int i;

	for (i = 0; i < header->attrs; i++) {
		struct perf_header_attr *attr = header->attr[i];

		if (!type)
			type = attr->attr.sample_type;
		else if (type != attr->attr.sample_type)
			die("non matching sample_type");
	}

	return type;
}

645
struct perf_event_attr *
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
perf_header__find_attr(u64 id, struct perf_header *header)
{
	int i;

	for (i = 0; i < header->attrs; i++) {
		struct perf_header_attr *attr = header->attr[i];
		int j;

		for (j = 0; j < attr->ids; j++) {
			if (attr->id[j] == id)
				return &attr->attr;
		}
	}

	return NULL;
}