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