1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/*
2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *
4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Lots of this code have been borrowed or heavily inspired from parts of
5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * the libunwind 0.99 code which are (amongst other contributors I may have
6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * forgotten):
7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *
8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Copyright (C) 2002-2007 Hewlett-Packard Co
9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *
11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * And the bugs have been added by:
12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *
13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com>
14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com>
15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *
16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */
17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <elf.h>
19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <gelf.h>
20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <fcntl.h>
21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <string.h>
22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <unistd.h>
23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <sys/mman.h>
24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <linux/list.h>
25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <libunwind.h>
26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <libunwind-ptrace.h>
27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "thread.h"
28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "session.h"
29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "perf_regs.h"
30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "unwind.h"
31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util.h"
32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengextern int
34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen ChengUNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    unw_word_t ip,
36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    unw_dyn_info_t *di,
37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    unw_proc_info_t *pi,
38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    int need_unwind_info, void *arg);
39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_FORMAT_MASK	0x0f	/* format of the encoded value */
43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_APPL_MASK	0x70	/* how the value is to be applied */
44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* Pointer-encoding formats: */
46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_omit		0xff
47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_ptr		0x00	/* pointer-sized unsigned value */
48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_udata4		0x03	/* unsigned 32-bit value */
49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_udata8		0x04	/* unsigned 64-bit value */
50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_sdata4		0x0b	/* signed 32-bit value */
51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_sdata8		0x0c	/* signed 64-bit value */
52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* Pointer-encoding application: */
54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_absptr		0x00	/* absolute value */
55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_pcrel		0x10	/* rel. to addr. of encoded value */
56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/*
58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * The following are not documented by LSB v1.3, yet they are used by
59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * GCC, presumably they aren't documented by LSB since they aren't
60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * used on Linux:
61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */
62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_funcrel	0x40	/* start-of-procedure-relative */
63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_aligned	0x50	/* aligned pointer */
64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* Flags intentionaly not handled, since they're not needed:
66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_indirect      0x80
67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_uleb128       0x01
68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_udata2        0x02
69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_sleb128       0x09
70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_sdata2        0x0a
71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_textrel       0x20
72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_datarel       0x30
73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */
74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct unwind_info {
76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_sample	*sample;
77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct machine		*machine;
78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread		*thread;
79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64			sample_uregs;
80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define dw_read(ptr, type, end) ({	\
83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	type *__p = (type *) ptr;	\
84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	type  __v;			\
85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if ((__p + 1) > (type *) end)	\
86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;		\
87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	__v = *__p++;			\
88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ptr = (typeof(ptr)) __p;	\
89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	__v;				\
90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	})
91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				   u8 encoding)
94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8 *cur = *p;
96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*val = 0;
97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	switch (encoding) {
99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case DW_EH_PE_omit:
100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*val = 0;
101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		goto out;
102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case DW_EH_PE_ptr:
103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*val = dw_read(cur, unsigned long, end);
104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		goto out;
105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	default:
106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	switch (encoding & DW_EH_PE_APPL_MASK) {
110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case DW_EH_PE_absptr:
111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case DW_EH_PE_pcrel:
113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*val = (unsigned long) cur;
114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	default:
116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if ((encoding & 0x07) == 0x00)
120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		encoding |= DW_EH_PE_udata4;
121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	switch (encoding & DW_EH_PE_FORMAT_MASK) {
123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case DW_EH_PE_sdata4:
124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*val += dw_read(cur, s32, end);
125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case DW_EH_PE_udata4:
127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*val += dw_read(cur, u32, end);
128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case DW_EH_PE_sdata8:
130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*val += dw_read(cur, s64, end);
131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case DW_EH_PE_udata8:
133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*val += dw_read(cur, u64, end);
134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	default:
136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng out:
140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*p = cur;
141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define dw_read_encoded_value(ptr, end, enc) ({			\
145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 __v;						\
146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (__dw_read_encoded_value(&ptr, end, &__v, enc)) {	\
147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;                                 \
148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}                                                       \
149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	__v;                                                    \
150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	})
151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				    GElf_Shdr *shp, const char *name)
154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	Elf_Scn *sec = NULL;
156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while ((sec = elf_nextscn(elf, sec)) != NULL) {
158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char *str;
159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		gelf_getshdr(sec, shp);
161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!strcmp(name, str))
163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return sec;
167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic u64 elf_section_offset(int fd, const char *name)
170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	Elf *elf;
172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	GElf_Ehdr ehdr;
173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	GElf_Shdr shdr;
174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 offset = 0;
175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (elf == NULL)
178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	do {
181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (gelf_getehdr(elf, &ehdr) == NULL)
182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (!elf_section_by_name(elf, &ehdr, &shdr, name))
185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		offset = shdr.sh_offset;
188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} while (0);
189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	elf_end(elf);
191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return offset;
192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct table_entry {
195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u32 start_ip_offset;
196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u32 fde_offset;
197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct eh_frame_hdr {
200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned char version;
201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned char eh_frame_ptr_enc;
202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned char fde_count_enc;
203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unsigned char table_enc;
204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * The rest of the header is variable-length and consists of the
207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * following members:
208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 *
209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 *	encoded_t eh_frame_ptr;
210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 *	encoded_t fde_count;
211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* A single encoded pointer should not be more than 8 bytes. */
214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 enc[2];
215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/*
217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * struct {
218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 *    encoded_t start_ip;
219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 *    encoded_t fde_addr;
220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 * } binary_search_table[fde_count];
221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	 */
222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char data[0];
223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} __packed;
224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			       u64 offset, u64 *table_data, u64 *segbase,
227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			       u64 *fde_count)
228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct eh_frame_hdr hdr;
230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8 *enc = (u8 *) &hdr.enc;
231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8 *end = (u8 *) &hdr.data;
232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ssize_t r;
233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	r = dso__data_read_offset(dso, machine, offset,
235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  (u8 *) &hdr, sizeof(hdr));
236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (r != sizeof(hdr))
237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* We dont need eh_frame_ptr, just skip it. */
240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*fde_count  = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*segbase    = offset;
244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*table_data = (enc - (u8 *) &hdr) + offset;
245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int read_unwind_spec(struct dso *dso, struct machine *machine,
249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    u64 *table_data, u64 *segbase, u64 *fde_count)
250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret = -EINVAL, fd;
252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 offset;
253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fd = dso__data_fd(dso, machine);
255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (fd < 0)
256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	offset = elf_section_offset(fd, ".eh_frame_hdr");
259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	close(fd);
260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (offset)
262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ret = unwind_spec_ehframe(dso, machine, offset,
263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					  table_data, segbase,
264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					  fde_count);
265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* TODO .debug_frame check if eh_frame_hdr fails */
267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ret;
268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct map *find_map(unw_word_t ip, struct unwind_info *ui)
271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct addr_location al;
273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			      MAP__FUNCTION, ip, &al);
276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return al.map;
277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int
280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengfind_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	       int need_unwind_info, void *arg)
282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct unwind_info *ui = arg;
284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map *map;
285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unw_dyn_info_t di;
286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 table_data, segbase, fde_count;
287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	map = find_map(ip, ui);
289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!map || !map->dso)
290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (read_unwind_spec(map->dso, ui->machine,
295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     &table_data, &segbase, &fde_count))
296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	memset(&di, 0, sizeof(di));
299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	di.format   = UNW_INFO_FORMAT_REMOTE_TABLE;
300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	di.start_ip = map->start;
301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	di.end_ip   = map->end;
302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	di.u.rti.segbase    = map->start + segbase;
303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	di.u.rti.table_data = map->start + table_data;
304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	di.u.rti.table_len  = fde_count * sizeof(struct table_entry)
305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			      / sizeof(unw_word_t);
306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return dwarf_search_unwind_table(as, ip, &di, pi,
307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					 need_unwind_info, arg);
308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int access_fpreg(unw_addr_space_t __maybe_unused as,
311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			unw_regnum_t __maybe_unused num,
312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			unw_fpreg_t __maybe_unused *val,
313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			int __maybe_unused __write,
314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			void __maybe_unused *arg)
315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_err("unwind: access_fpreg unsupported\n");
317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return -UNW_EINVAL;
318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  unw_word_t __maybe_unused *dil_addr,
322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				  void __maybe_unused *arg)
323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return -UNW_ENOINFO;
325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int resume(unw_addr_space_t __maybe_unused as,
328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		  unw_cursor_t __maybe_unused *cu,
329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		  void __maybe_unused *arg)
330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_err("unwind: resume unsupported\n");
332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return -UNW_EINVAL;
333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int
336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengget_proc_name(unw_addr_space_t __maybe_unused as,
337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	      unw_word_t __maybe_unused addr,
338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char __maybe_unused *bufp, size_t __maybe_unused buf_len,
339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_err("unwind: get_proc_name unsupported\n");
342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return -UNW_EINVAL;
343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			  unw_word_t *data)
347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct addr_location al;
349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ssize_t size;
350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			      MAP__FUNCTION, addr, &al);
353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!al.map) {
354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!al.map->dso)
359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				   addr, (u8 *) data, sizeof(*data));
363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return !(size == sizeof(*data));
365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		     u64 sample_regs)
369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i, idx = 0;
371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!(sample_regs & (1 << id)))
373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < id; i++) {
376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (sample_regs & (1 << i))
377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			idx++;
378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*valp = regs->regs[idx];
381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
383e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
384e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int access_mem(unw_addr_space_t __maybe_unused as,
385e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		      unw_word_t addr, unw_word_t *valp,
386e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		      int __write, void *arg)
387e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
388e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct unwind_info *ui = arg;
389e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct stack_dump *stack = &ui->sample->user_stack;
390e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unw_word_t start, end;
391e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int offset;
392e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret;
393e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
394e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* Don't support write, probably not needed. */
395e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (__write || !stack || !ui->sample->user_regs.regs) {
396e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*valp = 0;
397e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
398e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
399e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
400e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP,
401e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			ui->sample_uregs);
402e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ret)
403e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return ret;
404e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
405e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	end = start + stack->size;
406e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
407e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* Check overflow. */
408e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (addr + sizeof(unw_word_t) < addr)
409e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
410e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
411e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (addr < start || addr + sizeof(unw_word_t) >= end) {
412e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ret = access_dso_mem(ui, addr, valp);
413e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (ret) {
414e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			pr_debug("unwind: access_mem %p not inside range %p-%p\n",
415e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				(void *)addr, (void *)start, (void *)end);
416e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			*valp = 0;
417e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			return ret;
418e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
419e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
420e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
421e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
422e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	offset = addr - start;
423e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	*valp  = *(unw_word_t *)&stack->data[offset];
424e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
425e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 (void *)addr, (unsigned long)*valp, offset);
426e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
427e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
428e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
429e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int access_reg(unw_addr_space_t __maybe_unused as,
430e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		      unw_regnum_t regnum, unw_word_t *valp,
431e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		      int __write, void *arg)
432e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
433e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct unwind_info *ui = arg;
434e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int id, ret;
435e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
436e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* Don't support write, I suspect we don't need it. */
437e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (__write) {
438e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("unwind: access_reg w %d\n", regnum);
439e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
440e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
441e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
442e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!ui->sample->user_regs.regs) {
443e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		*valp = 0;
444e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
445e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
446e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
447e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	id = unwind__arch_reg_id(regnum);
448e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (id < 0)
449e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
450e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
451e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs);
452e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ret) {
453e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("unwind: can't read reg %d\n", regnum);
454e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return ret;
455e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
456e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
457e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
458e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
459e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
460e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
461e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void put_unwind_info(unw_addr_space_t __maybe_unused as,
462e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    unw_proc_info_t *pi __maybe_unused,
463e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			    void *arg __maybe_unused)
464e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
465e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_debug("unwind: put_unwind_info called\n");
466e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
467e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
468e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int entry(u64 ip, struct thread *thread, struct machine *machine,
469e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 unwind_entry_cb_t cb, void *arg)
470e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
471e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct unwind_entry e;
472e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct addr_location al;
473e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
474e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	thread__find_addr_location(thread, machine,
475e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				   PERF_RECORD_MISC_USER,
476e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				   MAP__FUNCTION, ip, &al);
477e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
478e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	e.ip = ip;
479e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	e.map = al.map;
480e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	e.sym = al.sym;
481e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
482e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
483e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 al.sym ? al.sym->name : "''",
484e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 ip,
485e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
486e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
487e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return cb(&e, arg);
488e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
489e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
490e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void display_error(int err)
491e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
492e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	switch (err) {
493e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case UNW_EINVAL:
494e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("unwind: Only supports local.\n");
495e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
496e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case UNW_EUNSPEC:
497e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("unwind: Unspecified error.\n");
498e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
499e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	case UNW_EBADREG:
500e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("unwind: Register unavailable.\n");
501e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
502e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	default:
503e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		break;
504e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
505e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
506e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
507e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic unw_accessors_t accessors = {
508e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.find_proc_info		= find_proc_info,
509e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.put_unwind_info	= put_unwind_info,
510e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.get_dyn_info_list_addr	= get_dyn_info_list_addr,
511e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.access_mem		= access_mem,
512e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.access_reg		= access_reg,
513e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.access_fpreg		= access_fpreg,
514e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.resume			= resume,
515e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	.get_proc_name		= get_proc_name,
516e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
517e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
518e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
519e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		       void *arg)
520e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
521e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unw_addr_space_t addr_space;
522e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unw_cursor_t c;
523e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret;
524e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
525e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	addr_space = unw_create_addr_space(&accessors, 0);
526e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!addr_space) {
527e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_err("unwind: Can't create unwind address space.\n");
528e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -ENOMEM;
529e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
530e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
531e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = unw_init_remote(&c, addr_space, ui);
532e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ret)
533e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		display_error(ret);
534e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
535e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (!ret && (unw_step(&c) > 0)) {
536e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		unw_word_t ip;
537e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
538e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		unw_get_reg(&c, UNW_REG_IP, &ip);
539e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ret = entry(ip, ui->thread, ui->machine, cb, arg);
540e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
541e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
542e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unw_destroy_addr_space(addr_space);
543e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ret;
544e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
545e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
546e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint unwind__get_entries(unwind_entry_cb_t cb, void *arg,
547e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			struct machine *machine, struct thread *thread,
548e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			u64 sample_uregs, struct perf_sample *data)
549e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
550e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	unw_word_t ip;
551e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct unwind_info ui = {
552e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.sample       = data,
553e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.sample_uregs = sample_uregs,
554e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.thread       = thread,
555e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.machine      = machine,
556e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
557e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret;
558e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
559e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!data->user_regs.regs)
560e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -EINVAL;
561e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
562e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs);
563e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ret)
564e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return ret;
565e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
566e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = entry(ip, thread, machine, cb, arg);
567e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ret)
568e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -ENOMEM;
569e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
570e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return get_entries(&ui, cb, arg);
571e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
572