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