1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/compiler.h>
3 #include <elfutils/libdw.h>
4 #include <elfutils/libdwfl.h>
9 #include "unwind-libdw.h"
12 #include <linux/types.h>
14 #include "perf_regs.h"
15 #include "callchain.h"
18 static char *debuginfo_path
;
20 static const Dwfl_Callbacks offline_callbacks
= {
21 .find_debuginfo
= dwfl_standard_find_debuginfo
,
22 .debuginfo_path
= &debuginfo_path
,
23 .section_address
= dwfl_offline_section_address
,
26 static int __report_module(struct addr_location
*al
, u64 ip
,
27 struct unwind_info
*ui
)
30 struct dso
*dso
= NULL
;
32 thread__find_addr_location(ui
->thread
,
33 PERF_RECORD_MISC_USER
,
34 MAP__FUNCTION
, ip
, al
);
42 mod
= dwfl_addrmodule(ui
->dwfl
, ip
);
46 dwfl_module_info(mod
, NULL
, &s
, NULL
, NULL
, NULL
, NULL
, NULL
);
47 if (s
!= al
->map
->start
)
52 mod
= dwfl_report_elf(ui
->dwfl
, dso
->short_name
,
53 dso
->long_name
, -1, al
->map
->start
,
56 return mod
&& dwfl_addrmodule(ui
->dwfl
, ip
) == mod
? 0 : -1;
59 static int report_module(u64 ip
, struct unwind_info
*ui
)
61 struct addr_location al
;
63 return __report_module(&al
, ip
, ui
);
67 * Store all entries within entries array,
68 * we will process it after we finish unwind.
70 static int entry(u64 ip
, struct unwind_info
*ui
)
73 struct unwind_entry
*e
= &ui
->entries
[ui
->idx
++];
74 struct addr_location al
;
76 if (__report_module(&al
, ip
, ui
))
83 pr_debug("unwind: %s:ip = 0x%" PRIx64
" (0x%" PRIx64
")\n",
84 al
.sym
? al
.sym
->name
: "''",
86 al
.map
? al
.map
->map_ip(al
.map
, ip
) : (u64
) 0);
90 static pid_t
next_thread(Dwfl
*dwfl
, void *arg
, void **thread_argp
)
92 /* We want only single thread to be processed. */
93 if (*thread_argp
!= NULL
)
97 return dwfl_pid(dwfl
);
100 static int access_dso_mem(struct unwind_info
*ui
, Dwarf_Addr addr
,
103 struct addr_location al
;
106 thread__find_addr_map(ui
->thread
, PERF_RECORD_MISC_USER
,
107 MAP__FUNCTION
, addr
, &al
);
110 * We've seen cases (softice) where DWARF unwinder went
111 * through non executable mmaps, which we need to lookup
112 * in MAP__VARIABLE tree.
114 thread__find_addr_map(ui
->thread
, PERF_RECORD_MISC_USER
,
115 MAP__VARIABLE
, addr
, &al
);
119 pr_debug("unwind: no map for %lx\n", (unsigned long)addr
);
126 size
= dso__data_read_addr(al
.map
->dso
, al
.map
, ui
->machine
,
127 addr
, (u8
*) data
, sizeof(*data
));
129 return !(size
== sizeof(*data
));
132 static bool memory_read(Dwfl
*dwfl __maybe_unused
, Dwarf_Addr addr
, Dwarf_Word
*result
,
135 struct unwind_info
*ui
= arg
;
136 struct stack_dump
*stack
= &ui
->sample
->user_stack
;
141 ret
= perf_reg_value(&start
, &ui
->sample
->user_regs
, PERF_REG_SP
);
145 end
= start
+ stack
->size
;
147 /* Check overflow. */
148 if (addr
+ sizeof(Dwarf_Word
) < addr
)
151 if (addr
< start
|| addr
+ sizeof(Dwarf_Word
) > end
) {
152 ret
= access_dso_mem(ui
, addr
, result
);
154 pr_debug("unwind: access_mem 0x%" PRIx64
" not inside range"
155 " 0x%" PRIx64
"-0x%" PRIx64
"\n",
162 offset
= addr
- start
;
163 *result
= *(Dwarf_Word
*)&stack
->data
[offset
];
164 pr_debug("unwind: access_mem addr 0x%" PRIx64
", val %lx, offset %d\n",
165 addr
, (unsigned long)*result
, offset
);
169 static const Dwfl_Thread_Callbacks callbacks
= {
170 .next_thread
= next_thread
,
171 .memory_read
= memory_read
,
172 .set_initial_registers
= libdw__arch_set_initial_registers
,
176 frame_callback(Dwfl_Frame
*state
, void *arg
)
178 struct unwind_info
*ui
= arg
;
182 if (!dwfl_frame_pc(state
, &pc
, NULL
)) {
183 pr_err("%s", dwfl_errmsg(-1));
184 return DWARF_CB_ABORT
;
187 // report the module before we query for isactivation
188 report_module(pc
, ui
);
190 if (!dwfl_frame_pc(state
, &pc
, &isactivation
)) {
191 pr_err("%s", dwfl_errmsg(-1));
192 return DWARF_CB_ABORT
;
198 return entry(pc
, ui
) || !(--ui
->max_stack
) ?
199 DWARF_CB_ABORT
: DWARF_CB_OK
;
202 int unwind__get_entries(unwind_entry_cb_t cb
, void *arg
,
203 struct thread
*thread
,
204 struct perf_sample
*data
,
207 struct unwind_info
*ui
, ui_buf
= {
210 .machine
= thread
->mg
->machine
,
213 .max_stack
= max_stack
,
216 int err
= -EINVAL
, i
;
218 if (!data
->user_regs
.regs
)
221 ui
= zalloc(sizeof(ui_buf
) + sizeof(ui_buf
.entries
[0]) * max_stack
);
227 ui
->dwfl
= dwfl_begin(&offline_callbacks
);
231 err
= perf_reg_value(&ip
, &data
->user_regs
, PERF_REG_IP
);
235 err
= report_module(ip
, ui
);
239 if (!dwfl_attach_state(ui
->dwfl
, EM_NONE
, thread
->tid
, &callbacks
, ui
))
242 err
= dwfl_getthread_frames(ui
->dwfl
, thread
->tid
, frame_callback
, ui
);
244 if (err
&& ui
->max_stack
!= max_stack
)
248 * Display what we got based on the order setup.
250 for (i
= 0; i
< ui
->idx
&& !err
; i
++) {
253 if (callchain_param
.order
== ORDER_CALLER
)
256 err
= ui
->entries
[j
].ip
? ui
->cb(&ui
->entries
[j
], ui
->arg
) : 0;
261 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));