Deleted Added
full compact
uwx_utable.c (129059) uwx_utable.c (160157)
1/*
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;
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;
80 unwind_flags = 0;
79 unwind_flags = 0;
81 unwind_start = 0;
82 unwind_end = 0;
83 while (*uvec != 0) {
84 switch ((int)*uvec++) {
85 case UWX_KEY_TBASE:
86 keys |= 1;
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++;
88 break;
89 case UWX_KEY_UFLAGS:
90 unwind_flags = *uvec++;
91 break;
92 case UWX_KEY_USTART:
93 keys |= 2;
94 unwind_start = *uvec++;
95 break;
96 case UWX_KEY_UEND:
97 keys |= 4;
98 unwind_end = *uvec++;
99 break;
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
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
137int uwx_search_utable32(
138 struct uwx_env *env,
139 uint32_t ip,
140 uint32_t text_base,
141 uint32_t unwind_start,
142 uint32_t unwind_end,
143 struct uwx_utable_entry *uentry)
144{
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;
145 int lb;
146 int ub;
147 int mid;
148 int len;
149 uint32_t code_start;
150 uint32_t code_end;
151 uint32_t unwind_info;
152
153 /* Since the unwind table uses segment-relative offsets, convert */
154 /* the IP in the current context to a segment-relative offset. */
155
156 ip -= text_base;
157
158 TRACE_T_SEARCH32(ip)
159
160 /* Standard binary search. */
161 /* Might modify this to do interpolation in the future. */
162
163 lb = 0;
164 ub = (unwind_end - unwind_start) / (3 * WORDSZ);
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;
166 while (ub > lb) {
167 mid = (lb + ub) / 2;
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);
170 len += COPYIN_UINFO_4((char *)&code_end,
171 len += COPYIN_UINFO_4((char *)&code_end,
171 (uintptr_t)(unwind_start+mid*3*WORDSZ+WORDSZ));
172 unwind_start+mid*3*WORDSZ+WORDSZ);
172 if (len != 2 * WORDSZ)
173 return UWX_ERR_COPYIN_UTBL;
174 if (env->byte_swap) {
175 uwx_swap4(&code_start);
176 uwx_swap4(&code_end);
177 }
178 TRACE_T_BINSEARCH32(lb, ub, mid, code_start, code_end)
179 if (ip >= code_end)
180 lb = mid + 1;
181 else if (ip < code_start)
182 ub = mid;
183 else
184 break;
185 }
186 if (ub <= lb)
187 return UWX_ERR_NOUENTRY;
188 len = COPYIN_UINFO_4((char *)&unwind_info,
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);
190 if (len != WORDSZ)
191 return UWX_ERR_COPYIN_UTBL;
192 if (env->byte_swap)
193 uwx_swap4(&unwind_info);
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);
197 return UWX_OK;
198}
199
200
201/* uwx_search_utable64: Binary search of 64-bit unwind table */
202
203#define COPYIN_UINFO_8(dest, src) \
204 (env->remote? \
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), \
206 DWORDSZ, env->cb_token) : \
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) )
208
209int uwx_search_utable64(
210 struct uwx_env *env,
211 uint64_t ip,
212 uint64_t text_base,
213 uint64_t unwind_start,
214 uint64_t unwind_end,
215 struct uwx_utable_entry *uentry)
216{
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;
217 int lb;
218 int ub;
219 int mid;
220 int len;
221 uint64_t code_start;
222 uint64_t code_end;
223 uint64_t unwind_info;
224
225 /* Since the unwind table uses segment-relative offsets, convert */
226 /* the IP in the current context to a segment-relative offset. */
227
228 ip -= text_base;
229
230 /* Standard binary search. */
231 /* Might modify this to do interpolation in the future. */
232
233 lb = 0;
234 ub = (unwind_end - unwind_start) / (3 * DWORDSZ);
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;
236 while (ub > lb) {
237 mid = (lb + ub) / 2;
238 len = COPYIN_UINFO_8((char *)&code_start, unwind_start+mid*3*DWORDSZ);
239 len += COPYIN_UINFO_8((char *)&code_end,
240 unwind_start+mid*3*DWORDSZ+DWORDSZ);
241 if (len != 2 * DWORDSZ)
242 return UWX_ERR_COPYIN_UTBL;
243 if (env->byte_swap) {
244 uwx_swap8(&code_start);
245 uwx_swap8(&code_end);
246 }
247 if (ip >= code_end)
248 lb = mid + 1;
249 else if (ip < code_start)
250 ub = mid;
251 else
252 break;
253 }
254 if (ub <= lb)
255 return UWX_ERR_NOUENTRY;
256 len = COPYIN_UINFO_8((char *)&unwind_info,
257 unwind_start+mid*3*DWORDSZ+2*DWORDSZ);
258 if (len != DWORDSZ)
259 return UWX_ERR_COPYIN_UTBL;
260 if (env->byte_swap)
261 uwx_swap8(&unwind_info);
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;
262 uentry->code_start = text_base + code_start;
263 uentry->code_end = text_base + code_end;
264 uentry->unwind_info = text_base + unwind_info;
265 return UWX_OK;
266}
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}