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