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