1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/compiler.h>
3 #include <elfutils/libdw.h>
4 #include <elfutils/libdwfl.h>
10 #include "unwind-libdw.h"
15 #include <linux/types.h>
16 #include <linux/zalloc.h>
18 #include "perf_regs.h"
19 #include "callchain.h"
22 static char *debuginfo_path
;
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
)
29 const struct dso
*dso
= *userdata
;
32 if (dso__symsrc_filename(dso
) && strcmp(file_name
, dso__symsrc_filename(dso
)))
33 *debuginfo_file_name
= strdup(dso__symsrc_filename(dso
));
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.
44 static int __report_module(struct addr_location
*al
, u64 ip
,
45 struct unwind_info
*ui
)
48 struct dso
*dso
= NULL
;
51 * Some callers will use al->sym, so we can't just use the
52 * cheaper thread__find_map() here.
54 thread__find_symbol(ui
->thread
, PERF_RECORD_MISC_USER
, ip
, al
);
57 dso
= map__dso(al
->map
);
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.
69 if (!strncmp(dso__long_name(dso
), "/tmp/jitted-", 12))
70 base
= map__start(al
->map
);
72 base
= map__start(al
->map
) - map__pgoff(al
->map
);
74 mod
= dwfl_addrmodule(ui
->dwfl
, ip
);
78 dwfl_module_info(mod
, NULL
, &s
, NULL
, NULL
, NULL
, NULL
, NULL
);
84 char filename
[PATH_MAX
];
86 __symbol__join_symfs(filename
, sizeof(filename
), dso__long_name(dso
));
87 mod
= dwfl_report_elf(ui
->dwfl
, dso__short_name(dso
), filename
, -1,
91 char filename
[PATH_MAX
];
93 if (dso__build_id_filename(dso
, filename
, sizeof(filename
), false))
94 mod
= dwfl_report_elf(ui
->dwfl
, dso__short_name(dso
), filename
, -1,
101 dwfl_module_info(mod
, &userdatap
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
105 return mod
&& dwfl_addrmodule(ui
->dwfl
, ip
) == mod
? 0 : -1;
108 static int report_module(u64 ip
, struct unwind_info
*ui
)
110 struct addr_location al
;
113 addr_location__init(&al
);
114 res
= __report_module(&al
, ip
, ui
);
115 addr_location__exit(&al
);
120 * Store all entries within entries array,
121 * we will process it after we finish unwind.
123 static int entry(u64 ip
, struct unwind_info
*ui
)
126 struct unwind_entry
*e
= &ui
->entries
[ui
->idx
++];
127 struct addr_location al
;
129 addr_location__init(&al
);
130 if (__report_module(&al
, ip
, ui
)) {
131 addr_location__exit(&al
);
136 e
->ms
.maps
= al
.maps
;
140 pr_debug("unwind: %s:ip = 0x%" PRIx64
" (0x%" PRIx64
")\n",
141 al
.sym
? al
.sym
->name
: "''",
143 al
.map
? map__map_ip(al
.map
, ip
) : (u64
) 0);
144 addr_location__exit(&al
);
148 static pid_t
next_thread(Dwfl
*dwfl
, void *arg
, void **thread_argp
)
150 /* We want only single thread to be processed. */
151 if (*thread_argp
!= NULL
)
155 return dwfl_pid(dwfl
);
158 static int access_dso_mem(struct unwind_info
*ui
, Dwarf_Addr addr
,
161 struct addr_location al
;
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
);
170 dso
= map__dso(al
.map
);
174 size
= dso__data_read_addr(dso
, al
.map
, ui
->machine
, addr
, (u8
*) data
, sizeof(*data
));
176 addr_location__exit(&al
);
177 return !(size
== sizeof(*data
));
179 addr_location__exit(&al
);
183 static bool memory_read(Dwfl
*dwfl __maybe_unused
, Dwarf_Addr addr
, Dwarf_Word
*result
,
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
;
193 ret
= perf_reg_value(&start
, &ui
->sample
->user_regs
,
194 perf_arch_reg_sp(arch
));
198 end
= start
+ stack
->size
;
200 /* Check overflow. */
201 if (addr
+ sizeof(Dwarf_Word
) < addr
)
204 if (addr
< start
|| addr
+ sizeof(Dwarf_Word
) > end
) {
205 ret
= access_dso_mem(ui
, addr
, result
);
207 pr_debug("unwind: access_mem 0x%" PRIx64
" not inside range"
208 " 0x%" PRIx64
"-0x%" PRIx64
"\n",
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
);
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
,
229 frame_callback(Dwfl_Frame
*state
, void *arg
)
231 struct unwind_info
*ui
= arg
;
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
;
241 // report the module before we query for isactivation
242 report_module(pc
, ui
);
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
;
253 return entry(pc
, ui
) || !(--ui
->max_stack
) ?
254 DWARF_CB_ABORT
: DWARF_CB_OK
;
257 int unwind__get_entries(unwind_entry_cb_t cb
, void *arg
,
258 struct thread
*thread
,
259 struct perf_sample
*data
,
263 struct unwind_info
*ui
, ui_buf
= {
266 .machine
= maps__machine((thread__maps(thread
))),
269 .max_stack
= max_stack
,
270 .best_effort
= best_effort
272 const char *arch
= perf_env__arch(ui_buf
.machine
->env
);
274 int err
= -EINVAL
, i
;
276 if (!data
->user_regs
.regs
)
279 ui
= zalloc(sizeof(ui_buf
) + sizeof(ui_buf
.entries
[0]) * max_stack
);
285 ui
->dwfl
= dwfl_begin(&offline_callbacks
);
289 err
= perf_reg_value(&ip
, &data
->user_regs
, perf_arch_reg_ip(arch
));
293 err
= report_module(ip
, ui
);
297 err
= !dwfl_attach_state(ui
->dwfl
, EM_NONE
, thread__tid(thread
), &callbacks
, ui
);
301 err
= dwfl_getthread_frames(ui
->dwfl
, thread__tid(thread
), frame_callback
, ui
);
303 if (err
&& ui
->max_stack
!= max_stack
)
307 * Display what we got based on the order setup.
309 for (i
= 0; i
< ui
->idx
&& !err
; i
++) {
312 if (callchain_param
.order
== ORDER_CALLER
)
315 err
= ui
->entries
[j
].ip
? ui
->cb(&ui
->entries
[j
], ui
->arg
) : 0;
320 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));