root/tools/perf/tests/dwarf-unwind.c

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

DEFINITIONS

This source file includes following definitions.
  1. mmap_handler
  2. init_live_machine
  3. unwind_entry
  4. test_dwarf_unwind__thread
  5. test_dwarf_unwind__compare
  6. test_dwarf_unwind__krava_3
  7. test_dwarf_unwind__krava_2
  8. test_dwarf_unwind__krava_1
  9. test__dwarf_unwind

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/compiler.h>
   3 #include <linux/types.h>
   4 #include <linux/zalloc.h>
   5 #include <inttypes.h>
   6 #include <limits.h>
   7 #include <unistd.h>
   8 #include "tests.h"
   9 #include "debug.h"
  10 #include "machine.h"
  11 #include "event.h"
  12 #include "../util/unwind.h"
  13 #include "perf_regs.h"
  14 #include "map.h"
  15 #include "symbol.h"
  16 #include "thread.h"
  17 #include "callchain.h"
  18 #include "util/synthetic-events.h"
  19 
  20 #if defined (__x86_64__) || defined (__i386__) || defined (__powerpc__)
  21 #include "arch-tests.h"
  22 #endif
  23 
  24 /* For bsearch. We try to unwind functions in shared object. */
  25 #include <stdlib.h>
  26 
  27 static int mmap_handler(struct perf_tool *tool __maybe_unused,
  28                         union perf_event *event,
  29                         struct perf_sample *sample,
  30                         struct machine *machine)
  31 {
  32         return machine__process_mmap2_event(machine, event, sample);
  33 }
  34 
  35 static int init_live_machine(struct machine *machine)
  36 {
  37         union perf_event event;
  38         pid_t pid = getpid();
  39 
  40         return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
  41                                                   mmap_handler, machine, true);
  42 }
  43 
  44 /*
  45  * We need to keep these functions global, despite the
  46  * fact that they are used only locally in this object,
  47  * in order to keep them around even if the binary is
  48  * stripped. If they are gone, the unwind check for
  49  * symbol fails.
  50  */
  51 int test_dwarf_unwind__thread(struct thread *thread);
  52 int test_dwarf_unwind__compare(void *p1, void *p2);
  53 int test_dwarf_unwind__krava_3(struct thread *thread);
  54 int test_dwarf_unwind__krava_2(struct thread *thread);
  55 int test_dwarf_unwind__krava_1(struct thread *thread);
  56 
  57 #define MAX_STACK 8
  58 
  59 static int unwind_entry(struct unwind_entry *entry, void *arg)
  60 {
  61         unsigned long *cnt = (unsigned long *) arg;
  62         char *symbol = entry->sym ? entry->sym->name : NULL;
  63         static const char *funcs[MAX_STACK] = {
  64                 "test__arch_unwind_sample",
  65                 "test_dwarf_unwind__thread",
  66                 "test_dwarf_unwind__compare",
  67                 "bsearch",
  68                 "test_dwarf_unwind__krava_3",
  69                 "test_dwarf_unwind__krava_2",
  70                 "test_dwarf_unwind__krava_1",
  71                 "test__dwarf_unwind"
  72         };
  73         /*
  74          * The funcs[MAX_STACK] array index, based on the
  75          * callchain order setup.
  76          */
  77         int idx = callchain_param.order == ORDER_CALLER ?
  78                   MAX_STACK - *cnt - 1 : *cnt;
  79 
  80         if (*cnt >= MAX_STACK) {
  81                 pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
  82                 return -1;
  83         }
  84 
  85         if (!symbol) {
  86                 pr_debug("failed: got unresolved address 0x%" PRIx64 "\n",
  87                          entry->ip);
  88                 return -1;
  89         }
  90 
  91         (*cnt)++;
  92         pr_debug("got: %s 0x%" PRIx64 ", expecting %s\n",
  93                  symbol, entry->ip, funcs[idx]);
  94         return strcmp((const char *) symbol, funcs[idx]);
  95 }
  96 
  97 noinline int test_dwarf_unwind__thread(struct thread *thread)
  98 {
  99         struct perf_sample sample;
 100         unsigned long cnt = 0;
 101         int err = -1;
 102 
 103         memset(&sample, 0, sizeof(sample));
 104 
 105         if (test__arch_unwind_sample(&sample, thread)) {
 106                 pr_debug("failed to get unwind sample\n");
 107                 goto out;
 108         }
 109 
 110         err = unwind__get_entries(unwind_entry, &cnt, thread,
 111                                   &sample, MAX_STACK);
 112         if (err)
 113                 pr_debug("unwind failed\n");
 114         else if (cnt != MAX_STACK) {
 115                 pr_debug("got wrong number of stack entries %lu != %d\n",
 116                          cnt, MAX_STACK);
 117                 err = -1;
 118         }
 119 
 120  out:
 121         zfree(&sample.user_stack.data);
 122         zfree(&sample.user_regs.regs);
 123         return err;
 124 }
 125 
 126 static int global_unwind_retval = -INT_MAX;
 127 
 128 noinline int test_dwarf_unwind__compare(void *p1, void *p2)
 129 {
 130         /* Any possible value should be 'thread' */
 131         struct thread *thread = *(struct thread **)p1;
 132 
 133         if (global_unwind_retval == -INT_MAX) {
 134                 /* Call unwinder twice for both callchain orders. */
 135                 callchain_param.order = ORDER_CALLER;
 136 
 137                 global_unwind_retval = test_dwarf_unwind__thread(thread);
 138                 if (!global_unwind_retval) {
 139                         callchain_param.order = ORDER_CALLEE;
 140                         global_unwind_retval = test_dwarf_unwind__thread(thread);
 141                 }
 142         }
 143 
 144         return p1 - p2;
 145 }
 146 
 147 noinline int test_dwarf_unwind__krava_3(struct thread *thread)
 148 {
 149         struct thread *array[2] = {thread, thread};
 150         void *fp = &bsearch;
 151         /*
 152          * make _bsearch a volatile function pointer to
 153          * prevent potential optimization, which may expand
 154          * bsearch and call compare directly from this function,
 155          * instead of libc shared object.
 156          */
 157         void *(*volatile _bsearch)(void *, void *, size_t,
 158                         size_t, int (*)(void *, void *));
 159 
 160         _bsearch = fp;
 161         _bsearch(array, &thread, 2, sizeof(struct thread **),
 162                  test_dwarf_unwind__compare);
 163         return global_unwind_retval;
 164 }
 165 
 166 noinline int test_dwarf_unwind__krava_2(struct thread *thread)
 167 {
 168         return test_dwarf_unwind__krava_3(thread);
 169 }
 170 
 171 noinline int test_dwarf_unwind__krava_1(struct thread *thread)
 172 {
 173         return test_dwarf_unwind__krava_2(thread);
 174 }
 175 
 176 int test__dwarf_unwind(struct test *test __maybe_unused, int subtest __maybe_unused)
 177 {
 178         struct machine *machine;
 179         struct thread *thread;
 180         int err = -1;
 181 
 182         machine = machine__new_host();
 183         if (!machine) {
 184                 pr_err("Could not get machine\n");
 185                 return -1;
 186         }
 187 
 188         if (machine__create_kernel_maps(machine)) {
 189                 pr_err("Failed to create kernel maps\n");
 190                 return -1;
 191         }
 192 
 193         callchain_param.record_mode = CALLCHAIN_DWARF;
 194         dwarf_callchain_users = true;
 195 
 196         if (init_live_machine(machine)) {
 197                 pr_err("Could not init machine\n");
 198                 goto out;
 199         }
 200 
 201         if (verbose > 1)
 202                 machine__fprintf(machine, stderr);
 203 
 204         thread = machine__find_thread(machine, getpid(), getpid());
 205         if (!thread) {
 206                 pr_err("Could not get thread\n");
 207                 goto out;
 208         }
 209 
 210         err = test_dwarf_unwind__krava_1(thread);
 211         thread__put(thread);
 212 
 213  out:
 214         machine__delete_threads(machine);
 215         machine__delete(machine);
 216         return err;
 217 }

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