Deleted Added
full compact
1/*
2Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
2Copyright (c) 2003-2006 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 ip,
46 uint32_t text_base,
47 uint32_t unwind_start,
48 uint32_t unwind_end,
49 struct uwx_utable_entry *uentry);
50
51int uwx_search_utable64(
52 struct uwx_env *env,
53 uint64_t ip,
54 uint64_t text_base,
55 uint64_t unwind_start,
56 uint64_t unwind_end,
57 struct uwx_utable_entry *uentry);
58
59
60/* uwx_search_utable: Searches an unwind table for IP in current context */
61
62int uwx_search_utable(
63 struct uwx_env *env,
64 uint64_t ip,
65 uint64_t *uvec,
66 struct uwx_utable_entry *uentry)
67{
68 uint64_t text_base;
69 uint64_t unwind_flags;
70 uint64_t unwind_start;
71 uint64_t unwind_end;
72 int keys;
73 int status;
74
75 /* Get unwind table information from the result vector. */
76 /* Make sure all three required values are given. */
77
78 keys = 0;
79 text_base = 0;
79 unwind_flags = 0;
81 unwind_start = 0;
82 unwind_end = 0;
80 while (*uvec != 0) {
81 switch ((int)*uvec++) {
82 case UWX_KEY_TBASE:
83 keys |= 1;
87 text_base = *uvec++;
84 env->text_base = text_base = *uvec++;
85 break;
86 case UWX_KEY_UFLAGS:
87 unwind_flags = *uvec++;
88 break;
89 case UWX_KEY_USTART:
90 keys |= 2;
91 unwind_start = *uvec++;
92 break;
93 case UWX_KEY_UEND:
94 keys |= 4;
95 unwind_end = *uvec++;
96 break;
97 case UWX_KEY_GP:
98 uwx_set_reg(env, UWX_REG_GP, *uvec++);
99 break;
100 default:
101 return UWX_ERR_BADKEY;
102 }
103 }
104 if (keys != 7)
105 return UWX_ERR_BADKEY;
106
107 /* Copy the unwind flags into the unwind entry. */
108 /* (uwx_decode_uinfo needs to know whether it's 32-bit or 64-bit.) */
109
110 uentry->unwind_flags = unwind_flags;
111
112 /* Call the appropriate binary search routine. */
113
114 if (unwind_flags & UNWIND_TBL_32BIT)
115 status = uwx_search_utable32(env,
116 (uint32_t) ip,
117 (uint32_t) text_base,
118 (uint32_t) unwind_start,
119 (uint32_t) unwind_end,
120 uentry);
121 else
122 status = uwx_search_utable64(env,
123 ip, text_base, unwind_start, unwind_end, uentry);
124
125 return status;
126}
127
128
129/* uwx_search_utable32: Binary search of 32-bit unwind table */
130
131#define COPYIN_UINFO_4(dest, src) \
132 (env->remote? \
133 (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \
134 WORDSZ, env->cb_token) : \
135 (*(uint32_t *)(dest) = *(uint32_t *)(src), WORDSZ) )
136
137#define SWIZZLE(x) (((uint64_t)((x) & 0xc0000000) << 31) | (x))
138
139int uwx_search_utable32(
140 struct uwx_env *env,
141 uint32_t ip,
142 uint32_t text_base,
143 uint32_t unwind_start,
144 uint32_t unwind_end,
145 struct uwx_utable_entry *uentry)
146{
147 int status;
148 int lb;
149 int ub;
150 int mid;
151 int len;
152 uint32_t code_start;
153 uint32_t code_end;
154 uint32_t unwind_info;
155
156 /* Since the unwind table uses segment-relative offsets, convert */
157 /* the IP in the current context to a segment-relative offset. */
158
159 ip -= text_base;
160
161 TRACE_T_SEARCH32(ip)
162
163 /* Standard binary search. */
164 /* Might modify this to do interpolation in the future. */
165
166 lb = 0;
167 ub = (unwind_end - unwind_start) / (3 * WORDSZ);
165 mid = 0;
168 while (ub > lb) {
169 mid = (lb + ub) / 2;
168 len = COPYIN_UINFO_4((char *)&code_start,
169 (uintptr_t)(unwind_start+mid*3*WORDSZ));
170 len = COPYIN_UINFO_4((char *)&code_start, unwind_start+mid*3*WORDSZ);
171 len += COPYIN_UINFO_4((char *)&code_end,
171 (uintptr_t)(unwind_start+mid*3*WORDSZ+WORDSZ));
172 unwind_start+mid*3*WORDSZ+WORDSZ);
173 if (len != 2 * WORDSZ)
174 return UWX_ERR_COPYIN_UTBL;
175 if (env->byte_swap) {
176 uwx_swap4(&code_start);
177 uwx_swap4(&code_end);
178 }
179 TRACE_T_BINSEARCH32(lb, ub, mid, code_start, code_end)
180 if (ip >= code_end)
181 lb = mid + 1;
182 else if (ip < code_start)
183 ub = mid;
184 else
185 break;
186 }
187 if (ub <= lb)
188 return UWX_ERR_NOUENTRY;
189 len = COPYIN_UINFO_4((char *)&unwind_info,
189 (uintptr_t)(unwind_start+mid*3*WORDSZ+2*WORDSZ));
190 unwind_start+mid*3*WORDSZ+2*WORDSZ);
191 if (len != WORDSZ)
192 return UWX_ERR_COPYIN_UTBL;
193 if (env->byte_swap)
194 uwx_swap4(&unwind_info);
194 uentry->code_start = text_base + code_start;
195 uentry->code_end = text_base + code_end;
196 uentry->unwind_info = text_base + unwind_info;
195 uentry->ptr_size = WORDSZ;
196 uentry->code_start = SWIZZLE(text_base + code_start);
197 uentry->code_end = SWIZZLE(text_base + code_end);
198 uentry->unwind_info = SWIZZLE(text_base + unwind_info);
199 return UWX_OK;
200}
201
202
203/* uwx_search_utable64: Binary search of 64-bit unwind table */
204
205#define COPYIN_UINFO_8(dest, src) \
206 (env->remote? \
205 (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \
207 (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \
208 DWORDSZ, env->cb_token) : \
207 (*(uint64_t *)(dest) = *(uint64_t *)(src), DWORDSZ) )
209 (*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), DWORDSZ) )
210
211int uwx_search_utable64(
212 struct uwx_env *env,
213 uint64_t ip,
214 uint64_t text_base,
215 uint64_t unwind_start,
216 uint64_t unwind_end,
217 struct uwx_utable_entry *uentry)
218{
219 int status;
220 int lb;
221 int ub;
222 int mid;
223 int len;
224 uint64_t code_start;
225 uint64_t code_end;
226 uint64_t unwind_info;
227
228 /* Since the unwind table uses segment-relative offsets, convert */
229 /* the IP in the current context to a segment-relative offset. */
230
231 ip -= text_base;
232
233 /* Standard binary search. */
234 /* Might modify this to do interpolation in the future. */
235
236 lb = 0;
237 ub = (unwind_end - unwind_start) / (3 * DWORDSZ);
235 mid = 0;
238 while (ub > lb) {
239 mid = (lb + ub) / 2;
240 len = COPYIN_UINFO_8((char *)&code_start, unwind_start+mid*3*DWORDSZ);
241 len += COPYIN_UINFO_8((char *)&code_end,
242 unwind_start+mid*3*DWORDSZ+DWORDSZ);
243 if (len != 2 * DWORDSZ)
244 return UWX_ERR_COPYIN_UTBL;
245 if (env->byte_swap) {
246 uwx_swap8(&code_start);
247 uwx_swap8(&code_end);
248 }
249 if (ip >= code_end)
250 lb = mid + 1;
251 else if (ip < code_start)
252 ub = mid;
253 else
254 break;
255 }
256 if (ub <= lb)
257 return UWX_ERR_NOUENTRY;
258 len = COPYIN_UINFO_8((char *)&unwind_info,
259 unwind_start+mid*3*DWORDSZ+2*DWORDSZ);
260 if (len != DWORDSZ)
261 return UWX_ERR_COPYIN_UTBL;
262 if (env->byte_swap)
263 uwx_swap8(&unwind_info);
264 uentry->ptr_size = DWORDSZ;
265 uentry->code_start = text_base + code_start;
266 uentry->code_end = text_base + code_end;
267 uentry->unwind_info = text_base + unwind_info;
268 return UWX_OK;
269}