| /* libunwind - a platform-independent unwind library |
| Copyright (C) 2003, 2005 Hewlett-Packard Co |
| Contributed by David Mosberger-Tang <davidm@hpl.hp.com> |
| |
| This file is part of libunwind. |
| |
| Permission is hereby granted, free of charge, to any person obtaining |
| a copy of this software and associated documentation files (the |
| "Software"), to deal in the Software without restriction, including |
| without limitation the rights to use, copy, modify, merge, publish, |
| distribute, sublicense, and/or sell copies of the Software, and to |
| permit persons to whom the Software is furnished to do so, subject to |
| the following conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| |
| #ifndef unwind_internal_h |
| #define unwind_internal_h |
| |
| #define UNW_LOCAL_ONLY |
| |
| #include <unwind.h> |
| #include <stdlib.h> |
| #include <libunwind.h> |
| |
| #include "libunwind_i.h" |
| |
| /* The version of the _Unwind_*() interface implemented by this code. */ |
| #define _U_VERSION 1 |
| |
| typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn) |
| (int, _Unwind_Action, uint64_t, struct _Unwind_Exception *, |
| struct _Unwind_Context *); |
| |
| struct _Unwind_Context { |
| unw_cursor_t cursor; |
| int end_of_stack; /* set to 1 if the end of stack was reached */ |
| }; |
| |
| /* This must be a macro because unw_getcontext() must be invoked from |
| the callee, even if optimization (and hence inlining) is turned |
| off. The macro arguments MUST NOT have any side-effects. */ |
| #define _Unwind_InitContext(context, uc) \ |
| ((context)->end_of_stack = 0, \ |
| ((unw_getcontext (uc) < 0 || unw_init_local (&(context)->cursor, uc) < 0) \ |
| ? -1 : 0)) |
| |
| static _Unwind_Reason_Code ALWAYS_INLINE |
| _Unwind_Phase2 (struct _Unwind_Exception *exception_object, |
| struct _Unwind_Context *context, |
| /* ANDROID support update. */ |
| int *destroy_map) |
| /* End of ANDROID update. */ |
| { |
| _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) exception_object->private_1; |
| uint64_t exception_class = exception_object->exception_class; |
| void *stop_parameter = (void *) exception_object->private_2; |
| _Unwind_Personality_Fn personality; |
| _Unwind_Reason_Code reason; |
| _Unwind_Action actions; |
| unw_proc_info_t pi; |
| unw_word_t ip; |
| int ret; |
| |
| /* ANDROID support update. */ |
| *destroy_map = 1; |
| /* End of ANDROID update. */ |
| |
| actions = _UA_CLEANUP_PHASE; |
| if (stop) |
| actions |= _UA_FORCE_UNWIND; |
| |
| while (1) |
| { |
| ret = unw_step (&context->cursor); |
| if (ret <= 0) |
| { |
| /* ANDROID support update. */ |
| /* Treat any stop as end of stack. */ |
| actions |= _UA_END_OF_STACK; |
| context->end_of_stack = 1; |
| /* End of ANDROID support. */ |
| } |
| |
| if (stop) |
| { |
| /* ANDROID support update. */ |
| /* The stop function might not return, so free any local map. */ |
| unw_map_local_destroy (); |
| /* End of ANDROID support. */ |
| reason = (*stop) (_U_VERSION, actions, exception_class, |
| exception_object, context, stop_parameter); |
| if (reason != _URC_NO_REASON) |
| { |
| /* Stop function may return _URC_FATAL_PHASE2_ERROR if |
| it's unable to handle end-of-stack condition or |
| _URC_FATAL_PHASE2_ERROR if something is wrong. Not |
| that it matters: the resulting state is indeterminate |
| anyhow so we must return _URC_FATAL_PHASE2_ERROR... */ |
| *destroy_map = 0; |
| return _URC_FATAL_PHASE2_ERROR; |
| } |
| /* ANDROID support update. */ |
| unw_map_local_create (); |
| /* End of ANDROID support. */ |
| } |
| |
| if (context->end_of_stack |
| || unw_get_proc_info (&context->cursor, &pi) < 0) |
| return _URC_FATAL_PHASE2_ERROR; |
| |
| personality = (_Unwind_Personality_Fn) (uintptr_t) pi.handler; |
| if (personality) |
| { |
| if (!stop) |
| { |
| if (unw_get_reg (&context->cursor, UNW_REG_IP, &ip) < 0) |
| return _URC_FATAL_PHASE2_ERROR; |
| |
| if ((unsigned long) stop_parameter == ip) |
| actions |= _UA_HANDLER_FRAME; |
| } |
| |
| reason = (*personality) (_U_VERSION, actions, exception_class, |
| exception_object, context); |
| if (reason != _URC_CONTINUE_UNWIND) |
| { |
| if (reason == _URC_INSTALL_CONTEXT) |
| { |
| /* we may regain control via _Unwind_Resume() */ |
| unw_resume (&context->cursor); |
| abort (); |
| } |
| else |
| return _URC_FATAL_PHASE2_ERROR; |
| } |
| if (actions & _UA_HANDLER_FRAME) |
| /* The personality routine for the handler-frame changed |
| it's mind; that's a no-no... */ |
| abort (); |
| } |
| } |
| return _URC_FATAL_PHASE2_ERROR; /* shouldn't be reached */ |
| } |
| |
| #endif /* unwind_internal_h */ |