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