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