diff options
Diffstat (limited to 'sys/contrib/ia64/libuwx/src/uwx_utable.c')
-rw-r--r-- | sys/contrib/ia64/libuwx/src/uwx_utable.c | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/sys/contrib/ia64/libuwx/src/uwx_utable.c b/sys/contrib/ia64/libuwx/src/uwx_utable.c new file mode 100644 index 0000000..908a3ae --- /dev/null +++ b/sys/contrib/ia64/libuwx/src/uwx_utable.c @@ -0,0 +1,273 @@ +/* +Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P. +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. +*/ + +#include "uwx_env.h" +#include "uwx_utable.h" +#include "uwx_swap.h" +#include "uwx_trace.h" + +/* + * uwx_utable.c + * + * This file contains the routines for searching an unwind table. + * The main entry point, uwx_search_utable(), gets the + * necessary information from the lookup ip callback's result + * vector, determines whether the table is 32-bit or 64-bit, + * then invokes the binary search routine for that format. + */ + + +/* Forward declarations */ + +int uwx_search_utable32( + struct uwx_env *env, + uint32_t ip, + uint32_t text_base, + uint32_t unwind_start, + uint32_t unwind_end, + struct uwx_utable_entry *uentry); + +int uwx_search_utable64( + struct uwx_env *env, + uint64_t ip, + uint64_t text_base, + uint64_t unwind_start, + uint64_t unwind_end, + struct uwx_utable_entry *uentry); + + +/* uwx_search_utable: Searches an unwind table for IP in current context */ + +int uwx_search_utable( + struct uwx_env *env, + uint64_t ip, + uint64_t *uvec, + struct uwx_utable_entry *uentry) +{ + uint64_t text_base; + uint64_t unwind_flags; + uint64_t unwind_start; + uint64_t unwind_end; + int keys; + int status; + + /* Get unwind table information from the result vector. */ + /* Make sure all three required values are given. */ + + keys = 0; + text_base = 0; + unwind_flags = 0; + unwind_start = 0; + unwind_end = 0; + while (*uvec != 0) { + switch ((int)*uvec++) { + case UWX_KEY_TBASE: + keys |= 1; + env->text_base = text_base = *uvec++; + break; + case UWX_KEY_UFLAGS: + unwind_flags = *uvec++; + break; + case UWX_KEY_USTART: + keys |= 2; + unwind_start = *uvec++; + break; + case UWX_KEY_UEND: + keys |= 4; + unwind_end = *uvec++; + break; + case UWX_KEY_GP: + uwx_set_reg(env, UWX_REG_GP, *uvec++); + break; + default: + return UWX_ERR_BADKEY; + } + } + if (keys != 7) + return UWX_ERR_BADKEY; + + /* Copy the unwind flags into the unwind entry. */ + /* (uwx_decode_uinfo needs to know whether it's 32-bit or 64-bit.) */ + + uentry->unwind_flags = unwind_flags; + + /* Call the appropriate binary search routine. */ + + if (unwind_flags & UNWIND_TBL_32BIT) + status = uwx_search_utable32(env, + (uint32_t) ip, + (uint32_t) text_base, + (uint32_t) unwind_start, + (uint32_t) unwind_end, + uentry); + else + status = uwx_search_utable64(env, + ip, text_base, unwind_start, unwind_end, uentry); + + return status; +} + + +/* uwx_search_utable32: Binary search of 32-bit unwind table */ + +#define COPYIN_UINFO_4(dest, src) \ + (env->remote? \ + (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \ + WORDSZ, env->cb_token) : \ + (*(uint32_t *)(dest) = *(uint32_t *)(src), WORDSZ) ) + +#define SWIZZLE(x) (((uint64_t)((x) & 0xc0000000) << 31) | (x)) + +int uwx_search_utable32( + struct uwx_env *env, + uint32_t ip, + uint32_t text_base, + uint32_t unwind_start, + uint32_t unwind_end, + struct uwx_utable_entry *uentry) +{ + int lb; + int ub; + int mid; + int len; + uint32_t code_start; + uint32_t code_end; + uint32_t unwind_info; + + /* Since the unwind table uses segment-relative offsets, convert */ + /* the IP in the current context to a segment-relative offset. */ + + ip -= text_base; + + TRACE_T_SEARCH32(ip) + + /* Standard binary search. */ + /* Might modify this to do interpolation in the future. */ + + lb = 0; + ub = (unwind_end - unwind_start) / (3 * WORDSZ); + mid = 0; + while (ub > lb) { + mid = (lb + ub) / 2; + len = COPYIN_UINFO_4((char *)&code_start, + (uintptr_t)(unwind_start+mid*3*WORDSZ)); + len += COPYIN_UINFO_4((char *)&code_end, + (uintptr_t)(unwind_start+mid*3*WORDSZ+WORDSZ)); + if (len != 2 * WORDSZ) + return UWX_ERR_COPYIN_UTBL; + if (env->byte_swap) { + uwx_swap4(&code_start); + uwx_swap4(&code_end); + } + TRACE_T_BINSEARCH32(lb, ub, mid, code_start, code_end) + if (ip >= code_end) + lb = mid + 1; + else if (ip < code_start) + ub = mid; + else + break; + } + if (ub <= lb) + return UWX_ERR_NOUENTRY; + len = COPYIN_UINFO_4((char *)&unwind_info, + (uintptr_t)(unwind_start+mid*3*WORDSZ+2*WORDSZ)); + if (len != WORDSZ) + return UWX_ERR_COPYIN_UTBL; + if (env->byte_swap) + uwx_swap4(&unwind_info); + uentry->ptr_size = WORDSZ; + uentry->code_start = SWIZZLE(text_base + code_start); + uentry->code_end = SWIZZLE(text_base + code_end); + uentry->unwind_info = SWIZZLE(text_base + unwind_info); + return UWX_OK; +} + + +/* uwx_search_utable64: Binary search of 64-bit unwind table */ + +#define COPYIN_UINFO_8(dest, src) \ + (env->remote? \ + (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \ + DWORDSZ, env->cb_token) : \ + (*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), DWORDSZ) ) + +int uwx_search_utable64( + struct uwx_env *env, + uint64_t ip, + uint64_t text_base, + uint64_t unwind_start, + uint64_t unwind_end, + struct uwx_utable_entry *uentry) +{ + int lb; + int ub; + int mid; + int len; + uint64_t code_start; + uint64_t code_end; + uint64_t unwind_info; + + /* Since the unwind table uses segment-relative offsets, convert */ + /* the IP in the current context to a segment-relative offset. */ + + ip -= text_base; + + /* Standard binary search. */ + /* Might modify this to do interpolation in the future. */ + + lb = 0; + ub = (unwind_end - unwind_start) / (3 * DWORDSZ); + mid = 0; + while (ub > lb) { + mid = (lb + ub) / 2; + len = COPYIN_UINFO_8((char *)&code_start, unwind_start+mid*3*DWORDSZ); + len += COPYIN_UINFO_8((char *)&code_end, + unwind_start+mid*3*DWORDSZ+DWORDSZ); + if (len != 2 * DWORDSZ) + return UWX_ERR_COPYIN_UTBL; + if (env->byte_swap) { + uwx_swap8(&code_start); + uwx_swap8(&code_end); + } + if (ip >= code_end) + lb = mid + 1; + else if (ip < code_start) + ub = mid; + else + break; + } + if (ub <= lb) + return UWX_ERR_NOUENTRY; + len = COPYIN_UINFO_8((char *)&unwind_info, + unwind_start+mid*3*DWORDSZ+2*DWORDSZ); + if (len != DWORDSZ) + return UWX_ERR_COPYIN_UTBL; + if (env->byte_swap) + uwx_swap8(&unwind_info); + uentry->ptr_size = DWORDSZ; + uentry->code_start = text_base + code_start; + uentry->code_end = text_base + code_end; + uentry->unwind_info = text_base + unwind_info; + return UWX_OK; +} |