Deleted Added
sdiff udiff text old ( 129059 ) new ( 160157 )
full compact
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_context.h"
27#include "uwx_utable.h"
28#include "uwx_uinfo.h"
29#include "uwx_scoreboard.h"
30#include "uwx_str.h"
31#include "uwx_step.h"
32#include "uwx_trace.h"
33
34/*
35 * uwx_step.c
36 *
37 * This file contains the routines for stepping from one frame
38 * into its callers frame. The context for the current frame
39 * is maintained inside the current unwind environment
40 * (struct uwx_env), and is updated with each call to
41 * uwx_step() to refer to the previous frame.
42 */
43
44
45/* Forward Declarations */
46
47int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate);
48int uwx_restore_reg(struct uwx_env *env, uint64_t rstate,
49 uint64_t *valp, uint64_t *histp);
50int uwx_restore_freg(struct uwx_env *env, uint64_t rstate,
51 uint64_t *valp, uint64_t *histp);
52int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat);
53
54
55/* uwx_lookupip_hook: Hook routine so dynamic instrumentation */
56/* tools can intercept Lookup IP events. When not */
57/* intercepted, it just returns "Not found", so that */
58/* the callback routine is invoked. */
59
60/*ARGSUSED*/
61int uwx_lookupip_hook(int request, uint64_t ip, intptr_t tok, uint64_t **vecp,
62 size_t uvecsize)
63{
64 return UWX_LKUP_NOTFOUND;
65}
66
67
68/* uwx_get_frame_info: Gets unwind info for current frame */
69static
70int uwx_get_frame_info(struct uwx_env *env)
71{
72 int i;
73 int status;
74 int cbstatus;
75 int cbcalled = 0;
76 uint64_t ip;
77 uint64_t *uvec;
78 uint64_t *rstate;
79 struct uwx_utable_entry uentry;
80 uint64_t uvecout[UVECSIZE];
81
82 if (env->copyin == 0 || env->lookupip == 0)
83 return UWX_ERR_NOCALLBACKS;
84
85 env->function_offset = -1LL;
86 env->function_name = 0;
87 env->module_name = 0;
88 uwx_reset_str_pool(env);
89
90 /* Use the lookup IP callback routine to find out about the */
91 /* current IP. If the predicate registers are valid, pass them */
92 /* in the uvec. */
93
94 /* When self-unwinding, we call a hook routine before the */
95 /* callback. If the application is running under control of */
96 /* a dynamic instrumentation tool, that tool will have an */
97 /* opportunity to intercept lookup IP requests. */
98
99 i = 0;
100 uvecout[i++] = UWX_KEY_VERSION;
101 uvecout[i++] = UWX_VERSION;
102 if (env->context.valid_regs & (1 << UWX_REG_PREDS)) {
103 uvecout[i++] = UWX_KEY_PREDS;
104 uvecout[i++] = env->context.special[UWX_REG_PREDS];
105 }
106 uvecout[i++] = UWX_KEY_END;
107 uvecout[i++] = 0;
108 uvec = uvecout;
109 cbstatus = UWX_LKUP_NOTFOUND;
110 ip = env->context.special[UWX_REG_IP];
111 env->remapped_ip = ip;
112
113 /* Call the hook routine. */
114
115 if (env->remote == 0)
116 cbstatus = uwx_lookupip_hook(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec,
117 sizeof(uvecout));
118
119 /* If the hook routine remapped the IP, use the new IP for */
120 /* the callback instead of the original IP. */
121
122 if (cbstatus == UWX_LKUP_REMAP) {
123 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
124 switch ((int)uvec[i]) {
125 case UWX_KEY_NEWIP:
126 ip = uvec[i+1];
127 break;
128 }
129 }
130 env->remapped_ip = ip;
131 }
132
133 /* Now call the callback routine unless the hook routine gave */
134 /* us all the info. */
135
136 if (cbstatus == UWX_LKUP_NOTFOUND || cbstatus == UWX_LKUP_REMAP) {
137 cbcalled = 1;
138 cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec);
139 }
140
141 /* If the callback routine remapped the IP, call it one more time */
142 /* with the new IP. */
143
144 if (cbstatus == UWX_LKUP_REMAP) {
145 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
146 switch ((int)uvec[i]) {
147 case UWX_KEY_NEWIP:
148 ip = uvec[i+1];
149 break;
150 }
151 }
152 env->remapped_ip = ip;
153 cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec);
154 }
155
156 /* If NOTFOUND, there's nothing we can do but return an error. */
157
158 if (cbstatus == UWX_LKUP_NOTFOUND) {
159 status = UWX_ERR_IPNOTFOUND;
160 }
161
162 /* If the callback returns an unwind table, we need to */
163 /* search the table for an unwind entry that describes the */
164 /* code region of interest, then decode the unwind information */
165 /* associated with that unwind table entry, and store the */
166 /* resulting register state array in the unwind environment */
167 /* block. */
168
169 else if (cbstatus == UWX_LKUP_UTABLE) {
170 status = uwx_search_utable(env, ip, uvec, &uentry);
171 if (cbcalled)
172 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
173 if (status == UWX_OK)
174 status = uwx_decode_uinfo(env, &uentry, &rstate);
175 else if (status == UWX_ERR_NOUENTRY)
176 status = uwx_default_rstate(env, &rstate);
177 if (status == UWX_OK)
178 env->rstate = rstate;
179 }
180
181 /* If the callback returns an unwind info block, we can */
182 /* proceed directly to decoding the unwind information. */
183
184 else if (cbstatus == UWX_LKUP_UINFO) {
185 uentry.code_start = 0;
186 uentry.code_end = 0;
187 uentry.unwind_info = 0;
188 uentry.unwind_flags = 0;
189 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
190 switch ((int)uvec[i]) {
191 case UWX_KEY_UFLAGS:
192 uentry.unwind_flags = uvec[i+1];
193 break;
194 case UWX_KEY_UINFO:
195 uentry.unwind_info = uvec[i+1];
196 break;
197 case UWX_KEY_MODULE:
198 env->module_name =
199 uwx_alloc_str(env, (char *)(uvec[i+1]));
200 break;
201 case UWX_KEY_FUNC:
202 env->function_name =
203 uwx_alloc_str(env, (char *)(uvec[i+1]));
204 break;
205 case UWX_KEY_FUNCSTART:
206 uentry.code_start = uvec[i+1];
207 break;
208 }
209 }
210 if (cbcalled)
211 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
212 status = uwx_decode_uinfo(env, &uentry, &rstate);
213 if (status == UWX_OK)
214 env->rstate = rstate;
215 }
216
217 /* If the callback returns a frame description (in the form */
218 /* of an update vector), convert the update vector into a */
219 /* register state array, then invoke the callback again to */
220 /* let it free any memory it allocated. */
221
222 else if (cbstatus == UWX_LKUP_FDESC) {
223 status = uwx_decode_uvec(env, uvec, &rstate);
224 if (cbcalled)
225 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
226 if (status == UWX_OK)
227 env->rstate = rstate;
228 }
229
230 /* Any other return from the callback is an error. */
231
232 else {
233 status = UWX_ERR_LOOKUPERR;
234 }
235 return status;
236}
237
238
239/* uwx_restore_markers: Restores the stack markers -- PSP, RP, PFS */
240
241int uwx_restore_markers(struct uwx_env *env)
242{
243 int status;
244 uint64_t val;
245 uint64_t hist;
246
247 if ((env->context.valid_regs & VALID_BASIC4) != VALID_BASIC4)
248 return UWX_ERR_NOCONTEXT;
249
250 /* If we haven't already obtained the frame info for the */
251 /* current frame, get it now. */
252
253 if (env->rstate == 0) {
254 status = uwx_get_frame_info(env);
255 if (status != UWX_OK)
256 return status;
257 }
258
259 TRACE_S_STEP(env->rstate)
260
261 if (env->rstate[SBREG_PSP] != UWX_DISP_NONE) {
262 status = uwx_restore_reg(env, env->rstate[SBREG_PSP], &val, &hist);
263 if (status != UWX_OK)
264 return status;
265 env->context.special[UWX_REG_PSP] = val;
266 env->history.special[UWX_REG_PSP] = hist;
267 env->context.valid_regs |= 1 << UWX_REG_PSP;
268 TRACE_S_RESTORE_REG("PSP", env->rstate[SBREG_PSP], val)
269 }
270
271 if (env->rstate[SBREG_RP] != UWX_DISP_NONE) {
272 status = uwx_restore_reg(env, env->rstate[SBREG_RP], &val, &hist);
273 if (status != UWX_OK)
274 return status;
275 env->context.special[UWX_REG_RP] = val;
276 env->history.special[UWX_REG_RP] = hist;
277 env->context.valid_regs |= 1 << UWX_REG_RP;
278 TRACE_S_RESTORE_REG("RP", env->rstate[SBREG_RP], val)
279 }
280
281 if (env->rstate[SBREG_PFS] != UWX_DISP_NONE) {
282 status = uwx_restore_reg(env, env->rstate[SBREG_PFS], &val, &hist);
283 if (status != UWX_OK)
284 return status;
285 env->context.special[UWX_REG_PFS] = val;
286 env->history.special[UWX_REG_PFS] = hist;
287 env->context.valid_regs |= 1 << UWX_REG_PFS;
288 TRACE_S_RESTORE_REG("PFS", env->rstate[SBREG_PFS], val)
289 }
290
291 return UWX_OK;
292}
293
294/* uwx_get_sym_info: Gets symbolic info from current frame */
295
296int uwx_get_sym_info(
297 struct uwx_env *env,
298 char **modp,
299 char **symp,
300 uint64_t *offsetp)
301{
302 int status;
303 int cbstatus;
304 uint64_t ip;
305 uint64_t *uvec;
306 uint64_t uvecout[2];
307 int i;
308
309 if (env == 0)
310 return UWX_ERR_NOENV;
311
312 /* If we haven't already obtained the frame info for the */
313 /* current frame, get it now. */
314
315 if (env->rstate == 0) {
316 status = uwx_get_frame_info(env);
317 if (status != UWX_OK)
318 return status;
319 }
320
321 /* Get the symbolic information from the lookup IP callback. */
322 if (env->function_name == 0) {
323 ip = env->remapped_ip;
324 i = 0;
325 if (env->function_offset >= 0) {
326 uvecout[i++] = UWX_KEY_FUNCSTART;
327 uvecout[i++] = ip - env->function_offset;
328 }
329 uvecout[i++] = UWX_KEY_END;
330 uvecout[i++] = 0;
331 uvec = uvecout;
332 cbstatus = (*env->lookupip)(UWX_LKUP_SYMBOLS, ip, env->cb_token, &uvec);
333
334 if (cbstatus == UWX_LKUP_SYMINFO) {
335 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
336 switch ((int)uvec[i]) {
337 case UWX_KEY_MODULE:
338 env->module_name =
339 uwx_alloc_str(env, (char *)(uvec[i+1]));
340 break;
341 case UWX_KEY_FUNC:
342 env->function_name =
343 uwx_alloc_str(env, (char *)(uvec[i+1]));
344 break;
345 case UWX_KEY_FUNCSTART:
346 env->function_offset = ip - uvec[i+1];
347 break;
348 }
349 }
350 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
351 }
352 }
353
354 *modp = env->module_name;
355 *symp = env->function_name;
356 *offsetp = env->function_offset;
357
358 return UWX_OK;
359}
360
361
362/* uwx_step: Steps from the current frame to the previous frame */
363
364int uwx_step(struct uwx_env *env)
365{
366 int i;
367 int status;
368 int pfs_sol;
369 int dispcode;
370 uint64_t val;
371 uint64_t fval[2];
372 uint64_t hist;
373 uint64_t tempgr[NPRESERVEDGR];
374 int needpriunat;
375 int unat;
376 int tempnat;
377
378 if (env == 0)
379 return UWX_ERR_NOENV;
380
381 /* Complete the current context by restoring the current values */
382 /* of psp, rp, and pfs. */
383
384 if (env->rstate == 0 ||
385 (env->context.valid_regs & VALID_MARKERS) != VALID_MARKERS) {
386 status = uwx_restore_markers(env);
387 if (status != UWX_OK)
388 return status;
389 }
390
391 /* Check for bottom of stack (rp == 0). */
392
393 if (env->context.special[UWX_REG_RP] == 0)
394 return UWX_BOTTOM;
395
396 /* Find where the primary unat is saved, get a copy. */
397 /* Then, as we restore the GRs, we'll merge the NaT bits into the */
398 /* priunat register in the context. */
399 /* (Make sure we need it, though, before we try to get it, */
400 /* because the attempt to get it might invoke the copy-in callback. */
401 /* We don't need the priunat unless one of GR 4-7 was */
402 /* saved to the memory stack.) */
403
404 needpriunat = 0;
405 for (i = 0; i < NSB_GR; i++) {
406 dispcode = UWX_GET_DISP_CODE(env->rstate[SBREG_GR + i]);
407 if (dispcode == UWX_DISP_SPREL(0) || dispcode == UWX_DISP_PSPREL(0))
408 needpriunat = 1;
409 }
410 unat = 0;
411 if (needpriunat && env->rstate[SBREG_PRIUNAT] != UWX_DISP_NONE) {
412 status = uwx_restore_reg(env, env->rstate[SBREG_PRIUNAT], &val, &hist);
413 if (status != UWX_OK)
414 return status;
415 unat = (int) val;
416 env->history.special[UWX_REG_PRIUNAT] = hist;
417 TRACE_S_RESTORE_REG("PRIUNAT", env->rstate[SBREG_PRIUNAT], val)
418 }
419
420 /* Retrieve saved values of the preserved GRs into temporaries. */
421
422 tempnat = (int) env->context.special[UWX_REG_PRIUNAT];
423 for (i = 0; i < NSB_GR; i++) {
424 if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) {
425 status = uwx_restore_reg(env,
426 env->rstate[SBREG_GR + i], &val, &hist);
427 if (status != UWX_OK)
428 return status;
429 tempgr[i] = val;
430 if (uwx_restore_nat(env, env->rstate[SBREG_GR + i], unat))
431 tempnat |= 1 << i;
432 else
433 tempnat &= ~(1 << i);
434 env->history.gr[i] = hist;
435 env->context.valid_regs |= 1 << (i + VALID_GR_SHIFT);
436 TRACE_S_RESTORE_GR(i, env->rstate[SBREG_GR + i], val)
437 }
438 }
439
440 /* Now we have everything we need to step back to the previous frame. */
441
442 /* Restore preserved BRs. */
443
444 for (i = 0; i < NSB_BR; i++) {
445 if (env->rstate[SBREG_BR + i] != UWX_DISP_NONE) {
446 status = uwx_restore_reg(env,
447 env->rstate[SBREG_BR + i], &val, &hist);
448 if (status != UWX_OK)
449 return status;
450 env->context.br[i] = val;
451 env->history.br[i] = hist;
452 env->context.valid_regs |= 1 << (i + VALID_BR_SHIFT);
453 TRACE_S_RESTORE_BR(i, env->rstate[SBREG_BR + i], val)
454 }
455 }
456
457 /* Restore preserved FRs. */
458
459 if (env->nsbreg == NSBREG) {
460 for (i = 0; i < NSB_FR; i++) {
461 if (env->rstate[SBREG_FR + i] != UWX_DISP_NONE) {
462 status = uwx_restore_freg(env,
463 env->rstate[SBREG_FR + i], fval, &hist);
464 if (status != UWX_OK)
465 return status;
466 env->context.fr[i].part0 = fval[0];
467 env->context.fr[i].part1 = fval[1];
468 env->history.fr[i] = hist;
469 env->context.valid_frs |= 1 << i;
470 TRACE_S_RESTORE_FR(i, env->rstate[SBREG_FR + i], fval)
471 }
472 }
473 }
474
475 /* Restore other preserved regs. */
476
477 if (env->rstate[SBREG_PREDS] != UWX_DISP_NONE) {
478 status = uwx_restore_reg(env, env->rstate[SBREG_PREDS], &val, &hist);
479 if (status != UWX_OK)
480 return status;
481 env->context.special[UWX_REG_PREDS] = val;
482 env->history.special[UWX_REG_PREDS] = hist;
483 env->context.valid_regs |= 1 << UWX_REG_PREDS;
484 TRACE_S_RESTORE_REG("PREDS", env->rstate[SBREG_PREDS], val)
485 }
486 if (env->rstate[SBREG_RNAT] != UWX_DISP_NONE) {
487 status = uwx_restore_reg(env, env->rstate[SBREG_RNAT], &val, &hist);
488 if (status != UWX_OK)
489 return status;
490 env->context.special[UWX_REG_AR_RNAT] = val;
491 env->history.special[UWX_REG_AR_RNAT] = hist;
492 env->context.valid_regs |= 1 << UWX_REG_AR_RNAT;
493 TRACE_S_RESTORE_REG("RNAT", env->rstate[SBREG_RNAT], val)
494 }
495 if (env->rstate[SBREG_UNAT] != UWX_DISP_NONE) {
496 status = uwx_restore_reg(env, env->rstate[SBREG_UNAT], &val, &hist);
497 if (status != UWX_OK)
498 return status;
499 env->context.special[UWX_REG_AR_UNAT] = val;
500 env->history.special[UWX_REG_AR_UNAT] = hist;
501 env->context.valid_regs |= 1 << UWX_REG_AR_UNAT;
502 TRACE_S_RESTORE_REG("UNAT", env->rstate[SBREG_UNAT], val)
503 }
504 if (env->rstate[SBREG_FPSR] != UWX_DISP_NONE) {
505 status = uwx_restore_reg(env, env->rstate[SBREG_FPSR], &val, &hist);
506 if (status != UWX_OK)
507 return status;
508 env->context.special[UWX_REG_AR_FPSR] = val;
509 env->history.special[UWX_REG_AR_FPSR] = hist;
510 env->context.valid_regs |= 1 << UWX_REG_AR_FPSR;
511 TRACE_S_RESTORE_REG("FPSR", env->rstate[SBREG_FPSR], val)
512 }
513 if (env->rstate[SBREG_LC] != UWX_DISP_NONE) {
514 status = uwx_restore_reg(env, env->rstate[SBREG_LC], &val, &hist);
515 if (status != UWX_OK)
516 return status;
517 env->context.special[UWX_REG_AR_LC] = val;
518 env->history.special[UWX_REG_AR_LC] = hist;
519 env->context.valid_regs |= 1 << UWX_REG_AR_LC;
520 TRACE_S_RESTORE_REG("LC", env->rstate[SBREG_LC], val)
521 }
522
523 /* Restore preserved GRs from temporaries. */
524
525 for (i = 0; i < NSB_GR; i++) {
526 if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE)
527 env->context.gr[i] = tempgr[i];
528 }
529 env->context.special[UWX_REG_PRIUNAT] = tempnat;
530
531 /* Restore the frame markers. */
532
533 env->context.special[UWX_REG_IP] = env->context.special[UWX_REG_RP];
534 env->history.special[UWX_REG_IP] = env->history.special[UWX_REG_RP];
535
536 env->context.special[UWX_REG_SP] = env->context.special[UWX_REG_PSP];
537 env->history.special[UWX_REG_SP] = env->history.special[UWX_REG_PSP];
538
539 pfs_sol = ((unsigned int)env->context.special[UWX_REG_PFS] >> 7) & 0x7f;
540 env->context.special[UWX_REG_BSP] = uwx_add_to_bsp(
541 env->context.special[UWX_REG_BSP],
542 -pfs_sol);
543
544 env->context.special[UWX_REG_CFM] = env->context.special[UWX_REG_PFS];
545 env->history.special[UWX_REG_CFM] = env->history.special[UWX_REG_PFS];
546
547 env->context.special[UWX_REG_RP] = 0;
548
549 /* The frame info for the new frame isn't yet available. */
550
551 env->rstate = 0;
552 env->context.valid_regs &= ~VALID_MARKERS;
553
554 return UWX_OK;
555}
556
557
558/* uwx_decode_uvec: Converts the update vector into a register state array */
559
560int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate)
561{
562 int i;
563 int status;
564
565 status = uwx_default_rstate(env, rstate);
566 if (status != UWX_OK)
567 return status;
568
569 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
570 switch ((int)uvec[i]) {
571 case UWX_KEY_CONTEXT:
572 env->abi_context = (int)(uvec[i+1]);
573 status = UWX_ABI_FRAME;
574 break;
575 case UWX_KEY_MODULE:
576 env->module_name =
577 uwx_alloc_str(env, (char *)(uvec[i+1]));
578 break;
579 case UWX_KEY_FUNC:
580 env->function_name =
581 uwx_alloc_str(env, (char *)(uvec[i+1]));
582 break;
583 case UWX_KEY_FUNCSTART:
584 env->function_offset = env->remapped_ip - uvec[i+1];
585 break;
586 default:
587 return UWX_ERR_CANTUNWIND;
588 }
589 }
590 return status;
591}
592
593
594/* uwx_restore_reg: Restores a register according to the scoreboard */
595
596#define COPYIN_MSTACK_8(dest, src) \
597 (env->remote? \
598 (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \
599 DWORDSZ, env->cb_token) : \
600 (*(uint64_t *)(dest) = *(uint64_t *)(src), DWORDSZ) )
601
602int uwx_restore_reg(struct uwx_env *env, uint64_t rstate,
603 uint64_t *valp, uint64_t *histp)
604{
605 int status;
606 uint64_t p;
607 int n;
608 int regid;
609
610 status = UWX_OK;
611
612 switch (UWX_GET_DISP_CODE(rstate)) {
613 case UWX_DISP_SPPLUS(0):
614 *valp = env->context.special[UWX_REG_SP] +
615 UWX_GET_DISP_OFFSET(rstate);
616 *histp = UWX_DISP_NONE;
617 break;
618 case UWX_DISP_SPREL(0):
619 p = env->context.special[UWX_REG_SP] +
620 UWX_GET_DISP_OFFSET(rstate);
621 n = COPYIN_MSTACK_8((char *)valp, p);
622 if (n != DWORDSZ)
623 status = UWX_ERR_COPYIN_MSTK;
624 *histp = UWX_DISP_MSTK(p);
625 break;
626 case UWX_DISP_PSPREL(0):
627 p = env->context.special[UWX_REG_PSP] + 16 -
628 UWX_GET_DISP_OFFSET(rstate);
629 n = COPYIN_MSTACK_8((char *)valp, p);
630 if (n != DWORDSZ)
631 status = UWX_ERR_COPYIN_MSTK;
632 *histp = UWX_DISP_MSTK(p);
633 break;
634 case UWX_DISP_REG(0):
635 regid = UWX_GET_DISP_REGID(rstate);
636 status = uwx_get_reg(env, regid, valp);
637 (void) uwx_get_spill_loc(env, regid, histp);
638 break;
639 }
640 return status;
641}
642
643#define COPYIN_MSTACK_16(dest, src) \
644 (env->remote? \
645 (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \
646 2*DWORDSZ, env->cb_token) : \
647 (*(uint64_t *)(dest) = *(uint64_t *)(src), \
648 *(uint64_t *)((dest)+8) = *(uint64_t *)((src)+8), \
649 2*DWORDSZ) )
650
651int uwx_restore_freg(struct uwx_env *env, uint64_t rstate,
652 uint64_t *valp, uint64_t *histp)
653{
654 int status;
655 uint64_t p;
656 int n;
657 int regid;
658
659 status = UWX_OK;
660
661 switch (UWX_GET_DISP_CODE(rstate)) {
662 case UWX_DISP_SPREL(0):
663 p = env->context.special[UWX_REG_SP] +
664 UWX_GET_DISP_OFFSET(rstate);
665 n = COPYIN_MSTACK_16((char *)valp, p);
666 if (n != 2*DWORDSZ)
667 status = UWX_ERR_COPYIN_MSTK;
668 *histp = UWX_DISP_MSTK(p);
669 break;
670 case UWX_DISP_PSPREL(0):
671 p = env->context.special[UWX_REG_PSP] + 16 -
672 UWX_GET_DISP_OFFSET(rstate);
673 n = COPYIN_MSTACK_16((char *)valp, p);
674 if (n != 2*DWORDSZ)
675 status = UWX_ERR_COPYIN_MSTK;
676 *histp = UWX_DISP_MSTK(p);
677 break;
678 case UWX_DISP_REG(0):
679 regid = UWX_GET_DISP_REGID(rstate);
680 status = uwx_get_reg(env, regid, valp);
681 (void) uwx_get_spill_loc(env, regid, histp);
682 break;
683 }
684 return status;
685}
686
687/* uwx_restore_nat: Returns the saved NaT bit for a preserved GR */
688
689int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat)
690{
691 int nat;
692 uint64_t p;
693
694 nat = 0;
695 switch (UWX_GET_DISP_CODE(rstate)) {
696 case UWX_DISP_SPREL(0):
697 p = env->context.special[UWX_REG_SP] +
698 UWX_GET_DISP_OFFSET(rstate);
699 nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01;
700 break;
701 case UWX_DISP_PSPREL(0):
702 p = env->context.special[UWX_REG_PSP] + 16 -
703 UWX_GET_DISP_OFFSET(rstate);
704 nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01;
705 break;
706 case UWX_DISP_REG(0):
707 (void) uwx_get_nat(env, UWX_GET_DISP_REGID(rstate), &nat);
708 break;
709 }
710 return nat;
711}
712