2 Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation
5 files (the "Software"), to deal in the Software without
6 restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
26 #include "uwx_utable.h"
27 #include "uwx_uinfo.h"
28 #include "uwx_scoreboard.h"
31 #include "uwx_trace.h"
36 * This file contains the routines for stepping from one frame
37 * into its callers frame. The context for the current frame
38 * is maintained inside the current unwind environment
39 * (struct uwx_env), and is updated with each call to
40 * uwx_step() to refer to the previous frame.
44 /* Forward Declarations */
46 int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate);
47 int uwx_restore_reg(struct uwx_env *env, uint64_t rstate,
48 uint64_t *valp, uint64_t *histp);
49 int uwx_restore_freg(struct uwx_env *env, uint64_t rstate,
50 uint64_t *valp, uint64_t *histp);
51 int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat);
54 /* uwx_lookupip_hook: Hook routine so dynamic instrumentation */
55 /* tools can intercept Lookup IP events. When not */
56 /* intercepted, it just returns "Not found", so that */
57 /* the callback routine is invoked. */
60 int uwx_lookupip_hook(int request, uint64_t ip, intptr_t tok, uint64_t **vecp,
63 return UWX_LKUP_NOTFOUND;
67 /* uwx_get_frame_info: Gets unwind info for current frame */
69 int uwx_get_frame_info(struct uwx_env *env)
78 struct uwx_utable_entry uentry;
79 uint64_t uvecout[UVECSIZE];
81 if (env->copyin == 0 || env->lookupip == 0)
82 return UWX_ERR_NOCALLBACKS;
84 env->ptr_size = DWORDSZ;
86 env->function_offset = -1LL;
87 env->function_name = 0;
90 uwx_reset_str_pool(env);
92 /* Use the lookup IP callback routine to find out about the */
93 /* current IP. If the predicate registers are valid, pass them */
96 /* When self-unwinding, we call a hook routine before the */
97 /* callback. If the application is running under control of */
98 /* a dynamic instrumentation tool, that tool will have an */
99 /* opportunity to intercept lookup IP requests. */
102 uvecout[i++] = UWX_KEY_VERSION;
103 uvecout[i++] = UWX_VERSION;
104 if (env->context.valid_regs & (1 << UWX_REG_PREDS)) {
105 uvecout[i++] = UWX_KEY_PREDS;
106 uvecout[i++] = env->context.special[UWX_REG_PREDS];
108 uvecout[i++] = UWX_KEY_END;
111 cbstatus = UWX_LKUP_NOTFOUND;
112 ip = env->context.special[UWX_REG_IP];
113 env->remapped_ip = ip;
115 /* Call the hook routine. */
117 if (env->remote == 0)
118 cbstatus = uwx_lookupip_hook(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec,
121 /* If the hook routine remapped the IP, use the new IP for */
122 /* the callback instead of the original IP. */
124 if (cbstatus == UWX_LKUP_REMAP) {
125 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
126 switch ((int)uvec[i]) {
132 env->remapped_ip = ip;
135 /* Now call the callback routine unless the hook routine gave */
136 /* us all the info. */
138 if (cbstatus == UWX_LKUP_NOTFOUND || cbstatus == UWX_LKUP_REMAP) {
140 cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec);
143 /* If the callback routine remapped the IP, call it one more time */
144 /* with the new IP. */
146 if (cbstatus == UWX_LKUP_REMAP) {
147 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
148 switch ((int)uvec[i]) {
154 env->remapped_ip = ip;
155 cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec);
158 /* If NOTFOUND, there's nothing we can do but return an error. */
160 if (cbstatus == UWX_LKUP_NOTFOUND) {
161 status = UWX_ERR_IPNOTFOUND;
164 /* If the callback returns an unwind table, we need to */
165 /* search the table for an unwind entry that describes the */
166 /* code region of interest, then decode the unwind information */
167 /* associated with that unwind table entry, and store the */
168 /* resulting register state array in the unwind environment */
171 else if (cbstatus == UWX_LKUP_UTABLE) {
172 status = uwx_search_utable(env, ip, uvec, &uentry);
174 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
175 if (status == UWX_OK) {
176 env->ptr_size = uentry.ptr_size;
177 env->code_start = uentry.code_start;
178 status = uwx_decode_uinfo(env, &uentry, &rstate);
180 if (status == UWX_ERR_NOUENTRY || status == UWX_ERR_NOUDESC)
181 status = uwx_default_rstate(env, &rstate);
182 if (status == UWX_OK)
183 env->rstate = rstate;
186 /* If the callback returns an unwind info block, we can */
187 /* proceed directly to decoding the unwind information. */
189 else if (cbstatus == UWX_LKUP_UINFO) {
190 uentry.ptr_size = DWORDSZ;
191 uentry.code_start = 0;
193 uentry.unwind_info = 0;
194 uentry.unwind_flags = 0;
195 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
196 switch ((int)uvec[i]) {
198 uentry.unwind_flags = uvec[i+1];
199 if (uentry.unwind_flags & UNWIND_TBL_32BIT)
200 uentry.ptr_size = WORDSZ;
203 uentry.unwind_info = uvec[i+1];
206 uwx_set_reg(env, UWX_REG_GP, uvec[i+1]);
210 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
214 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
216 case UWX_KEY_FUNCSTART:
217 uentry.code_start = uvec[i+1];
218 env->code_start = uentry.code_start;
222 env->ptr_size = uentry.ptr_size;
224 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
225 status = uwx_decode_uinfo(env, &uentry, &rstate);
226 if (status == UWX_ERR_NOUDESC)
227 status = uwx_default_rstate(env, &rstate);
228 if (status == UWX_OK)
229 env->rstate = rstate;
232 /* If the callback returns a frame description (in the form */
233 /* of an update vector), convert the update vector into a */
234 /* register state array, then invoke the callback again to */
235 /* let it free any memory it allocated. */
237 else if (cbstatus == UWX_LKUP_FDESC) {
238 status = uwx_decode_uvec(env, uvec, &rstate);
240 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
241 if (status == UWX_OK)
242 env->rstate = rstate;
245 /* Any other return from the callback is an error. */
248 status = UWX_ERR_LOOKUPERR;
254 /* uwx_restore_markers: Restores the stack markers -- PSP, RP, PFS */
256 int uwx_restore_markers(struct uwx_env *env)
262 if ((env->context.valid_regs & VALID_BASIC4) != VALID_BASIC4)
263 return UWX_ERR_NOCONTEXT;
265 /* If we haven't already obtained the frame info for the */
266 /* current frame, get it now. */
268 if (env->rstate == 0) {
269 status = uwx_get_frame_info(env);
270 if (status != UWX_OK)
274 TRACE_S_STEP(env->rstate)
276 if (env->rstate[SBREG_PSP] != UWX_DISP_NONE) {
277 status = uwx_restore_reg(env, env->rstate[SBREG_PSP], &val, &hist);
278 if (status != UWX_OK)
280 env->context.special[UWX_REG_PSP] = val;
281 env->history.special[UWX_REG_PSP] = hist;
282 env->context.valid_regs |= 1 << UWX_REG_PSP;
283 TRACE_S_RESTORE_REG("PSP", env->rstate[SBREG_PSP], val)
286 if (env->rstate[SBREG_RP] != UWX_DISP_NONE) {
287 status = uwx_restore_reg(env, env->rstate[SBREG_RP], &val, &hist);
288 if (status != UWX_OK)
290 env->context.special[UWX_REG_RP] = val;
291 env->history.special[UWX_REG_RP] = hist;
292 env->context.valid_regs |= 1 << UWX_REG_RP;
293 TRACE_S_RESTORE_REG("RP", env->rstate[SBREG_RP], val)
296 if (env->rstate[SBREG_PFS] != UWX_DISP_NONE) {
297 status = uwx_restore_reg(env, env->rstate[SBREG_PFS], &val, &hist);
298 if (status != UWX_OK)
300 env->context.special[UWX_REG_PFS] = val;
301 env->history.special[UWX_REG_PFS] = hist;
302 env->context.valid_regs |= 1 << UWX_REG_PFS;
303 TRACE_S_RESTORE_REG("PFS", env->rstate[SBREG_PFS], val)
309 /* uwx_get_module_info: Gets module name and text base for current frame */
311 int uwx_get_module_info(
321 uint64_t uvecout[UVECSIZE];
324 return UWX_ERR_NOENV;
326 /* If we haven't already obtained the frame info for the */
327 /* current frame, get it now. */
329 if (env->rstate == 0) {
330 status = uwx_get_frame_info(env);
331 if (status != UWX_OK)
335 /* Get the module name from the lookup IP callback. */
336 if (env->module_name == 0) {
337 ip = env->remapped_ip;
339 if (env->function_offset >= 0) {
340 uvecout[i++] = UWX_KEY_FUNCSTART;
341 uvecout[i++] = ip - env->function_offset;
343 uvecout[i++] = UWX_KEY_END;
346 cbstatus = (*env->lookupip)(UWX_LKUP_MODULE, ip, env->cb_token, &uvec);
348 if (cbstatus == UWX_LKUP_SYMINFO) {
349 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
350 switch ((int)uvec[i]) {
352 env->text_base = uvec[i+1];
356 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
360 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
362 case UWX_KEY_FUNCSTART:
363 env->function_offset = ip - uvec[i+1];
367 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
371 *modp = env->module_name;
372 *text_base = env->text_base;
377 /* uwx_get_funcstart: Gets start address of function from current frame */
379 int uwx_get_funcstart(
386 return UWX_ERR_NOENV;
388 /* If we haven't already obtained the frame info for the */
389 /* current frame, get it now. */
391 if (env->rstate == 0) {
392 status = uwx_get_frame_info(env);
393 if (status != UWX_OK)
397 *funcstart = env->remapped_ip - env->function_offset;
402 /* uwx_get_sym_info: Gets symbolic info from current frame */
403 /* (Will make a UWX_LKUP_SYMBOLS callback if info */
404 /* was not provided by UWX_LKUP_LOOKUP callback) */
406 int uwx_get_sym_info(
416 uint64_t uvecout[UVECSIZE];
420 return UWX_ERR_NOENV;
422 /* If we haven't already obtained the frame info for the */
423 /* current frame, get it now. */
425 if (env->rstate == 0) {
426 status = uwx_get_frame_info(env);
427 if (status != UWX_OK)
431 /* Get the symbolic information from the lookup IP callback. */
432 if (env->function_name == 0) {
433 ip = env->remapped_ip;
435 if (env->function_offset >= 0) {
436 uvecout[i++] = UWX_KEY_FUNCSTART;
437 uvecout[i++] = ip - env->function_offset;
439 uvecout[i++] = UWX_KEY_END;
442 cbstatus = (*env->lookupip)(UWX_LKUP_SYMBOLS, ip, env->cb_token, &uvec);
444 if (cbstatus == UWX_LKUP_SYMINFO) {
445 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
446 switch ((int)uvec[i]) {
449 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
453 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
455 case UWX_KEY_FUNCSTART:
456 env->function_offset = ip - uvec[i+1];
460 (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
464 *modp = env->module_name;
465 *symp = env->function_name;
466 *offsetp = env->function_offset;
472 /* uwx_step: Steps from the current frame to the previous frame */
474 int uwx_step(struct uwx_env *env)
483 uint64_t tempgr[NPRESERVEDGR];
489 return UWX_ERR_NOENV;
491 /* Complete the current context by restoring the current values */
492 /* of psp, rp, and pfs. */
494 if (env->rstate == 0 ||
495 (env->context.valid_regs & VALID_MARKERS) != VALID_MARKERS) {
496 status = uwx_restore_markers(env);
497 if (status != UWX_OK)
501 /* Check for bottom of stack (rp == 0). */
503 if (env->context.special[UWX_REG_RP] == 0)
506 /* Find where the primary unat is saved, get a copy. */
507 /* Then, as we restore the GRs, we'll merge the NaT bits into the */
508 /* priunat register in the context. */
509 /* (Make sure we need it, though, before we try to get it, */
510 /* because the attempt to get it might invoke the copy-in callback. */
511 /* We don't need the priunat unless one of GR 4-7 was */
512 /* saved to the memory stack.) */
515 for (i = 0; i < NSB_GR; i++) {
516 dispcode = UWX_GET_DISP_CODE(env->rstate[SBREG_GR + i]);
517 if (dispcode == UWX_DISP_SPREL(0) || dispcode == UWX_DISP_PSPREL(0))
521 if (needpriunat && env->rstate[SBREG_PRIUNAT] != UWX_DISP_NONE) {
522 status = uwx_restore_reg(env, env->rstate[SBREG_PRIUNAT], &val, &hist);
523 if (status != UWX_OK)
526 env->history.special[UWX_REG_PRIUNAT] = hist;
527 TRACE_S_RESTORE_REG("PRIUNAT", env->rstate[SBREG_PRIUNAT], val)
530 /* Retrieve saved values of the preserved GRs into temporaries. */
532 tempnat = (int) env->context.special[UWX_REG_PRIUNAT];
533 for (i = 0; i < NSB_GR; i++) {
534 if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) {
535 status = uwx_restore_reg(env,
536 env->rstate[SBREG_GR + i], &val, &hist);
537 if (status != UWX_OK)
540 if (uwx_restore_nat(env, env->rstate[SBREG_GR + i], unat))
543 tempnat &= ~(1 << i);
544 env->history.gr[i] = hist;
545 env->context.valid_regs |= 1 << (i + VALID_GR_SHIFT);
546 TRACE_S_RESTORE_GR(i, env->rstate[SBREG_GR + i], val)
550 /* Now we have everything we need to step back to the previous frame. */
552 /* Restore preserved BRs. */
554 for (i = 0; i < NSB_BR; i++) {
555 if (env->rstate[SBREG_BR + i] != UWX_DISP_NONE) {
556 status = uwx_restore_reg(env,
557 env->rstate[SBREG_BR + i], &val, &hist);
558 if (status != UWX_OK)
560 env->context.br[i] = val;
561 env->history.br[i] = hist;
562 env->context.valid_regs |= 1 << (i + VALID_BR_SHIFT);
563 TRACE_S_RESTORE_BR(i, env->rstate[SBREG_BR + i], val)
567 /* Restore preserved FRs. */
569 if (env->nsbreg == NSBREG) {
570 for (i = 0; i < NSB_FR; i++) {
571 if (env->rstate[SBREG_FR + i] != UWX_DISP_NONE) {
572 status = uwx_restore_freg(env,
573 env->rstate[SBREG_FR + i], fval, &hist);
574 if (status != UWX_OK)
576 env->context.fr[i].part0 = fval[0];
577 env->context.fr[i].part1 = fval[1];
578 env->history.fr[i] = hist;
579 env->context.valid_frs |= 1 << i;
580 TRACE_S_RESTORE_FR(i, env->rstate[SBREG_FR + i], fval)
585 /* Restore other preserved regs. */
587 if (env->rstate[SBREG_PREDS] != UWX_DISP_NONE) {
588 status = uwx_restore_reg(env, env->rstate[SBREG_PREDS], &val, &hist);
589 if (status != UWX_OK)
591 env->context.special[UWX_REG_PREDS] = val;
592 env->history.special[UWX_REG_PREDS] = hist;
593 env->context.valid_regs |= 1 << UWX_REG_PREDS;
594 TRACE_S_RESTORE_REG("PREDS", env->rstate[SBREG_PREDS], val)
596 if (env->rstate[SBREG_RNAT] != UWX_DISP_NONE) {
597 status = uwx_restore_reg(env, env->rstate[SBREG_RNAT], &val, &hist);
598 if (status != UWX_OK)
600 env->context.special[UWX_REG_AR_RNAT] = val;
601 env->history.special[UWX_REG_AR_RNAT] = hist;
602 env->context.valid_regs |= 1 << UWX_REG_AR_RNAT;
603 TRACE_S_RESTORE_REG("RNAT", env->rstate[SBREG_RNAT], val)
605 if (env->rstate[SBREG_UNAT] != UWX_DISP_NONE) {
606 status = uwx_restore_reg(env, env->rstate[SBREG_UNAT], &val, &hist);
607 if (status != UWX_OK)
609 env->context.special[UWX_REG_AR_UNAT] = val;
610 env->history.special[UWX_REG_AR_UNAT] = hist;
611 env->context.valid_regs |= 1 << UWX_REG_AR_UNAT;
612 TRACE_S_RESTORE_REG("UNAT", env->rstate[SBREG_UNAT], val)
614 if (env->rstate[SBREG_FPSR] != UWX_DISP_NONE) {
615 status = uwx_restore_reg(env, env->rstate[SBREG_FPSR], &val, &hist);
616 if (status != UWX_OK)
618 env->context.special[UWX_REG_AR_FPSR] = val;
619 env->history.special[UWX_REG_AR_FPSR] = hist;
620 env->context.valid_regs |= 1 << UWX_REG_AR_FPSR;
621 TRACE_S_RESTORE_REG("FPSR", env->rstate[SBREG_FPSR], val)
623 if (env->rstate[SBREG_LC] != UWX_DISP_NONE) {
624 status = uwx_restore_reg(env, env->rstate[SBREG_LC], &val, &hist);
625 if (status != UWX_OK)
627 env->context.special[UWX_REG_AR_LC] = val;
628 env->history.special[UWX_REG_AR_LC] = hist;
629 env->context.valid_regs |= 1 << UWX_REG_AR_LC;
630 TRACE_S_RESTORE_REG("LC", env->rstate[SBREG_LC], val)
633 /* Restore preserved GRs from temporaries. */
635 for (i = 0; i < NSB_GR; i++) {
636 if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE)
637 env->context.gr[i] = tempgr[i];
639 env->context.special[UWX_REG_PRIUNAT] = tempnat;
641 /* Restore the frame markers. */
643 env->context.special[UWX_REG_IP] = env->context.special[UWX_REG_RP];
644 env->history.special[UWX_REG_IP] = env->history.special[UWX_REG_RP];
646 env->context.special[UWX_REG_SP] = env->context.special[UWX_REG_PSP];
647 env->history.special[UWX_REG_SP] = env->history.special[UWX_REG_PSP];
649 pfs_sol = ((unsigned int)env->context.special[UWX_REG_PFS] >> 7) & 0x7f;
650 env->context.special[UWX_REG_BSP] = uwx_add_to_bsp(
651 env->context.special[UWX_REG_BSP],
654 env->context.special[UWX_REG_CFM] = env->context.special[UWX_REG_PFS];
655 env->history.special[UWX_REG_CFM] = env->history.special[UWX_REG_PFS];
657 env->context.special[UWX_REG_RP] = 0;
659 /* The frame info for the new frame isn't yet available. */
662 env->context.valid_regs &= ~VALID_MARKERS;
668 /* uwx_decode_uvec: Converts the update vector into a register state array */
670 int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate)
675 status = uwx_default_rstate(env, rstate);
676 if (status != UWX_OK)
679 for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
680 switch ((int)uvec[i]) {
681 case UWX_KEY_CONTEXT:
682 env->abi_context = (int)(uvec[i+1]);
683 status = UWX_ABI_FRAME;
686 uwx_set_reg(env, UWX_REG_GP, uvec[i+1]);
690 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
694 uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
696 case UWX_KEY_FUNCSTART:
697 env->function_offset = env->remapped_ip - uvec[i+1];
700 return UWX_ERR_CANTUNWIND;
707 /* uwx_restore_reg: Restores a register according to the scoreboard */
709 #define COPYIN_MSTACK_8(dest, src) \
711 (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \
712 DWORDSZ, env->cb_token) : \
713 (*(uint64_t *)(intptr_t)(dest) = \
714 *(uint64_t *)(intptr_t)(src), DWORDSZ) )
716 int uwx_restore_reg(struct uwx_env *env, uint64_t rstate,
717 uint64_t *valp, uint64_t *histp)
726 switch (UWX_GET_DISP_CODE(rstate)) {
727 case UWX_DISP_SPPLUS(0):
728 *valp = env->context.special[UWX_REG_SP] +
729 UWX_GET_DISP_OFFSET(rstate);
730 *histp = UWX_DISP_NONE;
732 case UWX_DISP_SPREL(0):
733 p = env->context.special[UWX_REG_SP] +
734 UWX_GET_DISP_OFFSET(rstate);
735 n = COPYIN_MSTACK_8((char *)valp, p);
737 status = UWX_ERR_COPYIN_MSTK;
738 *histp = UWX_DISP_MSTK(p);
740 case UWX_DISP_PSPREL(0):
741 p = env->context.special[UWX_REG_PSP] + 16 -
742 UWX_GET_DISP_OFFSET(rstate);
743 n = COPYIN_MSTACK_8((char *)valp, p);
745 status = UWX_ERR_COPYIN_MSTK;
746 *histp = UWX_DISP_MSTK(p);
748 case UWX_DISP_REG(0):
749 regid = UWX_GET_DISP_REGID(rstate);
750 status = uwx_get_reg(env, regid, valp);
751 (void) uwx_get_spill_loc(env, regid, histp);
757 #define COPYIN_MSTACK_16(dest, src) \
759 (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \
760 2*DWORDSZ, env->cb_token) : \
761 (*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), \
762 *(uint64_t *)(intptr_t)((dest)+8) = \
763 *(uint64_t *)(intptr_t)((src)+8), \
766 int uwx_restore_freg(struct uwx_env *env, uint64_t rstate,
767 uint64_t *valp, uint64_t *histp)
776 switch (UWX_GET_DISP_CODE(rstate)) {
777 case UWX_DISP_SPREL(0):
778 p = env->context.special[UWX_REG_SP] +
779 UWX_GET_DISP_OFFSET(rstate);
780 n = COPYIN_MSTACK_16((char *)valp, p);
782 status = UWX_ERR_COPYIN_MSTK;
783 *histp = UWX_DISP_MSTK(p);
785 case UWX_DISP_PSPREL(0):
786 p = env->context.special[UWX_REG_PSP] + 16 -
787 UWX_GET_DISP_OFFSET(rstate);
788 n = COPYIN_MSTACK_16((char *)valp, p);
790 status = UWX_ERR_COPYIN_MSTK;
791 *histp = UWX_DISP_MSTK(p);
793 case UWX_DISP_REG(0):
794 regid = UWX_GET_DISP_REGID(rstate);
795 status = uwx_get_reg(env, regid, valp);
796 (void) uwx_get_spill_loc(env, regid, histp);
802 /* uwx_restore_nat: Returns the saved NaT bit for a preserved GR */
804 int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat)
810 switch (UWX_GET_DISP_CODE(rstate)) {
811 case UWX_DISP_SPREL(0):
812 p = env->context.special[UWX_REG_SP] +
813 UWX_GET_DISP_OFFSET(rstate);
814 nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01;
816 case UWX_DISP_PSPREL(0):
817 p = env->context.special[UWX_REG_PSP] + 16 -
818 UWX_GET_DISP_OFFSET(rstate);
819 nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01;
821 case UWX_DISP_REG(0):
822 (void) uwx_get_nat(env, UWX_GET_DISP_REGID(rstate), &nat);