header.c 13.8 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 108 109
};

static int event_count;
static struct perf_trace_event_type *events;

void perf_header__push_event(u64 id, const char *name)
{
110
	if (strlen(name) > MAX_EVENT_NAME)
111
		pr_warning("Event %s will be truncated\n", name);
112 113 114 115 116 117 118 119 120 121 122 123

	if (!events) {
		events = malloc(sizeof(struct perf_trace_event_type));
		if (!events)
			die("nomem");
	} else {
		events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type));
		if (!events)
			die("nomem");
	}
	memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
	events[event_count].event_id = id;
124
	strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
125 126 127 128 129 130 131 132 133 134 135 136 137
	event_count++;
}

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;
}

138 139 140 141 142
static const char *__perf_magic = "PERFFILE";

#define PERF_MAGIC	(*(u64 *)__perf_magic)

struct perf_file_attr {
143
	struct perf_event_attr	attr;
144 145 146
	struct perf_file_section	ids;
};

147 148 149 150 151 152 153 154 155 156
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);
}

157
static int do_write(int fd, const void *buf, size_t size)
158 159 160 161 162
{
	while (size) {
		int ret = write(fd, buf, size);

		if (ret < 0)
163
			return -errno;
164 165 166 167

		size -= ret;
		buf += ret;
	}
168 169

	return 0;
170 171
}

172 173 174 175 176 177
#define dsos__for_each_with_build_id(pos, head)	\
	list_for_each_entry(pos, head, node)	\
		if (!pos->has_build_id)		\
			continue;		\
		else

178
static int __dsos__write_buildid_table(struct list_head *head, int fd)
179
{
O
OGAWA Hirofumi 已提交
180
#define NAME_ALIGN	64
181
	struct dso *pos;
O
OGAWA Hirofumi 已提交
182
	static const char zero_buf[NAME_ALIGN];
183

184
	dsos__for_each_with_build_id(pos, head) {
185
		int err;
186
		struct build_id_event b;
187
		size_t len = pos->long_name_len + 1;
188

O
OGAWA Hirofumi 已提交
189
		len = ALIGN(len, NAME_ALIGN);
190 191 192
		memset(&b, 0, sizeof(b));
		memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
		b.header.size = sizeof(b) + len;
193 194 195
		err = do_write(fd, &b, sizeof(b));
		if (err < 0)
			return err;
O
OGAWA Hirofumi 已提交
196 197 198
		err = do_write(fd, pos->long_name, pos->long_name_len + 1);
		if (err < 0)
			return err;
199
		err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
200 201
		if (err < 0)
			return err;
202
	}
203 204

	return 0;
205 206
}

207 208 209 210 211 212 213 214
static int dsos__write_buildid_table(int fd)
{
	int err = __dsos__write_buildid_table(&dsos__kernel, fd);
	if (err == 0)
		err = __dsos__write_buildid_table(&dsos__user, fd);
	return err;
}

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 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
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;
}

283
static int perf_header__adds_write(struct perf_header *self, int fd)
284
{
285 286 287 288
	int nr_sections;
	struct perf_file_section *feat_sec;
	int sec_size;
	u64 sec_start;
289
	int idx = 0, err;
290

291
	if (dsos__read_build_ids())
292 293 294 295
		perf_header__set_feat(self, HEADER_BUILD_ID);

	nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
	if (!nr_sections)
296
		return 0;
297 298

	feat_sec = calloc(sizeof(*feat_sec), nr_sections);
299 300
	if (feat_sec == NULL)
		return -ENOMEM;
301 302 303 304 305

	sec_size = sizeof(*feat_sec) * nr_sections;

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

307
	if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
308 309 310 311
		struct perf_file_section *trace_sec;

		trace_sec = &feat_sec[idx++];

312
		/* Write trace info */
313
		trace_sec->offset = lseek(fd, 0, SEEK_CUR);
314
		read_tracing_data(fd, attrs, nr_counters);
315
		trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
316
	}
317

318

319 320 321 322 323 324 325
	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);
326 327 328 329 330
		err = dsos__write_buildid_table(fd);
		if (err < 0) {
			pr_debug("failed to write buildid table\n");
			goto out_free;
		}
331
		buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
332
		dsos__cache_build_ids();
333
	}
334 335

	lseek(fd, sec_start, SEEK_SET);
336 337 338 339
	err = do_write(fd, feat_sec, sec_size);
	if (err < 0)
		pr_debug("failed to write feature section\n");
out_free:
340
	free(feat_sec);
341
	return err;
342
}
343

344
int perf_header__write(struct perf_header *self, int fd, bool at_exit)
345 346 347 348
{
	struct perf_file_header f_header;
	struct perf_file_attr   f_attr;
	struct perf_header_attr	*attr;
349
	int i, err;
350 351 352 353 354 355 356 357

	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);
358 359 360 361 362
		err = do_write(fd, attr->id, attr->ids * sizeof(u64));
		if (err < 0) {
			pr_debug("failed to write perf header\n");
			return err;
		}
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
	}


	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),
			}
		};
378 379 380 381 382
		err = do_write(fd, &f_attr, sizeof(f_attr));
		if (err < 0) {
			pr_debug("failed to write perf header attribute\n");
			return err;
		}
383 384
	}

385 386
	self->event_offset = lseek(fd, 0, SEEK_CUR);
	self->event_size = event_count * sizeof(struct perf_trace_event_type);
387 388 389 390 391 392 393
	if (events) {
		err = do_write(fd, events, self->event_size);
		if (err < 0) {
			pr_debug("failed to write perf header events\n");
			return err;
		}
	}
394

395 396
	self->data_offset = lseek(fd, 0, SEEK_CUR);

397 398 399 400 401
	if (at_exit) {
		err = perf_header__adds_write(self, fd);
		if (err < 0)
			return err;
	}
402

403 404 405 406 407 408 409 410 411 412 413 414
	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,
		},
415 416 417 418
		.event_types = {
			.offset = self->event_offset,
			.size	= self->event_size,
		},
419 420
	};

421
	memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
422

423
	lseek(fd, 0, SEEK_SET);
424 425 426 427 428
	err = do_write(fd, &f_header, sizeof(f_header));
	if (err < 0) {
		pr_debug("failed to write perf header\n");
		return err;
	}
429 430 431
	lseek(fd, self->data_offset + self->data_size, SEEK_SET);

	self->frozen = 1;
432
	return 0;
433 434 435 436 437 438 439 440 441
}

static void do_read(int fd, void *buf, size_t size)
{
	while (size) {
		int ret = read(fd, buf, size);

		if (ret < 0)
			die("failed to read");
442 443
		if (ret == 0)
			die("failed to read: missing data");
444 445 446 447 448 449

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

450 451 452
int perf_header__process_sections(struct perf_header *self, int fd,
				  int (*process)(struct perf_file_section *self,
						 int feat, int fd))
453
{
454 455 456 457
	struct perf_file_section *feat_sec;
	int nr_sections;
	int sec_size;
	int idx = 0;
458
	int err = 0, feat = 1;
459 460 461

	nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
	if (!nr_sections)
462
		return 0;
463 464 465

	feat_sec = calloc(sizeof(*feat_sec), nr_sections);
	if (!feat_sec)
466
		return -1;
467 468 469 470 471 472 473

	sec_size = sizeof(*feat_sec) * nr_sections;

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

	do_read(fd, feat_sec, sec_size);

474 475 476
	while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
		if (perf_header__has_feat(self, feat)) {
			struct perf_file_section *sec = &feat_sec[idx++];
477

478 479 480 481 482
			err = process(sec, feat, fd);
			if (err < 0)
				break;
		}
		++feat;
483
	}
484

485 486 487
	free(feat_sec);
	return err;
};
488

489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
int perf_file_header__read(struct perf_file_header *self,
			   struct perf_header *ph, int fd)
{
	lseek(fd, 0, SEEK_SET);
	do_read(fd, self, sizeof(*self));

	if (self->magic     != PERF_MAGIC ||
	    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;
505
	}
506

507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
	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;
}
541

542
int perf_header__read(struct perf_header *self, int fd)
543 544 545 546 547 548
{
	struct perf_file_header f_header;
	struct perf_file_attr	f_attr;
	u64			f_id;
	int nr_attrs, nr_ids, i, j;

549 550 551 552
	if (perf_file_header__read(&f_header, self, fd) < 0) {
		pr_debug("incompatible file format\n");
		return -EINVAL;
	}
553 554 555 556 557 558

	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;
559
		off_t tmp;
560 561

		do_read(fd, &f_attr, sizeof(f_attr));
562
		tmp = lseek(fd, 0, SEEK_CUR);
563 564

		attr = perf_header_attr__new(&f_attr.attr);
565
		if (attr == NULL)
566
			 return -ENOMEM;
567 568 569 570 571 572 573

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

		for (j = 0; j < nr_ids; j++) {
			do_read(fd, &f_id, sizeof(f_id));

574 575 576 577 578 579 580 581
			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;
582
		}
583

584 585 586
		lseek(fd, tmp, SEEK_SET);
	}

587 588 589
	if (f_header.event_types.size) {
		lseek(fd, f_header.event_types.offset, SEEK_SET);
		events = malloc(f_header.event_types.size);
590 591
		if (events == NULL)
			return -ENOMEM;
592 593 594
		do_read(fd, events, f_header.event_types.size);
		event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
	}
595

596
	perf_header__process_sections(self, fd, perf_file_section__process);
597

598
	lseek(fd, self->data_offset, SEEK_SET);
599 600

	self->frozen = 1;
601
	return 0;
602
}
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620

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;
}

621
struct perf_event_attr *
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
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;
}