Linux 6.9-rc1
[linux-2.6-microblaze.git] / tools / perf / util / unwind-libdw.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/compiler.h>
3 #include <elfutils/libdw.h>
4 #include <elfutils/libdwfl.h>
5 #include <inttypes.h>
6 #include <errno.h>
7 #include "debug.h"
8 #include "dso.h"
9 #include "unwind.h"
10 #include "unwind-libdw.h"
11 #include "machine.h"
12 #include "map.h"
13 #include "symbol.h"
14 #include "thread.h"
15 #include <linux/types.h>
16 #include <linux/zalloc.h>
17 #include "event.h"
18 #include "perf_regs.h"
19 #include "callchain.h"
20 #include "util/env.h"
21
22 static char *debuginfo_path;
23
24 static int __find_debuginfo(Dwfl_Module *mod __maybe_unused, void **userdata,
25                             const char *modname __maybe_unused, Dwarf_Addr base __maybe_unused,
26                             const char *file_name, const char *debuglink_file __maybe_unused,
27                             GElf_Word debuglink_crc __maybe_unused, char **debuginfo_file_name)
28 {
29         const struct dso *dso = *userdata;
30
31         assert(dso);
32         if (dso->symsrc_filename && strcmp (file_name, dso->symsrc_filename))
33                 *debuginfo_file_name = strdup(dso->symsrc_filename);
34         return -1;
35 }
36
37 static const Dwfl_Callbacks offline_callbacks = {
38         .find_debuginfo         = __find_debuginfo,
39         .debuginfo_path         = &debuginfo_path,
40         .section_address        = dwfl_offline_section_address,
41         // .find_elf is not set as we use dwfl_report_elf() instead.
42 };
43
44 static int __report_module(struct addr_location *al, u64 ip,
45                             struct unwind_info *ui)
46 {
47         Dwfl_Module *mod;
48         struct dso *dso = NULL;
49         Dwarf_Addr base;
50         /*
51          * Some callers will use al->sym, so we can't just use the
52          * cheaper thread__find_map() here.
53          */
54         thread__find_symbol(ui->thread, PERF_RECORD_MISC_USER, ip, al);
55
56         if (al->map)
57                 dso = map__dso(al->map);
58
59         if (!dso)
60                 return 0;
61
62         /*
63          * The generated JIT DSO files only map the code segment without
64          * ELF headers.  Since JIT codes used to be packed in a memory
65          * segment, calculating the base address using pgoff falls into
66          * a different code in another DSO.  So just use the map->start
67          * directly to pick the correct one.
68          */
69         if (!strncmp(dso->long_name, "/tmp/jitted-", 12))
70                 base = map__start(al->map);
71         else
72                 base = map__start(al->map) - map__pgoff(al->map);
73
74         mod = dwfl_addrmodule(ui->dwfl, ip);
75         if (mod) {
76                 Dwarf_Addr s;
77
78                 dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
79                 if (s != base)
80                         mod = NULL;
81         }
82
83         if (!mod) {
84                 char filename[PATH_MAX];
85
86                 __symbol__join_symfs(filename, sizeof(filename), dso->long_name);
87                 mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
88                                       base, false);
89         }
90         if (!mod) {
91                 char filename[PATH_MAX];
92
93                 if (dso__build_id_filename(dso, filename, sizeof(filename), false))
94                         mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
95                                               base, false);
96         }
97
98         if (mod) {
99                 void **userdatap;
100
101                 dwfl_module_info(mod, &userdatap, NULL, NULL, NULL, NULL, NULL, NULL);
102                 *userdatap = dso;
103         }
104
105         return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
106 }
107
108 static int report_module(u64 ip, struct unwind_info *ui)
109 {
110         struct addr_location al;
111         int res;
112
113         addr_location__init(&al);
114         res = __report_module(&al, ip, ui);
115         addr_location__exit(&al);
116         return res;
117 }
118
119 /*
120  * Store all entries within entries array,
121  * we will process it after we finish unwind.
122  */
123 static int entry(u64 ip, struct unwind_info *ui)
124
125 {
126         struct unwind_entry *e = &ui->entries[ui->idx++];
127         struct addr_location al;
128
129         addr_location__init(&al);
130         if (__report_module(&al, ip, ui)) {
131                 addr_location__exit(&al);
132                 return -1;
133         }
134
135         e->ip     = ip;
136         e->ms.maps = al.maps;
137         e->ms.map = al.map;
138         e->ms.sym = al.sym;
139
140         pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
141                  al.sym ? al.sym->name : "''",
142                  ip,
143                  al.map ? map__map_ip(al.map, ip) : (u64) 0);
144         addr_location__exit(&al);
145         return 0;
146 }
147
148 static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
149 {
150         /* We want only single thread to be processed. */
151         if (*thread_argp != NULL)
152                 return 0;
153
154         *thread_argp = arg;
155         return dwfl_pid(dwfl);
156 }
157
158 static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
159                           Dwarf_Word *data)
160 {
161         struct addr_location al;
162         ssize_t size;
163         struct dso *dso;
164
165         addr_location__init(&al);
166         if (!thread__find_map(ui->thread, PERF_RECORD_MISC_USER, addr, &al)) {
167                 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
168                 goto out_fail;
169         }
170         dso = map__dso(al.map);
171         if (!dso)
172                 goto out_fail;
173
174         size = dso__data_read_addr(dso, al.map, ui->machine, addr, (u8 *) data, sizeof(*data));
175
176         addr_location__exit(&al);
177         return !(size == sizeof(*data));
178 out_fail:
179         addr_location__exit(&al);
180         return -1;
181 }
182
183 static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
184                         void *arg)
185 {
186         struct unwind_info *ui = arg;
187         const char *arch = perf_env__arch(ui->machine->env);
188         struct stack_dump *stack = &ui->sample->user_stack;
189         u64 start, end;
190         int offset;
191         int ret;
192
193         ret = perf_reg_value(&start, &ui->sample->user_regs,
194                              perf_arch_reg_sp(arch));
195         if (ret)
196                 return false;
197
198         end = start + stack->size;
199
200         /* Check overflow. */
201         if (addr + sizeof(Dwarf_Word) < addr)
202                 return false;
203
204         if (addr < start || addr + sizeof(Dwarf_Word) > end) {
205                 ret = access_dso_mem(ui, addr, result);
206                 if (ret) {
207                         pr_debug("unwind: access_mem 0x%" PRIx64 " not inside range"
208                                  " 0x%" PRIx64 "-0x%" PRIx64 "\n",
209                                 addr, start, end);
210                         return false;
211                 }
212                 return true;
213         }
214
215         offset  = addr - start;
216         *result = *(Dwarf_Word *)&stack->data[offset];
217         pr_debug("unwind: access_mem addr 0x%" PRIx64 ", val %lx, offset %d\n",
218                  addr, (unsigned long)*result, offset);
219         return true;
220 }
221
222 static const Dwfl_Thread_Callbacks callbacks = {
223         .next_thread            = next_thread,
224         .memory_read            = memory_read,
225         .set_initial_registers  = libdw__arch_set_initial_registers,
226 };
227
228 static int
229 frame_callback(Dwfl_Frame *state, void *arg)
230 {
231         struct unwind_info *ui = arg;
232         Dwarf_Addr pc;
233         bool isactivation;
234
235         if (!dwfl_frame_pc(state, &pc, NULL)) {
236                 if (!ui->best_effort)
237                         pr_err("%s", dwfl_errmsg(-1));
238                 return DWARF_CB_ABORT;
239         }
240
241         // report the module before we query for isactivation
242         report_module(pc, ui);
243
244         if (!dwfl_frame_pc(state, &pc, &isactivation)) {
245                 if (!ui->best_effort)
246                         pr_err("%s", dwfl_errmsg(-1));
247                 return DWARF_CB_ABORT;
248         }
249
250         if (!isactivation)
251                 --pc;
252
253         return entry(pc, ui) || !(--ui->max_stack) ?
254                DWARF_CB_ABORT : DWARF_CB_OK;
255 }
256
257 int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
258                         struct thread *thread,
259                         struct perf_sample *data,
260                         int max_stack,
261                         bool best_effort)
262 {
263         struct unwind_info *ui, ui_buf = {
264                 .sample         = data,
265                 .thread         = thread,
266                 .machine        = maps__machine((thread__maps(thread))),
267                 .cb             = cb,
268                 .arg            = arg,
269                 .max_stack      = max_stack,
270                 .best_effort    = best_effort
271         };
272         const char *arch = perf_env__arch(ui_buf.machine->env);
273         Dwarf_Word ip;
274         int err = -EINVAL, i;
275
276         if (!data->user_regs.regs)
277                 return -EINVAL;
278
279         ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack);
280         if (!ui)
281                 return -ENOMEM;
282
283         *ui = ui_buf;
284
285         ui->dwfl = dwfl_begin(&offline_callbacks);
286         if (!ui->dwfl)
287                 goto out;
288
289         err = perf_reg_value(&ip, &data->user_regs, perf_arch_reg_ip(arch));
290         if (err)
291                 goto out;
292
293         err = report_module(ip, ui);
294         if (err)
295                 goto out;
296
297         err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), &callbacks, ui);
298         if (err)
299                 goto out;
300
301         err = dwfl_getthread_frames(ui->dwfl, thread__tid(thread), frame_callback, ui);
302
303         if (err && ui->max_stack != max_stack)
304                 err = 0;
305
306         /*
307          * Display what we got based on the order setup.
308          */
309         for (i = 0; i < ui->idx && !err; i++) {
310                 int j = i;
311
312                 if (callchain_param.order == ORDER_CALLER)
313                         j = ui->idx - i - 1;
314
315                 err = ui->entries[j].ip ? ui->cb(&ui->entries[j], ui->arg) : 0;
316         }
317
318  out:
319         if (err)
320                 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
321
322         dwfl_end(ui->dwfl);
323         free(ui);
324         return 0;
325 }