738 lines · c
1// SPDX-License-Identifier: GPL-2.02#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 "evlist.h"20#include "evsel.h"21#include "thread_map.h"22#include "machine.h"23#include "map.h"24#include "symbol.h"25#include "event.h"26#include "record.h"27#include "util/mmap.h"28#include "util/string2.h"29#include "util/synthetic-events.h"30#include "util/util.h"31#include "thread.h"32 33#include "tests.h"34 35#include <linux/ctype.h>36 37#define BUFSZ 102438#define READLEN 12839 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 endian76 * is LE and bytes_per_chunk > 1. In that case reverse77 * the chunk we just read.78 *79 * see disassemble_bytes() at binutils/objdump.c for details80 * how objdump chooses display endian)81 */82 if (bytes_read > 1 && !host_is_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' according162 * 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, test_objdump_path, 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, err = 0;240 struct dso *dso;241 242 pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);243 244 addr_location__init(&al);245 if (!thread__find_map(thread, cpumode, addr, &al) || !map__dso(al.map)) {246 if (cpumode == PERF_RECORD_MISC_HYPERVISOR) {247 pr_debug("Hypervisor address can not be resolved - skipping\n");248 goto out;249 }250 251 pr_debug("thread__find_map failed\n");252 err = -1;253 goto out;254 }255 dso = map__dso(al.map);256 pr_debug("File is: %s\n", dso__long_name(dso));257 258 if (dso__symtab_type(dso) == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(dso)) {259 pr_debug("Unexpected kernel address - skipping\n");260 goto out;261 }262 263 pr_debug("On file address is: %#"PRIx64"\n", al.addr);264 265 if (len > BUFSZ)266 len = BUFSZ;267 268 /* Do not go off the map */269 if (addr + len > map__end(al.map))270 len = map__end(al.map) - addr;271 272 /*273 * Some architectures (ex: powerpc) have stubs (trampolines) in kernel274 * modules to manage long jumps. Check if the ip offset falls in stubs275 * sections for kernel modules. And skip module address after text end276 */277 if (dso__is_kmod(dso) && al.addr > dso__text_end(dso)) {278 pr_debug("skipping the module address %#"PRIx64" after text end\n", al.addr);279 goto out;280 }281 282 /* Read the object code using perf */283 ret_len = dso__data_read_offset(dso, maps__machine(thread__maps(thread)),284 al.addr, buf1, len);285 if (ret_len != len) {286 pr_debug("dso__data_read_offset failed\n");287 err = -1;288 goto out;289 }290 291 /*292 * Converting addresses for use by objdump requires more information.293 * map__load() does that. See map__rip_2objdump() for details.294 */295 if (map__load(al.map)) {296 err = -1;297 goto out;298 }299 300 /* objdump struggles with kcore - try each map only once */301 if (dso__is_kcore(dso)) {302 size_t d;303 304 for (d = 0; d < state->done_cnt; d++) {305 if (state->done[d] == map__start(al.map)) {306 pr_debug("kcore map tested already");307 pr_debug(" - skipping\n");308 goto out;309 }310 }311 if (state->done_cnt >= ARRAY_SIZE(state->done)) {312 pr_debug("Too many kcore maps - skipping\n");313 goto out;314 }315 state->done[state->done_cnt++] = map__start(al.map);316 }317 318 objdump_name = dso__long_name(dso);319 if (dso__needs_decompress(dso)) {320 if (dso__decompress_kmodule_path(dso, objdump_name,321 decomp_name,322 sizeof(decomp_name)) < 0) {323 pr_debug("decompression failed\n");324 err = -1;325 goto out;326 }327 328 decomp = true;329 objdump_name = decomp_name;330 }331 332 /* Read the object code using objdump */333 objdump_addr = map__rip_2objdump(al.map, al.addr);334 ret = read_via_objdump(objdump_name, objdump_addr, buf2, len);335 336 if (decomp)337 unlink(objdump_name);338 339 if (ret > 0) {340 /*341 * The kernel maps are inaccurate - assume objdump is right in342 * that case.343 */344 if (cpumode == PERF_RECORD_MISC_KERNEL ||345 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) {346 len -= ret;347 if (len) {348 pr_debug("Reducing len to %zu\n", len);349 } else if (dso__is_kcore(dso)) {350 /*351 * objdump cannot handle very large segments352 * that may be found in kcore.353 */354 pr_debug("objdump failed for kcore");355 pr_debug(" - skipping\n");356 } else {357 err = -1;358 }359 goto out;360 }361 }362 if (ret < 0) {363 pr_debug("read_via_objdump failed\n");364 err = -1;365 goto out;366 }367 368 /* The results should be identical */369 if (memcmp(buf1, buf2, len)) {370 pr_debug("Bytes read differ from those read by objdump\n");371 pr_debug("buf1 (dso):\n");372 dump_buf(buf1, len);373 pr_debug("buf2 (objdump):\n");374 dump_buf(buf2, len);375 err = -1;376 goto out;377 }378 pr_debug("Bytes read match those read by objdump\n");379out:380 addr_location__exit(&al);381 return err;382}383 384static int process_sample_event(struct machine *machine,385 struct evlist *evlist,386 union perf_event *event, struct state *state)387{388 struct perf_sample sample;389 struct thread *thread;390 int ret;391 392 if (evlist__parse_sample(evlist, event, &sample)) {393 pr_debug("evlist__parse_sample failed\n");394 return -1;395 }396 397 thread = machine__findnew_thread(machine, sample.pid, sample.tid);398 if (!thread) {399 pr_debug("machine__findnew_thread failed\n");400 return -1;401 }402 403 ret = read_object_code(sample.ip, READLEN, sample.cpumode, thread, state);404 thread__put(thread);405 return ret;406}407 408static int process_event(struct machine *machine, struct evlist *evlist,409 union perf_event *event, struct state *state)410{411 if (event->header.type == PERF_RECORD_SAMPLE)412 return process_sample_event(machine, evlist, event, state);413 414 if (event->header.type == PERF_RECORD_THROTTLE ||415 event->header.type == PERF_RECORD_UNTHROTTLE)416 return 0;417 418 if (event->header.type < PERF_RECORD_MAX) {419 int ret;420 421 ret = machine__process_event(machine, event, NULL);422 if (ret < 0)423 pr_debug("machine__process_event failed, event type %u\n",424 event->header.type);425 return ret;426 }427 428 return 0;429}430 431static int process_events(struct machine *machine, struct evlist *evlist,432 struct state *state)433{434 union perf_event *event;435 struct mmap *md;436 int i, ret;437 438 for (i = 0; i < evlist->core.nr_mmaps; i++) {439 md = &evlist->mmap[i];440 if (perf_mmap__read_init(&md->core) < 0)441 continue;442 443 while ((event = perf_mmap__read_event(&md->core)) != NULL) {444 ret = process_event(machine, evlist, event, state);445 perf_mmap__consume(&md->core);446 if (ret < 0)447 return ret;448 }449 perf_mmap__read_done(&md->core);450 }451 return 0;452}453 454static int comp(const void *a, const void *b)455{456 return *(int *)a - *(int *)b;457}458 459static void do_sort_something(void)460{461 int buf[40960], i;462 463 for (i = 0; i < (int)ARRAY_SIZE(buf); i++)464 buf[i] = ARRAY_SIZE(buf) - i - 1;465 466 qsort(buf, ARRAY_SIZE(buf), sizeof(int), comp);467 468 for (i = 0; i < (int)ARRAY_SIZE(buf); i++) {469 if (buf[i] != i) {470 pr_debug("qsort failed\n");471 break;472 }473 }474}475 476static void sort_something(void)477{478 int i;479 480 for (i = 0; i < 10; i++)481 do_sort_something();482}483 484static void syscall_something(void)485{486 int pipefd[2];487 int i;488 489 for (i = 0; i < 1000; i++) {490 if (pipe(pipefd) < 0) {491 pr_debug("pipe failed\n");492 break;493 }494 close(pipefd[1]);495 close(pipefd[0]);496 }497}498 499static void fs_something(void)500{501 const char *test_file_name = "temp-perf-code-reading-test-file--";502 FILE *f;503 int i;504 505 for (i = 0; i < 1000; i++) {506 f = fopen(test_file_name, "w+");507 if (f) {508 fclose(f);509 unlink(test_file_name);510 }511 }512}513 514static void do_something(void)515{516 fs_something();517 518 sort_something();519 520 syscall_something();521}522 523enum {524 TEST_CODE_READING_OK,525 TEST_CODE_READING_NO_VMLINUX,526 TEST_CODE_READING_NO_KCORE,527 TEST_CODE_READING_NO_ACCESS,528 TEST_CODE_READING_NO_KERNEL_OBJ,529};530 531static int do_test_code_reading(bool try_kcore)532{533 struct machine *machine;534 struct thread *thread;535 struct record_opts opts = {536 .mmap_pages = UINT_MAX,537 .user_freq = UINT_MAX,538 .user_interval = ULLONG_MAX,539 .freq = 500,540 .target = {541 .uses_mmap = true,542 },543 };544 struct state state = {545 .done_cnt = 0,546 };547 struct perf_thread_map *threads = NULL;548 struct perf_cpu_map *cpus = NULL;549 struct evlist *evlist = NULL;550 struct evsel *evsel = NULL;551 int err = -1, ret;552 pid_t pid;553 struct map *map;554 bool have_vmlinux, have_kcore;555 struct dso *dso;556 const char *events[] = { "cycles", "cycles:u", "cpu-clock", "cpu-clock:u", NULL };557 int evidx = 0;558 559 pid = getpid();560 561 machine = machine__new_host();562 machine->env = &perf_env;563 564 ret = machine__create_kernel_maps(machine);565 if (ret < 0) {566 pr_debug("machine__create_kernel_maps failed\n");567 goto out_err;568 }569 570 /* Force the use of kallsyms instead of vmlinux to try kcore */571 if (try_kcore)572 symbol_conf.kallsyms_name = "/proc/kallsyms";573 574 /* Load kernel map */575 map = machine__kernel_map(machine);576 ret = map__load(map);577 if (ret < 0) {578 pr_debug("map__load failed\n");579 goto out_err;580 }581 dso = map__dso(map);582 have_vmlinux = dso__is_vmlinux(dso);583 have_kcore = dso__is_kcore(dso);584 585 /* 2nd time through we just try kcore */586 if (try_kcore && !have_kcore)587 return TEST_CODE_READING_NO_KCORE;588 589 /* No point getting kernel events if there is no kernel object */590 if (!have_vmlinux && !have_kcore)591 evidx++;592 593 threads = thread_map__new_by_tid(pid);594 if (!threads) {595 pr_debug("thread_map__new_by_tid failed\n");596 goto out_err;597 }598 599 ret = perf_event__synthesize_thread_map(NULL, threads,600 perf_event__process, machine,601 true, false);602 if (ret < 0) {603 pr_debug("perf_event__synthesize_thread_map failed\n");604 goto out_err;605 }606 607 thread = machine__findnew_thread(machine, pid, pid);608 if (!thread) {609 pr_debug("machine__findnew_thread failed\n");610 goto out_put;611 }612 613 cpus = perf_cpu_map__new_online_cpus();614 if (!cpus) {615 pr_debug("perf_cpu_map__new failed\n");616 goto out_put;617 }618 619 while (events[evidx]) {620 const char *str;621 622 evlist = evlist__new();623 if (!evlist) {624 pr_debug("evlist__new failed\n");625 goto out_put;626 }627 628 perf_evlist__set_maps(&evlist->core, cpus, threads);629 630 str = events[evidx];631 pr_debug("Parsing event '%s'\n", str);632 ret = parse_event(evlist, str);633 if (ret < 0) {634 pr_debug("parse_events failed\n");635 goto out_put;636 }637 638 evlist__config(evlist, &opts, NULL);639 640 evlist__for_each_entry(evlist, evsel) {641 evsel->core.attr.comm = 1;642 evsel->core.attr.disabled = 1;643 evsel->core.attr.enable_on_exec = 0;644 }645 646 ret = evlist__open(evlist);647 if (ret < 0) {648 evidx++;649 650 if (events[evidx] == NULL && verbose > 0) {651 char errbuf[512];652 evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));653 pr_debug("perf_evlist__open() failed!\n%s\n", errbuf);654 }655 656 /*657 * Both cpus and threads are now owned by evlist658 * and will be freed by following perf_evlist__set_maps659 * call. Getting reference to keep them alive.660 */661 perf_cpu_map__get(cpus);662 perf_thread_map__get(threads);663 perf_evlist__set_maps(&evlist->core, NULL, NULL);664 evlist__delete(evlist);665 evlist = NULL;666 continue;667 }668 break;669 }670 671 if (events[evidx] == NULL)672 goto out_put;673 674 ret = evlist__mmap(evlist, UINT_MAX);675 if (ret < 0) {676 pr_debug("evlist__mmap failed\n");677 goto out_put;678 }679 680 evlist__enable(evlist);681 682 do_something();683 684 evlist__disable(evlist);685 686 ret = process_events(machine, evlist, &state);687 if (ret < 0)688 goto out_put;689 690 if (!have_vmlinux && !have_kcore && !try_kcore)691 err = TEST_CODE_READING_NO_KERNEL_OBJ;692 else if (!have_vmlinux && !try_kcore)693 err = TEST_CODE_READING_NO_VMLINUX;694 else if (strstr(events[evidx], ":u"))695 err = TEST_CODE_READING_NO_ACCESS;696 else697 err = TEST_CODE_READING_OK;698out_put:699 thread__put(thread);700out_err:701 evlist__delete(evlist);702 perf_cpu_map__put(cpus);703 perf_thread_map__put(threads);704 machine__delete(machine);705 706 return err;707}708 709static int test__code_reading(struct test_suite *test __maybe_unused, int subtest __maybe_unused)710{711 int ret;712 713 ret = do_test_code_reading(false);714 if (!ret)715 ret = do_test_code_reading(true);716 717 switch (ret) {718 case TEST_CODE_READING_OK:719 return 0;720 case TEST_CODE_READING_NO_VMLINUX:721 pr_debug("no vmlinux\n");722 return 0;723 case TEST_CODE_READING_NO_KCORE:724 pr_debug("no kcore\n");725 return 0;726 case TEST_CODE_READING_NO_ACCESS:727 pr_debug("no access\n");728 return 0;729 case TEST_CODE_READING_NO_KERNEL_OBJ:730 pr_debug("no kernel obj\n");731 return 0;732 default:733 return -1;734 };735}736 737DEFINE_SUITE("Object code reading", code_reading);738