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