blob: 4079de38847fa618d41b32ac85a47eb893d8536a [file] [log] [blame]
Ed Maste17473fd2016-08-30 13:08:21 +00001//===--------------------------- libunwind.cpp ----------------------------===//
Saleem Abdulrasool675df582015-04-24 19:39:17 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//
9// Implements unw_* functions from <libunwind.h>
10//
11//===----------------------------------------------------------------------===//
12
13#include <libunwind.h>
14
15#ifndef NDEBUG
16#include <cstdlib> // getenv
17#endif
18#include <new>
Saleem Abdulrasoola802ef42015-05-11 16:35:13 +000019#include <algorithm>
Saleem Abdulrasool675df582015-04-24 19:39:17 +000020
21#include "libunwind_ext.h"
22#include "config.h"
23
24#include <stdlib.h>
25
26
Martin Storsjoe53dc3f2017-09-26 08:07:26 +000027#if !defined(__USING_SJLJ_EXCEPTIONS__)
Ed Schouten188f3c72017-03-09 08:04:07 +000028#include "AddressSpace.hpp"
Saleem Abdulrasool675df582015-04-24 19:39:17 +000029#include "UnwindCursor.hpp"
30
31using namespace libunwind;
32
33/// internal object to represent this processes address space
34LocalAddressSpace LocalAddressSpace::sThisAddressSpace;
35
36_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
37 (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace;
38
39/// record the registers and stack position of the caller
40extern int unw_getcontext(unw_context_t *);
41// note: unw_getcontext() implemented in assembly
42
43/// Create a cursor of a thread in this process given 'context' recorded by
44/// unw_getcontext().
45_LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
46 unw_context_t *context) {
Ed Masteadc29082016-08-30 15:38:10 +000047 _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +000048 static_cast<void *>(cursor),
49 static_cast<void *>(context));
Saleem Abdulrasool675df582015-04-24 19:39:17 +000050#if defined(__i386__)
Asiri Rathnayaked2d1ea92016-05-25 12:36:34 +000051# define REGISTER_KIND Registers_x86
Saleem Abdulrasool675df582015-04-24 19:39:17 +000052#elif defined(__x86_64__)
Asiri Rathnayaked2d1ea92016-05-25 12:36:34 +000053# define REGISTER_KIND Registers_x86_64
Martin Storsjodc25db12018-01-02 22:11:30 +000054#elif defined(__powerpc64__)
55# define REGISTER_KIND Registers_ppc64
Saleem Abdulrasool675df582015-04-24 19:39:17 +000056#elif defined(__ppc__)
Asiri Rathnayaked2d1ea92016-05-25 12:36:34 +000057# define REGISTER_KIND Registers_ppc
58#elif defined(__aarch64__)
59# define REGISTER_KIND Registers_arm64
Martin Storsjo23a943b2017-11-02 08:16:16 +000060#elif defined(__arm__)
Asiri Rathnayaked2d1ea92016-05-25 12:36:34 +000061# define REGISTER_KIND Registers_arm
Peter Zotovd4255ab2015-08-31 05:26:37 +000062#elif defined(__or1k__)
Asiri Rathnayaked2d1ea92016-05-25 12:36:34 +000063# define REGISTER_KIND Registers_or1k
John Baldwin375a3662017-12-12 21:43:36 +000064#elif defined(__mips__) && defined(_ABIO32) && defined(__mips_soft_float)
65# define REGISTER_KIND Registers_mips_o32
66#elif defined(__mips__) && defined(_ABI64) && defined(__mips_soft_float)
John Baldwinda0af182018-01-09 17:07:18 +000067# define REGISTER_KIND Registers_mips_newabi
Vasileios Kalintirisdb1c2632015-09-26 18:26:01 +000068#elif defined(__mips__)
John Baldwin375a3662017-12-12 21:43:36 +000069# warning The MIPS architecture is not supported with this ABI and environment!
Ed Maste40377de2015-08-13 14:21:03 +000070#else
Asiri Rathnayaked2d1ea92016-05-25 12:36:34 +000071# error Architecture not supported
Saleem Abdulrasool675df582015-04-24 19:39:17 +000072#endif
Asiri Rathnayaked2d1ea92016-05-25 12:36:34 +000073 // Use "placement new" to allocate UnwindCursor in the cursor buffer.
74 new ((void *)cursor) UnwindCursor<LocalAddressSpace, REGISTER_KIND>(
75 context, LocalAddressSpace::sThisAddressSpace);
76#undef REGISTER_KIND
Saleem Abdulrasool675df582015-04-24 19:39:17 +000077 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
78 co->setInfoBasedOnIPRegister();
79
80 return UNW_ESUCCESS;
81}
82
83#ifdef UNW_REMOTE
84/// Create a cursor into a thread in another process.
85_LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
86 unw_addr_space_t as,
87 void *arg) {
88 // special case: unw_init_remote(xx, unw_local_addr_space, xx)
89 if (as == (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace)
90 return unw_init_local(cursor, NULL); //FIXME
91
92 // use "placement new" to allocate UnwindCursor in the cursor buffer
93 switch (as->cpuType) {
94 case CPU_TYPE_I386:
95 new ((void *)cursor)
Saleem Abdulrasoolfa054682017-01-21 16:22:46 +000096 UnwindCursor<RemoteAddressSpace<Pointer32<LittleEndian>>,
Saleem Abdulrasool675df582015-04-24 19:39:17 +000097 Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg);
98 break;
99 case CPU_TYPE_X86_64:
Saleem Abdulrasoolfa054682017-01-21 16:22:46 +0000100 new ((void *)cursor)
101 UnwindCursor<RemoteAddressSpace<Pointer64<LittleEndian>>,
102 Registers_x86_64>(((unw_addr_space_x86_64 *)as)->oas, arg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000103 break;
104 case CPU_TYPE_POWERPC:
105 new ((void *)cursor)
Saleem Abdulrasoolfa054682017-01-21 16:22:46 +0000106 UnwindCursor<RemoteAddressSpace<Pointer32<BigEndian>>,
107 Registers_ppc>(((unw_addr_space_ppc *)as)->oas, arg);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000108 break;
109 default:
110 return UNW_EUNSPEC;
111 }
112 return UNW_ESUCCESS;
113}
114
115
116static bool is64bit(task_t task) {
117 return false; // FIXME
118}
119
120/// Create an address_space object for use in examining another task.
121_LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) {
122#if __i386__
123 if (is64bit(task)) {
124 unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task);
125 as->taskPort = task;
126 as->cpuType = CPU_TYPE_X86_64;
127 //as->oas
128 } else {
129 unw_addr_space_i386 *as = new unw_addr_space_i386(task);
130 as->taskPort = task;
131 as->cpuType = CPU_TYPE_I386;
132 //as->oas
133 }
134#else
135// FIXME
136#endif
137}
138
139
140/// Delete an address_space object.
141_LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) {
142 switch (asp->cpuType) {
143#if __i386__ || __x86_64__
144 case CPU_TYPE_I386: {
145 unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp;
146 delete as;
147 }
148 break;
149 case CPU_TYPE_X86_64: {
150 unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp;
151 delete as;
152 }
153 break;
154#endif
155 case CPU_TYPE_POWERPC: {
156 unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp;
157 delete as;
158 }
159 break;
160 }
161}
162#endif // UNW_REMOTE
163
164
165/// Get value of specified register at cursor position in stack frame.
166_LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
167 unw_word_t *value) {
Ed Masteadc29082016-08-30 15:38:10 +0000168 _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000169 static_cast<void *>(cursor), regNum,
170 static_cast<void *>(value));
171 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
172 if (co->validReg(regNum)) {
173 *value = co->getReg(regNum);
174 return UNW_ESUCCESS;
175 }
176 return UNW_EBADREG;
177}
178
179
180/// Set value of specified register at cursor position in stack frame.
181_LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
182 unw_word_t value) {
Martin Storsjo85f4cfd2017-10-30 19:06:34 +0000183 _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR ")",
184 static_cast<void *>(cursor), regNum, value);
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000185 typedef LocalAddressSpace::pint_t pint_t;
186 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
187 if (co->validReg(regNum)) {
188 co->setReg(regNum, (pint_t)value);
189 // specical case altering IP to re-find info (being called by personality
190 // function)
191 if (regNum == UNW_REG_IP)
192 co->setInfoBasedOnIPRegister(false);
193 return UNW_ESUCCESS;
194 }
195 return UNW_EBADREG;
196}
197
198
199/// Get value of specified float register at cursor position in stack frame.
200_LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
201 unw_fpreg_t *value) {
Ed Masteadc29082016-08-30 15:38:10 +0000202 _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000203 static_cast<void *>(cursor), regNum,
204 static_cast<void *>(value));
205 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
206 if (co->validFloatReg(regNum)) {
207 *value = co->getFloatReg(regNum);
208 return UNW_ESUCCESS;
209 }
210 return UNW_EBADREG;
211}
212
213
214/// Set value of specified float register at cursor position in stack frame.
215_LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
216 unw_fpreg_t value) {
Ranjeet Singh7d674132017-03-31 15:28:06 +0000217#if defined(_LIBUNWIND_ARM_EHABI)
Ed Masteadc29082016-08-30 15:38:10 +0000218 _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000219 static_cast<void *>(cursor), regNum, value);
220#else
Ed Masteadc29082016-08-30 15:38:10 +0000221 _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000222 static_cast<void *>(cursor), regNum, value);
223#endif
224 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
225 if (co->validFloatReg(regNum)) {
226 co->setFloatReg(regNum, value);
227 return UNW_ESUCCESS;
228 }
229 return UNW_EBADREG;
230}
231
232
233/// Move cursor to next frame.
234_LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) {
Ed Masteadc29082016-08-30 15:38:10 +0000235 _LIBUNWIND_TRACE_API("unw_step(cursor=%p)", static_cast<void *>(cursor));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000236 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
237 return co->step();
238}
239
240
241/// Get unwind info at cursor position in stack frame.
242_LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor,
243 unw_proc_info_t *info) {
Ed Masteadc29082016-08-30 15:38:10 +0000244 _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000245 static_cast<void *>(cursor), static_cast<void *>(info));
246 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
247 co->getInfo(info);
248 if (info->end_ip == 0)
249 return UNW_ENOINFO;
250 else
251 return UNW_ESUCCESS;
252}
253
254
255/// Resume execution at cursor position (aka longjump).
256_LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) {
Ed Masteadc29082016-08-30 15:38:10 +0000257 _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)", static_cast<void *>(cursor));
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000258 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
259 co->jumpto();
260 return UNW_EUNSPEC;
261}
262
263
264/// Get name of function at cursor position in stack frame.
265_LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf,
266 size_t bufLen, unw_word_t *offset) {
Ed Masteadc29082016-08-30 15:38:10 +0000267 _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000268 static_cast<void *>(cursor), static_cast<void *>(buf),
269 static_cast<unsigned long>(bufLen));
270 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
271 if (co->getFunctionName(buf, bufLen, offset))
272 return UNW_ESUCCESS;
273 else
274 return UNW_EUNSPEC;
275}
276
277
278/// Checks if a register is a floating-point register.
279_LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) {
Ed Masteadc29082016-08-30 15:38:10 +0000280 _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000281 static_cast<void *>(cursor), regNum);
282 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
283 return co->validFloatReg(regNum);
284}
285
286
287/// Checks if a register is a floating-point register.
288_LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor,
289 unw_regnum_t regNum) {
Ed Masteadc29082016-08-30 15:38:10 +0000290 _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000291 static_cast<void *>(cursor), regNum);
292 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
293 return co->getRegisterName(regNum);
294}
295
296
297/// Checks if current frame is signal trampoline.
298_LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) {
Ed Masteadc29082016-08-30 15:38:10 +0000299 _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000300 static_cast<void *>(cursor));
301 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
302 return co->isSignalFrame();
303}
304
305#ifdef __arm__
306// Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD
307_LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) {
Ed Masteadc29082016-08-30 15:38:10 +0000308 _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000309 static_cast<void *>(cursor));
310 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
311 return co->saveVFPAsX();
312}
313#endif
314
315
Ranjeet Singh7d674132017-03-31 15:28:06 +0000316#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Ed Maste63469ff2016-07-19 17:15:50 +0000317/// SPI: walks cached DWARF entries
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000318_LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(
319 unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
Ed Masteadc29082016-08-30 15:38:10 +0000320 _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)",
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000321 reinterpret_cast<void *>(func));
322 DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
323}
324
325
326/// IPI: for __register_frame()
327void _unw_add_dynamic_fde(unw_word_t fde) {
328 CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
329 CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
330 const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(
331 LocalAddressSpace::sThisAddressSpace,
332 (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);
333 if (message == NULL) {
334 // dynamically registered FDEs don't have a mach_header group they are in.
335 // Use fde as mh_group
336 unw_word_t mh_group = fdeInfo.fdeStart;
337 DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
338 fdeInfo.pcStart, fdeInfo.pcEnd,
339 fdeInfo.fdeStart);
340 } else {
341 _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message);
342 }
343}
344
345/// IPI: for __deregister_frame()
346void _unw_remove_dynamic_fde(unw_word_t fde) {
347 // fde is own mh_group
348 DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
349}
Ranjeet Singh7d674132017-03-31 15:28:06 +0000350#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Martin Storsjoe53dc3f2017-09-26 08:07:26 +0000351#endif // !defined(__USING_SJLJ_EXCEPTIONS__)
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000352
353
354
355// Add logging hooks in Debug builds only
356#ifndef NDEBUG
357#include <stdlib.h>
358
359_LIBUNWIND_HIDDEN
360bool logAPIs() {
361 // do manual lock to avoid use of _cxa_guard_acquire or initializers
362 static bool checked = false;
363 static bool log = false;
364 if (!checked) {
365 log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);
366 checked = true;
367 }
368 return log;
369}
370
371_LIBUNWIND_HIDDEN
372bool logUnwinding() {
373 // do manual lock to avoid use of _cxa_guard_acquire or initializers
374 static bool checked = false;
375 static bool log = false;
376 if (!checked) {
377 log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);
378 checked = true;
379 }
380 return log;
381}
382
Saleem Abdulrasoole1d4b2e2017-01-21 16:22:57 +0000383_LIBUNWIND_HIDDEN
384bool logDWARF() {
385 // do manual lock to avoid use of _cxa_guard_acquire or initializers
386 static bool checked = false;
387 static bool log = false;
388 if (!checked) {
389 log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL);
390 checked = true;
391 }
392 return log;
393}
394
Saleem Abdulrasool675df582015-04-24 19:39:17 +0000395#endif // NDEBUG
396