code-reading.c (16041B)
1// SPDX-License-Identifier: GPL-2.0 2#include <errno.h> 3#include <linux/kernel.h> 4#include <linux/types.h> 5#include <inttypes.h> 6#include <stdlib.h> 7#include <unistd.h> 8#include <stdio.h> 9#include <string.h> 10#include <sys/param.h> 11#include <perf/cpumap.h> 12#include <perf/evlist.h> 13#include <perf/mmap.h> 14 15#include "debug.h" 16#include "dso.h" 17#include "env.h" 18#include "parse-events.h" 19#include "trace-event.h" 20#include "evlist.h" 21#include "evsel.h" 22#include "thread_map.h" 23#include "machine.h" 24#include "map.h" 25#include "symbol.h" 26#include "event.h" 27#include "record.h" 28#include "util/mmap.h" 29#include "util/string2.h" 30#include "util/synthetic-events.h" 31#include "thread.h" 32 33#include "tests.h" 34 35#include <linux/ctype.h> 36 37#define BUFSZ 1024 38#define READLEN 128 39 40struct state { 41 u64 done[1024]; 42 size_t done_cnt; 43}; 44 45static size_t read_objdump_chunk(const char **line, unsigned char **buf, 46 size_t *buf_len) 47{ 48 size_t bytes_read = 0; 49 unsigned char *chunk_start = *buf; 50 51 /* Read bytes */ 52 while (*buf_len > 0) { 53 char c1, c2; 54 55 /* Get 2 hex digits */ 56 c1 = *(*line)++; 57 if (!isxdigit(c1)) 58 break; 59 c2 = *(*line)++; 60 if (!isxdigit(c2)) 61 break; 62 63 /* Store byte and advance buf */ 64 **buf = (hex(c1) << 4) | hex(c2); 65 (*buf)++; 66 (*buf_len)--; 67 bytes_read++; 68 69 /* End of chunk? */ 70 if (isspace(**line)) 71 break; 72 } 73 74 /* 75 * objdump will display raw insn as LE if code endian 76 * is LE and bytes_per_chunk > 1. In that case reverse 77 * the chunk we just read. 78 * 79 * see disassemble_bytes() at binutils/objdump.c for details 80 * how objdump chooses display endian) 81 */ 82 if (bytes_read > 1 && !bigendian()) { 83 unsigned char *chunk_end = chunk_start + bytes_read - 1; 84 unsigned char tmp; 85 86 while (chunk_start < chunk_end) { 87 tmp = *chunk_start; 88 *chunk_start = *chunk_end; 89 *chunk_end = tmp; 90 chunk_start++; 91 chunk_end--; 92 } 93 } 94 95 return bytes_read; 96} 97 98static size_t read_objdump_line(const char *line, unsigned char *buf, 99 size_t buf_len) 100{ 101 const char *p; 102 size_t ret, bytes_read = 0; 103 104 /* Skip to a colon */ 105 p = strchr(line, ':'); 106 if (!p) 107 return 0; 108 p++; 109 110 /* Skip initial spaces */ 111 while (*p) { 112 if (!isspace(*p)) 113 break; 114 p++; 115 } 116 117 do { 118 ret = read_objdump_chunk(&p, &buf, &buf_len); 119 bytes_read += ret; 120 p++; 121 } while (ret > 0); 122 123 /* return number of successfully read bytes */ 124 return bytes_read; 125} 126 127static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr) 128{ 129 char *line = NULL; 130 size_t line_len, off_last = 0; 131 ssize_t ret; 132 int err = 0; 133 u64 addr, last_addr = start_addr; 134 135 while (off_last < *len) { 136 size_t off, read_bytes, written_bytes; 137 unsigned char tmp[BUFSZ]; 138 139 ret = getline(&line, &line_len, f); 140 if (feof(f)) 141 break; 142 if (ret < 0) { 143 pr_debug("getline failed\n"); 144 err = -1; 145 break; 146 } 147 148 /* read objdump data into temporary buffer */ 149 read_bytes = read_objdump_line(line, tmp, sizeof(tmp)); 150 if (!read_bytes) 151 continue; 152 153 if (sscanf(line, "%"PRIx64, &addr) != 1) 154 continue; 155 if (addr < last_addr) { 156 pr_debug("addr going backwards, read beyond section?\n"); 157 break; 158 } 159 last_addr = addr; 160 161 /* copy it from temporary buffer to 'buf' according 162 * to address on current objdump line */ 163 off = addr - start_addr; 164 if (off >= *len) 165 break; 166 written_bytes = MIN(read_bytes, *len - off); 167 memcpy(buf + off, tmp, written_bytes); 168 off_last = off + written_bytes; 169 } 170 171 /* len returns number of bytes that could not be read */ 172 *len -= off_last; 173 174 free(line); 175 176 return err; 177} 178 179static int read_via_objdump(const char *filename, u64 addr, void *buf, 180 size_t len) 181{ 182 char cmd[PATH_MAX * 2]; 183 const char *fmt; 184 FILE *f; 185 int ret; 186 187 fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s"; 188 ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len, 189 filename); 190 if (ret <= 0 || (size_t)ret >= sizeof(cmd)) 191 return -1; 192 193 pr_debug("Objdump command is: %s\n", cmd); 194 195 /* Ignore objdump errors */ 196 strcat(cmd, " 2>/dev/null"); 197 198 f = popen(cmd, "r"); 199 if (!f) { 200 pr_debug("popen failed\n"); 201 return -1; 202 } 203 204 ret = read_objdump_output(f, buf, &len, addr); 205 if (len) { 206 pr_debug("objdump read too few bytes: %zd\n", len); 207 if (!ret) 208 ret = len; 209 } 210 211 pclose(f); 212 213 return ret; 214} 215 216static void dump_buf(unsigned char *buf, size_t len) 217{ 218 size_t i; 219 220 for (i = 0; i < len; i++) { 221 pr_debug("0x%02x ", buf[i]); 222 if (i % 16 == 15) 223 pr_debug("\n"); 224 } 225 pr_debug("\n"); 226} 227 228static int read_object_code(u64 addr, size_t len, u8 cpumode, 229 struct thread *thread, struct state *state) 230{ 231 struct addr_location al; 232 unsigned char buf1[BUFSZ] = {0}; 233 unsigned char buf2[BUFSZ] = {0}; 234 size_t ret_len; 235 u64 objdump_addr; 236 const char *objdump_name; 237 char decomp_name[KMOD_DECOMP_LEN]; 238 bool decomp = false; 239 int ret; 240 241 pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); 242 243 if (!thread__find_map(thread, cpumode, addr, &al) || !al.map->dso) { 244 if (cpumode == PERF_RECORD_MISC_HYPERVISOR) { 245 pr_debug("Hypervisor address can not be resolved - skipping\n"); 246 return 0; 247 } 248 249 pr_debug("thread__find_map failed\n"); 250 return -1; 251 } 252 253 pr_debug("File is: %s\n", al.map->dso->long_name); 254 255 if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && 256 !dso__is_kcore(al.map->dso)) { 257 pr_debug("Unexpected kernel address - skipping\n"); 258 return 0; 259 } 260 261 pr_debug("On file address is: %#"PRIx64"\n", al.addr); 262 263 if (len > BUFSZ) 264 len = BUFSZ; 265 266 /* Do not go off the map */ 267 if (addr + len > al.map->end) 268 len = al.map->end - addr; 269 270 /* Read the object code using perf */ 271 ret_len = dso__data_read_offset(al.map->dso, thread->maps->machine, 272 al.addr, buf1, len); 273 if (ret_len != len) { 274 pr_debug("dso__data_read_offset failed\n"); 275 return -1; 276 } 277 278 /* 279 * Converting addresses for use by objdump requires more information. 280 * map__load() does that. See map__rip_2objdump() for details. 281 */ 282 if (map__load(al.map)) 283 return -1; 284 285 /* objdump struggles with kcore - try each map only once */ 286 if (dso__is_kcore(al.map->dso)) { 287 size_t d; 288 289 for (d = 0; d < state->done_cnt; d++) { 290 if (state->done[d] == al.map->start) { 291 pr_debug("kcore map tested already"); 292 pr_debug(" - skipping\n"); 293 return 0; 294 } 295 } 296 if (state->done_cnt >= ARRAY_SIZE(state->done)) { 297 pr_debug("Too many kcore maps - skipping\n"); 298 return 0; 299 } 300 state->done[state->done_cnt++] = al.map->start; 301 } 302 303 objdump_name = al.map->dso->long_name; 304 if (dso__needs_decompress(al.map->dso)) { 305 if (dso__decompress_kmodule_path(al.map->dso, objdump_name, 306 decomp_name, 307 sizeof(decomp_name)) < 0) { 308 pr_debug("decompression failed\n"); 309 return -1; 310 } 311 312 decomp = true; 313 objdump_name = decomp_name; 314 } 315 316 /* Read the object code using objdump */ 317 objdump_addr = map__rip_2objdump(al.map, al.addr); 318 ret = read_via_objdump(objdump_name, objdump_addr, buf2, len); 319 320 if (decomp) 321 unlink(objdump_name); 322 323 if (ret > 0) { 324 /* 325 * The kernel maps are inaccurate - assume objdump is right in 326 * that case. 327 */ 328 if (cpumode == PERF_RECORD_MISC_KERNEL || 329 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) { 330 len -= ret; 331 if (len) { 332 pr_debug("Reducing len to %zu\n", len); 333 } else if (dso__is_kcore(al.map->dso)) { 334 /* 335 * objdump cannot handle very large segments 336 * that may be found in kcore. 337 */ 338 pr_debug("objdump failed for kcore"); 339 pr_debug(" - skipping\n"); 340 return 0; 341 } else { 342 return -1; 343 } 344 } 345 } 346 if (ret < 0) { 347 pr_debug("read_via_objdump failed\n"); 348 return -1; 349 } 350 351 /* The results should be identical */ 352 if (memcmp(buf1, buf2, len)) { 353 pr_debug("Bytes read differ from those read by objdump\n"); 354 pr_debug("buf1 (dso):\n"); 355 dump_buf(buf1, len); 356 pr_debug("buf2 (objdump):\n"); 357 dump_buf(buf2, len); 358 return -1; 359 } 360 pr_debug("Bytes read match those read by objdump\n"); 361 362 return 0; 363} 364 365static int process_sample_event(struct machine *machine, 366 struct evlist *evlist, 367 union perf_event *event, struct state *state) 368{ 369 struct perf_sample sample; 370 struct thread *thread; 371 int ret; 372 373 if (evlist__parse_sample(evlist, event, &sample)) { 374 pr_debug("evlist__parse_sample failed\n"); 375 return -1; 376 } 377 378 thread = machine__findnew_thread(machine, sample.pid, sample.tid); 379 if (!thread) { 380 pr_debug("machine__findnew_thread failed\n"); 381 return -1; 382 } 383 384 ret = read_object_code(sample.ip, READLEN, sample.cpumode, thread, state); 385 thread__put(thread); 386 return ret; 387} 388 389static int process_event(struct machine *machine, struct evlist *evlist, 390 union perf_event *event, struct state *state) 391{ 392 if (event->header.type == PERF_RECORD_SAMPLE) 393 return process_sample_event(machine, evlist, event, state); 394 395 if (event->header.type == PERF_RECORD_THROTTLE || 396 event->header.type == PERF_RECORD_UNTHROTTLE) 397 return 0; 398 399 if (event->header.type < PERF_RECORD_MAX) { 400 int ret; 401 402 ret = machine__process_event(machine, event, NULL); 403 if (ret < 0) 404 pr_debug("machine__process_event failed, event type %u\n", 405 event->header.type); 406 return ret; 407 } 408 409 return 0; 410} 411 412static int process_events(struct machine *machine, struct evlist *evlist, 413 struct state *state) 414{ 415 union perf_event *event; 416 struct mmap *md; 417 int i, ret; 418 419 for (i = 0; i < evlist->core.nr_mmaps; i++) { 420 md = &evlist->mmap[i]; 421 if (perf_mmap__read_init(&md->core) < 0) 422 continue; 423 424 while ((event = perf_mmap__read_event(&md->core)) != NULL) { 425 ret = process_event(machine, evlist, event, state); 426 perf_mmap__consume(&md->core); 427 if (ret < 0) 428 return ret; 429 } 430 perf_mmap__read_done(&md->core); 431 } 432 return 0; 433} 434 435static int comp(const void *a, const void *b) 436{ 437 return *(int *)a - *(int *)b; 438} 439 440static void do_sort_something(void) 441{ 442 int buf[40960], i; 443 444 for (i = 0; i < (int)ARRAY_SIZE(buf); i++) 445 buf[i] = ARRAY_SIZE(buf) - i - 1; 446 447 qsort(buf, ARRAY_SIZE(buf), sizeof(int), comp); 448 449 for (i = 0; i < (int)ARRAY_SIZE(buf); i++) { 450 if (buf[i] != i) { 451 pr_debug("qsort failed\n"); 452 break; 453 } 454 } 455} 456 457static void sort_something(void) 458{ 459 int i; 460 461 for (i = 0; i < 10; i++) 462 do_sort_something(); 463} 464 465static void syscall_something(void) 466{ 467 int pipefd[2]; 468 int i; 469 470 for (i = 0; i < 1000; i++) { 471 if (pipe(pipefd) < 0) { 472 pr_debug("pipe failed\n"); 473 break; 474 } 475 close(pipefd[1]); 476 close(pipefd[0]); 477 } 478} 479 480static void fs_something(void) 481{ 482 const char *test_file_name = "temp-perf-code-reading-test-file--"; 483 FILE *f; 484 int i; 485 486 for (i = 0; i < 1000; i++) { 487 f = fopen(test_file_name, "w+"); 488 if (f) { 489 fclose(f); 490 unlink(test_file_name); 491 } 492 } 493} 494 495#ifdef __s390x__ 496#include "header.h" // for get_cpuid() 497#endif 498 499static const char *do_determine_event(bool excl_kernel) 500{ 501 const char *event = excl_kernel ? "cycles:u" : "cycles"; 502 503#ifdef __s390x__ 504 char cpuid[128], model[16], model_c[16], cpum_cf_v[16]; 505 unsigned int family; 506 int ret, cpum_cf_a; 507 508 if (get_cpuid(cpuid, sizeof(cpuid))) 509 goto out_clocks; 510 ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%x", &family, model_c, 511 model, cpum_cf_v, &cpum_cf_a); 512 if (ret != 5) /* Not available */ 513 goto out_clocks; 514 if (excl_kernel && (cpum_cf_a & 4)) 515 return event; 516 if (!excl_kernel && (cpum_cf_a & 2)) 517 return event; 518 519 /* Fall through: missing authorization */ 520out_clocks: 521 event = excl_kernel ? "cpu-clock:u" : "cpu-clock"; 522 523#endif 524 return event; 525} 526 527static void do_something(void) 528{ 529 fs_something(); 530 531 sort_something(); 532 533 syscall_something(); 534} 535 536enum { 537 TEST_CODE_READING_OK, 538 TEST_CODE_READING_NO_VMLINUX, 539 TEST_CODE_READING_NO_KCORE, 540 TEST_CODE_READING_NO_ACCESS, 541 TEST_CODE_READING_NO_KERNEL_OBJ, 542}; 543 544static int do_test_code_reading(bool try_kcore) 545{ 546 struct machine *machine; 547 struct thread *thread; 548 struct record_opts opts = { 549 .mmap_pages = UINT_MAX, 550 .user_freq = UINT_MAX, 551 .user_interval = ULLONG_MAX, 552 .freq = 500, 553 .target = { 554 .uses_mmap = true, 555 }, 556 }; 557 struct state state = { 558 .done_cnt = 0, 559 }; 560 struct perf_thread_map *threads = NULL; 561 struct perf_cpu_map *cpus = NULL; 562 struct evlist *evlist = NULL; 563 struct evsel *evsel = NULL; 564 int err = -1, ret; 565 pid_t pid; 566 struct map *map; 567 bool have_vmlinux, have_kcore, excl_kernel = false; 568 569 pid = getpid(); 570 571 machine = machine__new_host(); 572 machine->env = &perf_env; 573 574 ret = machine__create_kernel_maps(machine); 575 if (ret < 0) { 576 pr_debug("machine__create_kernel_maps failed\n"); 577 goto out_err; 578 } 579 580 /* Force the use of kallsyms instead of vmlinux to try kcore */ 581 if (try_kcore) 582 symbol_conf.kallsyms_name = "/proc/kallsyms"; 583 584 /* Load kernel map */ 585 map = machine__kernel_map(machine); 586 ret = map__load(map); 587 if (ret < 0) { 588 pr_debug("map__load failed\n"); 589 goto out_err; 590 } 591 have_vmlinux = dso__is_vmlinux(map->dso); 592 have_kcore = dso__is_kcore(map->dso); 593 594 /* 2nd time through we just try kcore */ 595 if (try_kcore && !have_kcore) 596 return TEST_CODE_READING_NO_KCORE; 597 598 /* No point getting kernel events if there is no kernel object */ 599 if (!have_vmlinux && !have_kcore) 600 excl_kernel = true; 601 602 threads = thread_map__new_by_tid(pid); 603 if (!threads) { 604 pr_debug("thread_map__new_by_tid failed\n"); 605 goto out_err; 606 } 607 608 ret = perf_event__synthesize_thread_map(NULL, threads, 609 perf_event__process, machine, 610 true, false); 611 if (ret < 0) { 612 pr_debug("perf_event__synthesize_thread_map failed\n"); 613 goto out_err; 614 } 615 616 thread = machine__findnew_thread(machine, pid, pid); 617 if (!thread) { 618 pr_debug("machine__findnew_thread failed\n"); 619 goto out_put; 620 } 621 622 cpus = perf_cpu_map__new(NULL); 623 if (!cpus) { 624 pr_debug("perf_cpu_map__new failed\n"); 625 goto out_put; 626 } 627 628 while (1) { 629 const char *str; 630 631 evlist = evlist__new(); 632 if (!evlist) { 633 pr_debug("evlist__new failed\n"); 634 goto out_put; 635 } 636 637 perf_evlist__set_maps(&evlist->core, cpus, threads); 638 639 str = do_determine_event(excl_kernel); 640 pr_debug("Parsing event '%s'\n", str); 641 ret = parse_events(evlist, str, NULL); 642 if (ret < 0) { 643 pr_debug("parse_events failed\n"); 644 goto out_put; 645 } 646 647 evlist__config(evlist, &opts, NULL); 648 649 evsel = evlist__first(evlist); 650 651 evsel->core.attr.comm = 1; 652 evsel->core.attr.disabled = 1; 653 evsel->core.attr.enable_on_exec = 0; 654 655 ret = evlist__open(evlist); 656 if (ret < 0) { 657 if (!excl_kernel) { 658 excl_kernel = true; 659 /* 660 * Both cpus and threads are now owned by evlist 661 * and will be freed by following perf_evlist__set_maps 662 * call. Getting reference to keep them alive. 663 */ 664 perf_cpu_map__get(cpus); 665 perf_thread_map__get(threads); 666 perf_evlist__set_maps(&evlist->core, NULL, NULL); 667 evlist__delete(evlist); 668 evlist = NULL; 669 continue; 670 } 671 672 if (verbose > 0) { 673 char errbuf[512]; 674 evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf)); 675 pr_debug("perf_evlist__open() failed!\n%s\n", errbuf); 676 } 677 678 goto out_put; 679 } 680 break; 681 } 682 683 ret = evlist__mmap(evlist, UINT_MAX); 684 if (ret < 0) { 685 pr_debug("evlist__mmap failed\n"); 686 goto out_put; 687 } 688 689 evlist__enable(evlist); 690 691 do_something(); 692 693 evlist__disable(evlist); 694 695 ret = process_events(machine, evlist, &state); 696 if (ret < 0) 697 goto out_put; 698 699 if (!have_vmlinux && !have_kcore && !try_kcore) 700 err = TEST_CODE_READING_NO_KERNEL_OBJ; 701 else if (!have_vmlinux && !try_kcore) 702 err = TEST_CODE_READING_NO_VMLINUX; 703 else if (excl_kernel) 704 err = TEST_CODE_READING_NO_ACCESS; 705 else 706 err = TEST_CODE_READING_OK; 707out_put: 708 thread__put(thread); 709out_err: 710 evlist__delete(evlist); 711 perf_cpu_map__put(cpus); 712 perf_thread_map__put(threads); 713 machine__delete_threads(machine); 714 machine__delete(machine); 715 716 return err; 717} 718 719static int test__code_reading(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 720{ 721 int ret; 722 723 ret = do_test_code_reading(false); 724 if (!ret) 725 ret = do_test_code_reading(true); 726 727 switch (ret) { 728 case TEST_CODE_READING_OK: 729 return 0; 730 case TEST_CODE_READING_NO_VMLINUX: 731 pr_debug("no vmlinux\n"); 732 return 0; 733 case TEST_CODE_READING_NO_KCORE: 734 pr_debug("no kcore\n"); 735 return 0; 736 case TEST_CODE_READING_NO_ACCESS: 737 pr_debug("no access\n"); 738 return 0; 739 case TEST_CODE_READING_NO_KERNEL_OBJ: 740 pr_debug("no kernel obj\n"); 741 return 0; 742 default: 743 return -1; 744 }; 745} 746 747DEFINE_SUITE("Object code reading", code_reading);