uwx_step.c revision 121642
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_get_frame_info: Gets unwind info for current frame */
56static
57int uwx_get_frame_info(struct uwx_env *env)
58{
59    int i;
60    int status;
61    int cbstatus;
62    uint64_t *uvec;
63    uint64_t *rstate;
64    struct uwx_utable_entry uentry;
65    uint64_t uvecout[4];
66
67    if (env->copyin == 0 || env->lookupip == 0)
68	return UWX_ERR_NOCALLBACKS;
69
70    env->function_offset = -1LL;
71    env->function_name = 0;
72    env->module_name = 0;
73    uwx_reset_str_pool(env);
74
75    /* Use the lookup IP callback routine to find out about the */
76    /* current IP. If the predicate registers are valid, pass them */
77    /* in the uvec. */
78
79    i = 0;
80    if (env->context.valid_regs & (1 << UWX_REG_PREDS)) {
81	uvecout[i++] = UWX_KEY_PREDS;
82	uvecout[i++] = env->context.special[UWX_REG_PREDS];
83    }
84    uvecout[i++] = UWX_KEY_END;
85    uvecout[i++] = 0;
86    uvec = uvecout;
87    cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP,
88		env->context.special[UWX_REG_IP], env->cb_token, &uvec);
89
90    /* If NOTFOUND, there's nothing we can do but return an error. */
91
92    if (cbstatus == UWX_LKUP_NOTFOUND) {
93	status = UWX_ERR_IPNOTFOUND;
94    }
95
96    /* If the callback returns an unwind table, we need to */
97    /* search the table for an unwind entry that describes the */
98    /* code region of interest, then decode the unwind information */
99    /* associated with that unwind table entry, and store the */
100    /* resulting register state array in the unwind environment */
101    /* block. */
102
103    else if (cbstatus == UWX_LKUP_UTABLE) {
104	status = uwx_search_utable(env, uvec, &uentry);
105	(void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
106	if (status == UWX_OK)
107	    status = uwx_decode_uinfo(env, &uentry, &rstate);
108	else if (status == UWX_ERR_NOUENTRY)
109	    status = uwx_default_rstate(env, &rstate);
110	if (status == UWX_OK)
111	    env->rstate = rstate;
112    }
113
114    /* If the callback returns a frame description (in the form */
115    /* of an update vector), convert the update vector into a */
116    /* register state array, then invoke the callback again to */
117    /* let it free any memory it allocated. */
118
119    else if (cbstatus == UWX_LKUP_FDESC) {
120	status = uwx_decode_uvec(env, uvec, &rstate);
121	(void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
122	if (status == UWX_OK)
123	    env->rstate = rstate;
124    }
125
126    /* Any other return from the callback is an error. */
127
128    else {
129	status = UWX_ERR_LOOKUPERR;
130    }
131    return status;
132}
133
134
135/* uwx_restore_markers: Restores the stack markers -- PSP, RP, PFS */
136
137int uwx_restore_markers(struct uwx_env *env)
138{
139    int status;
140    uint64_t val;
141    uint64_t hist;
142
143    if ((env->context.valid_regs & VALID_BASIC4) != VALID_BASIC4)
144	return UWX_ERR_NOCONTEXT;
145
146    /* If we haven't already obtained the frame info for the */
147    /* current frame, get it now. */
148
149    if (env->rstate == 0) {
150	status = uwx_get_frame_info(env);
151	if (status != UWX_OK)
152	    return status;
153    }
154
155    TRACE_S_STEP(env->rstate)
156
157    if (env->rstate[SBREG_PSP] != UWX_DISP_NONE) {
158	status = uwx_restore_reg(env, env->rstate[SBREG_PSP], &val, &hist);
159	if (status != UWX_OK)
160	    return status;
161	env->context.special[UWX_REG_PSP] = val;
162	env->history.special[UWX_REG_PSP] = hist;
163	env->context.valid_regs |= 1 << UWX_REG_PSP;
164	TRACE_S_RESTORE_REG("PSP", env->rstate[SBREG_PSP], val)
165    }
166
167    if (env->rstate[SBREG_RP] != UWX_DISP_NONE) {
168	status = uwx_restore_reg(env, env->rstate[SBREG_RP], &val, &hist);
169	if (status != UWX_OK)
170	    return status;
171	env->context.special[UWX_REG_RP] = val;
172	env->history.special[UWX_REG_RP] = hist;
173	env->context.valid_regs |= 1 << UWX_REG_RP;
174	TRACE_S_RESTORE_REG("RP", env->rstate[SBREG_RP], val)
175    }
176
177    if (env->rstate[SBREG_PFS] != UWX_DISP_NONE) {
178	status = uwx_restore_reg(env, env->rstate[SBREG_PFS], &val, &hist);
179	if (status != UWX_OK)
180	    return status;
181	env->context.special[UWX_REG_PFS] = val;
182	env->history.special[UWX_REG_PFS] = hist;
183	env->context.valid_regs |= 1 << UWX_REG_PFS;
184	TRACE_S_RESTORE_REG("PFS", env->rstate[SBREG_PFS], val)
185    }
186
187    return UWX_OK;
188}
189
190/* uwx_get_sym_info: Gets symbolic info from current frame */
191
192int uwx_get_sym_info(
193    struct uwx_env *env,
194    char **modp,
195    char **symp,
196    uint64_t *offsetp)
197{
198    int status;
199    int cbstatus;
200    uint64_t ip;
201    uint64_t *uvec;
202    uint64_t uvecout[2];
203    int i;
204
205    if (env == 0)
206	return UWX_ERR_NOENV;
207
208    /* If we haven't already obtained the frame info for the */
209    /* current frame, get it now. */
210
211    if (env->rstate == 0) {
212	status = uwx_get_frame_info(env);
213	if (status != UWX_OK)
214	    return status;
215    }
216
217    /* Get the symbolic information from the lookup IP callback. */
218    if (env->function_name == 0) {
219	ip = env->context.special[UWX_REG_IP];
220	i = 0;
221	if (env->function_offset >= 0) {
222	    uvecout[i++] = UWX_KEY_FUNCSTART;
223	    uvecout[i++] = ip - env->function_offset;
224	}
225	uvecout[i++] = UWX_KEY_END;
226	uvecout[i++] = 0;
227	uvec = uvecout;
228	cbstatus = (*env->lookupip)(UWX_LKUP_SYMBOLS,
229		    env->context.special[UWX_REG_IP], env->cb_token, &uvec);
230
231	if (cbstatus == UWX_LKUP_SYMINFO) {
232	    for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
233		switch ((int)uvec[i]) {
234		    case UWX_KEY_MODULE:
235			env->module_name =
236				uwx_alloc_str(env, (char *)(uvec[i+1]));
237			break;
238		    case UWX_KEY_FUNC:
239			env->function_name =
240				uwx_alloc_str(env, (char *)(uvec[i+1]));
241			break;
242		    case UWX_KEY_FUNCSTART:
243			env->function_offset = ip - uvec[i+1];
244			break;
245		}
246	    }
247	    (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
248	}
249    }
250
251    *modp = env->module_name;
252    *symp = env->function_name;
253    *offsetp = env->function_offset;
254
255    return UWX_OK;
256}
257
258
259/* uwx_step: Steps from the current frame to the previous frame */
260
261int uwx_step(struct uwx_env *env)
262{
263    int i;
264    int status;
265    int pfs_sol;
266    int dispcode;
267    uint64_t val;
268    uint64_t fval[2];
269    uint64_t hist;
270    uint64_t tempgr[NPRESERVEDGR];
271    int needpriunat;
272    int unat;
273    int tempnat;
274
275    if (env == 0)
276	return UWX_ERR_NOENV;
277
278    /* Complete the current context by restoring the current values */
279    /* of psp, rp, and pfs. */
280
281    if (env->rstate == 0 ||
282	    (env->context.valid_regs & VALID_MARKERS) != VALID_MARKERS) {
283	status = uwx_restore_markers(env);
284	if (status != UWX_OK)
285	    return status;
286    }
287
288    /* Check for bottom of stack (rp == 0). */
289
290    if (env->context.special[UWX_REG_RP] == 0)
291	return UWX_BOTTOM;
292
293    /* Find where the primary unat is saved, get a copy. */
294    /* Then, as we restore the GRs, we'll merge the NaT bits into the */
295    /* priunat register in the context. */
296    /* (Make sure we need it, though, before we try to get it, */
297    /* because the attempt to get it might invoke the copy-in callback. */
298    /* We don't need the priunat unless one of GR 4-7 was */
299    /* saved to the memory stack.) */
300
301    needpriunat = 0;
302    for (i = 0; i < NSB_GR; i++) {
303	dispcode = UWX_GET_DISP_CODE(env->rstate[SBREG_GR + i]);
304	if (dispcode == UWX_DISP_SPREL(0) || dispcode == UWX_DISP_PSPREL(0))
305	    needpriunat = 1;
306    }
307    unat = 0;
308    if (needpriunat && env->rstate[SBREG_PRIUNAT] != UWX_DISP_NONE) {
309	status = uwx_restore_reg(env, env->rstate[SBREG_PRIUNAT], &val, &hist);
310	if (status != UWX_OK)
311	    return status;
312	unat = (int) val;
313	env->history.special[UWX_REG_PRIUNAT] = hist;
314	TRACE_S_RESTORE_REG("PRIUNAT", env->rstate[SBREG_PRIUNAT], val)
315    }
316
317    /* Retrieve saved values of the preserved GRs into temporaries. */
318
319    tempnat = (int) env->context.special[UWX_REG_PRIUNAT];
320    for (i = 0; i < NSB_GR; i++) {
321	if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) {
322	    status = uwx_restore_reg(env,
323			env->rstate[SBREG_GR + i], &val, &hist);
324	    if (status != UWX_OK)
325		return status;
326	    tempgr[i] = val;
327	    if (uwx_restore_nat(env, env->rstate[SBREG_GR + i], unat))
328		tempnat |= 1 << i;
329	    else
330		tempnat &= ~(1 << i);
331	    env->history.gr[i] = hist;
332	    env->context.valid_regs |= 1 << (i + VALID_GR_SHIFT);
333	    TRACE_S_RESTORE_GR(i, env->rstate[SBREG_GR + i], val)
334	}
335    }
336
337    /* Now we have everything we need to step back to the previous frame. */
338
339    /* Restore preserved BRs. */
340
341    for (i = 0; i < NSB_BR; i++) {
342	if (env->rstate[SBREG_BR + i] != UWX_DISP_NONE) {
343	    status = uwx_restore_reg(env,
344			env->rstate[SBREG_BR + i], &val, &hist);
345	    if (status != UWX_OK)
346		return status;
347	    env->context.br[i] = val;
348	    env->history.br[i] = hist;
349	    env->context.valid_regs |= 1 << (i + VALID_BR_SHIFT);
350	    TRACE_S_RESTORE_BR(i, env->rstate[SBREG_BR + i], val)
351	}
352    }
353
354    /* Restore preserved FRs. */
355
356    if (env->nsbreg == NSBREG) {
357	for (i = 0; i < NSB_FR; i++) {
358	    if (env->rstate[SBREG_FR + i] != UWX_DISP_NONE) {
359		status = uwx_restore_freg(env,
360			    env->rstate[SBREG_FR + i], fval, &hist);
361		if (status != UWX_OK)
362		    return status;
363		env->context.fr[i].part0 = fval[0];
364		env->context.fr[i].part1 = fval[1];
365		env->history.fr[i] = hist;
366		env->context.valid_frs |= 1 << i;
367		TRACE_S_RESTORE_FR(i, env->rstate[SBREG_FR + i], fval)
368	    }
369	}
370    }
371
372    /* Restore other preserved regs. */
373
374    if (env->rstate[SBREG_PREDS] != UWX_DISP_NONE) {
375	status = uwx_restore_reg(env, env->rstate[SBREG_PREDS], &val, &hist);
376	if (status != UWX_OK)
377	    return status;
378	env->context.special[UWX_REG_PREDS] = val;
379	env->history.special[UWX_REG_PREDS] = hist;
380	env->context.valid_regs |= 1 << UWX_REG_PREDS;
381	TRACE_S_RESTORE_REG("PREDS", env->rstate[SBREG_PREDS], val)
382    }
383    if (env->rstate[SBREG_RNAT] != UWX_DISP_NONE) {
384	status = uwx_restore_reg(env, env->rstate[SBREG_RNAT], &val, &hist);
385	if (status != UWX_OK)
386	    return status;
387	env->context.special[UWX_REG_AR_RNAT] = val;
388	env->history.special[UWX_REG_AR_RNAT] = hist;
389	env->context.valid_regs |= 1 << UWX_REG_AR_RNAT;
390	TRACE_S_RESTORE_REG("RNAT", env->rstate[SBREG_RNAT], val)
391    }
392    if (env->rstate[SBREG_UNAT] != UWX_DISP_NONE) {
393	status = uwx_restore_reg(env, env->rstate[SBREG_UNAT], &val, &hist);
394	if (status != UWX_OK)
395	    return status;
396	env->context.special[UWX_REG_AR_UNAT] = val;
397	env->history.special[UWX_REG_AR_UNAT] = hist;
398	env->context.valid_regs |= 1 << UWX_REG_AR_UNAT;
399	TRACE_S_RESTORE_REG("UNAT", env->rstate[SBREG_UNAT], val)
400    }
401    if (env->rstate[SBREG_FPSR] != UWX_DISP_NONE) {
402	status = uwx_restore_reg(env, env->rstate[SBREG_FPSR], &val, &hist);
403	if (status != UWX_OK)
404	    return status;
405	env->context.special[UWX_REG_AR_FPSR] = val;
406	env->history.special[UWX_REG_AR_FPSR] = hist;
407	env->context.valid_regs |= 1 << UWX_REG_AR_FPSR;
408	TRACE_S_RESTORE_REG("FPSR", env->rstate[SBREG_FPSR], val)
409    }
410    if (env->rstate[SBREG_LC] != UWX_DISP_NONE) {
411	status = uwx_restore_reg(env, env->rstate[SBREG_LC], &val, &hist);
412	if (status != UWX_OK)
413	    return status;
414	env->context.special[UWX_REG_AR_LC] = val;
415	env->history.special[UWX_REG_AR_LC] = hist;
416	env->context.valid_regs |= 1 << UWX_REG_AR_LC;
417	TRACE_S_RESTORE_REG("LC", env->rstate[SBREG_LC], val)
418    }
419
420    /* Restore preserved GRs from temporaries. */
421
422    for (i = 0; i < NSB_GR; i++) {
423	if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE)
424	    env->context.gr[i] = tempgr[i];
425    }
426    env->context.special[UWX_REG_PRIUNAT] = tempnat;
427
428    /* Restore the frame markers. */
429
430    env->context.special[UWX_REG_IP] = env->context.special[UWX_REG_RP];
431    env->history.special[UWX_REG_IP] = env->history.special[UWX_REG_RP];
432
433    env->context.special[UWX_REG_SP] = env->context.special[UWX_REG_PSP];
434    env->history.special[UWX_REG_SP] = env->history.special[UWX_REG_PSP];
435
436    pfs_sol = ((unsigned int)env->context.special[UWX_REG_PFS] >> 7) & 0x7f;
437    env->context.special[UWX_REG_BSP] = uwx_add_to_bsp(
438				env->context.special[UWX_REG_BSP],
439				-pfs_sol);
440
441    env->context.special[UWX_REG_CFM] = env->context.special[UWX_REG_PFS];
442    env->history.special[UWX_REG_CFM] = env->history.special[UWX_REG_PFS];
443
444    env->context.special[UWX_REG_RP] = 0;
445
446    /* The frame info for the new frame isn't yet available. */
447
448    env->rstate = 0;
449    env->context.valid_regs &= ~VALID_MARKERS;
450
451    return UWX_OK;
452}
453
454
455/* uwx_decode_uvec: Converts the update vector into a register state array */
456
457int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate)
458{
459    while (*uvec != 0) {
460	switch ((int)*uvec++) {
461	    case UWX_KEY_CONTEXT:
462		env->abi_context = (int)(*uvec++);
463		return UWX_ABI_FRAME;
464	    default:
465		return UWX_ERR_CANTUNWIND;
466	}
467    }
468    return UWX_OK;
469}
470
471
472/* uwx_restore_reg: Restores a register according to the scoreboard */
473
474#define COPYIN_MSTACK_8(dest, src) \
475    (env->remote? \
476	(*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \
477						DWORDSZ, env->cb_token) : \
478	(*(uint64_t *)(dest) = *(uint64_t *)(src), DWORDSZ) )
479
480int uwx_restore_reg(struct uwx_env *env, uint64_t rstate,
481				uint64_t *valp, uint64_t *histp)
482{
483    int status;
484    uint64_t p;
485    int n;
486    int regid;
487
488    status = UWX_OK;
489
490    switch (UWX_GET_DISP_CODE(rstate)) {
491	case UWX_DISP_SPPLUS(0):
492	    *valp = env->context.special[UWX_REG_SP] +
493				UWX_GET_DISP_OFFSET(rstate);
494	    *histp = UWX_DISP_NONE;
495	    break;
496	case UWX_DISP_SPREL(0):
497	    p = env->context.special[UWX_REG_SP] +
498				UWX_GET_DISP_OFFSET(rstate);
499	    n = COPYIN_MSTACK_8((char *)valp, p);
500	    if (n != DWORDSZ)
501		status = UWX_ERR_COPYIN_MSTK;
502	    *histp = UWX_DISP_MSTK(p);
503	    break;
504	case UWX_DISP_PSPREL(0):
505	    p = env->context.special[UWX_REG_PSP] + 16 -
506				UWX_GET_DISP_OFFSET(rstate);
507	    n = COPYIN_MSTACK_8((char *)valp, p);
508	    if (n != DWORDSZ)
509		status = UWX_ERR_COPYIN_MSTK;
510	    *histp = UWX_DISP_MSTK(p);
511	    break;
512	case UWX_DISP_REG(0):
513	    regid = UWX_GET_DISP_REGID(rstate);
514	    status = uwx_get_reg(env, regid, valp);
515	    (void) uwx_get_spill_loc(env, regid, histp);
516	    break;
517    }
518    return status;
519}
520
521#define COPYIN_MSTACK_16(dest, src) \
522    (env->remote? \
523	(*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \
524						2*DWORDSZ, env->cb_token) : \
525	(*(uint64_t *)(dest) = *(uint64_t *)(src), \
526		*(uint64_t *)((dest)+8) = *(uint64_t *)((src)+8), \
527		2*DWORDSZ) )
528
529int uwx_restore_freg(struct uwx_env *env, uint64_t rstate,
530				uint64_t *valp, uint64_t *histp)
531{
532    int status;
533    uint64_t p;
534    int n;
535    int regid;
536
537    status = UWX_OK;
538
539    switch (UWX_GET_DISP_CODE(rstate)) {
540	case UWX_DISP_SPREL(0):
541	    p = env->context.special[UWX_REG_SP] +
542				UWX_GET_DISP_OFFSET(rstate);
543	    n = COPYIN_MSTACK_16((char *)valp, p);
544	    if (n != 2*DWORDSZ)
545		status = UWX_ERR_COPYIN_MSTK;
546	    *histp = UWX_DISP_MSTK(p);
547	    break;
548	case UWX_DISP_PSPREL(0):
549	    p = env->context.special[UWX_REG_PSP] + 16 -
550				UWX_GET_DISP_OFFSET(rstate);
551	    n = COPYIN_MSTACK_16((char *)valp, p);
552	    if (n != 2*DWORDSZ)
553		status = UWX_ERR_COPYIN_MSTK;
554	    *histp = UWX_DISP_MSTK(p);
555	    break;
556	case UWX_DISP_REG(0):
557	    regid = UWX_GET_DISP_REGID(rstate);
558	    status = uwx_get_reg(env, regid, valp);
559	    (void) uwx_get_spill_loc(env, regid, histp);
560	    break;
561    }
562    return status;
563}
564
565/* uwx_restore_nat: Returns the saved NaT bit for a preserved GR */
566
567int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat)
568{
569    int nat;
570    uint64_t p;
571
572    nat = 0;
573    switch (UWX_GET_DISP_CODE(rstate)) {
574	case UWX_DISP_SPREL(0):
575	    p = env->context.special[UWX_REG_SP] +
576				UWX_GET_DISP_OFFSET(rstate);
577	    nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01;
578	    break;
579	case UWX_DISP_PSPREL(0):
580	    p = env->context.special[UWX_REG_PSP] + 16 -
581				UWX_GET_DISP_OFFSET(rstate);
582	    nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01;
583	    break;
584	case UWX_DISP_REG(0):
585	    (void) uwx_get_nat(env, UWX_GET_DISP_REGID(rstate), &nat);
586	    break;
587    }
588    return nat;
589}
590
591