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