root/tools/perf/tests/code-reading.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hex
  2. read_objdump_chunk
  3. read_objdump_line
  4. read_objdump_output
  5. read_via_objdump
  6. dump_buf
  7. read_object_code
  8. process_sample_event
  9. process_event
  10. process_events
  11. comp
  12. do_sort_something
  13. sort_something
  14. syscall_something
  15. fs_something
  16. do_determine_event
  17. do_something
  18. do_test_code_reading
  19. test__code_reading

   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 
  38 struct state {
  39         u64 done[1024];
  40         size_t done_cnt;
  41 };
  42 
  43 static 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 
  52 static 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 
 105 static 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 
 134 static 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 
 186 static 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 
 223 static 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 
 235 static 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 
 372 static 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 
 396 static 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 
 419 static 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 
 442 static int comp(const void *a, const void *b)
 443 {
 444         return *(int *)a - *(int *)b;
 445 }
 446 
 447 static 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 
 464 static void sort_something(void)
 465 {
 466         int i;
 467 
 468         for (i = 0; i < 10; i++)
 469                 do_sort_something();
 470 }
 471 
 472 static 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 
 487 static 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 
 506 static 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 */
 527 out_clocks:
 528         event = excl_kernel ? "cpu-clock:u" : "cpu-clock";
 529 
 530 #endif
 531         return event;
 532 }
 533 
 534 static void do_something(void)
 535 {
 536         fs_something();
 537 
 538         sort_something();
 539 
 540         syscall_something();
 541 }
 542 
 543 enum {
 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 
 551 static 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;
 713 out_put:
 714         thread__put(thread);
 715 out_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 
 729 int 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 }

/* [<][>][^][v][top][bottom][index][help] */