Merge tag 'mm-hotfixes-stable-2025-07-11-16-16' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-block.git] / tools / perf / tests / code-reading.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
a43783ae 2#include <errno.h>
0f9ad973 3#include <linux/kconfig.h>
877a7a11 4#include <linux/kernel.h>
d944c4ee 5#include <linux/types.h>
fd20e811 6#include <inttypes.h>
b55ae0a9
AH
7#include <stdlib.h>
8#include <unistd.h>
9#include <stdio.h>
b55ae0a9 10#include <string.h>
391e4206 11#include <sys/param.h>
0f9ad973 12#include <sys/utsname.h>
9c3516d1 13#include <perf/cpumap.h>
453fa030 14#include <perf/evlist.h>
7728fa0c 15#include <perf/mmap.h>
b55ae0a9 16
b4209025 17#include "debug.h"
4a3cec84 18#include "dso.h"
f2a39fe8 19#include "env.h"
b55ae0a9
AH
20#include "parse-events.h"
21#include "evlist.h"
22#include "evsel.h"
23#include "thread_map.h"
b55ae0a9 24#include "machine.h"
1101f69a 25#include "map.h"
daecf9e0 26#include "symbol.h"
b55ae0a9 27#include "event.h"
aeb00b1a 28#include "record.h"
e0fcfb08 29#include "util/mmap.h"
cef7af25 30#include "util/string2.h"
ea49e01c 31#include "util/synthetic-events.h"
5b7a29fb 32#include "util/util.h"
b55ae0a9
AH
33#include "thread.h"
34
35#include "tests.h"
36
3052ba56 37#include <linux/ctype.h>
3d689ed6 38
b55ae0a9
AH
39#define BUFSZ 1024
40#define READLEN 128
41
7a77bc2c
AH
42struct state {
43 u64 done[1024];
44 size_t done_cnt;
45};
46
b2d0dbf0
JS
47static size_t read_objdump_chunk(const char **line, unsigned char **buf,
48 size_t *buf_len)
b55ae0a9 49{
b2d0dbf0
JS
50 size_t bytes_read = 0;
51 unsigned char *chunk_start = *buf;
b55ae0a9
AH
52
53 /* Read bytes */
b2d0dbf0 54 while (*buf_len > 0) {
b55ae0a9
AH
55 char c1, c2;
56
b55ae0a9 57 /* Get 2 hex digits */
b2d0dbf0
JS
58 c1 = *(*line)++;
59 if (!isxdigit(c1))
b55ae0a9 60 break;
b2d0dbf0
JS
61 c2 = *(*line)++;
62 if (!isxdigit(c2))
b55ae0a9 63 break;
b2d0dbf0
JS
64
65 /* Store byte and advance buf */
66 **buf = (hex(c1) << 4) | hex(c2);
67 (*buf)++;
68 (*buf_len)--;
69 bytes_read++;
70
71 /* End of chunk? */
72 if (isspace(**line))
b55ae0a9 73 break;
b55ae0a9 74 }
b2d0dbf0
JS
75
76 /*
77 * objdump will display raw insn as LE if code endian
78 * is LE and bytes_per_chunk > 1. In that case reverse
79 * the chunk we just read.
80 *
81 * see disassemble_bytes() at binutils/objdump.c for details
82 * how objdump chooses display endian)
83 */
5b7a29fb 84 if (bytes_read > 1 && !host_is_bigendian()) {
b2d0dbf0
JS
85 unsigned char *chunk_end = chunk_start + bytes_read - 1;
86 unsigned char tmp;
87
88 while (chunk_start < chunk_end) {
89 tmp = *chunk_start;
90 *chunk_start = *chunk_end;
91 *chunk_end = tmp;
92 chunk_start++;
93 chunk_end--;
94 }
95 }
96
97 return bytes_read;
98}
99
100static size_t read_objdump_line(const char *line, unsigned char *buf,
101 size_t buf_len)
102{
103 const char *p;
104 size_t ret, bytes_read = 0;
105
106 /* Skip to a colon */
107 p = strchr(line, ':');
108 if (!p)
109 return 0;
110 p++;
111
112 /* Skip initial spaces */
113 while (*p) {
114 if (!isspace(*p))
115 break;
116 p++;
117 }
118
119 do {
120 ret = read_objdump_chunk(&p, &buf, &buf_len);
121 bytes_read += ret;
122 p++;
123 } while (ret > 0);
124
729a7ed1 125 /* return number of successfully read bytes */
b2d0dbf0 126 return bytes_read;
b55ae0a9
AH
127}
128
729a7ed1 129static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr)
b55ae0a9
AH
130{
131 char *line = NULL;
729a7ed1 132 size_t line_len, off_last = 0;
b55ae0a9
AH
133 ssize_t ret;
134 int err = 0;
edfdb7ea 135 u64 addr, last_addr = start_addr;
729a7ed1
JS
136
137 while (off_last < *len) {
138 size_t off, read_bytes, written_bytes;
139 unsigned char tmp[BUFSZ];
b55ae0a9 140
b55ae0a9
AH
141 ret = getline(&line, &line_len, f);
142 if (feof(f))
143 break;
144 if (ret < 0) {
145 pr_debug("getline failed\n");
146 err = -1;
147 break;
148 }
729a7ed1
JS
149
150 /* read objdump data into temporary buffer */
b2d0dbf0 151 read_bytes = read_objdump_line(line, tmp, sizeof(tmp));
729a7ed1
JS
152 if (!read_bytes)
153 continue;
154
155 if (sscanf(line, "%"PRIx64, &addr) != 1)
156 continue;
edfdb7ea
JS
157 if (addr < last_addr) {
158 pr_debug("addr going backwards, read beyond section?\n");
159 break;
160 }
161 last_addr = addr;
729a7ed1
JS
162
163 /* copy it from temporary buffer to 'buf' according
164 * to address on current objdump line */
165 off = addr - start_addr;
166 if (off >= *len)
167 break;
168 written_bytes = MIN(read_bytes, *len - off);
169 memcpy(buf + off, tmp, written_bytes);
170 off_last = off + written_bytes;
b55ae0a9
AH
171 }
172
729a7ed1
JS
173 /* len returns number of bytes that could not be read */
174 *len -= off_last;
175
b55ae0a9
AH
176 free(line);
177
178 return err;
179}
180
0f9ad973
CJ
181/*
182 * Only gets GNU objdump version. Returns 0 for llvm-objdump.
183 */
184static int objdump_version(void)
185{
186 size_t line_len;
187 char cmd[PATH_MAX * 2];
188 char *line = NULL;
189 const char *fmt;
190 FILE *f;
191 int ret;
192
193 int version_tmp, version_num = 0;
194 char *version = 0, *token;
195
196 fmt = "%s --version";
197 ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path);
198 if (ret <= 0 || (size_t)ret >= sizeof(cmd))
199 return -1;
200 /* Ignore objdump errors */
201 strcat(cmd, " 2>/dev/null");
202 f = popen(cmd, "r");
203 if (!f) {
204 pr_debug("popen failed\n");
205 return -1;
206 }
207 /* Get first line of objdump --version output */
208 ret = getline(&line, &line_len, f);
209 pclose(f);
210 if (ret < 0) {
211 pr_debug("getline failed\n");
212 return -1;
213 }
214
215 token = strsep(&line, " ");
216 if (token != NULL && !strcmp(token, "GNU")) {
217 // version is last part of first line of objdump --version output.
218 while ((token = strsep(&line, " ")))
219 version = token;
220
221 // Convert version into a format we can compare with
222 token = strsep(&version, ".");
223 version_num = atoi(token);
224 if (version_num)
225 version_num *= 10000;
226
227 token = strsep(&version, ".");
228 version_tmp = atoi(token);
229 if (token)
230 version_num += version_tmp * 100;
231
232 token = strsep(&version, ".");
233 version_tmp = atoi(token);
234 if (token)
235 version_num += version_tmp;
236 }
237
238 return version_num;
239}
240
b55ae0a9
AH
241static int read_via_objdump(const char *filename, u64 addr, void *buf,
242 size_t len)
243{
0f9ad973
CJ
244 u64 stop_address = addr + len;
245 struct utsname uname_buf;
b55ae0a9
AH
246 char cmd[PATH_MAX * 2];
247 const char *fmt;
248 FILE *f;
249 int ret;
250
0f9ad973
CJ
251 ret = uname(&uname_buf);
252 if (ret) {
253 pr_debug("uname failed\n");
254 return -1;
255 }
256
257 if (!strncmp(uname_buf.machine, "riscv", 5)) {
258 int version = objdump_version();
259
260 /* Default to this workaround if version parsing fails */
261 if (version < 0 || version > 24100) {
262 /*
263 * Starting at riscv objdump version 2.41, dumping in
264 * the middle of an instruction is not supported. riscv
265 * instructions are aligned along 2-byte intervals and
266 * can be either 2-bytes or 4-bytes. This makes it
267 * possible that the stop-address lands in the middle of
268 * a 4-byte instruction. Increase the stop_address by
269 * two to ensure an instruction is not cut in half, but
270 * leave the len as-is so only the expected number of
271 * bytes are collected.
272 */
273 stop_address += 2;
274 }
275 }
276
06f679c1 277 fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
0f9ad973 278 ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path, addr, stop_address,
b55ae0a9
AH
279 filename);
280 if (ret <= 0 || (size_t)ret >= sizeof(cmd))
281 return -1;
282
283 pr_debug("Objdump command is: %s\n", cmd);
284
7a77bc2c
AH
285 /* Ignore objdump errors */
286 strcat(cmd, " 2>/dev/null");
287
b55ae0a9
AH
288 f = popen(cmd, "r");
289 if (!f) {
290 pr_debug("popen failed\n");
291 return -1;
292 }
293
729a7ed1 294 ret = read_objdump_output(f, buf, &len, addr);
b55ae0a9 295 if (len) {
b2d0dbf0 296 pr_debug("objdump read too few bytes: %zd\n", len);
b55ae0a9
AH
297 if (!ret)
298 ret = len;
299 }
300
301 pclose(f);
302
303 return ret;
304}
305
fd405cf6
JS
306static void dump_buf(unsigned char *buf, size_t len)
307{
308 size_t i;
309
310 for (i = 0; i < len; i++) {
311 pr_debug("0x%02x ", buf[i]);
312 if (i % 16 == 15)
313 pr_debug("\n");
314 }
315 pr_debug("\n");
316}
317
b55ae0a9 318static int read_object_code(u64 addr, size_t len, u8 cpumode,
29f9e521 319 struct thread *thread, struct state *state)
b55ae0a9
AH
320{
321 struct addr_location al;
0f892fd1
JC
322 unsigned char buf1[BUFSZ] = {0};
323 unsigned char buf2[BUFSZ] = {0};
b55ae0a9
AH
324 size_t ret_len;
325 u64 objdump_addr;
94df1040
NK
326 const char *objdump_name;
327 char decomp_name[KMOD_DECOMP_LEN];
bcd4287e 328 bool decomp = false;
9bb5e1f6 329 int ret, err = 0;
63df0e4b 330 struct dso *dso;
b55ae0a9
AH
331
332 pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
333
0dd5041c 334 addr_location__init(&al);
63df0e4b 335 if (!thread__find_map(thread, cpumode, addr, &al) || !map__dso(al.map)) {
9a805d86
RB
336 if (cpumode == PERF_RECORD_MISC_HYPERVISOR) {
337 pr_debug("Hypervisor address can not be resolved - skipping\n");
9bb5e1f6 338 goto out;
9a805d86
RB
339 }
340
f07a2d32 341 pr_debug("thread__find_map failed\n");
9bb5e1f6
IR
342 err = -1;
343 goto out;
b55ae0a9 344 }
63df0e4b 345 dso = map__dso(al.map);
ee756ef7 346 pr_debug("File is: %s\n", dso__long_name(dso));
b55ae0a9 347
ee756ef7 348 if (dso__symtab_type(dso) == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(dso)) {
b55ae0a9 349 pr_debug("Unexpected kernel address - skipping\n");
9bb5e1f6 350 goto out;
b55ae0a9
AH
351 }
352
353 pr_debug("On file address is: %#"PRIx64"\n", al.addr);
354
355 if (len > BUFSZ)
356 len = BUFSZ;
357
358 /* Do not go off the map */
e5116f46
IR
359 if (addr + len > map__end(al.map))
360 len = map__end(al.map) - addr;
b55ae0a9 361
8f5b62a1
AR
362 /*
363 * Some architectures (ex: powerpc) have stubs (trampolines) in kernel
364 * modules to manage long jumps. Check if the ip offset falls in stubs
365 * sections for kernel modules. And skip module address after text end
366 */
ee756ef7 367 if (dso__is_kmod(dso) && al.addr > dso__text_end(dso)) {
8f5b62a1
AR
368 pr_debug("skipping the module address %#"PRIx64" after text end\n", al.addr);
369 goto out;
370 }
371
b55ae0a9 372 /* Read the object code using perf */
ee84a303 373 ret_len = dso__data_read_offset(dso, maps__machine(thread__maps(thread)),
29f9e521 374 al.addr, buf1, len);
b55ae0a9
AH
375 if (ret_len != len) {
376 pr_debug("dso__data_read_offset failed\n");
9bb5e1f6
IR
377 err = -1;
378 goto out;
b55ae0a9
AH
379 }
380
381 /*
382 * Converting addresses for use by objdump requires more information.
383 * map__load() does that. See map__rip_2objdump() for details.
384 */
9bb5e1f6
IR
385 if (map__load(al.map)) {
386 err = -1;
387 goto out;
388 }
b55ae0a9 389
7a77bc2c 390 /* objdump struggles with kcore - try each map only once */
63df0e4b 391 if (dso__is_kcore(dso)) {
7a77bc2c
AH
392 size_t d;
393
394 for (d = 0; d < state->done_cnt; d++) {
e5116f46 395 if (state->done[d] == map__start(al.map)) {
7a77bc2c
AH
396 pr_debug("kcore map tested already");
397 pr_debug(" - skipping\n");
9bb5e1f6 398 goto out;
7a77bc2c
AH
399 }
400 }
401 if (state->done_cnt >= ARRAY_SIZE(state->done)) {
402 pr_debug("Too many kcore maps - skipping\n");
9bb5e1f6 403 goto out;
7a77bc2c 404 }
e5116f46 405 state->done[state->done_cnt++] = map__start(al.map);
7a77bc2c
AH
406 }
407
ee756ef7 408 objdump_name = dso__long_name(dso);
63df0e4b
IR
409 if (dso__needs_decompress(dso)) {
410 if (dso__decompress_kmodule_path(dso, objdump_name,
94df1040
NK
411 decomp_name,
412 sizeof(decomp_name)) < 0) {
413 pr_debug("decompression failed\n");
9bb5e1f6
IR
414 err = -1;
415 goto out;
94df1040
NK
416 }
417
bcd4287e 418 decomp = true;
94df1040
NK
419 objdump_name = decomp_name;
420 }
421
b55ae0a9
AH
422 /* Read the object code using objdump */
423 objdump_addr = map__rip_2objdump(al.map, al.addr);
94df1040
NK
424 ret = read_via_objdump(objdump_name, objdump_addr, buf2, len);
425
bcd4287e 426 if (decomp)
94df1040
NK
427 unlink(objdump_name);
428
b55ae0a9
AH
429 if (ret > 0) {
430 /*
431 * The kernel maps are inaccurate - assume objdump is right in
432 * that case.
433 */
434 if (cpumode == PERF_RECORD_MISC_KERNEL ||
435 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) {
436 len -= ret;
7a77bc2c 437 if (len) {
b55ae0a9 438 pr_debug("Reducing len to %zu\n", len);
63df0e4b 439 } else if (dso__is_kcore(dso)) {
7a77bc2c
AH
440 /*
441 * objdump cannot handle very large segments
442 * that may be found in kcore.
443 */
444 pr_debug("objdump failed for kcore");
445 pr_debug(" - skipping\n");
7a77bc2c 446 } else {
9bb5e1f6 447 err = -1;
7a77bc2c 448 }
9bb5e1f6 449 goto out;
b55ae0a9
AH
450 }
451 }
452 if (ret < 0) {
453 pr_debug("read_via_objdump failed\n");
9bb5e1f6
IR
454 err = -1;
455 goto out;
b55ae0a9
AH
456 }
457
458 /* The results should be identical */
459 if (memcmp(buf1, buf2, len)) {
460 pr_debug("Bytes read differ from those read by objdump\n");
fd405cf6
JS
461 pr_debug("buf1 (dso):\n");
462 dump_buf(buf1, len);
463 pr_debug("buf2 (objdump):\n");
464 dump_buf(buf2, len);
9bb5e1f6
IR
465 err = -1;
466 goto out;
b55ae0a9
AH
467 }
468 pr_debug("Bytes read match those read by objdump\n");
9bb5e1f6 469out:
0dd5041c 470 addr_location__exit(&al);
9bb5e1f6 471 return err;
b55ae0a9
AH
472}
473
474static int process_sample_event(struct machine *machine,
63503dba 475 struct evlist *evlist,
7a77bc2c 476 union perf_event *event, struct state *state)
b55ae0a9
AH
477{
478 struct perf_sample sample;
479 struct thread *thread;
b91fc39f 480 int ret;
b55ae0a9 481
dc6d2bc2
IR
482 perf_sample__init(&sample, /*all=*/false);
483 ret = evlist__parse_sample(evlist, event, &sample);
484 if (ret) {
2a6599cd 485 pr_debug("evlist__parse_sample failed\n");
dc6d2bc2
IR
486 ret = -1;
487 goto out;
b55ae0a9
AH
488 }
489
13ce34df 490 thread = machine__findnew_thread(machine, sample.pid, sample.tid);
b55ae0a9
AH
491 if (!thread) {
492 pr_debug("machine__findnew_thread failed\n");
dc6d2bc2
IR
493 ret = -1;
494 goto out;
b55ae0a9
AH
495 }
496
473398a2 497 ret = read_object_code(sample.ip, READLEN, sample.cpumode, thread, state);
b91fc39f 498 thread__put(thread);
dc6d2bc2
IR
499out:
500 perf_sample__exit(&sample);
b91fc39f 501 return ret;
b55ae0a9
AH
502}
503
63503dba 504static int process_event(struct machine *machine, struct evlist *evlist,
7a77bc2c 505 union perf_event *event, struct state *state)
b55ae0a9
AH
506{
507 if (event->header.type == PERF_RECORD_SAMPLE)
7a77bc2c 508 return process_sample_event(machine, evlist, event, state);
b55ae0a9 509
48095b72
AH
510 if (event->header.type == PERF_RECORD_THROTTLE ||
511 event->header.type == PERF_RECORD_UNTHROTTLE)
512 return 0;
513
514 if (event->header.type < PERF_RECORD_MAX) {
515 int ret;
516
517 ret = machine__process_event(machine, event, NULL);
518 if (ret < 0)
519 pr_debug("machine__process_event failed, event type %u\n",
520 event->header.type);
521 return ret;
522 }
b55ae0a9
AH
523
524 return 0;
525}
526
63503dba 527static int process_events(struct machine *machine, struct evlist *evlist,
7a77bc2c 528 struct state *state)
b55ae0a9
AH
529{
530 union perf_event *event;
a5830532 531 struct mmap *md;
b55ae0a9
AH
532 int i, ret;
533
c976ee11 534 for (i = 0; i < evlist->core.nr_mmaps; i++) {
00fc2460 535 md = &evlist->mmap[i];
7c4d4182 536 if (perf_mmap__read_init(&md->core) < 0)
00fc2460
KL
537 continue;
538
151ed5d7 539 while ((event = perf_mmap__read_event(&md->core)) != NULL) {
7a77bc2c 540 ret = process_event(machine, evlist, event, state);
7728fa0c 541 perf_mmap__consume(&md->core);
b55ae0a9
AH
542 if (ret < 0)
543 return ret;
544 }
32fdc2ca 545 perf_mmap__read_done(&md->core);
b55ae0a9
AH
546 }
547 return 0;
548}
549
550static int comp(const void *a, const void *b)
551{
552 return *(int *)a - *(int *)b;
553}
554
555static void do_sort_something(void)
556{
309b5185 557 int buf[40960], i;
b55ae0a9 558
309b5185
DA
559 for (i = 0; i < (int)ARRAY_SIZE(buf); i++)
560 buf[i] = ARRAY_SIZE(buf) - i - 1;
b55ae0a9 561
309b5185 562 qsort(buf, ARRAY_SIZE(buf), sizeof(int), comp);
b55ae0a9 563
309b5185 564 for (i = 0; i < (int)ARRAY_SIZE(buf); i++) {
b55ae0a9
AH
565 if (buf[i] != i) {
566 pr_debug("qsort failed\n");
567 break;
568 }
569 }
570}
571
572static void sort_something(void)
573{
574 int i;
575
576 for (i = 0; i < 10; i++)
577 do_sort_something();
578}
579
580static void syscall_something(void)
581{
582 int pipefd[2];
583 int i;
584
585 for (i = 0; i < 1000; i++) {
586 if (pipe(pipefd) < 0) {
587 pr_debug("pipe failed\n");
588 break;
589 }
590 close(pipefd[1]);
591 close(pipefd[0]);
592 }
593}
594
595static void fs_something(void)
596{
597 const char *test_file_name = "temp-perf-code-reading-test-file--";
598 FILE *f;
599 int i;
600
601 for (i = 0; i < 1000; i++) {
602 f = fopen(test_file_name, "w+");
603 if (f) {
604 fclose(f);
605 unlink(test_file_name);
606 }
607 }
608}
609
610static void do_something(void)
611{
612 fs_something();
613
614 sort_something();
615
616 syscall_something();
617}
618
619enum {
620 TEST_CODE_READING_OK,
621 TEST_CODE_READING_NO_VMLINUX,
7a77bc2c 622 TEST_CODE_READING_NO_KCORE,
b55ae0a9 623 TEST_CODE_READING_NO_ACCESS,
7a77bc2c 624 TEST_CODE_READING_NO_KERNEL_OBJ,
b55ae0a9
AH
625};
626
7a77bc2c 627static int do_test_code_reading(bool try_kcore)
b55ae0a9 628{
b55ae0a9
AH
629 struct machine *machine;
630 struct thread *thread;
b4006796 631 struct record_opts opts = {
b55ae0a9
AH
632 .mmap_pages = UINT_MAX,
633 .user_freq = UINT_MAX,
634 .user_interval = ULLONG_MAX,
5243ba76 635 .freq = 500,
b55ae0a9
AH
636 .target = {
637 .uses_mmap = true,
638 },
639 };
7a77bc2c
AH
640 struct state state = {
641 .done_cnt = 0,
642 };
9749b90e 643 struct perf_thread_map *threads = NULL;
f854839b 644 struct perf_cpu_map *cpus = NULL;
63503dba 645 struct evlist *evlist = NULL;
32dcd021 646 struct evsel *evsel = NULL;
b55ae0a9
AH
647 int err = -1, ret;
648 pid_t pid;
649 struct map *map;
89d5c48c 650 bool have_vmlinux, have_kcore;
63df0e4b 651 struct dso *dso;
89d5c48c
NK
652 const char *events[] = { "cycles", "cycles:u", "cpu-clock", "cpu-clock:u", NULL };
653 int evidx = 0;
b55ae0a9
AH
654
655 pid = getpid();
656
0fd4008e 657 machine = machine__new_host();
f6c66d73 658 machine->env = &perf_env;
b55ae0a9
AH
659
660 ret = machine__create_kernel_maps(machine);
661 if (ret < 0) {
662 pr_debug("machine__create_kernel_maps failed\n");
663 goto out_err;
664 }
665
7a77bc2c
AH
666 /* Force the use of kallsyms instead of vmlinux to try kcore */
667 if (try_kcore)
668 symbol_conf.kallsyms_name = "/proc/kallsyms";
669
b55ae0a9 670 /* Load kernel map */
a5e813c6 671 map = machine__kernel_map(machine);
be39db9f 672 ret = map__load(map);
b55ae0a9
AH
673 if (ret < 0) {
674 pr_debug("map__load failed\n");
675 goto out_err;
676 }
63df0e4b
IR
677 dso = map__dso(map);
678 have_vmlinux = dso__is_vmlinux(dso);
679 have_kcore = dso__is_kcore(dso);
7a77bc2c
AH
680
681 /* 2nd time through we just try kcore */
682 if (try_kcore && !have_kcore)
683 return TEST_CODE_READING_NO_KCORE;
684
685 /* No point getting kernel events if there is no kernel object */
686 if (!have_vmlinux && !have_kcore)
89d5c48c 687 evidx++;
b55ae0a9
AH
688
689 threads = thread_map__new_by_tid(pid);
690 if (!threads) {
691 pr_debug("thread_map__new_by_tid failed\n");
692 goto out_err;
693 }
694
695 ret = perf_event__synthesize_thread_map(NULL, threads,
84111b9c
NK
696 perf_event__process, machine,
697 true, false);
b55ae0a9
AH
698 if (ret < 0) {
699 pr_debug("perf_event__synthesize_thread_map failed\n");
700 goto out_err;
701 }
702
314add6b 703 thread = machine__findnew_thread(machine, pid, pid);
b55ae0a9
AH
704 if (!thread) {
705 pr_debug("machine__findnew_thread failed\n");
b91fc39f 706 goto out_put;
b55ae0a9
AH
707 }
708
effe957c 709 cpus = perf_cpu_map__new_online_cpus();
b55ae0a9 710 if (!cpus) {
9c3516d1 711 pr_debug("perf_cpu_map__new failed\n");
b91fc39f 712 goto out_put;
b55ae0a9
AH
713 }
714
89d5c48c 715 while (events[evidx]) {
b55ae0a9
AH
716 const char *str;
717
0f98b11c 718 evlist = evlist__new();
b55ae0a9 719 if (!evlist) {
606e2c29 720 pr_debug("evlist__new failed\n");
b91fc39f 721 goto out_put;
b55ae0a9
AH
722 }
723
453fa030 724 perf_evlist__set_maps(&evlist->core, cpus, threads);
b55ae0a9 725
89d5c48c 726 str = events[evidx];
b55ae0a9 727 pr_debug("Parsing event '%s'\n", str);
806731a9 728 ret = parse_event(evlist, str);
b55ae0a9
AH
729 if (ret < 0) {
730 pr_debug("parse_events failed\n");
b91fc39f 731 goto out_put;
b55ae0a9
AH
732 }
733
78e1bc25 734 evlist__config(evlist, &opts, NULL);
b55ae0a9 735
2dade41a
JC
736 evlist__for_each_entry(evlist, evsel) {
737 evsel->core.attr.comm = 1;
738 evsel->core.attr.disabled = 1;
739 evsel->core.attr.enable_on_exec = 0;
740 }
b55ae0a9 741
474ddc4c 742 ret = evlist__open(evlist);
b55ae0a9 743 if (ret < 0) {
89d5c48c 744 evidx++;
6880bbf9 745
89d5c48c 746 if (events[evidx] == NULL && verbose > 0) {
6880bbf9 747 char errbuf[512];
d1f249ec 748 evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
6880bbf9
ACM
749 pr_debug("perf_evlist__open() failed!\n%s\n", errbuf);
750 }
751
89d5c48c
NK
752 /*
753 * Both cpus and threads are now owned by evlist
754 * and will be freed by following perf_evlist__set_maps
755 * call. Getting reference to keep them alive.
756 */
757 perf_cpu_map__get(cpus);
758 perf_thread_map__get(threads);
759 perf_evlist__set_maps(&evlist->core, NULL, NULL);
760 evlist__delete(evlist);
761 evlist = NULL;
762 continue;
b55ae0a9
AH
763 }
764 break;
765 }
766
89d5c48c
NK
767 if (events[evidx] == NULL)
768 goto out_put;
769
9521b5f2 770 ret = evlist__mmap(evlist, UINT_MAX);
b55ae0a9 771 if (ret < 0) {
9521b5f2 772 pr_debug("evlist__mmap failed\n");
b91fc39f 773 goto out_put;
b55ae0a9
AH
774 }
775
1c87f165 776 evlist__enable(evlist);
b55ae0a9
AH
777
778 do_something();
779
e74676de 780 evlist__disable(evlist);
b55ae0a9 781
7a77bc2c 782 ret = process_events(machine, evlist, &state);
b55ae0a9 783 if (ret < 0)
b91fc39f 784 goto out_put;
b55ae0a9 785
7a77bc2c
AH
786 if (!have_vmlinux && !have_kcore && !try_kcore)
787 err = TEST_CODE_READING_NO_KERNEL_OBJ;
788 else if (!have_vmlinux && !try_kcore)
b55ae0a9 789 err = TEST_CODE_READING_NO_VMLINUX;
89d5c48c 790 else if (strstr(events[evidx], ":u"))
b55ae0a9
AH
791 err = TEST_CODE_READING_NO_ACCESS;
792 else
793 err = TEST_CODE_READING_OK;
b91fc39f
ACM
794out_put:
795 thread__put(thread);
b55ae0a9 796out_err:
e06c3ca4
NK
797 evlist__delete(evlist);
798 perf_cpu_map__put(cpus);
799 perf_thread_map__put(threads);
0fd4008e 800 machine__delete(machine);
b55ae0a9
AH
801
802 return err;
803}
804
33f44bfd 805static int test__code_reading(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
b55ae0a9
AH
806{
807 int ret;
808
7a77bc2c
AH
809 ret = do_test_code_reading(false);
810 if (!ret)
811 ret = do_test_code_reading(true);
b55ae0a9
AH
812
813 switch (ret) {
814 case TEST_CODE_READING_OK:
815 return 0;
816 case TEST_CODE_READING_NO_VMLINUX:
597bdeb4 817 pr_debug("no vmlinux\n");
b55ae0a9 818 return 0;
7a77bc2c 819 case TEST_CODE_READING_NO_KCORE:
597bdeb4 820 pr_debug("no kcore\n");
7a77bc2c 821 return 0;
b55ae0a9 822 case TEST_CODE_READING_NO_ACCESS:
597bdeb4 823 pr_debug("no access\n");
b55ae0a9 824 return 0;
7a77bc2c 825 case TEST_CODE_READING_NO_KERNEL_OBJ:
597bdeb4 826 pr_debug("no kernel obj\n");
7a77bc2c 827 return 0;
b55ae0a9
AH
828 default:
829 return -1;
830 };
831}
d68f0365
IR
832
833DEFINE_SUITE("Object code reading", code_reading);