xref: /minix3/sys/lib/libunwind/libunwind.cxx (revision b5e2faaaaf60a8b9a02f8d72f64caa56a87eb312)
1 //===--------------------------- libuwind.cpp -----------------------------===//
2 //
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 C++ ABI Exception Handling Level 1 as documented at:
10 //      http://mentorembedded.github.io/cxx-abi/abi-eh.html
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include <unwind.h>
15 
16 #include "UnwindCursor.hpp"
17 
18 using namespace _Unwind;
19 
20 typedef CFI_Parser<LocalAddressSpace, NativeUnwindRegisters> MyCFIParser;
21 
22 // Internal object representing the address space of this process.
23 static LocalAddressSpace sThisAddressSpace(MyCFIParser::findPCRange);
24 
25 typedef UnwindCursor<LocalAddressSpace, NativeUnwindRegisters> ThisUnwindCursor;
26 
27 static _Unwind_Reason_Code unwind_phase1(ThisUnwindCursor &cursor,
28                                          struct _Unwind_Exception *exc) {
29   cursor.setInfoBasedOnIPRegister();
30 
31   // Walk frames looking for a place to stop.
32   for (;;) {
33     // Get next frame.
34     // First frame is _Unwind_RaiseException and skipped.
35     switch (cursor.step()) {
36     case UNW_STEP_END:
37       return _URC_END_OF_STACK;
38     case UNW_STEP_FAILED:
39       return _URC_FATAL_PHASE1_ERROR;
40     case UNW_STEP_SUCCESS:
41       break;
42     }
43 
44     // Check if there is a personality routine for this frame.
45     unw_proc_info_t frameInfo;
46     cursor.getInfo(&frameInfo);
47     if (frameInfo.end_ip == 0)
48       return _URC_FATAL_PHASE1_ERROR;
49 
50     if (frameInfo.handler == 0)
51       continue; // No personality routine, so try next frame.
52 
53     __personality_routine p = (__personality_routine)(frameInfo.handler);
54     _Unwind_Reason_Code result = (*p)(1, _UA_SEARCH_PHASE, exc->exception_class,
55                                       exc, (struct _Unwind_Context *)(&cursor));
56 
57     switch (result) {
58     case _URC_HANDLER_FOUND:
59       // This is either a catch clause or a local variable
60       // with destructor.
61       // Stop search and remember the frame for phase 2.
62       exc->private_2 = cursor.getSP();
63       return _URC_NO_REASON;
64 
65     case _URC_CONTINUE_UNWIND:
66       // Continue unwinding
67       break;
68 
69     default:
70       // Bad personality routine.
71       return _URC_FATAL_PHASE1_ERROR;
72     }
73   }
74 }
75 
76 static _Unwind_Reason_Code unwind_phase2(ThisUnwindCursor &cursor,
77                                          struct _Unwind_Exception *exc) {
78   cursor.setInfoBasedOnIPRegister();
79 
80   // Walk frames until the frame selected in phase 1 is reached.
81   for (;;) {
82     // Get next frame.
83     // First frame is _Unwind_RaiseException and skipped.
84     switch (cursor.step()) {
85     case UNW_STEP_END:
86       return _URC_END_OF_STACK;
87     case UNW_STEP_FAILED:
88       return _URC_FATAL_PHASE2_ERROR;
89     case UNW_STEP_SUCCESS:
90       break;
91     }
92 
93     unw_proc_info_t frameInfo;
94     cursor.getInfo(&frameInfo);
95     if (frameInfo.end_ip == 0)
96       return _URC_FATAL_PHASE2_ERROR;
97 
98     if (frameInfo.handler == 0)
99       continue; // No personality routine, continue.
100 
101     uintptr_t sp = cursor.getSP();
102 
103     _Unwind_Action action = _UA_CLEANUP_PHASE;
104     // If this frame was selected in phase 1,
105     // inform the personality routine.
106     if (sp == exc->private_2)
107       action = (_Unwind_Action)(action | _UA_HANDLER_FRAME);
108     __personality_routine p = (__personality_routine)(frameInfo.handler);
109     _Unwind_Reason_Code result = (*p)(1, action, exc->exception_class, exc,
110                                       (struct _Unwind_Context *)(&cursor));
111     switch (result) {
112     case _URC_CONTINUE_UNWIND:
113       // Continue unwinding unless the selected frame passed.
114       if (sp == exc->private_2)
115         return _URC_FATAL_PHASE2_ERROR;
116       break;
117     case _URC_INSTALL_CONTEXT:
118       // Transfer control to landing pad.
119       cursor.jumpto();
120     default:
121       // Bad personality routine.
122       return _URC_FATAL_PHASE2_ERROR;
123     }
124   }
125 }
126 
127 static _Unwind_Reason_Code unwind_phase2_forced(ThisUnwindCursor &cursor,
128                                                 struct _Unwind_Exception *exc,
129                                                 _Unwind_Stop_Fn stop,
130                                                 void *stop_arg) {
131   _Unwind_Action action;
132   cursor.setInfoBasedOnIPRegister();
133 
134   // Walk frames until the frame selected in phase 1 is reached.
135   for (;;) {
136     // Get next frame.
137     // First frame is _Unwind_RaiseException and skipped.
138     switch (cursor.step()) {
139     case UNW_STEP_END:
140     case UNW_STEP_FAILED:
141       // End of stack or error condition.
142       // Call the stop function one last time.
143       action = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE |
144                                 _UA_END_OF_STACK);
145       (*stop)(1, action, exc->exception_class, exc,
146               (struct _Unwind_Context *)(&cursor), stop_arg);
147 
148       // Didn't stop at the expected frame, so return error.
149       return _URC_FATAL_PHASE2_ERROR;
150 
151     case UNW_STEP_SUCCESS:
152       break;
153     }
154 
155     unw_proc_info_t frameInfo;
156     cursor.getInfo(&frameInfo);
157     if (frameInfo.end_ip == 0)
158       return _URC_FATAL_PHASE2_ERROR;
159 
160     // Call stop function for each frame
161     action = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
162     _Unwind_Reason_Code result =
163         (*stop)(1, action, exc->exception_class, exc,
164                 (struct _Unwind_Context *)(&cursor), stop_arg);
165     if (result != _URC_NO_REASON)
166       return _URC_FATAL_PHASE2_ERROR;
167 
168     if (frameInfo.handler == 0)
169       continue; // No personality routine, continue.
170 
171     __personality_routine p = (__personality_routine)(frameInfo.handler);
172     result = (*p)(1, action, exc->exception_class, exc,
173                   (struct _Unwind_Context *)(&cursor));
174 
175     switch (result) {
176     case _URC_CONTINUE_UNWIND:
177       // Destructors called, continue.
178       break;
179     case _URC_INSTALL_CONTEXT:
180       // Transfer control to landing pad.
181       cursor.jumpto();
182     default:
183       // Bad personality routine.
184       return _URC_FATAL_PHASE2_ERROR;
185     }
186   }
187 }
188 
189 _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *exc) {
190   NativeUnwindRegisters registers;
191   ThisUnwindCursor cursor1(registers, sThisAddressSpace);
192   ThisUnwindCursor cursor2(registers, sThisAddressSpace);
193 
194   // Mark this as a non-forced unwind for _Unwind_Resume().
195   exc->private_1 = 0;
196   exc->private_2 = 0;
197 
198   // Phase 1: searching.
199   _Unwind_Reason_Code phase1 = unwind_phase1(cursor1, exc);
200   if (phase1 != _URC_NO_REASON)
201     return phase1;
202 
203   // Phase 2: cleaning up.
204   return unwind_phase2(cursor2, exc);
205 }
206 
207 _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception *exc,
208                                          _Unwind_Stop_Fn stop, void *stop_arg) {
209   NativeUnwindRegisters registers;
210   ThisUnwindCursor cursor(registers, sThisAddressSpace);
211 
212   // Mark this as forced unwind for _Unwind_Resume().
213   exc->private_1 = (uintptr_t)stop;
214   exc->private_2 = (uintptr_t)stop_arg;
215 
216   return unwind_phase2_forced(cursor, exc, stop, stop_arg);
217 }
218 
219 void _Unwind_Resume(struct _Unwind_Exception *exc) {
220   NativeUnwindRegisters registers;
221   ThisUnwindCursor cursor(registers, sThisAddressSpace);
222 
223   if (exc->private_1 != 0)
224     unwind_phase2_forced(cursor, exc, (_Unwind_Stop_Fn)exc->private_1,
225                          (void *)exc->private_2);
226   else
227     unwind_phase2(cursor, exc);
228   abort();
229 }
230 
231 _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exc) {
232   // This is a re-throw, if this is a non-forced unwind
233   // and the stopping place was found.
234   // In that case, call _Unwind_RaiseException() as if
235   // it was a new exception.
236 
237   if (exc->private_1 != 0)
238     _Unwind_Resume(exc);
239 
240   // This can return if there is no catch clause.
241   // In that case, __cxa_rethrow is expected to call std::terminate().
242   return _Unwind_RaiseException(exc);
243 }
244 
245 void _Unwind_DeleteException(struct _Unwind_Exception *exc) {
246   if (exc->exception_cleanup != NULL)
247     (*exc->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
248 }
249 
250 uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) {
251   ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
252   return cursor->getReg(index);
253 }
254 
255 void _Unwind_SetGR(struct _Unwind_Context *context, int index,
256                    uintptr_t new_value) {
257   ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
258   cursor->setReg(index, new_value);
259 }
260 
261 uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
262   ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
263   return cursor->getIP();
264 }
265 
266 uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, int *isSignalFrame) {
267   ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
268   *isSignalFrame = cursor->isSignalFrame() ? 1 : 0;
269   return cursor->getIP();
270 }
271 
272 void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t new_value) {
273   ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
274   cursor->setIP(new_value);
275   unw_proc_info_t info;
276   cursor->getInfo(&info);
277   cursor->setInfoBasedOnIPRegister(false);
278 }
279 
280 uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context) {
281   ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
282   unw_proc_info_t frameInfo;
283   cursor->getInfo(&frameInfo);
284   return frameInfo.end_ip ? frameInfo.start_ip : 0;
285 }
286 
287 uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
288   ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
289   unw_proc_info_t frameInfo;
290   cursor->getInfo(&frameInfo);
291   return frameInfo.end_ip ? frameInfo.lsda : 0;
292 }
293 
294 _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
295   NativeUnwindRegisters registers;
296   ThisUnwindCursor cursor(registers, sThisAddressSpace);
297   cursor.setInfoBasedOnIPRegister();
298 
299   // Walk each frame.
300   while (true) {
301 
302     // Ask libuwind to get next frame (skip over first frame which is
303     // _Unwind_Backtrace()).
304     if (cursor.step() != UNW_STEP_SUCCESS)
305       return _URC_END_OF_STACK;
306 
307     // Call trace function with this frame.
308     _Unwind_Reason_Code result =
309         (*callback)((struct _Unwind_Context *)(&cursor), ref);
310     if (result != _URC_NO_REASON)
311       return result;
312   }
313 }
314 
315 uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
316   ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
317   return cursor->getSP();
318 }
319 
320 void *_Unwind_FindEnclosingFunction(void *pc) {
321   NativeUnwindRegisters registers;
322   ThisUnwindCursor cursor(registers, sThisAddressSpace);
323 
324   unw_proc_info_t info;
325   cursor.setIP((uintptr_t)pc);
326   cursor.setInfoBasedOnIPRegister();
327 
328   cursor.getInfo(&info);
329   return info.end_ip ? (void *)info.start_ip : NULL;
330 }
331 
332 uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) {
333   ThisUnwindCursor *cursor = (ThisUnwindCursor *)context;
334   unw_proc_info_t frameInfo;
335   cursor->getInfo(&frameInfo);
336   return frameInfo.data_base;
337 }
338 
339 uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) { return 0; }
340 
341 void __register_frame(const void *fde) {
342   MyCFIParser::pint_t pcStart, pcEnd;
343 
344   MyCFIParser::findPCRange(sThisAddressSpace, (uintptr_t)fde, pcStart, pcEnd);
345   if (pcEnd == 0)
346     return; // Bad FDE.
347 
348   sThisAddressSpace.addFDE(pcStart, pcEnd, (uintptr_t)fde);
349 }
350 
351 void __register_frame_info(const void *ehframe, void *storage) {
352   sThisAddressSpace.setLazyReload();
353 }
354 
355 void __deregister_frame(const void *fde) {
356   MyCFIParser::pint_t pcStart, pcEnd;
357 
358   MyCFIParser::findPCRange(sThisAddressSpace, (uintptr_t)fde, pcStart, pcEnd);
359   if (pcEnd == 0)
360     return; // Bad FDE.
361 
362   sThisAddressSpace.removeFDE(pcStart, pcEnd, (uintptr_t)fde);
363 }
364 
365 void *__deregister_frame_info(const void *ehFrameStart) {
366   sThisAddressSpace.removeDSO((LocalAddressSpace::pint_t)ehFrameStart);
367   return NULL;
368 }
369