1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2008 CodeSourcery
3 Copyright (C) 2011-2013 Linaro Limited
4 Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
5
6 This file is part of libunwind.
7
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
26
27 #include "unwind_i.h"
28 #include "offsets.h"
29 #include "os-ohos.h"
30 /* Recognise PLT entries such as:
31 40ddf0: b0000570 adrp x16, 4ba000 <_GLOBAL_OFFSET_TABLE_+0x2a8>
32 40ddf4: f9433611 ldr x17, [x16,#1640]
33 40ddf8: 9119a210 add x16, x16, #0x668
34 40ddfc: d61f0220 br x17 */
35 static int
is_plt_entry(struct dwarf_cursor * c)36 is_plt_entry (struct dwarf_cursor *c)
37 {
38 unw_word_t w0, w1;
39 unw_accessors_t *a;
40 int ret;
41
42 a = unw_get_accessors_int (c->as);
43 if ((ret = (*a->access_mem) (c->as, c->ip, &w0, 0, c->as_arg)) < 0
44 || (ret = (*a->access_mem) (c->as, c->ip + 8, &w1, 0, c->as_arg)) < 0)
45 return 0;
46
47 ret = (((w0 & 0xff0000009f000000) == 0xf900000090000000)
48 && ((w1 & 0xffffffffff000000) == 0xd61f022091000000));
49
50 Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret);
51 return ret;
52 }
53
54 static int
aarch64_handle_signal_frame(unw_cursor_t * cursor)55 aarch64_handle_signal_frame (unw_cursor_t *cursor)
56 {
57 struct cursor *c = (struct cursor *) cursor;
58 int i, ret;
59 unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
60 struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0);
61
62 if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0)
63 return -UNW_EUNSPEC;
64
65 ret = unw_is_signal_frame (cursor);
66 Debug(1, "unw_is_signal_frame()=%d\n", ret);
67
68 /* Save the SP and PC to be able to return execution at this point
69 later in time (unw_resume). */
70 c->sigcontext_sp = c->dwarf.cfa;
71 c->sigcontext_pc = c->dwarf.ip;
72
73 if (ret > 0)
74 {
75 c->sigcontext_format = AARCH64_SCF_LINUX_RT_SIGFRAME;
76 sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
77 }
78 else
79 return -UNW_EUNSPEC;
80
81 c->sigcontext_addr = sc_addr;
82 c->frame_info.frame_type = UNW_AARCH64_FRAME_SIGRETURN;
83 c->frame_info.cfa_reg_offset = sc_addr - sp_addr;
84
85 for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
86 c->dwarf.loc[i] = DWARF_NULL_LOC;
87
88 /* Update the dwarf cursor.
89 Set the location of the registers to the corresponding addresses of the
90 uc_mcontext / sigcontext structure contents. */
91 c->dwarf.loc[UNW_AARCH64_X0] = DWARF_LOC (sc_addr + LINUX_SC_X0_OFF, 0);
92 c->dwarf.loc[UNW_AARCH64_X1] = DWARF_LOC (sc_addr + LINUX_SC_X1_OFF, 0);
93 c->dwarf.loc[UNW_AARCH64_X2] = DWARF_LOC (sc_addr + LINUX_SC_X2_OFF, 0);
94 c->dwarf.loc[UNW_AARCH64_X3] = DWARF_LOC (sc_addr + LINUX_SC_X3_OFF, 0);
95 c->dwarf.loc[UNW_AARCH64_X4] = DWARF_LOC (sc_addr + LINUX_SC_X4_OFF, 0);
96 c->dwarf.loc[UNW_AARCH64_X5] = DWARF_LOC (sc_addr + LINUX_SC_X5_OFF, 0);
97 c->dwarf.loc[UNW_AARCH64_X6] = DWARF_LOC (sc_addr + LINUX_SC_X6_OFF, 0);
98 c->dwarf.loc[UNW_AARCH64_X7] = DWARF_LOC (sc_addr + LINUX_SC_X7_OFF, 0);
99 c->dwarf.loc[UNW_AARCH64_X8] = DWARF_LOC (sc_addr + LINUX_SC_X8_OFF, 0);
100 c->dwarf.loc[UNW_AARCH64_X9] = DWARF_LOC (sc_addr + LINUX_SC_X9_OFF, 0);
101 c->dwarf.loc[UNW_AARCH64_X10] = DWARF_LOC (sc_addr + LINUX_SC_X10_OFF, 0);
102 c->dwarf.loc[UNW_AARCH64_X11] = DWARF_LOC (sc_addr + LINUX_SC_X11_OFF, 0);
103 c->dwarf.loc[UNW_AARCH64_X12] = DWARF_LOC (sc_addr + LINUX_SC_X12_OFF, 0);
104 c->dwarf.loc[UNW_AARCH64_X13] = DWARF_LOC (sc_addr + LINUX_SC_X13_OFF, 0);
105 c->dwarf.loc[UNW_AARCH64_X14] = DWARF_LOC (sc_addr + LINUX_SC_X14_OFF, 0);
106 c->dwarf.loc[UNW_AARCH64_X15] = DWARF_LOC (sc_addr + LINUX_SC_X15_OFF, 0);
107 c->dwarf.loc[UNW_AARCH64_X16] = DWARF_LOC (sc_addr + LINUX_SC_X16_OFF, 0);
108 c->dwarf.loc[UNW_AARCH64_X17] = DWARF_LOC (sc_addr + LINUX_SC_X17_OFF, 0);
109 c->dwarf.loc[UNW_AARCH64_X18] = DWARF_LOC (sc_addr + LINUX_SC_X18_OFF, 0);
110 c->dwarf.loc[UNW_AARCH64_X19] = DWARF_LOC (sc_addr + LINUX_SC_X19_OFF, 0);
111 c->dwarf.loc[UNW_AARCH64_X20] = DWARF_LOC (sc_addr + LINUX_SC_X20_OFF, 0);
112 c->dwarf.loc[UNW_AARCH64_X21] = DWARF_LOC (sc_addr + LINUX_SC_X21_OFF, 0);
113 c->dwarf.loc[UNW_AARCH64_X22] = DWARF_LOC (sc_addr + LINUX_SC_X22_OFF, 0);
114 c->dwarf.loc[UNW_AARCH64_X23] = DWARF_LOC (sc_addr + LINUX_SC_X23_OFF, 0);
115 c->dwarf.loc[UNW_AARCH64_X24] = DWARF_LOC (sc_addr + LINUX_SC_X24_OFF, 0);
116 c->dwarf.loc[UNW_AARCH64_X25] = DWARF_LOC (sc_addr + LINUX_SC_X25_OFF, 0);
117 c->dwarf.loc[UNW_AARCH64_X26] = DWARF_LOC (sc_addr + LINUX_SC_X26_OFF, 0);
118 c->dwarf.loc[UNW_AARCH64_X27] = DWARF_LOC (sc_addr + LINUX_SC_X27_OFF, 0);
119 c->dwarf.loc[UNW_AARCH64_X28] = DWARF_LOC (sc_addr + LINUX_SC_X28_OFF, 0);
120 c->dwarf.loc[UNW_AARCH64_X29] = DWARF_LOC (sc_addr + LINUX_SC_X29_OFF, 0);
121 c->dwarf.loc[UNW_AARCH64_X30] = DWARF_LOC (sc_addr + LINUX_SC_X30_OFF, 0);
122 c->dwarf.loc[UNW_AARCH64_SP] = DWARF_LOC (sc_addr + LINUX_SC_SP_OFF, 0);
123 c->dwarf.loc[UNW_AARCH64_PC] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0);
124 c->dwarf.loc[UNW_AARCH64_PSTATE] = DWARF_LOC (sc_addr + LINUX_SC_PSTATE_OFF, 0);
125
126 /* Set SP/CFA and PC/IP. */
127 dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_SP], &c->dwarf.cfa);
128 dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_PC], &c->dwarf.ip);
129 dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_X29], &c->dwarf.fp);
130
131 c->dwarf.pi_valid = 0;
132 c->dwarf.use_prev_instr = 0;
133
134 return 1;
135 }
136
137 static int
step_by_frame_pointer(struct cursor * c)138 step_by_frame_pointer (struct cursor *c)
139 {
140 dwarf_loc_t ip_loc, fp_loc;
141 unw_word_t frame;
142 if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_AARCH64_X29], &frame) < 0) {
143 return 0;
144 }
145
146 ip_loc = DWARF_LOC(frame + 8, 0);
147 fp_loc = DWARF_LOC(frame, 0);
148 if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0)
149 {
150 return 0;
151 }
152 c->dwarf.loc[UNW_AARCH64_PC] = ip_loc;
153 c->dwarf.loc[UNW_AARCH64_X29] = fp_loc;
154 return (c->dwarf.ip == 0) ? 0 : 1;
155 }
156
157 int
unw_step(unw_cursor_t * cursor)158 unw_step (unw_cursor_t *cursor)
159 {
160 struct cursor *c = (struct cursor *) cursor;
161 int validate = c->validate;
162 int ret;
163
164 Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx))\n",
165 c, c->dwarf.ip, c->dwarf.cfa);
166
167 /* Validate all addresses before dereferencing. */
168 c->validate = 1;
169
170 /* Check if this is a signal frame. */
171 ret = unw_is_signal_frame (cursor);
172 if (ret > 0)
173 {
174 ret = aarch64_handle_signal_frame (cursor);
175 }
176
177 /* Restore default memory validation state */
178 c->validate = validate;
179
180 ret = dwarf_step (&c->dwarf);
181 #ifdef HAS_ARK_FRAME
182 if (ret < 0 && unw_is_ark_managed_frame(c)) {
183 dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_X29], &c->dwarf.fp);
184 char buf[128] = {0};
185 ret = unw_step_ark_managed_native_frame(c->dwarf.as->pid == -1 ? getpid() : c->dwarf.as->pid,
186 (uintptr_t*)&(c->dwarf.ip), (uintptr_t*)&(c->dwarf.fp), (uintptr_t*)&(c->dwarf.cfa), buf, 128);
187 if (ret > 0) {
188 c->dwarf.loc[UNW_AARCH64_X29] = DWARF_LOC(c->dwarf.fp, 0);
189 c->dwarf.loc[UNW_AARCH64_PC] = DWARF_LOC(c->dwarf.fp + 8, 0);
190 }
191 }
192 #endif
193 if (ret < 0 && c->dwarf.index == 0)
194 {
195 /* IP points to non-mapped memory. */
196 /* This is probably SIGBUS. */
197 /* Try to load LR in IP to recover. */
198 Debug(1, "Invalid address found in the call stack: 0x%lx\n", c->dwarf.ip);
199 unw_word_t lr;
200 dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_X30], &lr);
201 if (lr != c->dwarf.ip) {
202 ret = 1;
203 c->dwarf.ip = lr;
204 }
205 }
206
207 if (unlikely (ret < 0))
208 {
209 /* DWARF failed. */
210 if (is_plt_entry (&c->dwarf))
211 {
212 Debug (2, "found plt entry\n");
213 c->frame_info.frame_type = UNW_AARCH64_FRAME_STANDARD;
214 /* Use link register (X30). */
215 c->frame_info.cfa_reg_offset = 0;
216 c->frame_info.cfa_reg_sp = 0;
217 c->frame_info.fp_cfa_offset = -1;
218 c->frame_info.lr_cfa_offset = -1;
219 c->frame_info.sp_cfa_offset = -1;
220 c->dwarf.loc[UNW_AARCH64_PC] = c->dwarf.loc[UNW_AARCH64_X30];
221 c->dwarf.loc[UNW_AARCH64_X30] = DWARF_NULL_LOC;
222 if (!DWARF_IS_NULL_LOC (c->dwarf.loc[UNW_AARCH64_PC]))
223 {
224 ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_PC], &c->dwarf.ip);
225 if (ret < 0)
226 {
227 Debug (2, "failed to get pc from link register: %d\n", ret);
228 return ret;
229 }
230 Debug (2, "link register (x30) = 0x%016lx\n", c->dwarf.ip);
231 ret = 1;
232 }
233 else
234 c->dwarf.ip = 0;
235 }
236 else if (c->dwarf.index < 10)
237 {
238 Debug (2, "fallback\n");
239 c->frame_info.frame_type = UNW_AARCH64_FRAME_GUESSED;
240 ret = step_by_frame_pointer(c);
241 }
242 }
243
244 c->dwarf.index++;
245 if (ret > 0)
246 return ret;
247
248 return (c->dwarf.ip == 0) ? 0 : 1;
249 }
250
251