1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Lots of this code have been borrowed or heavily inspired from parts of
6*4882a593Smuzhiyun * the libunwind 0.99 code which are (amongst other contributors I may have
7*4882a593Smuzhiyun * forgotten):
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Copyright (C) 2002-2007 Hewlett-Packard Co
10*4882a593Smuzhiyun * Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * And the bugs have been added by:
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com>
15*4882a593Smuzhiyun * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com>
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <elf.h>
20*4882a593Smuzhiyun #include <errno.h>
21*4882a593Smuzhiyun #include <gelf.h>
22*4882a593Smuzhiyun #include <fcntl.h>
23*4882a593Smuzhiyun #include <inttypes.h>
24*4882a593Smuzhiyun #include <string.h>
25*4882a593Smuzhiyun #include <unistd.h>
26*4882a593Smuzhiyun #include <sys/mman.h>
27*4882a593Smuzhiyun #include <linux/list.h>
28*4882a593Smuzhiyun #include <linux/zalloc.h>
29*4882a593Smuzhiyun #ifndef REMOTE_UNWIND_LIBUNWIND
30*4882a593Smuzhiyun #include <libunwind.h>
31*4882a593Smuzhiyun #include <libunwind-ptrace.h>
32*4882a593Smuzhiyun #endif
33*4882a593Smuzhiyun #include "callchain.h"
34*4882a593Smuzhiyun #include "thread.h"
35*4882a593Smuzhiyun #include "session.h"
36*4882a593Smuzhiyun #include "perf_regs.h"
37*4882a593Smuzhiyun #include "unwind.h"
38*4882a593Smuzhiyun #include "map.h"
39*4882a593Smuzhiyun #include "symbol.h"
40*4882a593Smuzhiyun #include "debug.h"
41*4882a593Smuzhiyun #include "asm/bug.h"
42*4882a593Smuzhiyun #include "dso.h"
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun extern int
45*4882a593Smuzhiyun UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
46*4882a593Smuzhiyun unw_word_t ip,
47*4882a593Smuzhiyun unw_dyn_info_t *di,
48*4882a593Smuzhiyun unw_proc_info_t *pi,
49*4882a593Smuzhiyun int need_unwind_info, void *arg);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun extern int
54*4882a593Smuzhiyun UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
55*4882a593Smuzhiyun unw_word_t ip,
56*4882a593Smuzhiyun unw_word_t segbase,
57*4882a593Smuzhiyun const char *obj_name, unw_word_t start,
58*4882a593Smuzhiyun unw_word_t end);
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun #define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun #define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
63*4882a593Smuzhiyun #define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /* Pointer-encoding formats: */
66*4882a593Smuzhiyun #define DW_EH_PE_omit 0xff
67*4882a593Smuzhiyun #define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */
68*4882a593Smuzhiyun #define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */
69*4882a593Smuzhiyun #define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */
70*4882a593Smuzhiyun #define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */
71*4882a593Smuzhiyun #define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* Pointer-encoding application: */
74*4882a593Smuzhiyun #define DW_EH_PE_absptr 0x00 /* absolute value */
75*4882a593Smuzhiyun #define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /*
78*4882a593Smuzhiyun * The following are not documented by LSB v1.3, yet they are used by
79*4882a593Smuzhiyun * GCC, presumably they aren't documented by LSB since they aren't
80*4882a593Smuzhiyun * used on Linux:
81*4882a593Smuzhiyun */
82*4882a593Smuzhiyun #define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */
83*4882a593Smuzhiyun #define DW_EH_PE_aligned 0x50 /* aligned pointer */
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* Flags intentionaly not handled, since they're not needed:
86*4882a593Smuzhiyun * #define DW_EH_PE_indirect 0x80
87*4882a593Smuzhiyun * #define DW_EH_PE_uleb128 0x01
88*4882a593Smuzhiyun * #define DW_EH_PE_udata2 0x02
89*4882a593Smuzhiyun * #define DW_EH_PE_sleb128 0x09
90*4882a593Smuzhiyun * #define DW_EH_PE_sdata2 0x0a
91*4882a593Smuzhiyun * #define DW_EH_PE_textrel 0x20
92*4882a593Smuzhiyun * #define DW_EH_PE_datarel 0x30
93*4882a593Smuzhiyun */
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun struct unwind_info {
96*4882a593Smuzhiyun struct perf_sample *sample;
97*4882a593Smuzhiyun struct machine *machine;
98*4882a593Smuzhiyun struct thread *thread;
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun #define dw_read(ptr, type, end) ({ \
102*4882a593Smuzhiyun type *__p = (type *) ptr; \
103*4882a593Smuzhiyun type __v; \
104*4882a593Smuzhiyun if ((__p + 1) > (type *) end) \
105*4882a593Smuzhiyun return -EINVAL; \
106*4882a593Smuzhiyun __v = *__p++; \
107*4882a593Smuzhiyun ptr = (typeof(ptr)) __p; \
108*4882a593Smuzhiyun __v; \
109*4882a593Smuzhiyun })
110*4882a593Smuzhiyun
__dw_read_encoded_value(u8 ** p,u8 * end,u64 * val,u8 encoding)111*4882a593Smuzhiyun static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
112*4882a593Smuzhiyun u8 encoding)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun u8 *cur = *p;
115*4882a593Smuzhiyun *val = 0;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun switch (encoding) {
118*4882a593Smuzhiyun case DW_EH_PE_omit:
119*4882a593Smuzhiyun *val = 0;
120*4882a593Smuzhiyun goto out;
121*4882a593Smuzhiyun case DW_EH_PE_ptr:
122*4882a593Smuzhiyun *val = dw_read(cur, unsigned long, end);
123*4882a593Smuzhiyun goto out;
124*4882a593Smuzhiyun default:
125*4882a593Smuzhiyun break;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun switch (encoding & DW_EH_PE_APPL_MASK) {
129*4882a593Smuzhiyun case DW_EH_PE_absptr:
130*4882a593Smuzhiyun break;
131*4882a593Smuzhiyun case DW_EH_PE_pcrel:
132*4882a593Smuzhiyun *val = (unsigned long) cur;
133*4882a593Smuzhiyun break;
134*4882a593Smuzhiyun default:
135*4882a593Smuzhiyun return -EINVAL;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if ((encoding & 0x07) == 0x00)
139*4882a593Smuzhiyun encoding |= DW_EH_PE_udata4;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun switch (encoding & DW_EH_PE_FORMAT_MASK) {
142*4882a593Smuzhiyun case DW_EH_PE_sdata4:
143*4882a593Smuzhiyun *val += dw_read(cur, s32, end);
144*4882a593Smuzhiyun break;
145*4882a593Smuzhiyun case DW_EH_PE_udata4:
146*4882a593Smuzhiyun *val += dw_read(cur, u32, end);
147*4882a593Smuzhiyun break;
148*4882a593Smuzhiyun case DW_EH_PE_sdata8:
149*4882a593Smuzhiyun *val += dw_read(cur, s64, end);
150*4882a593Smuzhiyun break;
151*4882a593Smuzhiyun case DW_EH_PE_udata8:
152*4882a593Smuzhiyun *val += dw_read(cur, u64, end);
153*4882a593Smuzhiyun break;
154*4882a593Smuzhiyun default:
155*4882a593Smuzhiyun return -EINVAL;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun out:
159*4882a593Smuzhiyun *p = cur;
160*4882a593Smuzhiyun return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun #define dw_read_encoded_value(ptr, end, enc) ({ \
164*4882a593Smuzhiyun u64 __v; \
165*4882a593Smuzhiyun if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \
166*4882a593Smuzhiyun return -EINVAL; \
167*4882a593Smuzhiyun } \
168*4882a593Smuzhiyun __v; \
169*4882a593Smuzhiyun })
170*4882a593Smuzhiyun
elf_section_offset(int fd,const char * name)171*4882a593Smuzhiyun static u64 elf_section_offset(int fd, const char *name)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun Elf *elf;
174*4882a593Smuzhiyun GElf_Ehdr ehdr;
175*4882a593Smuzhiyun GElf_Shdr shdr;
176*4882a593Smuzhiyun u64 offset = 0;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
179*4882a593Smuzhiyun if (elf == NULL)
180*4882a593Smuzhiyun return 0;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun do {
183*4882a593Smuzhiyun if (gelf_getehdr(elf, &ehdr) == NULL)
184*4882a593Smuzhiyun break;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL))
187*4882a593Smuzhiyun break;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun offset = shdr.sh_offset;
190*4882a593Smuzhiyun } while (0);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun elf_end(elf);
193*4882a593Smuzhiyun return offset;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun #ifndef NO_LIBUNWIND_DEBUG_FRAME
elf_is_exec(int fd,const char * name)197*4882a593Smuzhiyun static int elf_is_exec(int fd, const char *name)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun Elf *elf;
200*4882a593Smuzhiyun GElf_Ehdr ehdr;
201*4882a593Smuzhiyun int retval = 0;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
204*4882a593Smuzhiyun if (elf == NULL)
205*4882a593Smuzhiyun return 0;
206*4882a593Smuzhiyun if (gelf_getehdr(elf, &ehdr) == NULL)
207*4882a593Smuzhiyun goto out;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun retval = (ehdr.e_type == ET_EXEC);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun out:
212*4882a593Smuzhiyun elf_end(elf);
213*4882a593Smuzhiyun pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval);
214*4882a593Smuzhiyun return retval;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun #endif
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun struct table_entry {
219*4882a593Smuzhiyun u32 start_ip_offset;
220*4882a593Smuzhiyun u32 fde_offset;
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun struct eh_frame_hdr {
224*4882a593Smuzhiyun unsigned char version;
225*4882a593Smuzhiyun unsigned char eh_frame_ptr_enc;
226*4882a593Smuzhiyun unsigned char fde_count_enc;
227*4882a593Smuzhiyun unsigned char table_enc;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /*
230*4882a593Smuzhiyun * The rest of the header is variable-length and consists of the
231*4882a593Smuzhiyun * following members:
232*4882a593Smuzhiyun *
233*4882a593Smuzhiyun * encoded_t eh_frame_ptr;
234*4882a593Smuzhiyun * encoded_t fde_count;
235*4882a593Smuzhiyun */
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun /* A single encoded pointer should not be more than 8 bytes. */
238*4882a593Smuzhiyun u64 enc[2];
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /*
241*4882a593Smuzhiyun * struct {
242*4882a593Smuzhiyun * encoded_t start_ip;
243*4882a593Smuzhiyun * encoded_t fde_addr;
244*4882a593Smuzhiyun * } binary_search_table[fde_count];
245*4882a593Smuzhiyun */
246*4882a593Smuzhiyun char data[];
247*4882a593Smuzhiyun } __packed;
248*4882a593Smuzhiyun
unwind_spec_ehframe(struct dso * dso,struct machine * machine,u64 offset,u64 * table_data,u64 * segbase,u64 * fde_count)249*4882a593Smuzhiyun static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
250*4882a593Smuzhiyun u64 offset, u64 *table_data, u64 *segbase,
251*4882a593Smuzhiyun u64 *fde_count)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun struct eh_frame_hdr hdr;
254*4882a593Smuzhiyun u8 *enc = (u8 *) &hdr.enc;
255*4882a593Smuzhiyun u8 *end = (u8 *) &hdr.data;
256*4882a593Smuzhiyun ssize_t r;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun r = dso__data_read_offset(dso, machine, offset,
259*4882a593Smuzhiyun (u8 *) &hdr, sizeof(hdr));
260*4882a593Smuzhiyun if (r != sizeof(hdr))
261*4882a593Smuzhiyun return -EINVAL;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /* We dont need eh_frame_ptr, just skip it. */
264*4882a593Smuzhiyun dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
267*4882a593Smuzhiyun *segbase = offset;
268*4882a593Smuzhiyun *table_data = (enc - (u8 *) &hdr) + offset;
269*4882a593Smuzhiyun return 0;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
read_unwind_spec_eh_frame(struct dso * dso,struct machine * machine,u64 * table_data,u64 * segbase,u64 * fde_count)272*4882a593Smuzhiyun static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
273*4882a593Smuzhiyun u64 *table_data, u64 *segbase,
274*4882a593Smuzhiyun u64 *fde_count)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun int ret = -EINVAL, fd;
277*4882a593Smuzhiyun u64 offset = dso->data.eh_frame_hdr_offset;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (offset == 0) {
280*4882a593Smuzhiyun fd = dso__data_get_fd(dso, machine);
281*4882a593Smuzhiyun if (fd < 0)
282*4882a593Smuzhiyun return -EINVAL;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* Check the .eh_frame section for unwinding info */
285*4882a593Smuzhiyun offset = elf_section_offset(fd, ".eh_frame_hdr");
286*4882a593Smuzhiyun dso->data.eh_frame_hdr_offset = offset;
287*4882a593Smuzhiyun dso__data_put_fd(dso);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun if (offset)
291*4882a593Smuzhiyun ret = unwind_spec_ehframe(dso, machine, offset,
292*4882a593Smuzhiyun table_data, segbase,
293*4882a593Smuzhiyun fde_count);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun return ret;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun #ifndef NO_LIBUNWIND_DEBUG_FRAME
read_unwind_spec_debug_frame(struct dso * dso,struct machine * machine,u64 * offset)299*4882a593Smuzhiyun static int read_unwind_spec_debug_frame(struct dso *dso,
300*4882a593Smuzhiyun struct machine *machine, u64 *offset)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun int fd;
303*4882a593Smuzhiyun u64 ofs = dso->data.debug_frame_offset;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun /* debug_frame can reside in:
306*4882a593Smuzhiyun * - dso
307*4882a593Smuzhiyun * - debug pointed by symsrc_filename
308*4882a593Smuzhiyun * - gnu_debuglink, which doesn't necessary
309*4882a593Smuzhiyun * has to be pointed by symsrc_filename
310*4882a593Smuzhiyun */
311*4882a593Smuzhiyun if (ofs == 0) {
312*4882a593Smuzhiyun fd = dso__data_get_fd(dso, machine);
313*4882a593Smuzhiyun if (fd >= 0) {
314*4882a593Smuzhiyun ofs = elf_section_offset(fd, ".debug_frame");
315*4882a593Smuzhiyun dso__data_put_fd(dso);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (ofs <= 0) {
319*4882a593Smuzhiyun fd = open(dso->symsrc_filename, O_RDONLY);
320*4882a593Smuzhiyun if (fd >= 0) {
321*4882a593Smuzhiyun ofs = elf_section_offset(fd, ".debug_frame");
322*4882a593Smuzhiyun close(fd);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun if (ofs <= 0) {
327*4882a593Smuzhiyun char *debuglink = malloc(PATH_MAX);
328*4882a593Smuzhiyun int ret = 0;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun ret = dso__read_binary_type_filename(
331*4882a593Smuzhiyun dso, DSO_BINARY_TYPE__DEBUGLINK,
332*4882a593Smuzhiyun machine->root_dir, debuglink, PATH_MAX);
333*4882a593Smuzhiyun if (!ret) {
334*4882a593Smuzhiyun fd = open(debuglink, O_RDONLY);
335*4882a593Smuzhiyun if (fd >= 0) {
336*4882a593Smuzhiyun ofs = elf_section_offset(fd,
337*4882a593Smuzhiyun ".debug_frame");
338*4882a593Smuzhiyun close(fd);
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun if (ofs > 0) {
342*4882a593Smuzhiyun if (dso->symsrc_filename != NULL) {
343*4882a593Smuzhiyun pr_warning(
344*4882a593Smuzhiyun "%s: overwrite symsrc(%s,%s)\n",
345*4882a593Smuzhiyun __func__,
346*4882a593Smuzhiyun dso->symsrc_filename,
347*4882a593Smuzhiyun debuglink);
348*4882a593Smuzhiyun zfree(&dso->symsrc_filename);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun dso->symsrc_filename = debuglink;
351*4882a593Smuzhiyun } else {
352*4882a593Smuzhiyun free(debuglink);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun dso->data.debug_frame_offset = ofs;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun *offset = ofs;
360*4882a593Smuzhiyun if (*offset)
361*4882a593Smuzhiyun return 0;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun return -EINVAL;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun #endif
366*4882a593Smuzhiyun
find_map(unw_word_t ip,struct unwind_info * ui)367*4882a593Smuzhiyun static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun struct addr_location al;
370*4882a593Smuzhiyun return thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun static int
find_proc_info(unw_addr_space_t as,unw_word_t ip,unw_proc_info_t * pi,int need_unwind_info,void * arg)374*4882a593Smuzhiyun find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
375*4882a593Smuzhiyun int need_unwind_info, void *arg)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun struct unwind_info *ui = arg;
378*4882a593Smuzhiyun struct map *map;
379*4882a593Smuzhiyun unw_dyn_info_t di;
380*4882a593Smuzhiyun u64 table_data, segbase, fde_count;
381*4882a593Smuzhiyun int ret = -EINVAL;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun map = find_map(ip, ui);
384*4882a593Smuzhiyun if (!map || !map->dso)
385*4882a593Smuzhiyun return -EINVAL;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun /* Check the .eh_frame section for unwinding info */
390*4882a593Smuzhiyun if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
391*4882a593Smuzhiyun &table_data, &segbase, &fde_count)) {
392*4882a593Smuzhiyun memset(&di, 0, sizeof(di));
393*4882a593Smuzhiyun di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
394*4882a593Smuzhiyun di.start_ip = map->start;
395*4882a593Smuzhiyun di.end_ip = map->end;
396*4882a593Smuzhiyun di.u.rti.segbase = map->start + segbase - map->pgoff;
397*4882a593Smuzhiyun di.u.rti.table_data = map->start + table_data - map->pgoff;
398*4882a593Smuzhiyun di.u.rti.table_len = fde_count * sizeof(struct table_entry)
399*4882a593Smuzhiyun / sizeof(unw_word_t);
400*4882a593Smuzhiyun ret = dwarf_search_unwind_table(as, ip, &di, pi,
401*4882a593Smuzhiyun need_unwind_info, arg);
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun #ifndef NO_LIBUNWIND_DEBUG_FRAME
405*4882a593Smuzhiyun /* Check the .debug_frame section for unwinding info */
406*4882a593Smuzhiyun if (ret < 0 &&
407*4882a593Smuzhiyun !read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
408*4882a593Smuzhiyun int fd = dso__data_get_fd(map->dso, ui->machine);
409*4882a593Smuzhiyun int is_exec = elf_is_exec(fd, map->dso->name);
410*4882a593Smuzhiyun unw_word_t base = is_exec ? 0 : map->start;
411*4882a593Smuzhiyun const char *symfile;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun if (fd >= 0)
414*4882a593Smuzhiyun dso__data_put_fd(map->dso);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun symfile = map->dso->symsrc_filename ?: map->dso->name;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun memset(&di, 0, sizeof(di));
419*4882a593Smuzhiyun if (dwarf_find_debug_frame(0, &di, ip, base, symfile,
420*4882a593Smuzhiyun map->start, map->end))
421*4882a593Smuzhiyun return dwarf_search_unwind_table(as, ip, &di, pi,
422*4882a593Smuzhiyun need_unwind_info, arg);
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun #endif
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun return ret;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
access_fpreg(unw_addr_space_t __maybe_unused as,unw_regnum_t __maybe_unused num,unw_fpreg_t __maybe_unused * val,int __maybe_unused __write,void __maybe_unused * arg)429*4882a593Smuzhiyun static int access_fpreg(unw_addr_space_t __maybe_unused as,
430*4882a593Smuzhiyun unw_regnum_t __maybe_unused num,
431*4882a593Smuzhiyun unw_fpreg_t __maybe_unused *val,
432*4882a593Smuzhiyun int __maybe_unused __write,
433*4882a593Smuzhiyun void __maybe_unused *arg)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun pr_err("unwind: access_fpreg unsupported\n");
436*4882a593Smuzhiyun return -UNW_EINVAL;
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun
get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,unw_word_t __maybe_unused * dil_addr,void __maybe_unused * arg)439*4882a593Smuzhiyun static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
440*4882a593Smuzhiyun unw_word_t __maybe_unused *dil_addr,
441*4882a593Smuzhiyun void __maybe_unused *arg)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun return -UNW_ENOINFO;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
resume(unw_addr_space_t __maybe_unused as,unw_cursor_t __maybe_unused * cu,void __maybe_unused * arg)446*4882a593Smuzhiyun static int resume(unw_addr_space_t __maybe_unused as,
447*4882a593Smuzhiyun unw_cursor_t __maybe_unused *cu,
448*4882a593Smuzhiyun void __maybe_unused *arg)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun pr_err("unwind: resume unsupported\n");
451*4882a593Smuzhiyun return -UNW_EINVAL;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun static int
get_proc_name(unw_addr_space_t __maybe_unused as,unw_word_t __maybe_unused addr,char __maybe_unused * bufp,size_t __maybe_unused buf_len,unw_word_t __maybe_unused * offp,void __maybe_unused * arg)455*4882a593Smuzhiyun get_proc_name(unw_addr_space_t __maybe_unused as,
456*4882a593Smuzhiyun unw_word_t __maybe_unused addr,
457*4882a593Smuzhiyun char __maybe_unused *bufp, size_t __maybe_unused buf_len,
458*4882a593Smuzhiyun unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun pr_err("unwind: get_proc_name unsupported\n");
461*4882a593Smuzhiyun return -UNW_EINVAL;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
access_dso_mem(struct unwind_info * ui,unw_word_t addr,unw_word_t * data)464*4882a593Smuzhiyun static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
465*4882a593Smuzhiyun unw_word_t *data)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun struct map *map;
468*4882a593Smuzhiyun ssize_t size;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun map = find_map(addr, ui);
471*4882a593Smuzhiyun if (!map) {
472*4882a593Smuzhiyun pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
473*4882a593Smuzhiyun return -1;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun if (!map->dso)
477*4882a593Smuzhiyun return -1;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun size = dso__data_read_addr(map->dso, map, ui->machine,
480*4882a593Smuzhiyun addr, (u8 *) data, sizeof(*data));
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun return !(size == sizeof(*data));
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
access_mem(unw_addr_space_t __maybe_unused as,unw_word_t addr,unw_word_t * valp,int __write,void * arg)485*4882a593Smuzhiyun static int access_mem(unw_addr_space_t __maybe_unused as,
486*4882a593Smuzhiyun unw_word_t addr, unw_word_t *valp,
487*4882a593Smuzhiyun int __write, void *arg)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun struct unwind_info *ui = arg;
490*4882a593Smuzhiyun struct stack_dump *stack = &ui->sample->user_stack;
491*4882a593Smuzhiyun u64 start, end;
492*4882a593Smuzhiyun int offset;
493*4882a593Smuzhiyun int ret;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun /* Don't support write, probably not needed. */
496*4882a593Smuzhiyun if (__write || !stack || !ui->sample->user_regs.regs) {
497*4882a593Smuzhiyun *valp = 0;
498*4882a593Smuzhiyun return 0;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun ret = perf_reg_value(&start, &ui->sample->user_regs,
502*4882a593Smuzhiyun LIBUNWIND__ARCH_REG_SP);
503*4882a593Smuzhiyun if (ret)
504*4882a593Smuzhiyun return ret;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun end = start + stack->size;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun /* Check overflow. */
509*4882a593Smuzhiyun if (addr + sizeof(unw_word_t) < addr)
510*4882a593Smuzhiyun return -EINVAL;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun if (addr < start || addr + sizeof(unw_word_t) >= end) {
513*4882a593Smuzhiyun ret = access_dso_mem(ui, addr, valp);
514*4882a593Smuzhiyun if (ret) {
515*4882a593Smuzhiyun pr_debug("unwind: access_mem %p not inside range"
516*4882a593Smuzhiyun " 0x%" PRIx64 "-0x%" PRIx64 "\n",
517*4882a593Smuzhiyun (void *) (uintptr_t) addr, start, end);
518*4882a593Smuzhiyun *valp = 0;
519*4882a593Smuzhiyun return ret;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun return 0;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun offset = addr - start;
525*4882a593Smuzhiyun *valp = *(unw_word_t *)&stack->data[offset];
526*4882a593Smuzhiyun pr_debug("unwind: access_mem addr %p val %lx, offset %d\n",
527*4882a593Smuzhiyun (void *) (uintptr_t) addr, (unsigned long)*valp, offset);
528*4882a593Smuzhiyun return 0;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
access_reg(unw_addr_space_t __maybe_unused as,unw_regnum_t regnum,unw_word_t * valp,int __write,void * arg)531*4882a593Smuzhiyun static int access_reg(unw_addr_space_t __maybe_unused as,
532*4882a593Smuzhiyun unw_regnum_t regnum, unw_word_t *valp,
533*4882a593Smuzhiyun int __write, void *arg)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun struct unwind_info *ui = arg;
536*4882a593Smuzhiyun int id, ret;
537*4882a593Smuzhiyun u64 val;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun /* Don't support write, I suspect we don't need it. */
540*4882a593Smuzhiyun if (__write) {
541*4882a593Smuzhiyun pr_err("unwind: access_reg w %d\n", regnum);
542*4882a593Smuzhiyun return 0;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun if (!ui->sample->user_regs.regs) {
546*4882a593Smuzhiyun *valp = 0;
547*4882a593Smuzhiyun return 0;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun id = LIBUNWIND__ARCH_REG_ID(regnum);
551*4882a593Smuzhiyun if (id < 0)
552*4882a593Smuzhiyun return -EINVAL;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun ret = perf_reg_value(&val, &ui->sample->user_regs, id);
555*4882a593Smuzhiyun if (ret) {
556*4882a593Smuzhiyun pr_err("unwind: can't read reg %d\n", regnum);
557*4882a593Smuzhiyun return ret;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun *valp = (unw_word_t) val;
561*4882a593Smuzhiyun pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
562*4882a593Smuzhiyun return 0;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun
put_unwind_info(unw_addr_space_t __maybe_unused as,unw_proc_info_t * pi __maybe_unused,void * arg __maybe_unused)565*4882a593Smuzhiyun static void put_unwind_info(unw_addr_space_t __maybe_unused as,
566*4882a593Smuzhiyun unw_proc_info_t *pi __maybe_unused,
567*4882a593Smuzhiyun void *arg __maybe_unused)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun pr_debug("unwind: put_unwind_info called\n");
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
entry(u64 ip,struct thread * thread,unwind_entry_cb_t cb,void * arg)572*4882a593Smuzhiyun static int entry(u64 ip, struct thread *thread,
573*4882a593Smuzhiyun unwind_entry_cb_t cb, void *arg)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun struct unwind_entry e;
576*4882a593Smuzhiyun struct addr_location al;
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun e.ms.sym = thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al);
579*4882a593Smuzhiyun e.ip = ip;
580*4882a593Smuzhiyun e.ms.map = al.map;
581*4882a593Smuzhiyun e.ms.maps = al.maps;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
584*4882a593Smuzhiyun al.sym ? al.sym->name : "''",
585*4882a593Smuzhiyun ip,
586*4882a593Smuzhiyun al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun return cb(&e, arg);
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun
display_error(int err)591*4882a593Smuzhiyun static void display_error(int err)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun switch (err) {
594*4882a593Smuzhiyun case UNW_EINVAL:
595*4882a593Smuzhiyun pr_err("unwind: Only supports local.\n");
596*4882a593Smuzhiyun break;
597*4882a593Smuzhiyun case UNW_EUNSPEC:
598*4882a593Smuzhiyun pr_err("unwind: Unspecified error.\n");
599*4882a593Smuzhiyun break;
600*4882a593Smuzhiyun case UNW_EBADREG:
601*4882a593Smuzhiyun pr_err("unwind: Register unavailable.\n");
602*4882a593Smuzhiyun break;
603*4882a593Smuzhiyun default:
604*4882a593Smuzhiyun break;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun static unw_accessors_t accessors = {
609*4882a593Smuzhiyun .find_proc_info = find_proc_info,
610*4882a593Smuzhiyun .put_unwind_info = put_unwind_info,
611*4882a593Smuzhiyun .get_dyn_info_list_addr = get_dyn_info_list_addr,
612*4882a593Smuzhiyun .access_mem = access_mem,
613*4882a593Smuzhiyun .access_reg = access_reg,
614*4882a593Smuzhiyun .access_fpreg = access_fpreg,
615*4882a593Smuzhiyun .resume = resume,
616*4882a593Smuzhiyun .get_proc_name = get_proc_name,
617*4882a593Smuzhiyun };
618*4882a593Smuzhiyun
_unwind__prepare_access(struct maps * maps)619*4882a593Smuzhiyun static int _unwind__prepare_access(struct maps *maps)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun maps->addr_space = unw_create_addr_space(&accessors, 0);
622*4882a593Smuzhiyun if (!maps->addr_space) {
623*4882a593Smuzhiyun pr_err("unwind: Can't create unwind address space.\n");
624*4882a593Smuzhiyun return -ENOMEM;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun unw_set_caching_policy(maps->addr_space, UNW_CACHE_GLOBAL);
628*4882a593Smuzhiyun return 0;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
_unwind__flush_access(struct maps * maps)631*4882a593Smuzhiyun static void _unwind__flush_access(struct maps *maps)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun unw_flush_cache(maps->addr_space, 0, 0);
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun
_unwind__finish_access(struct maps * maps)636*4882a593Smuzhiyun static void _unwind__finish_access(struct maps *maps)
637*4882a593Smuzhiyun {
638*4882a593Smuzhiyun unw_destroy_addr_space(maps->addr_space);
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
get_entries(struct unwind_info * ui,unwind_entry_cb_t cb,void * arg,int max_stack)641*4882a593Smuzhiyun static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
642*4882a593Smuzhiyun void *arg, int max_stack)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun u64 val;
645*4882a593Smuzhiyun unw_word_t ips[max_stack];
646*4882a593Smuzhiyun unw_addr_space_t addr_space;
647*4882a593Smuzhiyun unw_cursor_t c;
648*4882a593Smuzhiyun int ret, i = 0;
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun ret = perf_reg_value(&val, &ui->sample->user_regs,
651*4882a593Smuzhiyun LIBUNWIND__ARCH_REG_IP);
652*4882a593Smuzhiyun if (ret)
653*4882a593Smuzhiyun return ret;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun ips[i++] = (unw_word_t) val;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun /*
658*4882a593Smuzhiyun * If we need more than one entry, do the DWARF
659*4882a593Smuzhiyun * unwind itself.
660*4882a593Smuzhiyun */
661*4882a593Smuzhiyun if (max_stack - 1 > 0) {
662*4882a593Smuzhiyun WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL");
663*4882a593Smuzhiyun addr_space = ui->thread->maps->addr_space;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun if (addr_space == NULL)
666*4882a593Smuzhiyun return -1;
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun ret = unw_init_remote(&c, addr_space, ui);
669*4882a593Smuzhiyun if (ret)
670*4882a593Smuzhiyun display_error(ret);
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun while (!ret && (unw_step(&c) > 0) && i < max_stack) {
673*4882a593Smuzhiyun unw_get_reg(&c, UNW_REG_IP, &ips[i]);
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun /*
676*4882a593Smuzhiyun * Decrement the IP for any non-activation frames.
677*4882a593Smuzhiyun * this is required to properly find the srcline
678*4882a593Smuzhiyun * for caller frames.
679*4882a593Smuzhiyun * See also the documentation for dwfl_frame_pc(),
680*4882a593Smuzhiyun * which this code tries to replicate.
681*4882a593Smuzhiyun */
682*4882a593Smuzhiyun if (unw_is_signal_frame(&c) <= 0)
683*4882a593Smuzhiyun --ips[i];
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun ++i;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun max_stack = i;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun /*
692*4882a593Smuzhiyun * Display what we got based on the order setup.
693*4882a593Smuzhiyun */
694*4882a593Smuzhiyun for (i = 0; i < max_stack && !ret; i++) {
695*4882a593Smuzhiyun int j = i;
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun if (callchain_param.order == ORDER_CALLER)
698*4882a593Smuzhiyun j = max_stack - i - 1;
699*4882a593Smuzhiyun ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun return ret;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun
_unwind__get_entries(unwind_entry_cb_t cb,void * arg,struct thread * thread,struct perf_sample * data,int max_stack)705*4882a593Smuzhiyun static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,
706*4882a593Smuzhiyun struct thread *thread,
707*4882a593Smuzhiyun struct perf_sample *data, int max_stack)
708*4882a593Smuzhiyun {
709*4882a593Smuzhiyun struct unwind_info ui = {
710*4882a593Smuzhiyun .sample = data,
711*4882a593Smuzhiyun .thread = thread,
712*4882a593Smuzhiyun .machine = thread->maps->machine,
713*4882a593Smuzhiyun };
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun if (!data->user_regs.regs)
716*4882a593Smuzhiyun return -EINVAL;
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun if (max_stack <= 0)
719*4882a593Smuzhiyun return -EINVAL;
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun return get_entries(&ui, cb, arg, max_stack);
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun static struct unwind_libunwind_ops
725*4882a593Smuzhiyun _unwind_libunwind_ops = {
726*4882a593Smuzhiyun .prepare_access = _unwind__prepare_access,
727*4882a593Smuzhiyun .flush_access = _unwind__flush_access,
728*4882a593Smuzhiyun .finish_access = _unwind__finish_access,
729*4882a593Smuzhiyun .get_entries = _unwind__get_entries,
730*4882a593Smuzhiyun };
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun #ifndef REMOTE_UNWIND_LIBUNWIND
733*4882a593Smuzhiyun struct unwind_libunwind_ops *
734*4882a593Smuzhiyun local_unwind_libunwind_ops = &_unwind_libunwind_ops;
735*4882a593Smuzhiyun #endif
736