1 /* 2 * build-id.c 3 * 4 * build-id support 5 * 6 * Copyright (C) 2009, 2010 Red Hat Inc. 7 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com> 8 */ 9 #include "util.h" 10 #include <stdio.h> 11 #include "build-id.h" 12 #include "event.h" 13 #include "symbol.h" 14 #include <linux/kernel.h> 15 #include "debug.h" 16 #include "session.h" 17 #include "tool.h" 18 #include "header.h" 19 #include "vdso.h" 20 21 22 static bool no_buildid_cache; 23 24 int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 25 union perf_event *event, 26 struct perf_sample *sample, 27 struct perf_evsel *evsel __maybe_unused, 28 struct machine *machine) 29 { 30 struct addr_location al; 31 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 32 struct thread *thread = machine__findnew_thread(machine, sample->pid, 33 sample->tid); 34 35 if (thread == NULL) { 36 pr_err("problem processing %d event, skipping it.\n", 37 event->header.type); 38 return -1; 39 } 40 41 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al); 42 43 if (al.map != NULL) 44 al.map->dso->hit = 1; 45 46 thread__put(thread); 47 return 0; 48 } 49 50 static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, 51 union perf_event *event, 52 struct perf_sample *sample 53 __maybe_unused, 54 struct machine *machine) 55 { 56 struct thread *thread = machine__findnew_thread(machine, 57 event->fork.pid, 58 event->fork.tid); 59 60 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 61 event->fork.ppid, event->fork.ptid); 62 63 if (thread) { 64 machine__remove_thread(machine, thread); 65 thread__put(thread); 66 } 67 68 return 0; 69 } 70 71 struct perf_tool build_id__mark_dso_hit_ops = { 72 .sample = build_id__mark_dso_hit, 73 .mmap = perf_event__process_mmap, 74 .mmap2 = perf_event__process_mmap2, 75 .fork = perf_event__process_fork, 76 .exit = perf_event__exit_del_thread, 77 .attr = perf_event__process_attr, 78 .build_id = perf_event__process_build_id, 79 .ordered_events = true, 80 }; 81 82 int build_id__sprintf(const u8 *build_id, int len, char *bf) 83 { 84 char *bid = bf; 85 const u8 *raw = build_id; 86 int i; 87 88 for (i = 0; i < len; ++i) { 89 sprintf(bid, "%02x", *raw); 90 ++raw; 91 bid += 2; 92 } 93 94 return (bid - bf) + 1; 95 } 96 97 int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id) 98 { 99 char notes[PATH_MAX]; 100 u8 build_id[BUILD_ID_SIZE]; 101 int ret; 102 103 if (!root_dir) 104 root_dir = ""; 105 106 scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir); 107 108 ret = sysfs__read_build_id(notes, build_id, sizeof(build_id)); 109 if (ret < 0) 110 return ret; 111 112 return build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 113 } 114 115 int filename__sprintf_build_id(const char *pathname, char *sbuild_id) 116 { 117 u8 build_id[BUILD_ID_SIZE]; 118 int ret; 119 120 ret = filename__read_build_id(pathname, build_id, sizeof(build_id)); 121 if (ret < 0) 122 return ret; 123 else if (ret != sizeof(build_id)) 124 return -EINVAL; 125 126 return build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 127 } 128 129 /* asnprintf consolidates asprintf and snprintf */ 130 static int asnprintf(char **strp, size_t size, const char *fmt, ...) 131 { 132 va_list ap; 133 int ret; 134 135 if (!strp) 136 return -EINVAL; 137 138 va_start(ap, fmt); 139 if (*strp) 140 ret = vsnprintf(*strp, size, fmt, ap); 141 else 142 ret = vasprintf(strp, fmt, ap); 143 va_end(ap); 144 145 return ret; 146 } 147 148 static char *build_id__filename(const char *sbuild_id, char *bf, size_t size) 149 { 150 char *tmp = bf; 151 int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, 152 sbuild_id, sbuild_id + 2); 153 if (ret < 0 || (tmp && size < (unsigned int)ret)) 154 return NULL; 155 return bf; 156 } 157 158 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size) 159 { 160 char build_id_hex[SBUILD_ID_SIZE]; 161 162 if (!dso->has_build_id) 163 return NULL; 164 165 build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex); 166 return build_id__filename(build_id_hex, bf, size); 167 } 168 169 bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size) 170 { 171 char *id_name, *ch; 172 struct stat sb; 173 174 id_name = dso__build_id_filename(dso, bf, size); 175 if (!id_name) 176 goto err; 177 if (access(id_name, F_OK)) 178 goto err; 179 if (lstat(id_name, &sb) == -1) 180 goto err; 181 if ((size_t)sb.st_size > size - 1) 182 goto err; 183 if (readlink(id_name, bf, size - 1) < 0) 184 goto err; 185 186 bf[sb.st_size] = '\0'; 187 188 /* 189 * link should be: 190 * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92 191 */ 192 ch = strrchr(bf, '/'); 193 if (!ch) 194 goto err; 195 if (ch - 3 < bf) 196 goto err; 197 198 return strncmp(".ko", ch - 3, 3) == 0; 199 err: 200 /* 201 * If dso__build_id_filename work, get id_name again, 202 * because id_name points to bf and is broken. 203 */ 204 if (id_name) 205 id_name = dso__build_id_filename(dso, bf, size); 206 pr_err("Invalid build id: %s\n", id_name ? : 207 dso->long_name ? : 208 dso->short_name ? : 209 "[unknown]"); 210 return false; 211 } 212 213 #define dsos__for_each_with_build_id(pos, head) \ 214 list_for_each_entry(pos, head, node) \ 215 if (!pos->has_build_id) \ 216 continue; \ 217 else 218 219 static int write_buildid(const char *name, size_t name_len, u8 *build_id, 220 pid_t pid, u16 misc, int fd) 221 { 222 int err; 223 struct build_id_event b; 224 size_t len; 225 226 len = name_len + 1; 227 len = PERF_ALIGN(len, NAME_ALIGN); 228 229 memset(&b, 0, sizeof(b)); 230 memcpy(&b.build_id, build_id, BUILD_ID_SIZE); 231 b.pid = pid; 232 b.header.misc = misc; 233 b.header.size = sizeof(b) + len; 234 235 err = writen(fd, &b, sizeof(b)); 236 if (err < 0) 237 return err; 238 239 return write_padded(fd, name, name_len + 1, len); 240 } 241 242 static int machine__write_buildid_table(struct machine *machine, int fd) 243 { 244 int err = 0; 245 char nm[PATH_MAX]; 246 struct dso *pos; 247 u16 kmisc = PERF_RECORD_MISC_KERNEL, 248 umisc = PERF_RECORD_MISC_USER; 249 250 if (!machine__is_host(machine)) { 251 kmisc = PERF_RECORD_MISC_GUEST_KERNEL; 252 umisc = PERF_RECORD_MISC_GUEST_USER; 253 } 254 255 dsos__for_each_with_build_id(pos, &machine->dsos.head) { 256 const char *name; 257 size_t name_len; 258 bool in_kernel = false; 259 260 if (!pos->hit) 261 continue; 262 263 if (dso__is_vdso(pos)) { 264 name = pos->short_name; 265 name_len = pos->short_name_len + 1; 266 } else if (dso__is_kcore(pos)) { 267 machine__mmap_name(machine, nm, sizeof(nm)); 268 name = nm; 269 name_len = strlen(nm) + 1; 270 } else { 271 name = pos->long_name; 272 name_len = pos->long_name_len + 1; 273 } 274 275 in_kernel = pos->kernel || 276 is_kernel_module(name, 277 PERF_RECORD_MISC_CPUMODE_UNKNOWN); 278 err = write_buildid(name, name_len, pos->build_id, machine->pid, 279 in_kernel ? kmisc : umisc, fd); 280 if (err) 281 break; 282 } 283 284 return err; 285 } 286 287 int perf_session__write_buildid_table(struct perf_session *session, int fd) 288 { 289 struct rb_node *nd; 290 int err = machine__write_buildid_table(&session->machines.host, fd); 291 292 if (err) 293 return err; 294 295 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { 296 struct machine *pos = rb_entry(nd, struct machine, rb_node); 297 err = machine__write_buildid_table(pos, fd); 298 if (err) 299 break; 300 } 301 return err; 302 } 303 304 static int __dsos__hit_all(struct list_head *head) 305 { 306 struct dso *pos; 307 308 list_for_each_entry(pos, head, node) 309 pos->hit = true; 310 311 return 0; 312 } 313 314 static int machine__hit_all_dsos(struct machine *machine) 315 { 316 return __dsos__hit_all(&machine->dsos.head); 317 } 318 319 int dsos__hit_all(struct perf_session *session) 320 { 321 struct rb_node *nd; 322 int err; 323 324 err = machine__hit_all_dsos(&session->machines.host); 325 if (err) 326 return err; 327 328 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { 329 struct machine *pos = rb_entry(nd, struct machine, rb_node); 330 331 err = machine__hit_all_dsos(pos); 332 if (err) 333 return err; 334 } 335 336 return 0; 337 } 338 339 void disable_buildid_cache(void) 340 { 341 no_buildid_cache = true; 342 } 343 344 static char *build_id_cache__dirname_from_path(const char *name, 345 bool is_kallsyms, bool is_vdso) 346 { 347 char *realname = (char *)name, *filename; 348 bool slash = is_kallsyms || is_vdso; 349 350 if (!slash) { 351 realname = realpath(name, NULL); 352 if (!realname) 353 return NULL; 354 } 355 356 if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "", 357 is_vdso ? DSO__NAME_VDSO : realname) < 0) 358 filename = NULL; 359 360 if (!slash) 361 free(realname); 362 363 return filename; 364 } 365 366 int build_id_cache__list_build_ids(const char *pathname, 367 struct strlist **result) 368 { 369 struct strlist *list; 370 char *dir_name; 371 DIR *dir; 372 struct dirent *d; 373 int ret = 0; 374 375 list = strlist__new(NULL, NULL); 376 dir_name = build_id_cache__dirname_from_path(pathname, false, false); 377 if (!list || !dir_name) { 378 ret = -ENOMEM; 379 goto out; 380 } 381 382 /* List up all dirents */ 383 dir = opendir(dir_name); 384 if (!dir) { 385 ret = -errno; 386 goto out; 387 } 388 389 while ((d = readdir(dir)) != NULL) { 390 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) 391 continue; 392 strlist__add(list, d->d_name); 393 } 394 closedir(dir); 395 396 out: 397 free(dir_name); 398 if (ret) 399 strlist__delete(list); 400 else 401 *result = list; 402 403 return ret; 404 } 405 406 int build_id_cache__add_s(const char *sbuild_id, const char *name, 407 bool is_kallsyms, bool is_vdso) 408 { 409 const size_t size = PATH_MAX; 410 char *realname = NULL, *filename = NULL, *dir_name = NULL, 411 *linkname = zalloc(size), *targetname, *tmp; 412 int err = -1; 413 414 if (!is_kallsyms) { 415 realname = realpath(name, NULL); 416 if (!realname) 417 goto out_free; 418 } 419 420 dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, is_vdso); 421 if (!dir_name) 422 goto out_free; 423 424 if (mkdir_p(dir_name, 0755)) 425 goto out_free; 426 427 if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) { 428 filename = NULL; 429 goto out_free; 430 } 431 432 if (access(filename, F_OK)) { 433 if (is_kallsyms) { 434 if (copyfile("/proc/kallsyms", filename)) 435 goto out_free; 436 } else if (link(realname, filename) && errno != EEXIST && 437 copyfile(name, filename)) 438 goto out_free; 439 } 440 441 if (!build_id__filename(sbuild_id, linkname, size)) 442 goto out_free; 443 tmp = strrchr(linkname, '/'); 444 *tmp = '\0'; 445 446 if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) 447 goto out_free; 448 449 *tmp = '/'; 450 targetname = filename + strlen(buildid_dir) - 5; 451 memcpy(targetname, "../..", 5); 452 453 if (symlink(targetname, linkname) == 0) 454 err = 0; 455 out_free: 456 if (!is_kallsyms) 457 free(realname); 458 free(filename); 459 free(dir_name); 460 free(linkname); 461 return err; 462 } 463 464 static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, 465 const char *name, bool is_kallsyms, 466 bool is_vdso) 467 { 468 char sbuild_id[SBUILD_ID_SIZE]; 469 470 build_id__sprintf(build_id, build_id_size, sbuild_id); 471 472 return build_id_cache__add_s(sbuild_id, name, is_kallsyms, is_vdso); 473 } 474 475 bool build_id_cache__cached(const char *sbuild_id) 476 { 477 bool ret = false; 478 char *filename = build_id__filename(sbuild_id, NULL, 0); 479 480 if (filename && !access(filename, F_OK)) 481 ret = true; 482 free(filename); 483 484 return ret; 485 } 486 487 int build_id_cache__remove_s(const char *sbuild_id) 488 { 489 const size_t size = PATH_MAX; 490 char *filename = zalloc(size), 491 *linkname = zalloc(size), *tmp; 492 int err = -1; 493 494 if (filename == NULL || linkname == NULL) 495 goto out_free; 496 497 if (!build_id__filename(sbuild_id, linkname, size)) 498 goto out_free; 499 500 if (access(linkname, F_OK)) 501 goto out_free; 502 503 if (readlink(linkname, filename, size - 1) < 0) 504 goto out_free; 505 506 if (unlink(linkname)) 507 goto out_free; 508 509 /* 510 * Since the link is relative, we must make it absolute: 511 */ 512 tmp = strrchr(linkname, '/') + 1; 513 snprintf(tmp, size - (tmp - linkname), "%s", filename); 514 515 if (unlink(linkname)) 516 goto out_free; 517 518 err = 0; 519 out_free: 520 free(filename); 521 free(linkname); 522 return err; 523 } 524 525 static int dso__cache_build_id(struct dso *dso, struct machine *machine) 526 { 527 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 528 bool is_vdso = dso__is_vdso(dso); 529 const char *name = dso->long_name; 530 char nm[PATH_MAX]; 531 532 if (dso__is_kcore(dso)) { 533 is_kallsyms = true; 534 machine__mmap_name(machine, nm, sizeof(nm)); 535 name = nm; 536 } 537 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name, 538 is_kallsyms, is_vdso); 539 } 540 541 static int __dsos__cache_build_ids(struct list_head *head, 542 struct machine *machine) 543 { 544 struct dso *pos; 545 int err = 0; 546 547 dsos__for_each_with_build_id(pos, head) 548 if (dso__cache_build_id(pos, machine)) 549 err = -1; 550 551 return err; 552 } 553 554 static int machine__cache_build_ids(struct machine *machine) 555 { 556 return __dsos__cache_build_ids(&machine->dsos.head, machine); 557 } 558 559 int perf_session__cache_build_ids(struct perf_session *session) 560 { 561 struct rb_node *nd; 562 int ret; 563 564 if (no_buildid_cache) 565 return 0; 566 567 if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST) 568 return -1; 569 570 ret = machine__cache_build_ids(&session->machines.host); 571 572 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { 573 struct machine *pos = rb_entry(nd, struct machine, rb_node); 574 ret |= machine__cache_build_ids(pos); 575 } 576 return ret ? -1 : 0; 577 } 578 579 static bool machine__read_build_ids(struct machine *machine, bool with_hits) 580 { 581 return __dsos__read_build_ids(&machine->dsos.head, with_hits); 582 } 583 584 bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) 585 { 586 struct rb_node *nd; 587 bool ret = machine__read_build_ids(&session->machines.host, with_hits); 588 589 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { 590 struct machine *pos = rb_entry(nd, struct machine, rb_node); 591 ret |= machine__read_build_ids(pos, with_hits); 592 } 593 594 return ret; 595 } 596