xref: /OK3568_Linux_fs/kernel/tools/perf/util/unwind-libunwind-local.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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