uwx_step.c revision 129059
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
713