18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <errno.h> 38c2ecf20Sopenharmony_ci#include <linux/kernel.h> 48c2ecf20Sopenharmony_ci#include <linux/types.h> 58c2ecf20Sopenharmony_ci#include <inttypes.h> 68c2ecf20Sopenharmony_ci#include <stdlib.h> 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <stdio.h> 98c2ecf20Sopenharmony_ci#include <string.h> 108c2ecf20Sopenharmony_ci#include <sys/param.h> 118c2ecf20Sopenharmony_ci#include <perf/cpumap.h> 128c2ecf20Sopenharmony_ci#include <perf/evlist.h> 138c2ecf20Sopenharmony_ci#include <perf/mmap.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "debug.h" 168c2ecf20Sopenharmony_ci#include "dso.h" 178c2ecf20Sopenharmony_ci#include "env.h" 188c2ecf20Sopenharmony_ci#include "parse-events.h" 198c2ecf20Sopenharmony_ci#include "trace-event.h" 208c2ecf20Sopenharmony_ci#include "evlist.h" 218c2ecf20Sopenharmony_ci#include "evsel.h" 228c2ecf20Sopenharmony_ci#include "thread_map.h" 238c2ecf20Sopenharmony_ci#include "machine.h" 248c2ecf20Sopenharmony_ci#include "map.h" 258c2ecf20Sopenharmony_ci#include "symbol.h" 268c2ecf20Sopenharmony_ci#include "event.h" 278c2ecf20Sopenharmony_ci#include "record.h" 288c2ecf20Sopenharmony_ci#include "util/mmap.h" 298c2ecf20Sopenharmony_ci#include "util/synthetic-events.h" 308c2ecf20Sopenharmony_ci#include "thread.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "tests.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/ctype.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define BUFSZ 1024 378c2ecf20Sopenharmony_ci#define READLEN 128 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct state { 408c2ecf20Sopenharmony_ci u64 done[1024]; 418c2ecf20Sopenharmony_ci size_t done_cnt; 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic unsigned int hex(char c) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci if (c >= '0' && c <= '9') 478c2ecf20Sopenharmony_ci return c - '0'; 488c2ecf20Sopenharmony_ci if (c >= 'a' && c <= 'f') 498c2ecf20Sopenharmony_ci return c - 'a' + 10; 508c2ecf20Sopenharmony_ci return c - 'A' + 10; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic size_t read_objdump_chunk(const char **line, unsigned char **buf, 548c2ecf20Sopenharmony_ci size_t *buf_len) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci size_t bytes_read = 0; 578c2ecf20Sopenharmony_ci unsigned char *chunk_start = *buf; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* Read bytes */ 608c2ecf20Sopenharmony_ci while (*buf_len > 0) { 618c2ecf20Sopenharmony_ci char c1, c2; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* Get 2 hex digits */ 648c2ecf20Sopenharmony_ci c1 = *(*line)++; 658c2ecf20Sopenharmony_ci if (!isxdigit(c1)) 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci c2 = *(*line)++; 688c2ecf20Sopenharmony_ci if (!isxdigit(c2)) 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* Store byte and advance buf */ 728c2ecf20Sopenharmony_ci **buf = (hex(c1) << 4) | hex(c2); 738c2ecf20Sopenharmony_ci (*buf)++; 748c2ecf20Sopenharmony_ci (*buf_len)--; 758c2ecf20Sopenharmony_ci bytes_read++; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* End of chunk? */ 788c2ecf20Sopenharmony_ci if (isspace(**line)) 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * objdump will display raw insn as LE if code endian 848c2ecf20Sopenharmony_ci * is LE and bytes_per_chunk > 1. In that case reverse 858c2ecf20Sopenharmony_ci * the chunk we just read. 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * see disassemble_bytes() at binutils/objdump.c for details 888c2ecf20Sopenharmony_ci * how objdump chooses display endian) 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci if (bytes_read > 1 && !bigendian()) { 918c2ecf20Sopenharmony_ci unsigned char *chunk_end = chunk_start + bytes_read - 1; 928c2ecf20Sopenharmony_ci unsigned char tmp; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci while (chunk_start < chunk_end) { 958c2ecf20Sopenharmony_ci tmp = *chunk_start; 968c2ecf20Sopenharmony_ci *chunk_start = *chunk_end; 978c2ecf20Sopenharmony_ci *chunk_end = tmp; 988c2ecf20Sopenharmony_ci chunk_start++; 998c2ecf20Sopenharmony_ci chunk_end--; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return bytes_read; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic size_t read_objdump_line(const char *line, unsigned char *buf, 1078c2ecf20Sopenharmony_ci size_t buf_len) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci const char *p; 1108c2ecf20Sopenharmony_ci size_t ret, bytes_read = 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Skip to a colon */ 1138c2ecf20Sopenharmony_ci p = strchr(line, ':'); 1148c2ecf20Sopenharmony_ci if (!p) 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci p++; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Skip initial spaces */ 1198c2ecf20Sopenharmony_ci while (*p) { 1208c2ecf20Sopenharmony_ci if (!isspace(*p)) 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci p++; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci do { 1268c2ecf20Sopenharmony_ci ret = read_objdump_chunk(&p, &buf, &buf_len); 1278c2ecf20Sopenharmony_ci bytes_read += ret; 1288c2ecf20Sopenharmony_ci p++; 1298c2ecf20Sopenharmony_ci } while (ret > 0); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* return number of successfully read bytes */ 1328c2ecf20Sopenharmony_ci return bytes_read; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci char *line = NULL; 1388c2ecf20Sopenharmony_ci size_t line_len, off_last = 0; 1398c2ecf20Sopenharmony_ci ssize_t ret; 1408c2ecf20Sopenharmony_ci int err = 0; 1418c2ecf20Sopenharmony_ci u64 addr, last_addr = start_addr; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci while (off_last < *len) { 1448c2ecf20Sopenharmony_ci size_t off, read_bytes, written_bytes; 1458c2ecf20Sopenharmony_ci unsigned char tmp[BUFSZ]; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci ret = getline(&line, &line_len, f); 1488c2ecf20Sopenharmony_ci if (feof(f)) 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci if (ret < 0) { 1518c2ecf20Sopenharmony_ci pr_debug("getline failed\n"); 1528c2ecf20Sopenharmony_ci err = -1; 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* read objdump data into temporary buffer */ 1578c2ecf20Sopenharmony_ci read_bytes = read_objdump_line(line, tmp, sizeof(tmp)); 1588c2ecf20Sopenharmony_ci if (!read_bytes) 1598c2ecf20Sopenharmony_ci continue; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (sscanf(line, "%"PRIx64, &addr) != 1) 1628c2ecf20Sopenharmony_ci continue; 1638c2ecf20Sopenharmony_ci if (addr < last_addr) { 1648c2ecf20Sopenharmony_ci pr_debug("addr going backwards, read beyond section?\n"); 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci last_addr = addr; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* copy it from temporary buffer to 'buf' according 1708c2ecf20Sopenharmony_ci * to address on current objdump line */ 1718c2ecf20Sopenharmony_ci off = addr - start_addr; 1728c2ecf20Sopenharmony_ci if (off >= *len) 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci written_bytes = MIN(read_bytes, *len - off); 1758c2ecf20Sopenharmony_ci memcpy(buf + off, tmp, written_bytes); 1768c2ecf20Sopenharmony_ci off_last = off + written_bytes; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* len returns number of bytes that could not be read */ 1808c2ecf20Sopenharmony_ci *len -= off_last; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci free(line); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return err; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int read_via_objdump(const char *filename, u64 addr, void *buf, 1888c2ecf20Sopenharmony_ci size_t len) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci char cmd[PATH_MAX * 2]; 1918c2ecf20Sopenharmony_ci const char *fmt; 1928c2ecf20Sopenharmony_ci FILE *f; 1938c2ecf20Sopenharmony_ci int ret; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s"; 1968c2ecf20Sopenharmony_ci ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len, 1978c2ecf20Sopenharmony_ci filename); 1988c2ecf20Sopenharmony_ci if (ret <= 0 || (size_t)ret >= sizeof(cmd)) 1998c2ecf20Sopenharmony_ci return -1; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci pr_debug("Objdump command is: %s\n", cmd); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Ignore objdump errors */ 2048c2ecf20Sopenharmony_ci strcat(cmd, " 2>/dev/null"); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci f = popen(cmd, "r"); 2078c2ecf20Sopenharmony_ci if (!f) { 2088c2ecf20Sopenharmony_ci pr_debug("popen failed\n"); 2098c2ecf20Sopenharmony_ci return -1; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ret = read_objdump_output(f, buf, &len, addr); 2138c2ecf20Sopenharmony_ci if (len) { 2148c2ecf20Sopenharmony_ci pr_debug("objdump read too few bytes: %zd\n", len); 2158c2ecf20Sopenharmony_ci if (!ret) 2168c2ecf20Sopenharmony_ci ret = len; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci pclose(f); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return ret; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic void dump_buf(unsigned char *buf, size_t len) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci size_t i; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 2298c2ecf20Sopenharmony_ci pr_debug("0x%02x ", buf[i]); 2308c2ecf20Sopenharmony_ci if (i % 16 == 15) 2318c2ecf20Sopenharmony_ci pr_debug("\n"); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci pr_debug("\n"); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int read_object_code(u64 addr, size_t len, u8 cpumode, 2378c2ecf20Sopenharmony_ci struct thread *thread, struct state *state) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct addr_location al; 2408c2ecf20Sopenharmony_ci unsigned char buf1[BUFSZ]; 2418c2ecf20Sopenharmony_ci unsigned char buf2[BUFSZ]; 2428c2ecf20Sopenharmony_ci size_t ret_len; 2438c2ecf20Sopenharmony_ci u64 objdump_addr; 2448c2ecf20Sopenharmony_ci const char *objdump_name; 2458c2ecf20Sopenharmony_ci char decomp_name[KMOD_DECOMP_LEN]; 2468c2ecf20Sopenharmony_ci bool decomp = false; 2478c2ecf20Sopenharmony_ci int ret; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (!thread__find_map(thread, cpumode, addr, &al) || !al.map->dso) { 2528c2ecf20Sopenharmony_ci if (cpumode == PERF_RECORD_MISC_HYPERVISOR) { 2538c2ecf20Sopenharmony_ci pr_debug("Hypervisor address can not be resolved - skipping\n"); 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci pr_debug("thread__find_map failed\n"); 2588c2ecf20Sopenharmony_ci return -1; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci pr_debug("File is: %s\n", al.map->dso->long_name); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && 2648c2ecf20Sopenharmony_ci !dso__is_kcore(al.map->dso)) { 2658c2ecf20Sopenharmony_ci pr_debug("Unexpected kernel address - skipping\n"); 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci pr_debug("On file address is: %#"PRIx64"\n", al.addr); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (len > BUFSZ) 2728c2ecf20Sopenharmony_ci len = BUFSZ; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Do not go off the map */ 2758c2ecf20Sopenharmony_ci if (addr + len > al.map->end) 2768c2ecf20Sopenharmony_ci len = al.map->end - addr; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Read the object code using perf */ 2798c2ecf20Sopenharmony_ci ret_len = dso__data_read_offset(al.map->dso, thread->maps->machine, 2808c2ecf20Sopenharmony_ci al.addr, buf1, len); 2818c2ecf20Sopenharmony_ci if (ret_len != len) { 2828c2ecf20Sopenharmony_ci pr_debug("dso__data_read_offset failed\n"); 2838c2ecf20Sopenharmony_ci return -1; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * Converting addresses for use by objdump requires more information. 2888c2ecf20Sopenharmony_ci * map__load() does that. See map__rip_2objdump() for details. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci if (map__load(al.map)) 2918c2ecf20Sopenharmony_ci return -1; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* objdump struggles with kcore - try each map only once */ 2948c2ecf20Sopenharmony_ci if (dso__is_kcore(al.map->dso)) { 2958c2ecf20Sopenharmony_ci size_t d; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci for (d = 0; d < state->done_cnt; d++) { 2988c2ecf20Sopenharmony_ci if (state->done[d] == al.map->start) { 2998c2ecf20Sopenharmony_ci pr_debug("kcore map tested already"); 3008c2ecf20Sopenharmony_ci pr_debug(" - skipping\n"); 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci if (state->done_cnt >= ARRAY_SIZE(state->done)) { 3058c2ecf20Sopenharmony_ci pr_debug("Too many kcore maps - skipping\n"); 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci state->done[state->done_cnt++] = al.map->start; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci objdump_name = al.map->dso->long_name; 3128c2ecf20Sopenharmony_ci if (dso__needs_decompress(al.map->dso)) { 3138c2ecf20Sopenharmony_ci if (dso__decompress_kmodule_path(al.map->dso, objdump_name, 3148c2ecf20Sopenharmony_ci decomp_name, 3158c2ecf20Sopenharmony_ci sizeof(decomp_name)) < 0) { 3168c2ecf20Sopenharmony_ci pr_debug("decompression failed\n"); 3178c2ecf20Sopenharmony_ci return -1; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci decomp = true; 3218c2ecf20Sopenharmony_ci objdump_name = decomp_name; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Read the object code using objdump */ 3258c2ecf20Sopenharmony_ci objdump_addr = map__rip_2objdump(al.map, al.addr); 3268c2ecf20Sopenharmony_ci ret = read_via_objdump(objdump_name, objdump_addr, buf2, len); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (decomp) 3298c2ecf20Sopenharmony_ci unlink(objdump_name); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (ret > 0) { 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * The kernel maps are inaccurate - assume objdump is right in 3348c2ecf20Sopenharmony_ci * that case. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci if (cpumode == PERF_RECORD_MISC_KERNEL || 3378c2ecf20Sopenharmony_ci cpumode == PERF_RECORD_MISC_GUEST_KERNEL) { 3388c2ecf20Sopenharmony_ci len -= ret; 3398c2ecf20Sopenharmony_ci if (len) { 3408c2ecf20Sopenharmony_ci pr_debug("Reducing len to %zu\n", len); 3418c2ecf20Sopenharmony_ci } else if (dso__is_kcore(al.map->dso)) { 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * objdump cannot handle very large segments 3448c2ecf20Sopenharmony_ci * that may be found in kcore. 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci pr_debug("objdump failed for kcore"); 3478c2ecf20Sopenharmony_ci pr_debug(" - skipping\n"); 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci } else { 3508c2ecf20Sopenharmony_ci return -1; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci if (ret < 0) { 3558c2ecf20Sopenharmony_ci pr_debug("read_via_objdump failed\n"); 3568c2ecf20Sopenharmony_ci return -1; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* The results should be identical */ 3608c2ecf20Sopenharmony_ci if (memcmp(buf1, buf2, len)) { 3618c2ecf20Sopenharmony_ci pr_debug("Bytes read differ from those read by objdump\n"); 3628c2ecf20Sopenharmony_ci pr_debug("buf1 (dso):\n"); 3638c2ecf20Sopenharmony_ci dump_buf(buf1, len); 3648c2ecf20Sopenharmony_ci pr_debug("buf2 (objdump):\n"); 3658c2ecf20Sopenharmony_ci dump_buf(buf2, len); 3668c2ecf20Sopenharmony_ci return -1; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci pr_debug("Bytes read match those read by objdump\n"); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic int process_sample_event(struct machine *machine, 3748c2ecf20Sopenharmony_ci struct evlist *evlist, 3758c2ecf20Sopenharmony_ci union perf_event *event, struct state *state) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct perf_sample sample; 3788c2ecf20Sopenharmony_ci struct thread *thread; 3798c2ecf20Sopenharmony_ci int ret; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (perf_evlist__parse_sample(evlist, event, &sample)) { 3828c2ecf20Sopenharmony_ci pr_debug("perf_evlist__parse_sample failed\n"); 3838c2ecf20Sopenharmony_ci return -1; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci thread = machine__findnew_thread(machine, sample.pid, sample.tid); 3878c2ecf20Sopenharmony_ci if (!thread) { 3888c2ecf20Sopenharmony_ci pr_debug("machine__findnew_thread failed\n"); 3898c2ecf20Sopenharmony_ci return -1; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ret = read_object_code(sample.ip, READLEN, sample.cpumode, thread, state); 3938c2ecf20Sopenharmony_ci thread__put(thread); 3948c2ecf20Sopenharmony_ci return ret; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int process_event(struct machine *machine, struct evlist *evlist, 3988c2ecf20Sopenharmony_ci union perf_event *event, struct state *state) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci if (event->header.type == PERF_RECORD_SAMPLE) 4018c2ecf20Sopenharmony_ci return process_sample_event(machine, evlist, event, state); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (event->header.type == PERF_RECORD_THROTTLE || 4048c2ecf20Sopenharmony_ci event->header.type == PERF_RECORD_UNTHROTTLE) 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (event->header.type < PERF_RECORD_MAX) { 4088c2ecf20Sopenharmony_ci int ret; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci ret = machine__process_event(machine, event, NULL); 4118c2ecf20Sopenharmony_ci if (ret < 0) 4128c2ecf20Sopenharmony_ci pr_debug("machine__process_event failed, event type %u\n", 4138c2ecf20Sopenharmony_ci event->header.type); 4148c2ecf20Sopenharmony_ci return ret; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return 0; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int process_events(struct machine *machine, struct evlist *evlist, 4218c2ecf20Sopenharmony_ci struct state *state) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci union perf_event *event; 4248c2ecf20Sopenharmony_ci struct mmap *md; 4258c2ecf20Sopenharmony_ci int i, ret; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci for (i = 0; i < evlist->core.nr_mmaps; i++) { 4288c2ecf20Sopenharmony_ci md = &evlist->mmap[i]; 4298c2ecf20Sopenharmony_ci if (perf_mmap__read_init(&md->core) < 0) 4308c2ecf20Sopenharmony_ci continue; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci while ((event = perf_mmap__read_event(&md->core)) != NULL) { 4338c2ecf20Sopenharmony_ci ret = process_event(machine, evlist, event, state); 4348c2ecf20Sopenharmony_ci perf_mmap__consume(&md->core); 4358c2ecf20Sopenharmony_ci if (ret < 0) 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci perf_mmap__read_done(&md->core); 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int comp(const void *a, const void *b) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci return *(int *)a - *(int *)b; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic void do_sort_something(void) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci int buf[40960], i; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci for (i = 0; i < (int)ARRAY_SIZE(buf); i++) 4538c2ecf20Sopenharmony_ci buf[i] = ARRAY_SIZE(buf) - i - 1; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci qsort(buf, ARRAY_SIZE(buf), sizeof(int), comp); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci for (i = 0; i < (int)ARRAY_SIZE(buf); i++) { 4588c2ecf20Sopenharmony_ci if (buf[i] != i) { 4598c2ecf20Sopenharmony_ci pr_debug("qsort failed\n"); 4608c2ecf20Sopenharmony_ci break; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic void sort_something(void) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci int i; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) 4708c2ecf20Sopenharmony_ci do_sort_something(); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic void syscall_something(void) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci int pipefd[2]; 4768c2ecf20Sopenharmony_ci int i; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) { 4798c2ecf20Sopenharmony_ci if (pipe(pipefd) < 0) { 4808c2ecf20Sopenharmony_ci pr_debug("pipe failed\n"); 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci close(pipefd[1]); 4848c2ecf20Sopenharmony_ci close(pipefd[0]); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic void fs_something(void) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci const char *test_file_name = "temp-perf-code-reading-test-file--"; 4918c2ecf20Sopenharmony_ci FILE *f; 4928c2ecf20Sopenharmony_ci int i; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) { 4958c2ecf20Sopenharmony_ci f = fopen(test_file_name, "w+"); 4968c2ecf20Sopenharmony_ci if (f) { 4978c2ecf20Sopenharmony_ci fclose(f); 4988c2ecf20Sopenharmony_ci unlink(test_file_name); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci#ifdef __s390x__ 5048c2ecf20Sopenharmony_ci#include "header.h" // for get_cpuid() 5058c2ecf20Sopenharmony_ci#endif 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic const char *do_determine_event(bool excl_kernel) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci const char *event = excl_kernel ? "cycles:u" : "cycles"; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci#ifdef __s390x__ 5128c2ecf20Sopenharmony_ci char cpuid[128], model[16], model_c[16], cpum_cf_v[16]; 5138c2ecf20Sopenharmony_ci unsigned int family; 5148c2ecf20Sopenharmony_ci int ret, cpum_cf_a; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (get_cpuid(cpuid, sizeof(cpuid))) 5178c2ecf20Sopenharmony_ci goto out_clocks; 5188c2ecf20Sopenharmony_ci ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%x", &family, model_c, 5198c2ecf20Sopenharmony_ci model, cpum_cf_v, &cpum_cf_a); 5208c2ecf20Sopenharmony_ci if (ret != 5) /* Not available */ 5218c2ecf20Sopenharmony_ci goto out_clocks; 5228c2ecf20Sopenharmony_ci if (excl_kernel && (cpum_cf_a & 4)) 5238c2ecf20Sopenharmony_ci return event; 5248c2ecf20Sopenharmony_ci if (!excl_kernel && (cpum_cf_a & 2)) 5258c2ecf20Sopenharmony_ci return event; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* Fall through: missing authorization */ 5288c2ecf20Sopenharmony_ciout_clocks: 5298c2ecf20Sopenharmony_ci event = excl_kernel ? "cpu-clock:u" : "cpu-clock"; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci#endif 5328c2ecf20Sopenharmony_ci return event; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic void do_something(void) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci fs_something(); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci sort_something(); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci syscall_something(); 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cienum { 5458c2ecf20Sopenharmony_ci TEST_CODE_READING_OK, 5468c2ecf20Sopenharmony_ci TEST_CODE_READING_NO_VMLINUX, 5478c2ecf20Sopenharmony_ci TEST_CODE_READING_NO_KCORE, 5488c2ecf20Sopenharmony_ci TEST_CODE_READING_NO_ACCESS, 5498c2ecf20Sopenharmony_ci TEST_CODE_READING_NO_KERNEL_OBJ, 5508c2ecf20Sopenharmony_ci}; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic int do_test_code_reading(bool try_kcore) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct machine *machine; 5558c2ecf20Sopenharmony_ci struct thread *thread; 5568c2ecf20Sopenharmony_ci struct record_opts opts = { 5578c2ecf20Sopenharmony_ci .mmap_pages = UINT_MAX, 5588c2ecf20Sopenharmony_ci .user_freq = UINT_MAX, 5598c2ecf20Sopenharmony_ci .user_interval = ULLONG_MAX, 5608c2ecf20Sopenharmony_ci .freq = 500, 5618c2ecf20Sopenharmony_ci .target = { 5628c2ecf20Sopenharmony_ci .uses_mmap = true, 5638c2ecf20Sopenharmony_ci }, 5648c2ecf20Sopenharmony_ci }; 5658c2ecf20Sopenharmony_ci struct state state = { 5668c2ecf20Sopenharmony_ci .done_cnt = 0, 5678c2ecf20Sopenharmony_ci }; 5688c2ecf20Sopenharmony_ci struct perf_thread_map *threads = NULL; 5698c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus = NULL; 5708c2ecf20Sopenharmony_ci struct evlist *evlist = NULL; 5718c2ecf20Sopenharmony_ci struct evsel *evsel = NULL; 5728c2ecf20Sopenharmony_ci int err = -1, ret; 5738c2ecf20Sopenharmony_ci pid_t pid; 5748c2ecf20Sopenharmony_ci struct map *map; 5758c2ecf20Sopenharmony_ci bool have_vmlinux, have_kcore, excl_kernel = false; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci pid = getpid(); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci machine = machine__new_host(); 5808c2ecf20Sopenharmony_ci machine->env = &perf_env; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci ret = machine__create_kernel_maps(machine); 5838c2ecf20Sopenharmony_ci if (ret < 0) { 5848c2ecf20Sopenharmony_ci pr_debug("machine__create_kernel_maps failed\n"); 5858c2ecf20Sopenharmony_ci goto out_err; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Force the use of kallsyms instead of vmlinux to try kcore */ 5898c2ecf20Sopenharmony_ci if (try_kcore) 5908c2ecf20Sopenharmony_ci symbol_conf.kallsyms_name = "/proc/kallsyms"; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* Load kernel map */ 5938c2ecf20Sopenharmony_ci map = machine__kernel_map(machine); 5948c2ecf20Sopenharmony_ci ret = map__load(map); 5958c2ecf20Sopenharmony_ci if (ret < 0) { 5968c2ecf20Sopenharmony_ci pr_debug("map__load failed\n"); 5978c2ecf20Sopenharmony_ci goto out_err; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci have_vmlinux = dso__is_vmlinux(map->dso); 6008c2ecf20Sopenharmony_ci have_kcore = dso__is_kcore(map->dso); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* 2nd time through we just try kcore */ 6038c2ecf20Sopenharmony_ci if (try_kcore && !have_kcore) 6048c2ecf20Sopenharmony_ci return TEST_CODE_READING_NO_KCORE; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* No point getting kernel events if there is no kernel object */ 6078c2ecf20Sopenharmony_ci if (!have_vmlinux && !have_kcore) 6088c2ecf20Sopenharmony_ci excl_kernel = true; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci threads = thread_map__new_by_tid(pid); 6118c2ecf20Sopenharmony_ci if (!threads) { 6128c2ecf20Sopenharmony_ci pr_debug("thread_map__new_by_tid failed\n"); 6138c2ecf20Sopenharmony_ci goto out_err; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci ret = perf_event__synthesize_thread_map(NULL, threads, 6178c2ecf20Sopenharmony_ci perf_event__process, machine, false); 6188c2ecf20Sopenharmony_ci if (ret < 0) { 6198c2ecf20Sopenharmony_ci pr_debug("perf_event__synthesize_thread_map failed\n"); 6208c2ecf20Sopenharmony_ci goto out_err; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci thread = machine__findnew_thread(machine, pid, pid); 6248c2ecf20Sopenharmony_ci if (!thread) { 6258c2ecf20Sopenharmony_ci pr_debug("machine__findnew_thread failed\n"); 6268c2ecf20Sopenharmony_ci goto out_put; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci cpus = perf_cpu_map__new(NULL); 6308c2ecf20Sopenharmony_ci if (!cpus) { 6318c2ecf20Sopenharmony_ci pr_debug("perf_cpu_map__new failed\n"); 6328c2ecf20Sopenharmony_ci goto out_put; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci while (1) { 6368c2ecf20Sopenharmony_ci const char *str; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci evlist = evlist__new(); 6398c2ecf20Sopenharmony_ci if (!evlist) { 6408c2ecf20Sopenharmony_ci pr_debug("perf_evlist__new failed\n"); 6418c2ecf20Sopenharmony_ci goto out_put; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci perf_evlist__set_maps(&evlist->core, cpus, threads); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci str = do_determine_event(excl_kernel); 6478c2ecf20Sopenharmony_ci pr_debug("Parsing event '%s'\n", str); 6488c2ecf20Sopenharmony_ci ret = parse_events(evlist, str, NULL); 6498c2ecf20Sopenharmony_ci if (ret < 0) { 6508c2ecf20Sopenharmony_ci pr_debug("parse_events failed\n"); 6518c2ecf20Sopenharmony_ci goto out_put; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci perf_evlist__config(evlist, &opts, NULL); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci evsel = evlist__first(evlist); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci evsel->core.attr.comm = 1; 6598c2ecf20Sopenharmony_ci evsel->core.attr.disabled = 1; 6608c2ecf20Sopenharmony_ci evsel->core.attr.enable_on_exec = 0; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci ret = evlist__open(evlist); 6638c2ecf20Sopenharmony_ci if (ret < 0) { 6648c2ecf20Sopenharmony_ci if (!excl_kernel) { 6658c2ecf20Sopenharmony_ci excl_kernel = true; 6668c2ecf20Sopenharmony_ci /* 6678c2ecf20Sopenharmony_ci * Both cpus and threads are now owned by evlist 6688c2ecf20Sopenharmony_ci * and will be freed by following perf_evlist__set_maps 6698c2ecf20Sopenharmony_ci * call. Getting refference to keep them alive. 6708c2ecf20Sopenharmony_ci */ 6718c2ecf20Sopenharmony_ci perf_cpu_map__get(cpus); 6728c2ecf20Sopenharmony_ci perf_thread_map__get(threads); 6738c2ecf20Sopenharmony_ci perf_evlist__set_maps(&evlist->core, NULL, NULL); 6748c2ecf20Sopenharmony_ci evlist__delete(evlist); 6758c2ecf20Sopenharmony_ci evlist = NULL; 6768c2ecf20Sopenharmony_ci continue; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (verbose > 0) { 6808c2ecf20Sopenharmony_ci char errbuf[512]; 6818c2ecf20Sopenharmony_ci evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf)); 6828c2ecf20Sopenharmony_ci pr_debug("perf_evlist__open() failed!\n%s\n", errbuf); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci goto out_put; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci ret = evlist__mmap(evlist, UINT_MAX); 6918c2ecf20Sopenharmony_ci if (ret < 0) { 6928c2ecf20Sopenharmony_ci pr_debug("evlist__mmap failed\n"); 6938c2ecf20Sopenharmony_ci goto out_put; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci evlist__enable(evlist); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci do_something(); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci evlist__disable(evlist); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci ret = process_events(machine, evlist, &state); 7038c2ecf20Sopenharmony_ci if (ret < 0) 7048c2ecf20Sopenharmony_ci goto out_put; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (!have_vmlinux && !have_kcore && !try_kcore) 7078c2ecf20Sopenharmony_ci err = TEST_CODE_READING_NO_KERNEL_OBJ; 7088c2ecf20Sopenharmony_ci else if (!have_vmlinux && !try_kcore) 7098c2ecf20Sopenharmony_ci err = TEST_CODE_READING_NO_VMLINUX; 7108c2ecf20Sopenharmony_ci else if (excl_kernel) 7118c2ecf20Sopenharmony_ci err = TEST_CODE_READING_NO_ACCESS; 7128c2ecf20Sopenharmony_ci else 7138c2ecf20Sopenharmony_ci err = TEST_CODE_READING_OK; 7148c2ecf20Sopenharmony_ciout_put: 7158c2ecf20Sopenharmony_ci thread__put(thread); 7168c2ecf20Sopenharmony_ciout_err: 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (evlist) { 7198c2ecf20Sopenharmony_ci evlist__delete(evlist); 7208c2ecf20Sopenharmony_ci } else { 7218c2ecf20Sopenharmony_ci perf_cpu_map__put(cpus); 7228c2ecf20Sopenharmony_ci perf_thread_map__put(threads); 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci machine__delete_threads(machine); 7258c2ecf20Sopenharmony_ci machine__delete(machine); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return err; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ciint test__code_reading(struct test *test __maybe_unused, int subtest __maybe_unused) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci int ret; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci ret = do_test_code_reading(false); 7358c2ecf20Sopenharmony_ci if (!ret) 7368c2ecf20Sopenharmony_ci ret = do_test_code_reading(true); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci switch (ret) { 7398c2ecf20Sopenharmony_ci case TEST_CODE_READING_OK: 7408c2ecf20Sopenharmony_ci return 0; 7418c2ecf20Sopenharmony_ci case TEST_CODE_READING_NO_VMLINUX: 7428c2ecf20Sopenharmony_ci pr_debug("no vmlinux\n"); 7438c2ecf20Sopenharmony_ci return 0; 7448c2ecf20Sopenharmony_ci case TEST_CODE_READING_NO_KCORE: 7458c2ecf20Sopenharmony_ci pr_debug("no kcore\n"); 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci case TEST_CODE_READING_NO_ACCESS: 7488c2ecf20Sopenharmony_ci pr_debug("no access\n"); 7498c2ecf20Sopenharmony_ci return 0; 7508c2ecf20Sopenharmony_ci case TEST_CODE_READING_NO_KERNEL_OBJ: 7518c2ecf20Sopenharmony_ci pr_debug("no kernel obj\n"); 7528c2ecf20Sopenharmony_ci return 0; 7538c2ecf20Sopenharmony_ci default: 7548c2ecf20Sopenharmony_ci return -1; 7558c2ecf20Sopenharmony_ci }; 7568c2ecf20Sopenharmony_ci} 757