header.c 14.1 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, 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 208
		memset(&b, 0, sizeof(b));
		memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
		b.header.size = sizeof(b) + len;
209 210 211
		err = do_write(fd, &b, sizeof(b));
		if (err < 0)
			return err;
212 213
		err = write_padded(fd, pos->long_name,
				   pos->long_name_len + 1, len);
214 215
		if (err < 0)
			return err;
216
	}
217 218

	return 0;
219 220
}

221 222 223 224 225 226 227 228
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;
}

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 283 284 285 286 287 288 289 290 291 292 293 294 295 296
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;
}

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

305
	if (dsos__read_build_ids())
306 307 308 309
		perf_header__set_feat(self, HEADER_BUILD_ID);

	nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
	if (!nr_sections)
310
		return 0;
311 312

	feat_sec = calloc(sizeof(*feat_sec), nr_sections);
313 314
	if (feat_sec == NULL)
		return -ENOMEM;
315 316 317 318 319

	sec_size = sizeof(*feat_sec) * nr_sections;

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

321
	if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
322 323 324 325
		struct perf_file_section *trace_sec;

		trace_sec = &feat_sec[idx++];

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

332

333 334 335 336 337 338 339
	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);
340 341 342 343 344
		err = dsos__write_buildid_table(fd);
		if (err < 0) {
			pr_debug("failed to write buildid table\n");
			goto out_free;
		}
345
		buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
346
		dsos__cache_build_ids();
347
	}
348 349

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

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

	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);
372 373 374 375 376
		err = do_write(fd, attr->id, attr->ids * sizeof(u64));
		if (err < 0) {
			pr_debug("failed to write perf header\n");
			return err;
		}
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
	}


	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),
			}
		};
392 393 394 395 396
		err = do_write(fd, &f_attr, sizeof(f_attr));
		if (err < 0) {
			pr_debug("failed to write perf header attribute\n");
			return err;
		}
397 398
	}

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

409 410
	self->data_offset = lseek(fd, 0, SEEK_CUR);

411 412 413 414 415
	if (at_exit) {
		err = perf_header__adds_write(self, fd);
		if (err < 0)
			return err;
	}
416

417 418 419 420 421 422 423 424 425 426 427 428
	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,
		},
429 430 431 432
		.event_types = {
			.offset = self->event_offset,
			.size	= self->event_size,
		},
433 434
	};

435
	memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
436

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

	self->frozen = 1;
446
	return 0;
447 448
}

449
static int do_read(int fd, void *buf, size_t size)
450 451 452 453
{
	while (size) {
		int ret = read(fd, buf, size);

454 455
		if (ret <= 0)
			return -1;
456 457 458 459

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

	return 0;
462 463
}

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

	nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
	if (!nr_sections)
476
		return 0;
477 478 479

	feat_sec = calloc(sizeof(*feat_sec), nr_sections);
	if (!feat_sec)
480
		return -1;
481 482 483 484 485

	sec_size = sizeof(*feat_sec) * nr_sections;

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

486 487
	if (do_read(fd, feat_sec, sec_size))
		goto out_free;
488

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

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

505 506 507 508 509
int perf_file_header__read(struct perf_file_header *self,
			   struct perf_header *ph, int fd)
{
	lseek(fd, 0, SEEK_SET);

510 511
	if (do_read(fd, self, sizeof(*self)) ||
	    self->magic     != PERF_MAGIC ||
512 513 514 515 516 517 518 519 520
	    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;
521
	}
522

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

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

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

	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;
575
		off_t tmp;
576

577 578
		if (do_read(fd, &f_attr, sizeof(f_attr)))
			goto out_errno;
579
		tmp = lseek(fd, 0, SEEK_CUR);
580 581

		attr = perf_header_attr__new(&f_attr.attr);
582
		if (attr == NULL)
583
			 return -ENOMEM;
584 585 586 587 588

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

		for (j = 0; j < nr_ids; j++) {
589 590
			if (do_read(fd, &f_id, sizeof(f_id)))
				goto out_errno;
591

592 593 594 595 596 597 598 599
			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;
600
		}
601

602 603 604
		lseek(fd, tmp, SEEK_SET);
	}

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

615
	perf_header__process_sections(self, fd, perf_file_section__process);
616

617
	lseek(fd, self->data_offset, SEEK_SET);
618 619

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

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

642
struct perf_event_attr *
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
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;
}