uwx_utable.c revision 115013
1/* 2 * Copyright (c) 2002,2003 Hewlett-Packard Company 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23#include "uwx_env.h" 24#include "uwx_utable.h" 25#include "uwx_swap.h" 26#include "uwx_trace.h" 27 28/* 29 * uwx_utable.c 30 * 31 * This file contains the routines for searching an unwind table. 32 * The main entry point, uwx_search_utable(), gets the 33 * necessary information from the lookup ip callback's result 34 * vector, determines whether the table is 32-bit or 64-bit, 35 * then invokes the binary search routine for that format. 36 */ 37 38 39/* Forward declarations */ 40 41int uwx_search_utable32( 42 struct uwx_env *env, 43 uint32_t text_base, 44 uint32_t unwind_start, 45 uint32_t unwind_end, 46 struct uwx_utable_entry *uentry); 47 48int uwx_search_utable64( 49 struct uwx_env *env, 50 uint64_t text_base, 51 uint64_t unwind_start, 52 uint64_t unwind_end, 53 struct uwx_utable_entry *uentry); 54 55 56/* uwx_search_utable: Searches an unwind table for IP in current context */ 57 58int uwx_search_utable( 59 struct uwx_env *env, 60 uint64_t *uvec, 61 struct uwx_utable_entry *uentry) 62{ 63 uint64_t text_base = 0; 64 uint64_t unwind_flags; 65 uint64_t unwind_start = 0; 66 uint64_t unwind_end = 0; 67 int keys; 68 int status; 69 70 /* Get unwind table information from the result vector. */ 71 /* Make sure all three required values are given. */ 72 73 keys = 0; 74 unwind_flags = 0; 75 while (*uvec != 0) { 76 switch ((int)*uvec++) { 77 case UWX_KEY_TBASE: 78 keys |= 1; 79 text_base = *uvec++; 80 break; 81 case UWX_KEY_UFLAGS: 82 unwind_flags = *uvec++; 83 break; 84 case UWX_KEY_USTART: 85 keys |= 2; 86 unwind_start = *uvec++; 87 break; 88 case UWX_KEY_UEND: 89 keys |= 4; 90 unwind_end = *uvec++; 91 break; 92 default: 93 return UWX_ERR_BADKEY; 94 } 95 } 96 if (keys != 7) 97 return UWX_ERR_BADKEY; 98 99 /* Copy the unwind flags into the unwind entry. */ 100 /* (uwx_decode_uinfo needs to know whether it's 32-bit or 64-bit.) */ 101 102 uentry->unwind_flags = unwind_flags; 103 104 /* Call the appropriate binary search routine. */ 105 106 if (unwind_flags & UNWIND_TBL_32BIT) 107 status = uwx_search_utable32(env, 108 (uint32_t) text_base, 109 (uint32_t) unwind_start, 110 (uint32_t) unwind_end, 111 uentry); 112 else 113 status = uwx_search_utable64(env, 114 text_base, unwind_start, unwind_end, uentry); 115 116 return status; 117} 118 119 120/* uwx_search_utable32: Binary search of 32-bit unwind table */ 121 122#define COPYIN_UINFO_4(dest, src) \ 123 (env->remote? \ 124 (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \ 125 WORDSZ, env->cb_token) : \ 126 (*(uint32_t *)(dest) = *(uint32_t *)(src), WORDSZ) ) 127 128int uwx_search_utable32( 129 struct uwx_env *env, 130 uint32_t text_base, 131 uint32_t unwind_start, 132 uint32_t unwind_end, 133 struct uwx_utable_entry *uentry) 134{ 135 int lb; 136 int ub; 137 int mid = 0; 138 int len; 139 uint32_t ip; 140 uint32_t code_start; 141 uint32_t code_end; 142 uint32_t unwind_info; 143 144 /* Since the unwind table uses segment-relative offsets, convert */ 145 /* the IP in the current context to a segment-relative offset. */ 146 147 ip = env->context.special[UWX_REG_IP] - text_base; 148 149 TRACE_T_SEARCH32(ip) 150 151 /* Standard binary search. */ 152 /* Might modify this to do interpolation in the future. */ 153 154 lb = 0; 155 ub = (unwind_end - unwind_start) / (3 * WORDSZ); 156 while (ub > lb) { 157 mid = (lb + ub) / 2; 158 len = COPYIN_UINFO_4((char *)&code_start, 159 (intptr_t)(unwind_start+mid*3*WORDSZ)); 160 len += COPYIN_UINFO_4((char *)&code_end, 161 (intptr_t)(unwind_start+mid*3*WORDSZ+WORDSZ)); 162 if (len != 2 * WORDSZ) 163 return UWX_ERR_COPYIN_UTBL; 164 if (env->byte_swap) { 165 uwx_swap4(&code_start); 166 uwx_swap4(&code_end); 167 } 168 TRACE_T_BINSEARCH32(lb, ub, mid, code_start, code_end) 169 if (ip >= code_end) 170 lb = mid + 1; 171 else if (ip < code_start) 172 ub = mid; 173 else 174 break; 175 } 176 if (ub <= lb) 177 return UWX_ERR_NOUENTRY; 178 len = COPYIN_UINFO_4((char *)&unwind_info, 179 (intptr_t)(unwind_start+mid*3*WORDSZ+2*WORDSZ)); 180 if (len != WORDSZ) 181 return UWX_ERR_COPYIN_UTBL; 182 if (env->byte_swap) 183 uwx_swap4(&unwind_info); 184 uentry->code_start = text_base + code_start; 185 uentry->code_end = text_base + code_end; 186 uentry->unwind_info = text_base + unwind_info; 187 return UWX_OK; 188} 189 190 191/* uwx_search_utable64: Binary search of 64-bit unwind table */ 192 193#define COPYIN_UINFO_8(dest, src) \ 194 (env->remote? \ 195 (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \ 196 DWORDSZ, env->cb_token) : \ 197 (*(uint64_t *)(dest) = *(uint64_t *)(src), DWORDSZ) ) 198 199int uwx_search_utable64( 200 struct uwx_env *env, 201 uint64_t text_base, 202 uint64_t unwind_start, 203 uint64_t unwind_end, 204 struct uwx_utable_entry *uentry) 205{ 206 int lb; 207 int ub; 208 int mid = 0; 209 int len; 210 uint64_t ip; 211 uint64_t code_start; 212 uint64_t code_end; 213 uint64_t unwind_info; 214 215 /* Since the unwind table uses segment-relative offsets, convert */ 216 /* the IP in the current context to a segment-relative offset. */ 217 218 ip = env->context.special[UWX_REG_IP] - text_base; 219 220 /* Standard binary search. */ 221 /* Might modify this to do interpolation in the future. */ 222 223 lb = 0; 224 ub = (unwind_end - unwind_start) / (3 * DWORDSZ); 225 while (ub > lb) { 226 mid = (lb + ub) / 2; 227 len = COPYIN_UINFO_8((char *)&code_start, unwind_start+mid*3*DWORDSZ); 228 len += COPYIN_UINFO_8((char *)&code_end, 229 unwind_start+mid*3*DWORDSZ+DWORDSZ); 230 if (len != 2 * DWORDSZ) 231 return UWX_ERR_COPYIN_UTBL; 232 if (env->byte_swap) { 233 uwx_swap8(&code_start); 234 uwx_swap8(&code_end); 235 } 236 if (ip >= code_end) 237 lb = mid + 1; 238 else if (ip < code_start) 239 ub = mid; 240 else 241 break; 242 } 243 if (ub <= lb) 244 return UWX_ERR_NOUENTRY; 245 len = COPYIN_UINFO_8((char *)&unwind_info, 246 unwind_start+mid*3*DWORDSZ+2*DWORDSZ); 247 if (len != DWORDSZ) 248 return UWX_ERR_COPYIN_UTBL; 249 if (env->byte_swap) 250 uwx_swap8(&unwind_info); 251 uentry->code_start = text_base + code_start; 252 uentry->code_end = text_base + code_end; 253 uentry->unwind_info = text_base + unwind_info; 254 return UWX_OK; 255} 256