1*b5893f02SDimitry Andric //===--------------------------- libunwind.cpp ----------------------------===//
2*b5893f02SDimitry Andric //
3*b5893f02SDimitry Andric //                     The LLVM Compiler Infrastructure
4*b5893f02SDimitry Andric //
5*b5893f02SDimitry Andric // This file is dual licensed under the MIT and the University of Illinois Open
6*b5893f02SDimitry Andric // Source Licenses. See LICENSE.TXT for details.
7*b5893f02SDimitry Andric //
8*b5893f02SDimitry Andric //
9*b5893f02SDimitry Andric //  Implements unw_* functions from <libunwind.h>
10*b5893f02SDimitry Andric //
11*b5893f02SDimitry Andric //===----------------------------------------------------------------------===//
12*b5893f02SDimitry Andric 
13*b5893f02SDimitry Andric #include <libunwind.h>
14*b5893f02SDimitry Andric 
15*b5893f02SDimitry Andric #ifndef NDEBUG
16*b5893f02SDimitry Andric #include <cstdlib> // getenv
17*b5893f02SDimitry Andric #endif
18*b5893f02SDimitry Andric #include <new>
19*b5893f02SDimitry Andric #include <algorithm>
20*b5893f02SDimitry Andric 
21*b5893f02SDimitry Andric #include "libunwind_ext.h"
22*b5893f02SDimitry Andric #include "config.h"
23*b5893f02SDimitry Andric 
24*b5893f02SDimitry Andric #include <stdlib.h>
25*b5893f02SDimitry Andric 
26*b5893f02SDimitry Andric 
27*b5893f02SDimitry Andric #if !defined(__USING_SJLJ_EXCEPTIONS__)
28*b5893f02SDimitry Andric #include "AddressSpace.hpp"
29*b5893f02SDimitry Andric #include "UnwindCursor.hpp"
30*b5893f02SDimitry Andric 
31*b5893f02SDimitry Andric using namespace libunwind;
32*b5893f02SDimitry Andric 
33*b5893f02SDimitry Andric /// internal object to represent this processes address space
34*b5893f02SDimitry Andric LocalAddressSpace LocalAddressSpace::sThisAddressSpace;
35*b5893f02SDimitry Andric 
36*b5893f02SDimitry Andric _LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
37*b5893f02SDimitry Andric     (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace;
38*b5893f02SDimitry Andric 
39*b5893f02SDimitry Andric /// record the registers and stack position of the caller
40*b5893f02SDimitry Andric extern int unw_getcontext(unw_context_t *);
41*b5893f02SDimitry Andric // note: unw_getcontext() implemented in assembly
42*b5893f02SDimitry Andric 
43*b5893f02SDimitry Andric /// Create a cursor of a thread in this process given 'context' recorded by
44*b5893f02SDimitry Andric /// unw_getcontext().
unw_init_local(unw_cursor_t * cursor,unw_context_t * context)45*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
46*b5893f02SDimitry Andric                                      unw_context_t *context) {
47*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)",
48*b5893f02SDimitry Andric                        static_cast<void *>(cursor),
49*b5893f02SDimitry Andric                        static_cast<void *>(context));
50*b5893f02SDimitry Andric #if defined(__i386__)
51*b5893f02SDimitry Andric # define REGISTER_KIND Registers_x86
52*b5893f02SDimitry Andric #elif defined(__x86_64__)
53*b5893f02SDimitry Andric # define REGISTER_KIND Registers_x86_64
54*b5893f02SDimitry Andric #elif defined(__powerpc64__)
55*b5893f02SDimitry Andric # define REGISTER_KIND Registers_ppc64
56*b5893f02SDimitry Andric #elif defined(__ppc__)
57*b5893f02SDimitry Andric # define REGISTER_KIND Registers_ppc
58*b5893f02SDimitry Andric #elif defined(__aarch64__)
59*b5893f02SDimitry Andric # define REGISTER_KIND Registers_arm64
60*b5893f02SDimitry Andric #elif defined(__arm__)
61*b5893f02SDimitry Andric # define REGISTER_KIND Registers_arm
62*b5893f02SDimitry Andric #elif defined(__or1k__)
63*b5893f02SDimitry Andric # define REGISTER_KIND Registers_or1k
64*b5893f02SDimitry Andric #elif defined(__riscv)
65*b5893f02SDimitry Andric # define REGISTER_KIND Registers_riscv
66*b5893f02SDimitry Andric #elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
67*b5893f02SDimitry Andric # define REGISTER_KIND Registers_mips_o32
68*b5893f02SDimitry Andric #elif defined(__mips64)
69*b5893f02SDimitry Andric # define REGISTER_KIND Registers_mips_newabi
70*b5893f02SDimitry Andric #elif defined(__mips__)
71*b5893f02SDimitry Andric # warning The MIPS architecture is not supported with this ABI and environment!
72*b5893f02SDimitry Andric #elif defined(__sparc__)
73*b5893f02SDimitry Andric # define REGISTER_KIND Registers_sparc
74*b5893f02SDimitry Andric #else
75*b5893f02SDimitry Andric # error Architecture not supported
76*b5893f02SDimitry Andric #endif
77*b5893f02SDimitry Andric   // Use "placement new" to allocate UnwindCursor in the cursor buffer.
78*b5893f02SDimitry Andric   new ((void *)cursor) UnwindCursor<LocalAddressSpace, REGISTER_KIND>(
79*b5893f02SDimitry Andric                                  context, LocalAddressSpace::sThisAddressSpace);
80*b5893f02SDimitry Andric #undef REGISTER_KIND
81*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
82*b5893f02SDimitry Andric   co->setInfoBasedOnIPRegister();
83*b5893f02SDimitry Andric 
84*b5893f02SDimitry Andric   return UNW_ESUCCESS;
85*b5893f02SDimitry Andric }
86*b5893f02SDimitry Andric 
87*b5893f02SDimitry Andric #ifdef UNW_REMOTE
88*b5893f02SDimitry Andric /// Create a cursor into a thread in another process.
unw_init_remote_thread(unw_cursor_t * cursor,unw_addr_space_t as,void * arg)89*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
90*b5893f02SDimitry Andric                                              unw_addr_space_t as,
91*b5893f02SDimitry Andric                                              void *arg) {
92*b5893f02SDimitry Andric   // special case: unw_init_remote(xx, unw_local_addr_space, xx)
93*b5893f02SDimitry Andric   if (as == (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace)
94*b5893f02SDimitry Andric     return unw_init_local(cursor, NULL); //FIXME
95*b5893f02SDimitry Andric 
96*b5893f02SDimitry Andric   // use "placement new" to allocate UnwindCursor in the cursor buffer
97*b5893f02SDimitry Andric   switch (as->cpuType) {
98*b5893f02SDimitry Andric   case CPU_TYPE_I386:
99*b5893f02SDimitry Andric     new ((void *)cursor)
100*b5893f02SDimitry Andric         UnwindCursor<RemoteAddressSpace<Pointer32<LittleEndian>>,
101*b5893f02SDimitry Andric                      Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg);
102*b5893f02SDimitry Andric     break;
103*b5893f02SDimitry Andric   case CPU_TYPE_X86_64:
104*b5893f02SDimitry Andric     new ((void *)cursor)
105*b5893f02SDimitry Andric         UnwindCursor<RemoteAddressSpace<Pointer64<LittleEndian>>,
106*b5893f02SDimitry Andric                      Registers_x86_64>(((unw_addr_space_x86_64 *)as)->oas, arg);
107*b5893f02SDimitry Andric     break;
108*b5893f02SDimitry Andric   case CPU_TYPE_POWERPC:
109*b5893f02SDimitry Andric     new ((void *)cursor)
110*b5893f02SDimitry Andric         UnwindCursor<RemoteAddressSpace<Pointer32<BigEndian>>,
111*b5893f02SDimitry Andric                      Registers_ppc>(((unw_addr_space_ppc *)as)->oas, arg);
112*b5893f02SDimitry Andric     break;
113*b5893f02SDimitry Andric   default:
114*b5893f02SDimitry Andric     return UNW_EUNSPEC;
115*b5893f02SDimitry Andric   }
116*b5893f02SDimitry Andric   return UNW_ESUCCESS;
117*b5893f02SDimitry Andric }
118*b5893f02SDimitry Andric 
119*b5893f02SDimitry Andric 
is64bit(task_t task)120*b5893f02SDimitry Andric static bool is64bit(task_t task) {
121*b5893f02SDimitry Andric   return false; // FIXME
122*b5893f02SDimitry Andric }
123*b5893f02SDimitry Andric 
124*b5893f02SDimitry Andric /// Create an address_space object for use in examining another task.
unw_create_addr_space_for_task(task_t task)125*b5893f02SDimitry Andric _LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) {
126*b5893f02SDimitry Andric #if __i386__
127*b5893f02SDimitry Andric   if (is64bit(task)) {
128*b5893f02SDimitry Andric     unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task);
129*b5893f02SDimitry Andric     as->taskPort = task;
130*b5893f02SDimitry Andric     as->cpuType = CPU_TYPE_X86_64;
131*b5893f02SDimitry Andric     //as->oas
132*b5893f02SDimitry Andric   } else {
133*b5893f02SDimitry Andric     unw_addr_space_i386 *as = new unw_addr_space_i386(task);
134*b5893f02SDimitry Andric     as->taskPort = task;
135*b5893f02SDimitry Andric     as->cpuType = CPU_TYPE_I386;
136*b5893f02SDimitry Andric     //as->oas
137*b5893f02SDimitry Andric   }
138*b5893f02SDimitry Andric #else
139*b5893f02SDimitry Andric // FIXME
140*b5893f02SDimitry Andric #endif
141*b5893f02SDimitry Andric }
142*b5893f02SDimitry Andric 
143*b5893f02SDimitry Andric 
144*b5893f02SDimitry Andric /// Delete an address_space object.
unw_destroy_addr_space(unw_addr_space_t asp)145*b5893f02SDimitry Andric _LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) {
146*b5893f02SDimitry Andric   switch (asp->cpuType) {
147*b5893f02SDimitry Andric #if __i386__ || __x86_64__
148*b5893f02SDimitry Andric   case CPU_TYPE_I386: {
149*b5893f02SDimitry Andric     unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp;
150*b5893f02SDimitry Andric     delete as;
151*b5893f02SDimitry Andric   }
152*b5893f02SDimitry Andric   break;
153*b5893f02SDimitry Andric   case CPU_TYPE_X86_64: {
154*b5893f02SDimitry Andric     unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp;
155*b5893f02SDimitry Andric     delete as;
156*b5893f02SDimitry Andric   }
157*b5893f02SDimitry Andric   break;
158*b5893f02SDimitry Andric #endif
159*b5893f02SDimitry Andric   case CPU_TYPE_POWERPC: {
160*b5893f02SDimitry Andric     unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp;
161*b5893f02SDimitry Andric     delete as;
162*b5893f02SDimitry Andric   }
163*b5893f02SDimitry Andric   break;
164*b5893f02SDimitry Andric   }
165*b5893f02SDimitry Andric }
166*b5893f02SDimitry Andric #endif // UNW_REMOTE
167*b5893f02SDimitry Andric 
168*b5893f02SDimitry Andric 
169*b5893f02SDimitry Andric /// Get value of specified register at cursor position in stack frame.
unw_get_reg(unw_cursor_t * cursor,unw_regnum_t regNum,unw_word_t * value)170*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
171*b5893f02SDimitry Andric                                   unw_word_t *value) {
172*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)",
173*b5893f02SDimitry Andric                        static_cast<void *>(cursor), regNum,
174*b5893f02SDimitry Andric                        static_cast<void *>(value));
175*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
176*b5893f02SDimitry Andric   if (co->validReg(regNum)) {
177*b5893f02SDimitry Andric     *value = co->getReg(regNum);
178*b5893f02SDimitry Andric     return UNW_ESUCCESS;
179*b5893f02SDimitry Andric   }
180*b5893f02SDimitry Andric   return UNW_EBADREG;
181*b5893f02SDimitry Andric }
182*b5893f02SDimitry Andric 
183*b5893f02SDimitry Andric 
184*b5893f02SDimitry Andric /// Set value of specified register at cursor position in stack frame.
unw_set_reg(unw_cursor_t * cursor,unw_regnum_t regNum,unw_word_t value)185*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
186*b5893f02SDimitry Andric                                   unw_word_t value) {
187*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR ")",
188*b5893f02SDimitry Andric                        static_cast<void *>(cursor), regNum, value);
189*b5893f02SDimitry Andric   typedef LocalAddressSpace::pint_t pint_t;
190*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
191*b5893f02SDimitry Andric   if (co->validReg(regNum)) {
192*b5893f02SDimitry Andric     co->setReg(regNum, (pint_t)value);
193*b5893f02SDimitry Andric     // specical case altering IP to re-find info (being called by personality
194*b5893f02SDimitry Andric     // function)
195*b5893f02SDimitry Andric     if (regNum == UNW_REG_IP) {
196*b5893f02SDimitry Andric       unw_proc_info_t info;
197*b5893f02SDimitry Andric       // First, get the FDE for the old location and then update it.
198*b5893f02SDimitry Andric       co->getInfo(&info);
199*b5893f02SDimitry Andric       co->setInfoBasedOnIPRegister(false);
200*b5893f02SDimitry Andric       // If the original call expects stack adjustment, perform this now.
201*b5893f02SDimitry Andric       // Normal frame unwinding would have included the offset already in the
202*b5893f02SDimitry Andric       // CFA computation.
203*b5893f02SDimitry Andric       // Note: for PA-RISC and other platforms where the stack grows up,
204*b5893f02SDimitry Andric       // this should actually be - info.gp. LLVM doesn't currently support
205*b5893f02SDimitry Andric       // any such platforms and Clang doesn't export a macro for them.
206*b5893f02SDimitry Andric       if (info.gp)
207*b5893f02SDimitry Andric         co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp);
208*b5893f02SDimitry Andric     }
209*b5893f02SDimitry Andric     return UNW_ESUCCESS;
210*b5893f02SDimitry Andric   }
211*b5893f02SDimitry Andric   return UNW_EBADREG;
212*b5893f02SDimitry Andric }
213*b5893f02SDimitry Andric 
214*b5893f02SDimitry Andric 
215*b5893f02SDimitry Andric /// Get value of specified float register at cursor position in stack frame.
unw_get_fpreg(unw_cursor_t * cursor,unw_regnum_t regNum,unw_fpreg_t * value)216*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
217*b5893f02SDimitry Andric                                     unw_fpreg_t *value) {
218*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)",
219*b5893f02SDimitry Andric                        static_cast<void *>(cursor), regNum,
220*b5893f02SDimitry Andric                        static_cast<void *>(value));
221*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
222*b5893f02SDimitry Andric   if (co->validFloatReg(regNum)) {
223*b5893f02SDimitry Andric     *value = co->getFloatReg(regNum);
224*b5893f02SDimitry Andric     return UNW_ESUCCESS;
225*b5893f02SDimitry Andric   }
226*b5893f02SDimitry Andric   return UNW_EBADREG;
227*b5893f02SDimitry Andric }
228*b5893f02SDimitry Andric 
229*b5893f02SDimitry Andric 
230*b5893f02SDimitry Andric /// Set value of specified float register at cursor position in stack frame.
unw_set_fpreg(unw_cursor_t * cursor,unw_regnum_t regNum,unw_fpreg_t value)231*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
232*b5893f02SDimitry Andric                                     unw_fpreg_t value) {
233*b5893f02SDimitry Andric #if defined(_LIBUNWIND_ARM_EHABI)
234*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)",
235*b5893f02SDimitry Andric                        static_cast<void *>(cursor), regNum, value);
236*b5893f02SDimitry Andric #else
237*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)",
238*b5893f02SDimitry Andric                        static_cast<void *>(cursor), regNum, value);
239*b5893f02SDimitry Andric #endif
240*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
241*b5893f02SDimitry Andric   if (co->validFloatReg(regNum)) {
242*b5893f02SDimitry Andric     co->setFloatReg(regNum, value);
243*b5893f02SDimitry Andric     return UNW_ESUCCESS;
244*b5893f02SDimitry Andric   }
245*b5893f02SDimitry Andric   return UNW_EBADREG;
246*b5893f02SDimitry Andric }
247*b5893f02SDimitry Andric 
248*b5893f02SDimitry Andric 
249*b5893f02SDimitry Andric /// Move cursor to next frame.
unw_step(unw_cursor_t * cursor)250*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) {
251*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_step(cursor=%p)", static_cast<void *>(cursor));
252*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
253*b5893f02SDimitry Andric   return co->step();
254*b5893f02SDimitry Andric }
255*b5893f02SDimitry Andric 
256*b5893f02SDimitry Andric 
257*b5893f02SDimitry Andric /// Get unwind info at cursor position in stack frame.
unw_get_proc_info(unw_cursor_t * cursor,unw_proc_info_t * info)258*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor,
259*b5893f02SDimitry Andric                                         unw_proc_info_t *info) {
260*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)",
261*b5893f02SDimitry Andric                        static_cast<void *>(cursor), static_cast<void *>(info));
262*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
263*b5893f02SDimitry Andric   co->getInfo(info);
264*b5893f02SDimitry Andric   if (info->end_ip == 0)
265*b5893f02SDimitry Andric     return UNW_ENOINFO;
266*b5893f02SDimitry Andric   else
267*b5893f02SDimitry Andric     return UNW_ESUCCESS;
268*b5893f02SDimitry Andric }
269*b5893f02SDimitry Andric 
270*b5893f02SDimitry Andric 
271*b5893f02SDimitry Andric /// Resume execution at cursor position (aka longjump).
unw_resume(unw_cursor_t * cursor)272*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) {
273*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)", static_cast<void *>(cursor));
274*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
275*b5893f02SDimitry Andric   co->jumpto();
276*b5893f02SDimitry Andric   return UNW_EUNSPEC;
277*b5893f02SDimitry Andric }
278*b5893f02SDimitry Andric 
279*b5893f02SDimitry Andric 
280*b5893f02SDimitry Andric /// Get name of function at cursor position in stack frame.
unw_get_proc_name(unw_cursor_t * cursor,char * buf,size_t bufLen,unw_word_t * offset)281*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf,
282*b5893f02SDimitry Andric                                         size_t bufLen, unw_word_t *offset) {
283*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)",
284*b5893f02SDimitry Andric                        static_cast<void *>(cursor), static_cast<void *>(buf),
285*b5893f02SDimitry Andric                        static_cast<unsigned long>(bufLen));
286*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
287*b5893f02SDimitry Andric   if (co->getFunctionName(buf, bufLen, offset))
288*b5893f02SDimitry Andric     return UNW_ESUCCESS;
289*b5893f02SDimitry Andric   else
290*b5893f02SDimitry Andric     return UNW_EUNSPEC;
291*b5893f02SDimitry Andric }
292*b5893f02SDimitry Andric 
293*b5893f02SDimitry Andric 
294*b5893f02SDimitry Andric /// Checks if a register is a floating-point register.
unw_is_fpreg(unw_cursor_t * cursor,unw_regnum_t regNum)295*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) {
296*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)",
297*b5893f02SDimitry Andric                        static_cast<void *>(cursor), regNum);
298*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
299*b5893f02SDimitry Andric   return co->validFloatReg(regNum);
300*b5893f02SDimitry Andric }
301*b5893f02SDimitry Andric 
302*b5893f02SDimitry Andric 
303*b5893f02SDimitry Andric /// Checks if a register is a floating-point register.
unw_regname(unw_cursor_t * cursor,unw_regnum_t regNum)304*b5893f02SDimitry Andric _LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor,
305*b5893f02SDimitry Andric                                           unw_regnum_t regNum) {
306*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)",
307*b5893f02SDimitry Andric                        static_cast<void *>(cursor), regNum);
308*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
309*b5893f02SDimitry Andric   return co->getRegisterName(regNum);
310*b5893f02SDimitry Andric }
311*b5893f02SDimitry Andric 
312*b5893f02SDimitry Andric 
313*b5893f02SDimitry Andric /// Checks if current frame is signal trampoline.
unw_is_signal_frame(unw_cursor_t * cursor)314*b5893f02SDimitry Andric _LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) {
315*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)",
316*b5893f02SDimitry Andric                        static_cast<void *>(cursor));
317*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
318*b5893f02SDimitry Andric   return co->isSignalFrame();
319*b5893f02SDimitry Andric }
320*b5893f02SDimitry Andric 
321*b5893f02SDimitry Andric #ifdef __arm__
322*b5893f02SDimitry Andric // Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD
unw_save_vfp_as_X(unw_cursor_t * cursor)323*b5893f02SDimitry Andric _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) {
324*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)",
325*b5893f02SDimitry Andric                        static_cast<void *>(cursor));
326*b5893f02SDimitry Andric   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
327*b5893f02SDimitry Andric   return co->saveVFPAsX();
328*b5893f02SDimitry Andric }
329*b5893f02SDimitry Andric #endif
330*b5893f02SDimitry Andric 
331*b5893f02SDimitry Andric 
332*b5893f02SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
333*b5893f02SDimitry Andric /// SPI: walks cached DWARF entries
unw_iterate_dwarf_unwind_cache(void (* func)(unw_word_t ip_start,unw_word_t ip_end,unw_word_t fde,unw_word_t mh))334*b5893f02SDimitry Andric _LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(
335*b5893f02SDimitry Andric     unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
336*b5893f02SDimitry Andric   _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)",
337*b5893f02SDimitry Andric                        reinterpret_cast<void *>(func));
338*b5893f02SDimitry Andric   DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
339*b5893f02SDimitry Andric }
340*b5893f02SDimitry Andric 
341*b5893f02SDimitry Andric 
342*b5893f02SDimitry Andric /// IPI: for __register_frame()
_unw_add_dynamic_fde(unw_word_t fde)343*b5893f02SDimitry Andric void _unw_add_dynamic_fde(unw_word_t fde) {
344*b5893f02SDimitry Andric   CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
345*b5893f02SDimitry Andric   CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
346*b5893f02SDimitry Andric   const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(
347*b5893f02SDimitry Andric                            LocalAddressSpace::sThisAddressSpace,
348*b5893f02SDimitry Andric                           (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);
349*b5893f02SDimitry Andric   if (message == NULL) {
350*b5893f02SDimitry Andric     // dynamically registered FDEs don't have a mach_header group they are in.
351*b5893f02SDimitry Andric     // Use fde as mh_group
352*b5893f02SDimitry Andric     unw_word_t mh_group = fdeInfo.fdeStart;
353*b5893f02SDimitry Andric     DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
354*b5893f02SDimitry Andric                                           fdeInfo.pcStart, fdeInfo.pcEnd,
355*b5893f02SDimitry Andric                                           fdeInfo.fdeStart);
356*b5893f02SDimitry Andric   } else {
357*b5893f02SDimitry Andric     _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message);
358*b5893f02SDimitry Andric   }
359*b5893f02SDimitry Andric }
360*b5893f02SDimitry Andric 
361*b5893f02SDimitry Andric /// IPI: for __deregister_frame()
_unw_remove_dynamic_fde(unw_word_t fde)362*b5893f02SDimitry Andric void _unw_remove_dynamic_fde(unw_word_t fde) {
363*b5893f02SDimitry Andric   // fde is own mh_group
364*b5893f02SDimitry Andric   DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
365*b5893f02SDimitry Andric }
366*b5893f02SDimitry Andric #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
367*b5893f02SDimitry Andric #endif // !defined(__USING_SJLJ_EXCEPTIONS__)
368*b5893f02SDimitry Andric 
369*b5893f02SDimitry Andric 
370*b5893f02SDimitry Andric 
371*b5893f02SDimitry Andric // Add logging hooks in Debug builds only
372*b5893f02SDimitry Andric #ifndef NDEBUG
373*b5893f02SDimitry Andric #include <stdlib.h>
374*b5893f02SDimitry Andric 
375*b5893f02SDimitry Andric _LIBUNWIND_HIDDEN
logAPIs()376*b5893f02SDimitry Andric bool logAPIs() {
377*b5893f02SDimitry Andric   // do manual lock to avoid use of _cxa_guard_acquire or initializers
378*b5893f02SDimitry Andric   static bool checked = false;
379*b5893f02SDimitry Andric   static bool log = false;
380*b5893f02SDimitry Andric   if (!checked) {
381*b5893f02SDimitry Andric     log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);
382*b5893f02SDimitry Andric     checked = true;
383*b5893f02SDimitry Andric   }
384*b5893f02SDimitry Andric   return log;
385*b5893f02SDimitry Andric }
386*b5893f02SDimitry Andric 
387*b5893f02SDimitry Andric _LIBUNWIND_HIDDEN
logUnwinding()388*b5893f02SDimitry Andric bool logUnwinding() {
389*b5893f02SDimitry Andric   // do manual lock to avoid use of _cxa_guard_acquire or initializers
390*b5893f02SDimitry Andric   static bool checked = false;
391*b5893f02SDimitry Andric   static bool log = false;
392*b5893f02SDimitry Andric   if (!checked) {
393*b5893f02SDimitry Andric     log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);
394*b5893f02SDimitry Andric     checked = true;
395*b5893f02SDimitry Andric   }
396*b5893f02SDimitry Andric   return log;
397*b5893f02SDimitry Andric }
398*b5893f02SDimitry Andric 
399*b5893f02SDimitry Andric _LIBUNWIND_HIDDEN
logDWARF()400*b5893f02SDimitry Andric bool logDWARF() {
401*b5893f02SDimitry Andric   // do manual lock to avoid use of _cxa_guard_acquire or initializers
402*b5893f02SDimitry Andric   static bool checked = false;
403*b5893f02SDimitry Andric   static bool log = false;
404*b5893f02SDimitry Andric   if (!checked) {
405*b5893f02SDimitry Andric     log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL);
406*b5893f02SDimitry Andric     checked = true;
407*b5893f02SDimitry Andric   }
408*b5893f02SDimitry Andric   return log;
409*b5893f02SDimitry Andric }
410*b5893f02SDimitry Andric 
411*b5893f02SDimitry Andric #endif // NDEBUG
412*b5893f02SDimitry Andric 
413