xref: /openbmc/linux/tools/perf/tests/dwarf-unwind.c (revision 84d517f3)
1 #include <linux/compiler.h>
2 #include <linux/types.h>
3 #include <unistd.h>
4 #include "tests.h"
5 #include "debug.h"
6 #include "machine.h"
7 #include "event.h"
8 #include "unwind.h"
9 #include "perf_regs.h"
10 #include "map.h"
11 #include "thread.h"
12 
13 static int mmap_handler(struct perf_tool *tool __maybe_unused,
14 			union perf_event *event,
15 			struct perf_sample *sample __maybe_unused,
16 			struct machine *machine)
17 {
18 	return machine__process_mmap_event(machine, event, NULL);
19 }
20 
21 static int init_live_machine(struct machine *machine)
22 {
23 	union perf_event event;
24 	pid_t pid = getpid();
25 
26 	return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
27 						  mmap_handler, machine, true);
28 }
29 
30 #define MAX_STACK 6
31 
32 static int unwind_entry(struct unwind_entry *entry, void *arg)
33 {
34 	unsigned long *cnt = (unsigned long *) arg;
35 	char *symbol = entry->sym ? entry->sym->name : NULL;
36 	static const char *funcs[MAX_STACK] = {
37 		"test__arch_unwind_sample",
38 		"unwind_thread",
39 		"krava_3",
40 		"krava_2",
41 		"krava_1",
42 		"test__dwarf_unwind"
43 	};
44 
45 	if (*cnt >= MAX_STACK) {
46 		pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
47 		return -1;
48 	}
49 
50 	if (!symbol) {
51 		pr_debug("failed: got unresolved address 0x%" PRIx64 "\n",
52 			 entry->ip);
53 		return -1;
54 	}
55 
56 	pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip);
57 	return strcmp((const char *) symbol, funcs[(*cnt)++]);
58 }
59 
60 __attribute__ ((noinline))
61 static int unwind_thread(struct thread *thread, struct machine *machine)
62 {
63 	struct perf_sample sample;
64 	unsigned long cnt = 0;
65 	int err = -1;
66 
67 	memset(&sample, 0, sizeof(sample));
68 
69 	if (test__arch_unwind_sample(&sample, thread)) {
70 		pr_debug("failed to get unwind sample\n");
71 		goto out;
72 	}
73 
74 	err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
75 				  &sample, MAX_STACK);
76 	if (err)
77 		pr_debug("unwind failed\n");
78 	else if (cnt != MAX_STACK) {
79 		pr_debug("got wrong number of stack entries %lu != %d\n",
80 			 cnt, MAX_STACK);
81 		err = -1;
82 	}
83 
84  out:
85 	free(sample.user_stack.data);
86 	free(sample.user_regs.regs);
87 	return err;
88 }
89 
90 __attribute__ ((noinline))
91 static int krava_3(struct thread *thread, struct machine *machine)
92 {
93 	return unwind_thread(thread, machine);
94 }
95 
96 __attribute__ ((noinline))
97 static int krava_2(struct thread *thread, struct machine *machine)
98 {
99 	return krava_3(thread, machine);
100 }
101 
102 __attribute__ ((noinline))
103 static int krava_1(struct thread *thread, struct machine *machine)
104 {
105 	return krava_2(thread, machine);
106 }
107 
108 int test__dwarf_unwind(void)
109 {
110 	struct machines machines;
111 	struct machine *machine;
112 	struct thread *thread;
113 	int err = -1;
114 
115 	machines__init(&machines);
116 
117 	machine = machines__find(&machines, HOST_KERNEL_ID);
118 	if (!machine) {
119 		pr_err("Could not get machine\n");
120 		return -1;
121 	}
122 
123 	if (init_live_machine(machine)) {
124 		pr_err("Could not init machine\n");
125 		goto out;
126 	}
127 
128 	if (verbose > 1)
129 		machine__fprintf(machine, stderr);
130 
131 	thread = machine__find_thread(machine, getpid(), getpid());
132 	if (!thread) {
133 		pr_err("Could not get thread\n");
134 		goto out;
135 	}
136 
137 	err = krava_1(thread, machine);
138 
139  out:
140 	machine__delete_threads(machine);
141 	machine__exit(machine);
142 	machines__exit(&machines);
143 	return err;
144 }
145