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