1/*
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_uinfo.h"
28#include "uwx_scoreboard.h"
29#include "uwx_str.h"
30#include "uwx_step.h"
31#include "uwx_trace.h"
32
33/*
34 *  uwx_step.c
35 *
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.
41 */
42
43
44/* Forward Declarations */
45
46int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate);
47int uwx_restore_reg(struct uwx_env *env, uint64_t rstate,
48					uint64_t *valp, uint64_t *histp);
49int uwx_restore_freg(struct uwx_env *env, uint64_t rstate,
50					uint64_t *valp, uint64_t *histp);
51int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat);
52
53
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. */
58
59/*ARGSUSED*/
60int uwx_lookupip_hook(int request, uint64_t ip, intptr_t tok, uint64_t **vecp,
61			size_t uvecsize)
62{
63    return UWX_LKUP_NOTFOUND;
64}
65
66
67/* uwx_get_frame_info: Gets unwind info for current frame */
68static
69int uwx_get_frame_info(struct uwx_env *env)
70{
71    int i;
72    int status;
73    int cbstatus;
74    int cbcalled = 0;
75    uint64_t ip;
76    uint64_t *uvec;
77    uint64_t *rstate;
78    struct uwx_utable_entry uentry;
79    uint64_t uvecout[UVECSIZE];
80
81    if (env->copyin == 0 || env->lookupip == 0)
82	return UWX_ERR_NOCALLBACKS;
83
84    env->ptr_size = DWORDSZ;
85    env->code_start = 0;
86    env->function_offset = -1LL;
87    env->function_name = 0;
88    env->module_name = 0;
89    env->abi_context = 0;
90    uwx_reset_str_pool(env);
91
92    /* Use the lookup IP callback routine to find out about the */
93    /* current IP. If the predicate registers are valid, pass them */
94    /* in the uvec. */
95
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. */
100
101    i = 0;
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];
107    }
108    uvecout[i++] = UWX_KEY_END;
109    uvecout[i++] = 0;
110    uvec = uvecout;
111    cbstatus = UWX_LKUP_NOTFOUND;
112    ip = env->context.special[UWX_REG_IP];
113    env->remapped_ip = ip;
114
115    /* Call the hook routine. */
116
117    if (env->remote == 0)
118	cbstatus = uwx_lookupip_hook(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec,
119		sizeof(uvecout));
120
121    /* If the hook routine remapped the IP, use the new IP for */
122    /* the callback instead of the original IP. */
123
124    if (cbstatus == UWX_LKUP_REMAP) {
125	for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
126	    switch ((int)uvec[i]) {
127		case UWX_KEY_NEWIP:
128		    ip = uvec[i+1];
129		    break;
130	    }
131	}
132	env->remapped_ip = ip;
133    }
134
135    /* Now call the callback routine unless the hook routine gave */
136    /* us all the info. */
137
138    if (cbstatus == UWX_LKUP_NOTFOUND || cbstatus == UWX_LKUP_REMAP) {
139	cbcalled = 1;
140	cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec);
141    }
142
143    /* If the callback routine remapped the IP, call it one more time */
144    /* with the new IP. */
145
146    if (cbstatus == UWX_LKUP_REMAP) {
147	for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
148	    switch ((int)uvec[i]) {
149		case UWX_KEY_NEWIP:
150		    ip = uvec[i+1];
151		    break;
152	    }
153	}
154	env->remapped_ip = ip;
155	cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec);
156    }
157
158    /* If NOTFOUND, there's nothing we can do but return an error. */
159
160    if (cbstatus == UWX_LKUP_NOTFOUND) {
161	status = UWX_ERR_IPNOTFOUND;
162    }
163
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 */
169    /* block. */
170
171    else if (cbstatus == UWX_LKUP_UTABLE) {
172	status = uwx_search_utable(env, ip, uvec, &uentry);
173	if (cbcalled)
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);
179	}
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;
184    }
185
186    /* If the callback returns an unwind info block, we can */
187    /* proceed directly to decoding the unwind information. */
188
189    else if (cbstatus == UWX_LKUP_UINFO) {
190	uentry.ptr_size = DWORDSZ;
191	uentry.code_start = 0;
192	uentry.code_end = 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]) {
197		case UWX_KEY_UFLAGS:
198		    uentry.unwind_flags = uvec[i+1];
199		    if (uentry.unwind_flags & UNWIND_TBL_32BIT)
200			uentry.ptr_size = WORDSZ;
201		    break;
202		case UWX_KEY_UINFO:
203		    uentry.unwind_info = uvec[i+1];
204		    break;
205		case UWX_KEY_GP:
206		    uwx_set_reg(env, UWX_REG_GP, uvec[i+1]);
207		    break;
208		case UWX_KEY_MODULE:
209		    env->module_name =
210			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
211		    break;
212		case UWX_KEY_FUNC:
213		    env->function_name =
214			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
215		    break;
216		case UWX_KEY_FUNCSTART:
217		    uentry.code_start = uvec[i+1];
218		    env->code_start = uentry.code_start;
219		    break;
220	    }
221	}
222	env->ptr_size = uentry.ptr_size;
223	if (cbcalled)
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;
230    }
231
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. */
236
237    else if (cbstatus == UWX_LKUP_FDESC) {
238	status = uwx_decode_uvec(env, uvec, &rstate);
239	if (cbcalled)
240	    (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
241	if (status == UWX_OK)
242	    env->rstate = rstate;
243    }
244
245    /* Any other return from the callback is an error. */
246
247    else {
248	status = UWX_ERR_LOOKUPERR;
249    }
250    return status;
251}
252
253
254/* uwx_restore_markers: Restores the stack markers -- PSP, RP, PFS */
255
256int uwx_restore_markers(struct uwx_env *env)
257{
258    int status;
259    uint64_t val;
260    uint64_t hist;
261
262    if ((env->context.valid_regs & VALID_BASIC4) != VALID_BASIC4)
263	return UWX_ERR_NOCONTEXT;
264
265    /* If we haven't already obtained the frame info for the */
266    /* current frame, get it now. */
267
268    if (env->rstate == 0) {
269	status = uwx_get_frame_info(env);
270	if (status != UWX_OK)
271	    return status;
272    }
273
274    TRACE_S_STEP(env->rstate)
275
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)
279	    return status;
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)
284    }
285
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)
289	    return status;
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)
294    }
295
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)
299	    return status;
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)
304    }
305
306    return UWX_OK;
307}
308
309/* uwx_get_module_info: Gets module name and text base for current frame */
310
311int uwx_get_module_info(
312    struct uwx_env *env,
313    char **modp,
314    uint64_t *text_base)
315{
316    int i;
317    int status;
318    int cbstatus;
319    uint64_t ip;
320    uint64_t *uvec;
321    uint64_t uvecout[UVECSIZE];
322
323    if (env == 0)
324	return UWX_ERR_NOENV;
325
326    /* If we haven't already obtained the frame info for the */
327    /* current frame, get it now. */
328
329    if (env->rstate == 0) {
330	status = uwx_get_frame_info(env);
331	if (status != UWX_OK)
332	    return status;
333    }
334
335    /* Get the module name from the lookup IP callback. */
336    if (env->module_name == 0) {
337	ip = env->remapped_ip;
338	i = 0;
339	if (env->function_offset >= 0) {
340	    uvecout[i++] = UWX_KEY_FUNCSTART;
341	    uvecout[i++] = ip - env->function_offset;
342	}
343	uvecout[i++] = UWX_KEY_END;
344	uvecout[i++] = 0;
345	uvec = uvecout;
346	cbstatus = (*env->lookupip)(UWX_LKUP_MODULE, ip, env->cb_token, &uvec);
347
348	if (cbstatus == UWX_LKUP_SYMINFO) {
349	    for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
350		switch ((int)uvec[i]) {
351		    case UWX_KEY_TBASE:
352			env->text_base = uvec[i+1];
353			break;
354		    case UWX_KEY_MODULE:
355			env->module_name =
356			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
357			break;
358		    case UWX_KEY_FUNC:
359			env->function_name =
360			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
361			break;
362		    case UWX_KEY_FUNCSTART:
363			env->function_offset = ip - uvec[i+1];
364			break;
365		}
366	    }
367	    (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
368	}
369    }
370
371    *modp = env->module_name;
372    *text_base = env->text_base;
373
374    return UWX_OK;
375}
376
377/* uwx_get_funcstart: Gets start address of function from current frame */
378
379int uwx_get_funcstart(
380    struct uwx_env *env,
381    uint64_t *funcstart)
382{
383    int status;
384
385    if (env == 0)
386	return UWX_ERR_NOENV;
387
388    /* If we haven't already obtained the frame info for the */
389    /* current frame, get it now. */
390
391    if (env->rstate == 0) {
392	status = uwx_get_frame_info(env);
393	if (status != UWX_OK)
394	    return status;
395    }
396
397    *funcstart = env->remapped_ip - env->function_offset;
398
399    return UWX_OK;
400}
401
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) */
405
406int uwx_get_sym_info(
407    struct uwx_env *env,
408    char **modp,
409    char **symp,
410    uint64_t *offsetp)
411{
412    int status;
413    int cbstatus;
414    uint64_t ip;
415    uint64_t *uvec;
416    uint64_t uvecout[UVECSIZE];
417    int i;
418
419    if (env == 0)
420	return UWX_ERR_NOENV;
421
422    /* If we haven't already obtained the frame info for the */
423    /* current frame, get it now. */
424
425    if (env->rstate == 0) {
426	status = uwx_get_frame_info(env);
427	if (status != UWX_OK)
428	    return status;
429    }
430
431    /* Get the symbolic information from the lookup IP callback. */
432    if (env->function_name == 0) {
433	ip = env->remapped_ip;
434	i = 0;
435	if (env->function_offset >= 0) {
436	    uvecout[i++] = UWX_KEY_FUNCSTART;
437	    uvecout[i++] = ip - env->function_offset;
438	}
439	uvecout[i++] = UWX_KEY_END;
440	uvecout[i++] = 0;
441	uvec = uvecout;
442	cbstatus = (*env->lookupip)(UWX_LKUP_SYMBOLS, ip, env->cb_token, &uvec);
443
444	if (cbstatus == UWX_LKUP_SYMINFO) {
445	    for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
446		switch ((int)uvec[i]) {
447		    case UWX_KEY_MODULE:
448			env->module_name =
449			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
450			break;
451		    case UWX_KEY_FUNC:
452			env->function_name =
453			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
454			break;
455		    case UWX_KEY_FUNCSTART:
456			env->function_offset = ip - uvec[i+1];
457			break;
458		}
459	    }
460	    (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
461	}
462    }
463
464    *modp = env->module_name;
465    *symp = env->function_name;
466    *offsetp = env->function_offset;
467
468    return UWX_OK;
469}
470
471
472/* uwx_step: Steps from the current frame to the previous frame */
473
474int uwx_step(struct uwx_env *env)
475{
476    int i;
477    int status;
478    int pfs_sol;
479    int dispcode;
480    uint64_t val;
481    uint64_t fval[2];
482    uint64_t hist;
483    uint64_t tempgr[NPRESERVEDGR];
484    int needpriunat;
485    int unat;
486    int tempnat;
487
488    if (env == 0)
489	return UWX_ERR_NOENV;
490
491    /* Complete the current context by restoring the current values */
492    /* of psp, rp, and pfs. */
493
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)
498	    return status;
499    }
500
501    /* Check for bottom of stack (rp == 0). */
502
503    if (env->context.special[UWX_REG_RP] == 0)
504	return UWX_BOTTOM;
505
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.) */
513
514    needpriunat = 0;
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))
518	    needpriunat = 1;
519    }
520    unat = 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)
524	    return status;
525	unat = (int) val;
526	env->history.special[UWX_REG_PRIUNAT] = hist;
527	TRACE_S_RESTORE_REG("PRIUNAT", env->rstate[SBREG_PRIUNAT], val)
528    }
529
530    /* Retrieve saved values of the preserved GRs into temporaries. */
531
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)
538		return status;
539	    tempgr[i] = val;
540	    if (uwx_restore_nat(env, env->rstate[SBREG_GR + i], unat))
541		tempnat |= 1 << i;
542	    else
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)
547	}
548    }
549
550    /* Now we have everything we need to step back to the previous frame. */
551
552    /* Restore preserved BRs. */
553
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)
559		return status;
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)
564	}
565    }
566
567    /* Restore preserved FRs. */
568
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)
575		    return status;
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)
581	    }
582	}
583    }
584
585    /* Restore other preserved regs. */
586
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)
590	    return status;
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)
595    }
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)
599	    return status;
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)
604    }
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)
608	    return status;
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)
613    }
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)
617	    return status;
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)
622    }
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)
626	    return status;
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)
631    }
632
633    /* Restore preserved GRs from temporaries. */
634
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];
638    }
639    env->context.special[UWX_REG_PRIUNAT] = tempnat;
640
641    /* Restore the frame markers. */
642
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];
645
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];
648
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],
652				-pfs_sol);
653
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];
656
657    env->context.special[UWX_REG_RP] = 0;
658
659    /* The frame info for the new frame isn't yet available. */
660
661    env->rstate = 0;
662    env->context.valid_regs &= ~VALID_MARKERS;
663
664    return UWX_OK;
665}
666
667
668/* uwx_decode_uvec: Converts the update vector into a register state array */
669
670int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate)
671{
672    int i;
673    int status;
674
675    status = uwx_default_rstate(env, rstate);
676    if (status != UWX_OK)
677	return status;
678
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;
684		break;
685	    case UWX_KEY_GP:
686		uwx_set_reg(env, UWX_REG_GP, uvec[i+1]);
687		break;
688	    case UWX_KEY_MODULE:
689		env->module_name =
690			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
691		break;
692	    case UWX_KEY_FUNC:
693		env->function_name =
694			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
695		break;
696	    case UWX_KEY_FUNCSTART:
697		env->function_offset = env->remapped_ip - uvec[i+1];
698		break;
699	    default:
700		return UWX_ERR_CANTUNWIND;
701	}
702    }
703    return status;
704}
705
706
707/* uwx_restore_reg: Restores a register according to the scoreboard */
708
709#define COPYIN_MSTACK_8(dest, src) \
710    (env->remote? \
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) )
715
716int uwx_restore_reg(struct uwx_env *env, uint64_t rstate,
717				uint64_t *valp, uint64_t *histp)
718{
719    int status;
720    uint64_t p;
721    int n;
722    int regid;
723
724    status = UWX_OK;
725
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;
731	    break;
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);
736	    if (n != DWORDSZ)
737		status = UWX_ERR_COPYIN_MSTK;
738	    *histp = UWX_DISP_MSTK(p);
739	    break;
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);
744	    if (n != DWORDSZ)
745		status = UWX_ERR_COPYIN_MSTK;
746	    *histp = UWX_DISP_MSTK(p);
747	    break;
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);
752	    break;
753    }
754    return status;
755}
756
757#define COPYIN_MSTACK_16(dest, src) \
758    (env->remote? \
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), \
764	    2*DWORDSZ) )
765
766int uwx_restore_freg(struct uwx_env *env, uint64_t rstate,
767				uint64_t *valp, uint64_t *histp)
768{
769    int status;
770    uint64_t p;
771    int n;
772    int regid;
773
774    status = UWX_OK;
775
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);
781	    if (n != 2*DWORDSZ)
782		status = UWX_ERR_COPYIN_MSTK;
783	    *histp = UWX_DISP_MSTK(p);
784	    break;
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);
789	    if (n != 2*DWORDSZ)
790		status = UWX_ERR_COPYIN_MSTK;
791	    *histp = UWX_DISP_MSTK(p);
792	    break;
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);
797	    break;
798    }
799    return status;
800}
801
802/* uwx_restore_nat: Returns the saved NaT bit for a preserved GR */
803
804int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat)
805{
806    int nat;
807    uint64_t p;
808
809    nat = 0;
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;
815	    break;
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;
820	    break;
821	case UWX_DISP_REG(0):
822	    (void) uwx_get_nat(env, UWX_GET_DISP_REGID(rstate), &nat);
823	    break;
824    }
825    return nat;
826}
827
828