xref: /linux/tools/perf/tests/dwarf-unwind.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2aa16b81fSJiri Olsa #include <linux/compiler.h>
3d944c4eeSBorislav Petkov #include <linux/types.h>
4d8f9da24SArnaldo Carvalho de Melo #include <linux/zalloc.h>
5fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
64a3cec84SArnaldo Carvalho de Melo #include <limits.h>
7aa16b81fSJiri Olsa #include <unistd.h>
8aa16b81fSJiri Olsa #include "tests.h"
9aa16b81fSJiri Olsa #include "debug.h"
10aa16b81fSJiri Olsa #include "machine.h"
11aa16b81fSJiri Olsa #include "event.h"
12df90cc41SMilian Wolff #include "../util/unwind.h"
13aa16b81fSJiri Olsa #include "perf_regs.h"
14aa16b81fSJiri Olsa #include "map.h"
15daecf9e0SArnaldo Carvalho de Melo #include "symbol.h"
16aa16b81fSJiri Olsa #include "thread.h"
170cdccac6SNamhyung Kim #include "callchain.h"
18ea49e01cSArnaldo Carvalho de Melo #include "util/synthetic-events.h"
19aa16b81fSJiri Olsa 
20b93b0967SWang Nan /* For bsearch. We try to unwind functions in shared object. */
21b93b0967SWang Nan #include <stdlib.h>
22b93b0967SWang Nan 
235c34aea3SIan Rogers /*
245c34aea3SIan Rogers  * The test will assert frames are on the stack but tail call optimizations lose
255c34aea3SIan Rogers  * the frame of the caller. Clang can disable this optimization on a called
265c34aea3SIan Rogers  * function but GCC currently (11/2020) lacks this attribute. The barrier is
275c34aea3SIan Rogers  * used to inhibit tail calls in these cases.
285c34aea3SIan Rogers  */
295c34aea3SIan Rogers #ifdef __has_attribute
305c34aea3SIan Rogers #if __has_attribute(disable_tail_calls)
315c34aea3SIan Rogers #define NO_TAIL_CALL_ATTRIBUTE __attribute__((disable_tail_calls))
325c34aea3SIan Rogers #define NO_TAIL_CALL_BARRIER
335c34aea3SIan Rogers #endif
345c34aea3SIan Rogers #endif
355c34aea3SIan Rogers #ifndef NO_TAIL_CALL_ATTRIBUTE
365c34aea3SIan Rogers #define NO_TAIL_CALL_ATTRIBUTE
375c34aea3SIan Rogers #define NO_TAIL_CALL_BARRIER __asm__ __volatile__("" : : : "memory");
385c34aea3SIan Rogers #endif
395c34aea3SIan Rogers 
mmap_handler(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)40*30f29baeSIan Rogers static int mmap_handler(const struct perf_tool *tool __maybe_unused,
41aa16b81fSJiri Olsa 			union perf_event *event,
42eb9f0323SArnaldo Carvalho de Melo 			struct perf_sample *sample,
43aa16b81fSJiri Olsa 			struct machine *machine)
44aa16b81fSJiri Olsa {
45eb9f0323SArnaldo Carvalho de Melo 	return machine__process_mmap2_event(machine, event, sample);
46aa16b81fSJiri Olsa }
47aa16b81fSJiri Olsa 
init_live_machine(struct machine * machine)48aa16b81fSJiri Olsa static int init_live_machine(struct machine *machine)
49aa16b81fSJiri Olsa {
50aa16b81fSJiri Olsa 	union perf_event event;
51aa16b81fSJiri Olsa 	pid_t pid = getpid();
52aa16b81fSJiri Olsa 
530fb0d615SIan Rogers 	memset(&event, 0, sizeof(event));
54aa16b81fSJiri Olsa 	return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
553fcb10e4SMark Drayton 						  mmap_handler, machine, true);
56aa16b81fSJiri Olsa }
57aa16b81fSJiri Olsa 
58fdf7c49cSJiri Olsa /*
59fdf7c49cSJiri Olsa  * We need to keep these functions global, despite the
60fdf7c49cSJiri Olsa  * fact that they are used only locally in this object,
61fdf7c49cSJiri Olsa  * in order to keep them around even if the binary is
62fdf7c49cSJiri Olsa  * stripped. If they are gone, the unwind check for
63fdf7c49cSJiri Olsa  * symbol fails.
64fdf7c49cSJiri Olsa  */
65fdf7c49cSJiri Olsa int test_dwarf_unwind__thread(struct thread *thread);
66fdf7c49cSJiri Olsa int test_dwarf_unwind__compare(void *p1, void *p2);
67fdf7c49cSJiri Olsa int test_dwarf_unwind__krava_3(struct thread *thread);
68fdf7c49cSJiri Olsa int test_dwarf_unwind__krava_2(struct thread *thread);
69fdf7c49cSJiri Olsa int test_dwarf_unwind__krava_1(struct thread *thread);
70dfadf8b3SNaveen N. Rao int test__dwarf_unwind(struct test_suite *test, int subtest);
71fdf7c49cSJiri Olsa 
72b93b0967SWang Nan #define MAX_STACK 8
73aa16b81fSJiri Olsa 
unwind_entry(struct unwind_entry * entry,void * arg)74aa16b81fSJiri Olsa static int unwind_entry(struct unwind_entry *entry, void *arg)
75aa16b81fSJiri Olsa {
76aa16b81fSJiri Olsa 	unsigned long *cnt = (unsigned long *) arg;
77c1529738SArnaldo Carvalho de Melo 	char *symbol = entry->ms.sym ? entry->ms.sym->name : NULL;
78aa16b81fSJiri Olsa 	static const char *funcs[MAX_STACK] = {
79aa16b81fSJiri Olsa 		"test__arch_unwind_sample",
80fdf7c49cSJiri Olsa 		"test_dwarf_unwind__thread",
81fdf7c49cSJiri Olsa 		"test_dwarf_unwind__compare",
82b93b0967SWang Nan 		"bsearch",
83fdf7c49cSJiri Olsa 		"test_dwarf_unwind__krava_3",
84fdf7c49cSJiri Olsa 		"test_dwarf_unwind__krava_2",
85fdf7c49cSJiri Olsa 		"test_dwarf_unwind__krava_1",
86aa16b81fSJiri Olsa 		"test__dwarf_unwind"
87aa16b81fSJiri Olsa 	};
888dc0564dSJiri Olsa 	/*
898dc0564dSJiri Olsa 	 * The funcs[MAX_STACK] array index, based on the
908dc0564dSJiri Olsa 	 * callchain order setup.
918dc0564dSJiri Olsa 	 */
928dc0564dSJiri Olsa 	int idx = callchain_param.order == ORDER_CALLER ?
938dc0564dSJiri Olsa 		  MAX_STACK - *cnt - 1 : *cnt;
94aa16b81fSJiri Olsa 
95aa16b81fSJiri Olsa 	if (*cnt >= MAX_STACK) {
96aa16b81fSJiri Olsa 		pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
97aa16b81fSJiri Olsa 		return -1;
98aa16b81fSJiri Olsa 	}
99aa16b81fSJiri Olsa 
100aa16b81fSJiri Olsa 	if (!symbol) {
101aa16b81fSJiri Olsa 		pr_debug("failed: got unresolved address 0x%" PRIx64 "\n",
102aa16b81fSJiri Olsa 			 entry->ip);
103aa16b81fSJiri Olsa 		return -1;
104aa16b81fSJiri Olsa 	}
105aa16b81fSJiri Olsa 
1068dc0564dSJiri Olsa 	(*cnt)++;
1078dc0564dSJiri Olsa 	pr_debug("got: %s 0x%" PRIx64 ", expecting %s\n",
1088dc0564dSJiri Olsa 		 symbol, entry->ip, funcs[idx]);
1098dc0564dSJiri Olsa 	return strcmp((const char *) symbol, funcs[idx]);
110aa16b81fSJiri Olsa }
111aa16b81fSJiri Olsa 
test_dwarf_unwind__thread(struct thread * thread)1125c34aea3SIan Rogers NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__thread(struct thread *thread)
113aa16b81fSJiri Olsa {
114aa16b81fSJiri Olsa 	struct perf_sample sample;
115aa16b81fSJiri Olsa 	unsigned long cnt = 0;
116aa16b81fSJiri Olsa 	int err = -1;
117aa16b81fSJiri Olsa 
118aa16b81fSJiri Olsa 	memset(&sample, 0, sizeof(sample));
119aa16b81fSJiri Olsa 
120aa16b81fSJiri Olsa 	if (test__arch_unwind_sample(&sample, thread)) {
121aa16b81fSJiri Olsa 		pr_debug("failed to get unwind sample\n");
122aa16b81fSJiri Olsa 		goto out;
123aa16b81fSJiri Olsa 	}
124aa16b81fSJiri Olsa 
125dd8c17a5SArnaldo Carvalho de Melo 	err = unwind__get_entries(unwind_entry, &cnt, thread,
126fa7095c5SJames Clark 				  &sample, MAX_STACK, false);
127aa16b81fSJiri Olsa 	if (err)
128aa16b81fSJiri Olsa 		pr_debug("unwind failed\n");
129aa16b81fSJiri Olsa 	else if (cnt != MAX_STACK) {
130aa16b81fSJiri Olsa 		pr_debug("got wrong number of stack entries %lu != %d\n",
131aa16b81fSJiri Olsa 			 cnt, MAX_STACK);
132aa16b81fSJiri Olsa 		err = -1;
133aa16b81fSJiri Olsa 	}
134aa16b81fSJiri Olsa 
135aa16b81fSJiri Olsa  out:
136d8f9da24SArnaldo Carvalho de Melo 	zfree(&sample.user_stack.data);
137d8f9da24SArnaldo Carvalho de Melo 	zfree(&sample.user_regs.regs);
138aa16b81fSJiri Olsa 	return err;
139aa16b81fSJiri Olsa }
140aa16b81fSJiri Olsa 
141b93b0967SWang Nan static int global_unwind_retval = -INT_MAX;
142b93b0967SWang Nan 
test_dwarf_unwind__compare(void * p1,void * p2)1435c34aea3SIan Rogers NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__compare(void *p1, void *p2)
144b93b0967SWang Nan {
145b93b0967SWang Nan 	/* Any possible value should be 'thread' */
146b93b0967SWang Nan 	struct thread *thread = *(struct thread **)p1;
147b93b0967SWang Nan 
1488dc0564dSJiri Olsa 	if (global_unwind_retval == -INT_MAX) {
1498dc0564dSJiri Olsa 		/* Call unwinder twice for both callchain orders. */
1508dc0564dSJiri Olsa 		callchain_param.order = ORDER_CALLER;
1518dc0564dSJiri Olsa 
152fdf7c49cSJiri Olsa 		global_unwind_retval = test_dwarf_unwind__thread(thread);
1538dc0564dSJiri Olsa 		if (!global_unwind_retval) {
1548dc0564dSJiri Olsa 			callchain_param.order = ORDER_CALLEE;
155fdf7c49cSJiri Olsa 			global_unwind_retval = test_dwarf_unwind__thread(thread);
1568dc0564dSJiri Olsa 		}
1578dc0564dSJiri Olsa 	}
158b93b0967SWang Nan 
159b93b0967SWang Nan 	return p1 - p2;
160b93b0967SWang Nan }
161b93b0967SWang Nan 
test_dwarf_unwind__krava_3(struct thread * thread)1625c34aea3SIan Rogers NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__krava_3(struct thread *thread)
163aa16b81fSJiri Olsa {
164b93b0967SWang Nan 	struct thread *array[2] = {thread, thread};
165b93b0967SWang Nan 	void *fp = &bsearch;
166b93b0967SWang Nan 	/*
167b93b0967SWang Nan 	 * make _bsearch a volatile function pointer to
168b93b0967SWang Nan 	 * prevent potential optimization, which may expand
169b93b0967SWang Nan 	 * bsearch and call compare directly from this function,
170b93b0967SWang Nan 	 * instead of libc shared object.
171b93b0967SWang Nan 	 */
172b93b0967SWang Nan 	void *(*volatile _bsearch)(void *, void *, size_t,
173b93b0967SWang Nan 			size_t, int (*)(void *, void *));
174b93b0967SWang Nan 
175b93b0967SWang Nan 	_bsearch = fp;
176fdf7c49cSJiri Olsa 	_bsearch(array, &thread, 2, sizeof(struct thread **),
177fdf7c49cSJiri Olsa 		 test_dwarf_unwind__compare);
178b93b0967SWang Nan 	return global_unwind_retval;
179aa16b81fSJiri Olsa }
180aa16b81fSJiri Olsa 
test_dwarf_unwind__krava_2(struct thread * thread)1815c34aea3SIan Rogers NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__krava_2(struct thread *thread)
182aa16b81fSJiri Olsa {
1835c34aea3SIan Rogers 	int ret;
1845c34aea3SIan Rogers 
1855c34aea3SIan Rogers 	ret =  test_dwarf_unwind__krava_3(thread);
1865c34aea3SIan Rogers 	NO_TAIL_CALL_BARRIER;
1875c34aea3SIan Rogers 	return ret;
188aa16b81fSJiri Olsa }
189aa16b81fSJiri Olsa 
test_dwarf_unwind__krava_1(struct thread * thread)1905c34aea3SIan Rogers NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__krava_1(struct thread *thread)
191aa16b81fSJiri Olsa {
1925c34aea3SIan Rogers 	int ret;
1935c34aea3SIan Rogers 
1945c34aea3SIan Rogers 	ret =  test_dwarf_unwind__krava_2(thread);
1955c34aea3SIan Rogers 	NO_TAIL_CALL_BARRIER;
1965c34aea3SIan Rogers 	return ret;
197aa16b81fSJiri Olsa }
198aa16b81fSJiri Olsa 
test__dwarf_unwind(struct test_suite * test __maybe_unused,int subtest __maybe_unused)199dfadf8b3SNaveen N. Rao noinline int test__dwarf_unwind(struct test_suite *test __maybe_unused,
20033f44bfdSIan Rogers 				int subtest __maybe_unused)
201aa16b81fSJiri Olsa {
202aa16b81fSJiri Olsa 	struct machine *machine;
203aa16b81fSJiri Olsa 	struct thread *thread;
204aa16b81fSJiri Olsa 	int err = -1;
205aa16b81fSJiri Olsa 
206bdaba8aeSJiri Olsa 	machine = machine__new_host();
207aa16b81fSJiri Olsa 	if (!machine) {
208aa16b81fSJiri Olsa 		pr_err("Could not get machine\n");
209aa16b81fSJiri Olsa 		return -1;
210aa16b81fSJiri Olsa 	}
211aa16b81fSJiri Olsa 
2129bdcede5SJiri Olsa 	if (machine__create_kernel_maps(machine)) {
2139bdcede5SJiri Olsa 		pr_err("Failed to create kernel maps\n");
2149bdcede5SJiri Olsa 		return -1;
2159bdcede5SJiri Olsa 	}
2169bdcede5SJiri Olsa 
2170cdccac6SNamhyung Kim 	callchain_param.record_mode = CALLCHAIN_DWARF;
218eabad8c6SArnaldo Carvalho de Melo 	dwarf_callchain_users = true;
2190cdccac6SNamhyung Kim 
220aa16b81fSJiri Olsa 	if (init_live_machine(machine)) {
221aa16b81fSJiri Olsa 		pr_err("Could not init machine\n");
222aa16b81fSJiri Olsa 		goto out;
223aa16b81fSJiri Olsa 	}
224aa16b81fSJiri Olsa 
225aa16b81fSJiri Olsa 	if (verbose > 1)
226aa16b81fSJiri Olsa 		machine__fprintf(machine, stderr);
227aa16b81fSJiri Olsa 
228d75e6097SJiri Olsa 	thread = machine__find_thread(machine, getpid(), getpid());
229aa16b81fSJiri Olsa 	if (!thread) {
230aa16b81fSJiri Olsa 		pr_err("Could not get thread\n");
231aa16b81fSJiri Olsa 		goto out;
232aa16b81fSJiri Olsa 	}
233aa16b81fSJiri Olsa 
234fdf7c49cSJiri Olsa 	err = test_dwarf_unwind__krava_1(thread);
235b91fc39fSArnaldo Carvalho de Melo 	thread__put(thread);
236aa16b81fSJiri Olsa 
237aa16b81fSJiri Olsa  out:
238bdaba8aeSJiri Olsa 	machine__delete(machine);
239aa16b81fSJiri Olsa 	return err;
240aa16b81fSJiri Olsa }
241df225205SIan Rogers 
242d68f0365SIan Rogers DEFINE_SUITE("Test dwarf unwind", dwarf_unwind);
243