]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/ia64/libuwx/src/uwx_step.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / ia64 / libuwx / src / uwx_step.c
1 /*
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
10 conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
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.
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
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);
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*/
60 int 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 */
68 static
69 int 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
256 int 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
311 int 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
379 int 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
406 int 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
474 int 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
670 int 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
716 int 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
766 int 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
804 int 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