diff options
Diffstat (limited to 'tools/perf/util/header.c')
| -rw-r--r-- | tools/perf/util/header.c | 388 |
1 files changed, 31 insertions, 357 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ce0de00399da..b20e40c74468 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -24,8 +24,6 @@ | |||
| 24 | #include "build-id.h" | 24 | #include "build-id.h" |
| 25 | #include "data.h" | 25 | #include "data.h" |
| 26 | 26 | ||
| 27 | static bool no_buildid_cache = false; | ||
| 28 | |||
| 29 | static u32 header_argc; | 27 | static u32 header_argc; |
| 30 | static const char **header_argv; | 28 | static const char **header_argv; |
| 31 | 29 | ||
| @@ -79,10 +77,7 @@ static int do_write(int fd, const void *buf, size_t size) | |||
| 79 | return 0; | 77 | return 0; |
| 80 | } | 78 | } |
| 81 | 79 | ||
| 82 | #define NAME_ALIGN 64 | 80 | int write_padded(int fd, const void *bf, size_t count, size_t count_aligned) |
| 83 | |||
| 84 | static int write_padded(int fd, const void *bf, size_t count, | ||
| 85 | size_t count_aligned) | ||
| 86 | { | 81 | { |
| 87 | static const char zero_buf[NAME_ALIGN]; | 82 | static const char zero_buf[NAME_ALIGN]; |
| 88 | int err = do_write(fd, bf, count); | 83 | int err = do_write(fd, bf, count); |
| @@ -171,340 +166,6 @@ perf_header__set_cmdline(int argc, const char **argv) | |||
| 171 | return 0; | 166 | return 0; |
| 172 | } | 167 | } |
| 173 | 168 | ||
| 174 | #define dsos__for_each_with_build_id(pos, head) \ | ||
| 175 | list_for_each_entry(pos, head, node) \ | ||
| 176 | if (!pos->has_build_id) \ | ||
| 177 | continue; \ | ||
| 178 | else | ||
| 179 | |||
| 180 | static int write_buildid(const char *name, size_t name_len, u8 *build_id, | ||
| 181 | pid_t pid, u16 misc, int fd) | ||
| 182 | { | ||
| 183 | int err; | ||
| 184 | struct build_id_event b; | ||
| 185 | size_t len; | ||
| 186 | |||
| 187 | len = name_len + 1; | ||
| 188 | len = PERF_ALIGN(len, NAME_ALIGN); | ||
| 189 | |||
| 190 | memset(&b, 0, sizeof(b)); | ||
| 191 | memcpy(&b.build_id, build_id, BUILD_ID_SIZE); | ||
| 192 | b.pid = pid; | ||
| 193 | b.header.misc = misc; | ||
| 194 | b.header.size = sizeof(b) + len; | ||
| 195 | |||
| 196 | err = do_write(fd, &b, sizeof(b)); | ||
| 197 | if (err < 0) | ||
| 198 | return err; | ||
| 199 | |||
| 200 | return write_padded(fd, name, name_len + 1, len); | ||
| 201 | } | ||
| 202 | |||
| 203 | static int __dsos__hit_all(struct list_head *head) | ||
| 204 | { | ||
| 205 | struct dso *pos; | ||
| 206 | |||
| 207 | list_for_each_entry(pos, head, node) | ||
| 208 | pos->hit = true; | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | static int machine__hit_all_dsos(struct machine *machine) | ||
| 214 | { | ||
| 215 | int err; | ||
| 216 | |||
| 217 | err = __dsos__hit_all(&machine->kernel_dsos.head); | ||
| 218 | if (err) | ||
| 219 | return err; | ||
| 220 | |||
| 221 | return __dsos__hit_all(&machine->user_dsos.head); | ||
| 222 | } | ||
| 223 | |||
| 224 | int dsos__hit_all(struct perf_session *session) | ||
| 225 | { | ||
| 226 | struct rb_node *nd; | ||
| 227 | int err; | ||
| 228 | |||
| 229 | err = machine__hit_all_dsos(&session->machines.host); | ||
| 230 | if (err) | ||
| 231 | return err; | ||
| 232 | |||
| 233 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { | ||
| 234 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
| 235 | |||
| 236 | err = machine__hit_all_dsos(pos); | ||
| 237 | if (err) | ||
| 238 | return err; | ||
| 239 | } | ||
| 240 | |||
| 241 | return 0; | ||
| 242 | } | ||
| 243 | |||
| 244 | static int __dsos__write_buildid_table(struct list_head *head, | ||
| 245 | struct machine *machine, | ||
| 246 | pid_t pid, u16 misc, int fd) | ||
| 247 | { | ||
| 248 | char nm[PATH_MAX]; | ||
| 249 | struct dso *pos; | ||
| 250 | |||
| 251 | dsos__for_each_with_build_id(pos, head) { | ||
| 252 | int err; | ||
| 253 | const char *name; | ||
| 254 | size_t name_len; | ||
| 255 | |||
| 256 | if (!pos->hit) | ||
| 257 | continue; | ||
| 258 | |||
| 259 | if (dso__is_vdso(pos)) { | ||
| 260 | name = pos->short_name; | ||
| 261 | name_len = pos->short_name_len + 1; | ||
| 262 | } else if (dso__is_kcore(pos)) { | ||
| 263 | machine__mmap_name(machine, nm, sizeof(nm)); | ||
| 264 | name = nm; | ||
| 265 | name_len = strlen(nm) + 1; | ||
| 266 | } else { | ||
| 267 | name = pos->long_name; | ||
| 268 | name_len = pos->long_name_len + 1; | ||
| 269 | } | ||
| 270 | |||
| 271 | err = write_buildid(name, name_len, pos->build_id, | ||
| 272 | pid, misc, fd); | ||
| 273 | if (err) | ||
| 274 | return err; | ||
| 275 | } | ||
| 276 | |||
| 277 | return 0; | ||
| 278 | } | ||
| 279 | |||
| 280 | static int machine__write_buildid_table(struct machine *machine, int fd) | ||
| 281 | { | ||
| 282 | int err; | ||
| 283 | u16 kmisc = PERF_RECORD_MISC_KERNEL, | ||
| 284 | umisc = PERF_RECORD_MISC_USER; | ||
| 285 | |||
| 286 | if (!machine__is_host(machine)) { | ||
| 287 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; | ||
| 288 | umisc = PERF_RECORD_MISC_GUEST_USER; | ||
| 289 | } | ||
| 290 | |||
| 291 | err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine, | ||
| 292 | machine->pid, kmisc, fd); | ||
| 293 | if (err == 0) | ||
| 294 | err = __dsos__write_buildid_table(&machine->user_dsos.head, | ||
| 295 | machine, machine->pid, umisc, | ||
| 296 | fd); | ||
| 297 | return err; | ||
| 298 | } | ||
| 299 | |||
| 300 | static int dsos__write_buildid_table(struct perf_header *header, int fd) | ||
| 301 | { | ||
| 302 | struct perf_session *session = container_of(header, | ||
| 303 | struct perf_session, header); | ||
| 304 | struct rb_node *nd; | ||
| 305 | int err = machine__write_buildid_table(&session->machines.host, fd); | ||
| 306 | |||
| 307 | if (err) | ||
| 308 | return err; | ||
| 309 | |||
| 310 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { | ||
| 311 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
| 312 | err = machine__write_buildid_table(pos, fd); | ||
| 313 | if (err) | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | return err; | ||
| 317 | } | ||
| 318 | |||
| 319 | int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | ||
| 320 | const char *name, bool is_kallsyms, bool is_vdso) | ||
| 321 | { | ||
| 322 | const size_t size = PATH_MAX; | ||
| 323 | char *realname, *filename = zalloc(size), | ||
| 324 | *linkname = zalloc(size), *targetname; | ||
| 325 | int len, err = -1; | ||
| 326 | bool slash = is_kallsyms || is_vdso; | ||
| 327 | |||
| 328 | if (is_kallsyms) { | ||
| 329 | if (symbol_conf.kptr_restrict) { | ||
| 330 | pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); | ||
| 331 | err = 0; | ||
| 332 | goto out_free; | ||
| 333 | } | ||
| 334 | realname = (char *) name; | ||
| 335 | } else | ||
| 336 | realname = realpath(name, NULL); | ||
| 337 | |||
| 338 | if (realname == NULL || filename == NULL || linkname == NULL) | ||
| 339 | goto out_free; | ||
| 340 | |||
| 341 | len = scnprintf(filename, size, "%s%s%s", | ||
| 342 | debugdir, slash ? "/" : "", | ||
| 343 | is_vdso ? DSO__NAME_VDSO : realname); | ||
| 344 | if (mkdir_p(filename, 0755)) | ||
| 345 | goto out_free; | ||
| 346 | |||
| 347 | snprintf(filename + len, size - len, "/%s", sbuild_id); | ||
| 348 | |||
| 349 | if (access(filename, F_OK)) { | ||
| 350 | if (is_kallsyms) { | ||
| 351 | if (copyfile("/proc/kallsyms", filename)) | ||
| 352 | goto out_free; | ||
| 353 | } else if (link(realname, filename) && copyfile(name, filename)) | ||
| 354 | goto out_free; | ||
| 355 | } | ||
| 356 | |||
| 357 | len = scnprintf(linkname, size, "%s/.build-id/%.2s", | ||
| 358 | debugdir, sbuild_id); | ||
| 359 | |||
| 360 | if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) | ||
| 361 | goto out_free; | ||
| 362 | |||
| 363 | snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); | ||
| 364 | targetname = filename + strlen(debugdir) - 5; | ||
| 365 | memcpy(targetname, "../..", 5); | ||
| 366 | |||
| 367 | if (symlink(targetname, linkname) == 0) | ||
| 368 | err = 0; | ||
| 369 | out_free: | ||
| 370 | if (!is_kallsyms) | ||
| 371 | free(realname); | ||
| 372 | free(filename); | ||
| 373 | free(linkname); | ||
| 374 | return err; | ||
| 375 | } | ||
| 376 | |||
| 377 | static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, | ||
| 378 | const char *name, const char *debugdir, | ||
| 379 | bool is_kallsyms, bool is_vdso) | ||
| 380 | { | ||
| 381 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
| 382 | |||
| 383 | build_id__sprintf(build_id, build_id_size, sbuild_id); | ||
| 384 | |||
| 385 | return build_id_cache__add_s(sbuild_id, debugdir, name, | ||
| 386 | is_kallsyms, is_vdso); | ||
| 387 | } | ||
| 388 | |||
| 389 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) | ||
| 390 | { | ||
| 391 | const size_t size = PATH_MAX; | ||
| 392 | char *filename = zalloc(size), | ||
| 393 | *linkname = zalloc(size); | ||
| 394 | int err = -1; | ||
| 395 | |||
| 396 | if (filename == NULL || linkname == NULL) | ||
| 397 | goto out_free; | ||
| 398 | |||
| 399 | snprintf(linkname, size, "%s/.build-id/%.2s/%s", | ||
| 400 | debugdir, sbuild_id, sbuild_id + 2); | ||
| 401 | |||
| 402 | if (access(linkname, F_OK)) | ||
| 403 | goto out_free; | ||
| 404 | |||
| 405 | if (readlink(linkname, filename, size - 1) < 0) | ||
| 406 | goto out_free; | ||
| 407 | |||
| 408 | if (unlink(linkname)) | ||
| 409 | goto out_free; | ||
| 410 | |||
| 411 | /* | ||
| 412 | * Since the link is relative, we must make it absolute: | ||
| 413 | */ | ||
| 414 | snprintf(linkname, size, "%s/.build-id/%.2s/%s", | ||
| 415 | debugdir, sbuild_id, filename); | ||
| 416 | |||
| 417 | if (unlink(linkname)) | ||
| 418 | goto out_free; | ||
| 419 | |||
| 420 | err = 0; | ||
| 421 | out_free: | ||
| 422 | free(filename); | ||
| 423 | free(linkname); | ||
| 424 | return err; | ||
| 425 | } | ||
| 426 | |||
| 427 | static int dso__cache_build_id(struct dso *dso, struct machine *machine, | ||
| 428 | const char *debugdir) | ||
| 429 | { | ||
| 430 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; | ||
| 431 | bool is_vdso = dso__is_vdso(dso); | ||
| 432 | const char *name = dso->long_name; | ||
| 433 | char nm[PATH_MAX]; | ||
| 434 | |||
| 435 | if (dso__is_kcore(dso)) { | ||
| 436 | is_kallsyms = true; | ||
| 437 | machine__mmap_name(machine, nm, sizeof(nm)); | ||
| 438 | name = nm; | ||
| 439 | } | ||
| 440 | return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name, | ||
| 441 | debugdir, is_kallsyms, is_vdso); | ||
| 442 | } | ||
| 443 | |||
| 444 | static int __dsos__cache_build_ids(struct list_head *head, | ||
| 445 | struct machine *machine, const char *debugdir) | ||
| 446 | { | ||
| 447 | struct dso *pos; | ||
| 448 | int err = 0; | ||
| 449 | |||
| 450 | dsos__for_each_with_build_id(pos, head) | ||
| 451 | if (dso__cache_build_id(pos, machine, debugdir)) | ||
| 452 | err = -1; | ||
| 453 | |||
| 454 | return err; | ||
| 455 | } | ||
| 456 | |||
| 457 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) | ||
| 458 | { | ||
| 459 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine, | ||
| 460 | debugdir); | ||
| 461 | ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine, | ||
| 462 | debugdir); | ||
| 463 | return ret; | ||
| 464 | } | ||
| 465 | |||
| 466 | static int perf_session__cache_build_ids(struct perf_session *session) | ||
| 467 | { | ||
| 468 | struct rb_node *nd; | ||
| 469 | int ret; | ||
| 470 | char debugdir[PATH_MAX]; | ||
| 471 | |||
| 472 | snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); | ||
| 473 | |||
| 474 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | ||
| 475 | return -1; | ||
| 476 | |||
| 477 | ret = machine__cache_build_ids(&session->machines.host, debugdir); | ||
| 478 | |||
| 479 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { | ||
| 480 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
| 481 | ret |= machine__cache_build_ids(pos, debugdir); | ||
| 482 | } | ||
| 483 | return ret ? -1 : 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | static bool machine__read_build_ids(struct machine *machine, bool with_hits) | ||
| 487 | { | ||
| 488 | bool ret; | ||
| 489 | |||
| 490 | ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits); | ||
| 491 | ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits); | ||
| 492 | return ret; | ||
| 493 | } | ||
| 494 | |||
| 495 | static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) | ||
| 496 | { | ||
| 497 | struct rb_node *nd; | ||
| 498 | bool ret = machine__read_build_ids(&session->machines.host, with_hits); | ||
| 499 | |||
| 500 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { | ||
| 501 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
| 502 | ret |= machine__read_build_ids(pos, with_hits); | ||
| 503 | } | ||
| 504 | |||
| 505 | return ret; | ||
| 506 | } | ||
| 507 | |||
| 508 | static int write_tracing_data(int fd, struct perf_header *h __maybe_unused, | 169 | static int write_tracing_data(int fd, struct perf_header *h __maybe_unused, |
| 509 | struct perf_evlist *evlist) | 170 | struct perf_evlist *evlist) |
| 510 | { | 171 | { |
| @@ -523,13 +184,12 @@ static int write_build_id(int fd, struct perf_header *h, | |||
| 523 | if (!perf_session__read_build_ids(session, true)) | 184 | if (!perf_session__read_build_ids(session, true)) |
| 524 | return -1; | 185 | return -1; |
| 525 | 186 | ||
| 526 | err = dsos__write_buildid_table(h, fd); | 187 | err = perf_session__write_buildid_table(session, fd); |
| 527 | if (err < 0) { | 188 | if (err < 0) { |
| 528 | pr_debug("failed to write buildid table\n"); | 189 | pr_debug("failed to write buildid table\n"); |
| 529 | return err; | 190 | return err; |
| 530 | } | 191 | } |
| 531 | if (!no_buildid_cache) | 192 | perf_session__cache_build_ids(session); |
| 532 | perf_session__cache_build_ids(session); | ||
| 533 | 193 | ||
| 534 | return 0; | 194 | return 0; |
| 535 | } | 195 | } |
| @@ -579,16 +239,12 @@ static int write_version(int fd, struct perf_header *h __maybe_unused, | |||
| 579 | return do_write_string(fd, perf_version_string); | 239 | return do_write_string(fd, perf_version_string); |
| 580 | } | 240 | } |
| 581 | 241 | ||
| 582 | static int write_cpudesc(int fd, struct perf_header *h __maybe_unused, | 242 | static int __write_cpudesc(int fd, const char *cpuinfo_proc) |
| 583 | struct perf_evlist *evlist __maybe_unused) | ||
| 584 | { | 243 | { |
| 585 | #ifndef CPUINFO_PROC | ||
| 586 | #define CPUINFO_PROC NULL | ||
| 587 | #endif | ||
| 588 | FILE *file; | 244 | FILE *file; |
| 589 | char *buf = NULL; | 245 | char *buf = NULL; |
| 590 | char *s, *p; | 246 | char *s, *p; |
| 591 | const char *search = CPUINFO_PROC; | 247 | const char *search = cpuinfo_proc; |
| 592 | size_t len = 0; | 248 | size_t len = 0; |
| 593 | int ret = -1; | 249 | int ret = -1; |
| 594 | 250 | ||
| @@ -605,8 +261,10 @@ static int write_cpudesc(int fd, struct perf_header *h __maybe_unused, | |||
| 605 | break; | 261 | break; |
| 606 | } | 262 | } |
| 607 | 263 | ||
| 608 | if (ret) | 264 | if (ret) { |
| 265 | ret = -1; | ||
| 609 | goto done; | 266 | goto done; |
| 267 | } | ||
| 610 | 268 | ||
| 611 | s = buf; | 269 | s = buf; |
| 612 | 270 | ||
| @@ -638,6 +296,25 @@ done: | |||
| 638 | return ret; | 296 | return ret; |
| 639 | } | 297 | } |
| 640 | 298 | ||
| 299 | static int write_cpudesc(int fd, struct perf_header *h __maybe_unused, | ||
| 300 | struct perf_evlist *evlist __maybe_unused) | ||
| 301 | { | ||
| 302 | #ifndef CPUINFO_PROC | ||
| 303 | #define CPUINFO_PROC {"model name", } | ||
| 304 | #endif | ||
| 305 | const char *cpuinfo_procs[] = CPUINFO_PROC; | ||
| 306 | unsigned int i; | ||
| 307 | |||
| 308 | for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) { | ||
| 309 | int ret; | ||
| 310 | ret = __write_cpudesc(fd, cpuinfo_procs[i]); | ||
| 311 | if (ret >= 0) | ||
| 312 | return ret; | ||
| 313 | } | ||
| 314 | return -1; | ||
| 315 | } | ||
| 316 | |||
| 317 | |||
| 641 | static int write_nrcpus(int fd, struct perf_header *h __maybe_unused, | 318 | static int write_nrcpus(int fd, struct perf_header *h __maybe_unused, |
| 642 | struct perf_evlist *evlist __maybe_unused) | 319 | struct perf_evlist *evlist __maybe_unused) |
| 643 | { | 320 | { |
| @@ -950,7 +627,8 @@ static int write_total_mem(int fd, struct perf_header *h __maybe_unused, | |||
| 950 | n = sscanf(buf, "%*s %"PRIu64, &mem); | 627 | n = sscanf(buf, "%*s %"PRIu64, &mem); |
| 951 | if (n == 1) | 628 | if (n == 1) |
| 952 | ret = do_write(fd, &mem, sizeof(mem)); | 629 | ret = do_write(fd, &mem, sizeof(mem)); |
| 953 | } | 630 | } else |
| 631 | ret = -1; | ||
| 954 | free(buf); | 632 | free(buf); |
| 955 | fclose(fp); | 633 | fclose(fp); |
| 956 | return ret; | 634 | return ret; |
| @@ -1588,7 +1266,7 @@ static int __event_process_build_id(struct build_id_event *bev, | |||
| 1588 | 1266 | ||
| 1589 | dso__set_build_id(dso, &bev->build_id); | 1267 | dso__set_build_id(dso, &bev->build_id); |
| 1590 | 1268 | ||
| 1591 | if (filename[0] == '[') | 1269 | if (!is_kernel_module(filename, NULL)) |
| 1592 | dso->kernel = dso_type; | 1270 | dso->kernel = dso_type; |
| 1593 | 1271 | ||
| 1594 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), | 1272 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), |
| @@ -2462,6 +2140,7 @@ static const int attr_file_abi_sizes[] = { | |||
| 2462 | [1] = PERF_ATTR_SIZE_VER1, | 2140 | [1] = PERF_ATTR_SIZE_VER1, |
| 2463 | [2] = PERF_ATTR_SIZE_VER2, | 2141 | [2] = PERF_ATTR_SIZE_VER2, |
| 2464 | [3] = PERF_ATTR_SIZE_VER3, | 2142 | [3] = PERF_ATTR_SIZE_VER3, |
| 2143 | [4] = PERF_ATTR_SIZE_VER4, | ||
| 2465 | 0, | 2144 | 0, |
| 2466 | }; | 2145 | }; |
| 2467 | 2146 | ||
| @@ -3109,8 +2788,3 @@ int perf_event__process_build_id(struct perf_tool *tool __maybe_unused, | |||
| 3109 | session); | 2788 | session); |
| 3110 | return 0; | 2789 | return 0; |
| 3111 | } | 2790 | } |
| 3112 | |||
| 3113 | void disable_buildid_cache(void) | ||
| 3114 | { | ||
| 3115 | no_buildid_cache = true; | ||
| 3116 | } | ||
