1115013Smarcel/*
2160157SmarcelCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3121642SmarcelPermission is hereby granted, free of charge, to any person
4121642Smarcelobtaining a copy of this software and associated documentation
5121642Smarcelfiles (the "Software"), to deal in the Software without
6121642Smarcelrestriction, including without limitation the rights to use,
7121642Smarcelcopy, modify, merge, publish, distribute, sublicense, and/or sell
8121642Smarcelcopies of the Software, and to permit persons to whom the
9121642SmarcelSoftware is furnished to do so, subject to the following
10121642Smarcelconditions:
11115013Smarcel
12121642SmarcelThe above copyright notice and this permission notice shall be
13121642Smarcelincluded in all copies or substantial portions of the Software.
14121642Smarcel
15121642SmarcelTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16121642SmarcelEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17121642SmarcelOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18121642SmarcelNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19121642SmarcelHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20121642SmarcelWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21121642SmarcelFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22121642SmarcelOTHER DEALINGS IN THE SOFTWARE.
23121642Smarcel*/
24121642Smarcel
25115013Smarcel#include "uwx_env.h"
26115013Smarcel#include "uwx_utable.h"
27115013Smarcel#include "uwx_uinfo.h"
28115013Smarcel#include "uwx_scoreboard.h"
29115013Smarcel#include "uwx_str.h"
30120925Smarcel#include "uwx_step.h"
31115013Smarcel#include "uwx_trace.h"
32115013Smarcel
33115013Smarcel/*
34115013Smarcel *  uwx_step.c
35115013Smarcel *
36115013Smarcel *  This file contains the routines for stepping from one frame
37115013Smarcel *  into its callers frame. The context for the current frame
38115013Smarcel *  is maintained inside the current unwind environment
39115013Smarcel *  (struct uwx_env), and is updated with each call to
40115013Smarcel *  uwx_step() to refer to the previous frame.
41115013Smarcel */
42115013Smarcel
43115013Smarcel
44115013Smarcel/* Forward Declarations */
45115013Smarcel
46115013Smarcelint uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate);
47115013Smarcelint uwx_restore_reg(struct uwx_env *env, uint64_t rstate,
48115013Smarcel					uint64_t *valp, uint64_t *histp);
49120925Smarcelint uwx_restore_freg(struct uwx_env *env, uint64_t rstate,
50120925Smarcel					uint64_t *valp, uint64_t *histp);
51115013Smarcelint uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat);
52115013Smarcel
53115013Smarcel
54129059Smarcel/* uwx_lookupip_hook: Hook routine so dynamic instrumentation */
55129059Smarcel/*      tools can intercept Lookup IP events. When not */
56129059Smarcel/*      intercepted, it just returns "Not found", so that */
57129059Smarcel/*      the callback routine is invoked. */
58129059Smarcel
59129059Smarcel/*ARGSUSED*/
60129059Smarcelint uwx_lookupip_hook(int request, uint64_t ip, intptr_t tok, uint64_t **vecp,
61129059Smarcel			size_t uvecsize)
62129059Smarcel{
63129059Smarcel    return UWX_LKUP_NOTFOUND;
64129059Smarcel}
65129059Smarcel
66129059Smarcel
67115013Smarcel/* uwx_get_frame_info: Gets unwind info for current frame */
68160163Smarcelstatic
69115013Smarcelint uwx_get_frame_info(struct uwx_env *env)
70115013Smarcel{
71115013Smarcel    int i;
72115013Smarcel    int status;
73115013Smarcel    int cbstatus;
74129059Smarcel    int cbcalled = 0;
75129059Smarcel    uint64_t ip;
76115013Smarcel    uint64_t *uvec;
77115013Smarcel    uint64_t *rstate;
78115013Smarcel    struct uwx_utable_entry uentry;
79129059Smarcel    uint64_t uvecout[UVECSIZE];
80115013Smarcel
81115013Smarcel    if (env->copyin == 0 || env->lookupip == 0)
82115013Smarcel	return UWX_ERR_NOCALLBACKS;
83115013Smarcel
84160157Smarcel    env->ptr_size = DWORDSZ;
85160157Smarcel    env->code_start = 0;
86115013Smarcel    env->function_offset = -1LL;
87115013Smarcel    env->function_name = 0;
88115013Smarcel    env->module_name = 0;
89160157Smarcel    env->abi_context = 0;
90115013Smarcel    uwx_reset_str_pool(env);
91115013Smarcel
92115013Smarcel    /* Use the lookup IP callback routine to find out about the */
93115013Smarcel    /* current IP. If the predicate registers are valid, pass them */
94115013Smarcel    /* in the uvec. */
95115013Smarcel
96129059Smarcel    /* When self-unwinding, we call a hook routine before the */
97129059Smarcel    /* callback. If the application is running under control of */
98129059Smarcel    /* a dynamic instrumentation tool, that tool will have an */
99129059Smarcel    /* opportunity to intercept lookup IP requests. */
100129059Smarcel
101115013Smarcel    i = 0;
102129059Smarcel    uvecout[i++] = UWX_KEY_VERSION;
103129059Smarcel    uvecout[i++] = UWX_VERSION;
104115013Smarcel    if (env->context.valid_regs & (1 << UWX_REG_PREDS)) {
105115013Smarcel	uvecout[i++] = UWX_KEY_PREDS;
106115013Smarcel	uvecout[i++] = env->context.special[UWX_REG_PREDS];
107115013Smarcel    }
108115013Smarcel    uvecout[i++] = UWX_KEY_END;
109115013Smarcel    uvecout[i++] = 0;
110115013Smarcel    uvec = uvecout;
111129059Smarcel    cbstatus = UWX_LKUP_NOTFOUND;
112129059Smarcel    ip = env->context.special[UWX_REG_IP];
113129059Smarcel    env->remapped_ip = ip;
114115013Smarcel
115129059Smarcel    /* Call the hook routine. */
116129059Smarcel
117129059Smarcel    if (env->remote == 0)
118129059Smarcel	cbstatus = uwx_lookupip_hook(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec,
119129059Smarcel		sizeof(uvecout));
120129059Smarcel
121129059Smarcel    /* If the hook routine remapped the IP, use the new IP for */
122129059Smarcel    /* the callback instead of the original IP. */
123129059Smarcel
124129059Smarcel    if (cbstatus == UWX_LKUP_REMAP) {
125129059Smarcel	for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
126129059Smarcel	    switch ((int)uvec[i]) {
127129059Smarcel		case UWX_KEY_NEWIP:
128129059Smarcel		    ip = uvec[i+1];
129129059Smarcel		    break;
130129059Smarcel	    }
131129059Smarcel	}
132129059Smarcel	env->remapped_ip = ip;
133129059Smarcel    }
134129059Smarcel
135129059Smarcel    /* Now call the callback routine unless the hook routine gave */
136129059Smarcel    /* us all the info. */
137129059Smarcel
138129059Smarcel    if (cbstatus == UWX_LKUP_NOTFOUND || cbstatus == UWX_LKUP_REMAP) {
139129059Smarcel	cbcalled = 1;
140129059Smarcel	cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec);
141129059Smarcel    }
142129059Smarcel
143129059Smarcel    /* If the callback routine remapped the IP, call it one more time */
144129059Smarcel    /* with the new IP. */
145129059Smarcel
146129059Smarcel    if (cbstatus == UWX_LKUP_REMAP) {
147129059Smarcel	for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
148129059Smarcel	    switch ((int)uvec[i]) {
149129059Smarcel		case UWX_KEY_NEWIP:
150129059Smarcel		    ip = uvec[i+1];
151129059Smarcel		    break;
152129059Smarcel	    }
153129059Smarcel	}
154129059Smarcel	env->remapped_ip = ip;
155129059Smarcel	cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec);
156129059Smarcel    }
157129059Smarcel
158115013Smarcel    /* If NOTFOUND, there's nothing we can do but return an error. */
159115013Smarcel
160115013Smarcel    if (cbstatus == UWX_LKUP_NOTFOUND) {
161115013Smarcel	status = UWX_ERR_IPNOTFOUND;
162115013Smarcel    }
163115013Smarcel
164115013Smarcel    /* If the callback returns an unwind table, we need to */
165115013Smarcel    /* search the table for an unwind entry that describes the */
166115013Smarcel    /* code region of interest, then decode the unwind information */
167115013Smarcel    /* associated with that unwind table entry, and store the */
168115013Smarcel    /* resulting register state array in the unwind environment */
169115013Smarcel    /* block. */
170115013Smarcel
171115013Smarcel    else if (cbstatus == UWX_LKUP_UTABLE) {
172129059Smarcel	status = uwx_search_utable(env, ip, uvec, &uentry);
173129059Smarcel	if (cbcalled)
174129059Smarcel	    (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
175160157Smarcel	if (status == UWX_OK) {
176160157Smarcel	    env->ptr_size = uentry.ptr_size;
177160157Smarcel	    env->code_start = uentry.code_start;
178115013Smarcel	    status = uwx_decode_uinfo(env, &uentry, &rstate);
179160157Smarcel	}
180160157Smarcel	if (status == UWX_ERR_NOUENTRY || status == UWX_ERR_NOUDESC)
181115013Smarcel	    status = uwx_default_rstate(env, &rstate);
182115013Smarcel	if (status == UWX_OK)
183115013Smarcel	    env->rstate = rstate;
184115013Smarcel    }
185115013Smarcel
186129059Smarcel    /* If the callback returns an unwind info block, we can */
187129059Smarcel    /* proceed directly to decoding the unwind information. */
188129059Smarcel
189129059Smarcel    else if (cbstatus == UWX_LKUP_UINFO) {
190160157Smarcel	uentry.ptr_size = DWORDSZ;
191129059Smarcel	uentry.code_start = 0;
192129059Smarcel	uentry.code_end = 0;
193129059Smarcel	uentry.unwind_info = 0;
194129059Smarcel	uentry.unwind_flags = 0;
195129059Smarcel	for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
196129059Smarcel	    switch ((int)uvec[i]) {
197129059Smarcel		case UWX_KEY_UFLAGS:
198129059Smarcel		    uentry.unwind_flags = uvec[i+1];
199160157Smarcel		    if (uentry.unwind_flags & UNWIND_TBL_32BIT)
200160157Smarcel			uentry.ptr_size = WORDSZ;
201129059Smarcel		    break;
202129059Smarcel		case UWX_KEY_UINFO:
203129059Smarcel		    uentry.unwind_info = uvec[i+1];
204129059Smarcel		    break;
205160157Smarcel		case UWX_KEY_GP:
206160157Smarcel		    uwx_set_reg(env, UWX_REG_GP, uvec[i+1]);
207160157Smarcel		    break;
208129059Smarcel		case UWX_KEY_MODULE:
209129059Smarcel		    env->module_name =
210160157Smarcel			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
211129059Smarcel		    break;
212129059Smarcel		case UWX_KEY_FUNC:
213129059Smarcel		    env->function_name =
214160157Smarcel			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
215129059Smarcel		    break;
216129059Smarcel		case UWX_KEY_FUNCSTART:
217129059Smarcel		    uentry.code_start = uvec[i+1];
218160157Smarcel		    env->code_start = uentry.code_start;
219129059Smarcel		    break;
220129059Smarcel	    }
221129059Smarcel	}
222160157Smarcel	env->ptr_size = uentry.ptr_size;
223129059Smarcel	if (cbcalled)
224129059Smarcel	    (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
225129059Smarcel	status = uwx_decode_uinfo(env, &uentry, &rstate);
226160157Smarcel	if (status == UWX_ERR_NOUDESC)
227160157Smarcel	    status = uwx_default_rstate(env, &rstate);
228129059Smarcel	if (status == UWX_OK)
229129059Smarcel	    env->rstate = rstate;
230129059Smarcel    }
231129059Smarcel
232115013Smarcel    /* If the callback returns a frame description (in the form */
233115013Smarcel    /* of an update vector), convert the update vector into a */
234115013Smarcel    /* register state array, then invoke the callback again to */
235115013Smarcel    /* let it free any memory it allocated. */
236115013Smarcel
237115013Smarcel    else if (cbstatus == UWX_LKUP_FDESC) {
238115013Smarcel	status = uwx_decode_uvec(env, uvec, &rstate);
239129059Smarcel	if (cbcalled)
240129059Smarcel	    (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
241115013Smarcel	if (status == UWX_OK)
242115013Smarcel	    env->rstate = rstate;
243115013Smarcel    }
244115013Smarcel
245115013Smarcel    /* Any other return from the callback is an error. */
246115013Smarcel
247115013Smarcel    else {
248115013Smarcel	status = UWX_ERR_LOOKUPERR;
249115013Smarcel    }
250115013Smarcel    return status;
251115013Smarcel}
252115013Smarcel
253115013Smarcel
254120925Smarcel/* uwx_restore_markers: Restores the stack markers -- PSP, RP, PFS */
255120925Smarcel
256120925Smarcelint uwx_restore_markers(struct uwx_env *env)
257120925Smarcel{
258120925Smarcel    int status;
259120925Smarcel    uint64_t val;
260120925Smarcel    uint64_t hist;
261120925Smarcel
262120925Smarcel    if ((env->context.valid_regs & VALID_BASIC4) != VALID_BASIC4)
263120925Smarcel	return UWX_ERR_NOCONTEXT;
264120925Smarcel
265120925Smarcel    /* If we haven't already obtained the frame info for the */
266120925Smarcel    /* current frame, get it now. */
267120925Smarcel
268120925Smarcel    if (env->rstate == 0) {
269120925Smarcel	status = uwx_get_frame_info(env);
270120925Smarcel	if (status != UWX_OK)
271120925Smarcel	    return status;
272120925Smarcel    }
273120925Smarcel
274120925Smarcel    TRACE_S_STEP(env->rstate)
275120925Smarcel
276120925Smarcel    if (env->rstate[SBREG_PSP] != UWX_DISP_NONE) {
277120925Smarcel	status = uwx_restore_reg(env, env->rstate[SBREG_PSP], &val, &hist);
278120925Smarcel	if (status != UWX_OK)
279120925Smarcel	    return status;
280120925Smarcel	env->context.special[UWX_REG_PSP] = val;
281120925Smarcel	env->history.special[UWX_REG_PSP] = hist;
282120925Smarcel	env->context.valid_regs |= 1 << UWX_REG_PSP;
283120925Smarcel	TRACE_S_RESTORE_REG("PSP", env->rstate[SBREG_PSP], val)
284120925Smarcel    }
285120925Smarcel
286120925Smarcel    if (env->rstate[SBREG_RP] != UWX_DISP_NONE) {
287120925Smarcel	status = uwx_restore_reg(env, env->rstate[SBREG_RP], &val, &hist);
288120925Smarcel	if (status != UWX_OK)
289120925Smarcel	    return status;
290120925Smarcel	env->context.special[UWX_REG_RP] = val;
291120925Smarcel	env->history.special[UWX_REG_RP] = hist;
292120925Smarcel	env->context.valid_regs |= 1 << UWX_REG_RP;
293120925Smarcel	TRACE_S_RESTORE_REG("RP", env->rstate[SBREG_RP], val)
294120925Smarcel    }
295120925Smarcel
296120925Smarcel    if (env->rstate[SBREG_PFS] != UWX_DISP_NONE) {
297120925Smarcel	status = uwx_restore_reg(env, env->rstate[SBREG_PFS], &val, &hist);
298120925Smarcel	if (status != UWX_OK)
299120925Smarcel	    return status;
300120925Smarcel	env->context.special[UWX_REG_PFS] = val;
301120925Smarcel	env->history.special[UWX_REG_PFS] = hist;
302120925Smarcel	env->context.valid_regs |= 1 << UWX_REG_PFS;
303120925Smarcel	TRACE_S_RESTORE_REG("PFS", env->rstate[SBREG_PFS], val)
304120925Smarcel    }
305120925Smarcel
306120925Smarcel    return UWX_OK;
307120925Smarcel}
308120925Smarcel
309160157Smarcel/* uwx_get_module_info: Gets module name and text base for current frame */
310160157Smarcel
311160157Smarcelint uwx_get_module_info(
312160157Smarcel    struct uwx_env *env,
313160157Smarcel    char **modp,
314160157Smarcel    uint64_t *text_base)
315160157Smarcel{
316160157Smarcel    int i;
317160157Smarcel    int status;
318160157Smarcel    int cbstatus;
319160157Smarcel    uint64_t ip;
320160157Smarcel    uint64_t *uvec;
321160157Smarcel    uint64_t uvecout[UVECSIZE];
322160157Smarcel
323160157Smarcel    if (env == 0)
324160157Smarcel	return UWX_ERR_NOENV;
325160157Smarcel
326160157Smarcel    /* If we haven't already obtained the frame info for the */
327160157Smarcel    /* current frame, get it now. */
328160157Smarcel
329160157Smarcel    if (env->rstate == 0) {
330160157Smarcel	status = uwx_get_frame_info(env);
331160157Smarcel	if (status != UWX_OK)
332160157Smarcel	    return status;
333160157Smarcel    }
334160157Smarcel
335160157Smarcel    /* Get the module name from the lookup IP callback. */
336160157Smarcel    if (env->module_name == 0) {
337160157Smarcel	ip = env->remapped_ip;
338160157Smarcel	i = 0;
339160157Smarcel	if (env->function_offset >= 0) {
340160157Smarcel	    uvecout[i++] = UWX_KEY_FUNCSTART;
341160157Smarcel	    uvecout[i++] = ip - env->function_offset;
342160157Smarcel	}
343160157Smarcel	uvecout[i++] = UWX_KEY_END;
344160157Smarcel	uvecout[i++] = 0;
345160157Smarcel	uvec = uvecout;
346160157Smarcel	cbstatus = (*env->lookupip)(UWX_LKUP_MODULE, ip, env->cb_token, &uvec);
347160157Smarcel
348160157Smarcel	if (cbstatus == UWX_LKUP_SYMINFO) {
349160157Smarcel	    for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
350160157Smarcel		switch ((int)uvec[i]) {
351160157Smarcel		    case UWX_KEY_TBASE:
352160157Smarcel			env->text_base = uvec[i+1];
353160157Smarcel			break;
354160157Smarcel		    case UWX_KEY_MODULE:
355160157Smarcel			env->module_name =
356160157Smarcel			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
357160157Smarcel			break;
358160157Smarcel		    case UWX_KEY_FUNC:
359160157Smarcel			env->function_name =
360160157Smarcel			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
361160157Smarcel			break;
362160157Smarcel		    case UWX_KEY_FUNCSTART:
363160157Smarcel			env->function_offset = ip - uvec[i+1];
364160157Smarcel			break;
365160157Smarcel		}
366160157Smarcel	    }
367160157Smarcel	    (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
368160157Smarcel	}
369160157Smarcel    }
370160157Smarcel
371160157Smarcel    *modp = env->module_name;
372160157Smarcel    *text_base = env->text_base;
373160157Smarcel
374160157Smarcel    return UWX_OK;
375160157Smarcel}
376160157Smarcel
377160157Smarcel/* uwx_get_funcstart: Gets start address of function from current frame */
378160157Smarcel
379160157Smarcelint uwx_get_funcstart(
380160157Smarcel    struct uwx_env *env,
381160157Smarcel    uint64_t *funcstart)
382160157Smarcel{
383160157Smarcel    int status;
384160157Smarcel
385160157Smarcel    if (env == 0)
386160157Smarcel	return UWX_ERR_NOENV;
387160157Smarcel
388160157Smarcel    /* If we haven't already obtained the frame info for the */
389160157Smarcel    /* current frame, get it now. */
390160157Smarcel
391160157Smarcel    if (env->rstate == 0) {
392160157Smarcel	status = uwx_get_frame_info(env);
393160157Smarcel	if (status != UWX_OK)
394160157Smarcel	    return status;
395160157Smarcel    }
396160157Smarcel
397160157Smarcel    *funcstart = env->remapped_ip - env->function_offset;
398160157Smarcel
399160157Smarcel    return UWX_OK;
400160157Smarcel}
401160157Smarcel
402115013Smarcel/* uwx_get_sym_info: Gets symbolic info from current frame */
403160157Smarcel/* (Will make a UWX_LKUP_SYMBOLS callback if info */
404160157Smarcel/* was not provided by UWX_LKUP_LOOKUP callback) */
405120925Smarcel
406115013Smarcelint uwx_get_sym_info(
407115013Smarcel    struct uwx_env *env,
408115013Smarcel    char **modp,
409115013Smarcel    char **symp,
410115013Smarcel    uint64_t *offsetp)
411115013Smarcel{
412115013Smarcel    int status;
413115013Smarcel    int cbstatus;
414115013Smarcel    uint64_t ip;
415115013Smarcel    uint64_t *uvec;
416160157Smarcel    uint64_t uvecout[UVECSIZE];
417115013Smarcel    int i;
418115013Smarcel
419115013Smarcel    if (env == 0)
420115013Smarcel	return UWX_ERR_NOENV;
421115013Smarcel
422115013Smarcel    /* If we haven't already obtained the frame info for the */
423115013Smarcel    /* current frame, get it now. */
424115013Smarcel
425115013Smarcel    if (env->rstate == 0) {
426115013Smarcel	status = uwx_get_frame_info(env);
427115013Smarcel	if (status != UWX_OK)
428115013Smarcel	    return status;
429115013Smarcel    }
430115013Smarcel
431115013Smarcel    /* Get the symbolic information from the lookup IP callback. */
432115013Smarcel    if (env->function_name == 0) {
433129059Smarcel	ip = env->remapped_ip;
434115013Smarcel	i = 0;
435115013Smarcel	if (env->function_offset >= 0) {
436115013Smarcel	    uvecout[i++] = UWX_KEY_FUNCSTART;
437115013Smarcel	    uvecout[i++] = ip - env->function_offset;
438115013Smarcel	}
439115013Smarcel	uvecout[i++] = UWX_KEY_END;
440115013Smarcel	uvecout[i++] = 0;
441115013Smarcel	uvec = uvecout;
442129059Smarcel	cbstatus = (*env->lookupip)(UWX_LKUP_SYMBOLS, ip, env->cb_token, &uvec);
443115013Smarcel
444115013Smarcel	if (cbstatus == UWX_LKUP_SYMINFO) {
445115013Smarcel	    for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
446115013Smarcel		switch ((int)uvec[i]) {
447115013Smarcel		    case UWX_KEY_MODULE:
448115013Smarcel			env->module_name =
449160157Smarcel			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
450115013Smarcel			break;
451115013Smarcel		    case UWX_KEY_FUNC:
452115013Smarcel			env->function_name =
453160157Smarcel			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
454115013Smarcel			break;
455115013Smarcel		    case UWX_KEY_FUNCSTART:
456115013Smarcel			env->function_offset = ip - uvec[i+1];
457115013Smarcel			break;
458115013Smarcel		}
459115013Smarcel	    }
460115013Smarcel	    (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec);
461115013Smarcel	}
462115013Smarcel    }
463115013Smarcel
464115013Smarcel    *modp = env->module_name;
465115013Smarcel    *symp = env->function_name;
466115013Smarcel    *offsetp = env->function_offset;
467115013Smarcel
468115013Smarcel    return UWX_OK;
469115013Smarcel}
470115013Smarcel
471115013Smarcel
472115013Smarcel/* uwx_step: Steps from the current frame to the previous frame */
473115013Smarcel
474115013Smarcelint uwx_step(struct uwx_env *env)
475115013Smarcel{
476115013Smarcel    int i;
477115013Smarcel    int status;
478115013Smarcel    int pfs_sol;
479115013Smarcel    int dispcode;
480115013Smarcel    uint64_t val;
481115013Smarcel    uint64_t fval[2];
482115013Smarcel    uint64_t hist;
483115013Smarcel    uint64_t tempgr[NPRESERVEDGR];
484115013Smarcel    int needpriunat;
485115013Smarcel    int unat;
486115013Smarcel    int tempnat;
487115013Smarcel
488115013Smarcel    if (env == 0)
489115013Smarcel	return UWX_ERR_NOENV;
490115013Smarcel
491115013Smarcel    /* Complete the current context by restoring the current values */
492115013Smarcel    /* of psp, rp, and pfs. */
493115013Smarcel
494120925Smarcel    if (env->rstate == 0 ||
495120925Smarcel	    (env->context.valid_regs & VALID_MARKERS) != VALID_MARKERS) {
496120925Smarcel	status = uwx_restore_markers(env);
497115013Smarcel	if (status != UWX_OK)
498115013Smarcel	    return status;
499115013Smarcel    }
500115013Smarcel
501115013Smarcel    /* Check for bottom of stack (rp == 0). */
502115013Smarcel
503115013Smarcel    if (env->context.special[UWX_REG_RP] == 0)
504115013Smarcel	return UWX_BOTTOM;
505115013Smarcel
506115013Smarcel    /* Find where the primary unat is saved, get a copy. */
507115013Smarcel    /* Then, as we restore the GRs, we'll merge the NaT bits into the */
508115013Smarcel    /* priunat register in the context. */
509115013Smarcel    /* (Make sure we need it, though, before we try to get it, */
510115013Smarcel    /* because the attempt to get it might invoke the copy-in callback. */
511115013Smarcel    /* We don't need the priunat unless one of GR 4-7 was */
512115013Smarcel    /* saved to the memory stack.) */
513115013Smarcel
514115013Smarcel    needpriunat = 0;
515115013Smarcel    for (i = 0; i < NSB_GR; i++) {
516115013Smarcel	dispcode = UWX_GET_DISP_CODE(env->rstate[SBREG_GR + i]);
517115013Smarcel	if (dispcode == UWX_DISP_SPREL(0) || dispcode == UWX_DISP_PSPREL(0))
518115013Smarcel	    needpriunat = 1;
519115013Smarcel    }
520115013Smarcel    unat = 0;
521115013Smarcel    if (needpriunat && env->rstate[SBREG_PRIUNAT] != UWX_DISP_NONE) {
522115013Smarcel	status = uwx_restore_reg(env, env->rstate[SBREG_PRIUNAT], &val, &hist);
523115013Smarcel	if (status != UWX_OK)
524115013Smarcel	    return status;
525115013Smarcel	unat = (int) val;
526115013Smarcel	env->history.special[UWX_REG_PRIUNAT] = hist;
527115013Smarcel	TRACE_S_RESTORE_REG("PRIUNAT", env->rstate[SBREG_PRIUNAT], val)
528115013Smarcel    }
529115013Smarcel
530115013Smarcel    /* Retrieve saved values of the preserved GRs into temporaries. */
531115013Smarcel
532115013Smarcel    tempnat = (int) env->context.special[UWX_REG_PRIUNAT];
533115013Smarcel    for (i = 0; i < NSB_GR; i++) {
534115013Smarcel	if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) {
535115013Smarcel	    status = uwx_restore_reg(env,
536115013Smarcel			env->rstate[SBREG_GR + i], &val, &hist);
537115013Smarcel	    if (status != UWX_OK)
538115013Smarcel		return status;
539115013Smarcel	    tempgr[i] = val;
540115013Smarcel	    if (uwx_restore_nat(env, env->rstate[SBREG_GR + i], unat))
541115013Smarcel		tempnat |= 1 << i;
542115013Smarcel	    else
543115013Smarcel		tempnat &= ~(1 << i);
544115013Smarcel	    env->history.gr[i] = hist;
545115013Smarcel	    env->context.valid_regs |= 1 << (i + VALID_GR_SHIFT);
546115013Smarcel	    TRACE_S_RESTORE_GR(i, env->rstate[SBREG_GR + i], val)
547115013Smarcel	}
548115013Smarcel    }
549115013Smarcel
550115013Smarcel    /* Now we have everything we need to step back to the previous frame. */
551115013Smarcel
552115013Smarcel    /* Restore preserved BRs. */
553115013Smarcel
554115013Smarcel    for (i = 0; i < NSB_BR; i++) {
555115013Smarcel	if (env->rstate[SBREG_BR + i] != UWX_DISP_NONE) {
556115013Smarcel	    status = uwx_restore_reg(env,
557115013Smarcel			env->rstate[SBREG_BR + i], &val, &hist);
558115013Smarcel	    if (status != UWX_OK)
559115013Smarcel		return status;
560115013Smarcel	    env->context.br[i] = val;
561115013Smarcel	    env->history.br[i] = hist;
562115013Smarcel	    env->context.valid_regs |= 1 << (i + VALID_BR_SHIFT);
563115013Smarcel	    TRACE_S_RESTORE_BR(i, env->rstate[SBREG_BR + i], val)
564115013Smarcel	}
565115013Smarcel    }
566115013Smarcel
567115013Smarcel    /* Restore preserved FRs. */
568115013Smarcel
569115013Smarcel    if (env->nsbreg == NSBREG) {
570115013Smarcel	for (i = 0; i < NSB_FR; i++) {
571115013Smarcel	    if (env->rstate[SBREG_FR + i] != UWX_DISP_NONE) {
572120925Smarcel		status = uwx_restore_freg(env,
573115013Smarcel			    env->rstate[SBREG_FR + i], fval, &hist);
574115013Smarcel		if (status != UWX_OK)
575115013Smarcel		    return status;
576115013Smarcel		env->context.fr[i].part0 = fval[0];
577115013Smarcel		env->context.fr[i].part1 = fval[1];
578115013Smarcel		env->history.fr[i] = hist;
579115013Smarcel		env->context.valid_frs |= 1 << i;
580115013Smarcel		TRACE_S_RESTORE_FR(i, env->rstate[SBREG_FR + i], fval)
581115013Smarcel	    }
582115013Smarcel	}
583115013Smarcel    }
584115013Smarcel
585115013Smarcel    /* Restore other preserved regs. */
586115013Smarcel
587115013Smarcel    if (env->rstate[SBREG_PREDS] != UWX_DISP_NONE) {
588115013Smarcel	status = uwx_restore_reg(env, env->rstate[SBREG_PREDS], &val, &hist);
589115013Smarcel	if (status != UWX_OK)
590115013Smarcel	    return status;
591115013Smarcel	env->context.special[UWX_REG_PREDS] = val;
592115013Smarcel	env->history.special[UWX_REG_PREDS] = hist;
593115013Smarcel	env->context.valid_regs |= 1 << UWX_REG_PREDS;
594115013Smarcel	TRACE_S_RESTORE_REG("PREDS", env->rstate[SBREG_PREDS], val)
595115013Smarcel    }
596115013Smarcel    if (env->rstate[SBREG_RNAT] != UWX_DISP_NONE) {
597115013Smarcel	status = uwx_restore_reg(env, env->rstate[SBREG_RNAT], &val, &hist);
598115013Smarcel	if (status != UWX_OK)
599115013Smarcel	    return status;
600120925Smarcel	env->context.special[UWX_REG_AR_RNAT] = val;
601120925Smarcel	env->history.special[UWX_REG_AR_RNAT] = hist;
602120925Smarcel	env->context.valid_regs |= 1 << UWX_REG_AR_RNAT;
603115013Smarcel	TRACE_S_RESTORE_REG("RNAT", env->rstate[SBREG_RNAT], val)
604115013Smarcel    }
605115013Smarcel    if (env->rstate[SBREG_UNAT] != UWX_DISP_NONE) {
606115013Smarcel	status = uwx_restore_reg(env, env->rstate[SBREG_UNAT], &val, &hist);
607115013Smarcel	if (status != UWX_OK)
608115013Smarcel	    return status;
609120925Smarcel	env->context.special[UWX_REG_AR_UNAT] = val;
610120925Smarcel	env->history.special[UWX_REG_AR_UNAT] = hist;
611120925Smarcel	env->context.valid_regs |= 1 << UWX_REG_AR_UNAT;
612115013Smarcel	TRACE_S_RESTORE_REG("UNAT", env->rstate[SBREG_UNAT], val)
613115013Smarcel    }
614115013Smarcel    if (env->rstate[SBREG_FPSR] != UWX_DISP_NONE) {
615115013Smarcel	status = uwx_restore_reg(env, env->rstate[SBREG_FPSR], &val, &hist);
616115013Smarcel	if (status != UWX_OK)
617115013Smarcel	    return status;
618120925Smarcel	env->context.special[UWX_REG_AR_FPSR] = val;
619120925Smarcel	env->history.special[UWX_REG_AR_FPSR] = hist;
620120925Smarcel	env->context.valid_regs |= 1 << UWX_REG_AR_FPSR;
621115013Smarcel	TRACE_S_RESTORE_REG("FPSR", env->rstate[SBREG_FPSR], val)
622115013Smarcel    }
623115013Smarcel    if (env->rstate[SBREG_LC] != UWX_DISP_NONE) {
624115013Smarcel	status = uwx_restore_reg(env, env->rstate[SBREG_LC], &val, &hist);
625115013Smarcel	if (status != UWX_OK)
626115013Smarcel	    return status;
627120925Smarcel	env->context.special[UWX_REG_AR_LC] = val;
628120925Smarcel	env->history.special[UWX_REG_AR_LC] = hist;
629120925Smarcel	env->context.valid_regs |= 1 << UWX_REG_AR_LC;
630115013Smarcel	TRACE_S_RESTORE_REG("LC", env->rstate[SBREG_LC], val)
631115013Smarcel    }
632115013Smarcel
633115013Smarcel    /* Restore preserved GRs from temporaries. */
634115013Smarcel
635115013Smarcel    for (i = 0; i < NSB_GR; i++) {
636115013Smarcel	if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE)
637115013Smarcel	    env->context.gr[i] = tempgr[i];
638115013Smarcel    }
639115013Smarcel    env->context.special[UWX_REG_PRIUNAT] = tempnat;
640115013Smarcel
641115013Smarcel    /* Restore the frame markers. */
642115013Smarcel
643115013Smarcel    env->context.special[UWX_REG_IP] = env->context.special[UWX_REG_RP];
644115013Smarcel    env->history.special[UWX_REG_IP] = env->history.special[UWX_REG_RP];
645115013Smarcel
646115013Smarcel    env->context.special[UWX_REG_SP] = env->context.special[UWX_REG_PSP];
647115013Smarcel    env->history.special[UWX_REG_SP] = env->history.special[UWX_REG_PSP];
648115013Smarcel
649115013Smarcel    pfs_sol = ((unsigned int)env->context.special[UWX_REG_PFS] >> 7) & 0x7f;
650115013Smarcel    env->context.special[UWX_REG_BSP] = uwx_add_to_bsp(
651115013Smarcel				env->context.special[UWX_REG_BSP],
652115013Smarcel				-pfs_sol);
653115013Smarcel
654115013Smarcel    env->context.special[UWX_REG_CFM] = env->context.special[UWX_REG_PFS];
655115013Smarcel    env->history.special[UWX_REG_CFM] = env->history.special[UWX_REG_PFS];
656115013Smarcel
657115013Smarcel    env->context.special[UWX_REG_RP] = 0;
658115013Smarcel
659115013Smarcel    /* The frame info for the new frame isn't yet available. */
660115013Smarcel
661115013Smarcel    env->rstate = 0;
662120925Smarcel    env->context.valid_regs &= ~VALID_MARKERS;
663115013Smarcel
664115013Smarcel    return UWX_OK;
665115013Smarcel}
666115013Smarcel
667115013Smarcel
668115013Smarcel/* uwx_decode_uvec: Converts the update vector into a register state array */
669115013Smarcel
670115013Smarcelint uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate)
671115013Smarcel{
672129059Smarcel    int i;
673129059Smarcel    int status;
674129059Smarcel
675129059Smarcel    status = uwx_default_rstate(env, rstate);
676129059Smarcel    if (status != UWX_OK)
677129059Smarcel	return status;
678129059Smarcel
679129059Smarcel    for (i = 0; uvec[i] != UWX_KEY_END; i += 2) {
680129059Smarcel	switch ((int)uvec[i]) {
681115013Smarcel	    case UWX_KEY_CONTEXT:
682129059Smarcel		env->abi_context = (int)(uvec[i+1]);
683129059Smarcel		status = UWX_ABI_FRAME;
684129059Smarcel		break;
685160157Smarcel	    case UWX_KEY_GP:
686160157Smarcel		uwx_set_reg(env, UWX_REG_GP, uvec[i+1]);
687160157Smarcel		break;
688129059Smarcel	    case UWX_KEY_MODULE:
689129059Smarcel		env->module_name =
690160157Smarcel			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
691129059Smarcel		break;
692129059Smarcel	    case UWX_KEY_FUNC:
693129059Smarcel		env->function_name =
694160157Smarcel			    uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1]));
695129059Smarcel		break;
696129059Smarcel	    case UWX_KEY_FUNCSTART:
697129059Smarcel		env->function_offset = env->remapped_ip - uvec[i+1];
698129059Smarcel		break;
699115013Smarcel	    default:
700115013Smarcel		return UWX_ERR_CANTUNWIND;
701115013Smarcel	}
702115013Smarcel    }
703129059Smarcel    return status;
704115013Smarcel}
705115013Smarcel
706115013Smarcel
707115013Smarcel/* uwx_restore_reg: Restores a register according to the scoreboard */
708115013Smarcel
709115013Smarcel#define COPYIN_MSTACK_8(dest, src) \
710115013Smarcel    (env->remote? \
711115013Smarcel	(*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \
712115013Smarcel						DWORDSZ, env->cb_token) : \
713160157Smarcel	(*(uint64_t *)(intptr_t)(dest) = \
714160157Smarcel				*(uint64_t *)(intptr_t)(src), DWORDSZ) )
715115013Smarcel
716115013Smarcelint uwx_restore_reg(struct uwx_env *env, uint64_t rstate,
717115013Smarcel				uint64_t *valp, uint64_t *histp)
718115013Smarcel{
719115013Smarcel    int status;
720115013Smarcel    uint64_t p;
721115013Smarcel    int n;
722115013Smarcel    int regid;
723115013Smarcel
724115013Smarcel    status = UWX_OK;
725115013Smarcel
726115013Smarcel    switch (UWX_GET_DISP_CODE(rstate)) {
727115013Smarcel	case UWX_DISP_SPPLUS(0):
728115013Smarcel	    *valp = env->context.special[UWX_REG_SP] +
729115013Smarcel				UWX_GET_DISP_OFFSET(rstate);
730115013Smarcel	    *histp = UWX_DISP_NONE;
731115013Smarcel	    break;
732115013Smarcel	case UWX_DISP_SPREL(0):
733115013Smarcel	    p = env->context.special[UWX_REG_SP] +
734115013Smarcel				UWX_GET_DISP_OFFSET(rstate);
735115013Smarcel	    n = COPYIN_MSTACK_8((char *)valp, p);
736115013Smarcel	    if (n != DWORDSZ)
737115013Smarcel		status = UWX_ERR_COPYIN_MSTK;
738115013Smarcel	    *histp = UWX_DISP_MSTK(p);
739115013Smarcel	    break;
740115013Smarcel	case UWX_DISP_PSPREL(0):
741115013Smarcel	    p = env->context.special[UWX_REG_PSP] + 16 -
742115013Smarcel				UWX_GET_DISP_OFFSET(rstate);
743115013Smarcel	    n = COPYIN_MSTACK_8((char *)valp, p);
744115013Smarcel	    if (n != DWORDSZ)
745115013Smarcel		status = UWX_ERR_COPYIN_MSTK;
746115013Smarcel	    *histp = UWX_DISP_MSTK(p);
747115013Smarcel	    break;
748115013Smarcel	case UWX_DISP_REG(0):
749115013Smarcel	    regid = UWX_GET_DISP_REGID(rstate);
750115013Smarcel	    status = uwx_get_reg(env, regid, valp);
751115013Smarcel	    (void) uwx_get_spill_loc(env, regid, histp);
752115013Smarcel	    break;
753115013Smarcel    }
754115013Smarcel    return status;
755115013Smarcel}
756115013Smarcel
757120925Smarcel#define COPYIN_MSTACK_16(dest, src) \
758120925Smarcel    (env->remote? \
759120925Smarcel	(*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \
760120925Smarcel						2*DWORDSZ, env->cb_token) : \
761160157Smarcel	(*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), \
762160157Smarcel	    *(uint64_t *)(intptr_t)((dest)+8) = \
763160157Smarcel					*(uint64_t *)(intptr_t)((src)+8), \
764160157Smarcel	    2*DWORDSZ) )
765120925Smarcel
766120925Smarcelint uwx_restore_freg(struct uwx_env *env, uint64_t rstate,
767120925Smarcel				uint64_t *valp, uint64_t *histp)
768120925Smarcel{
769120925Smarcel    int status;
770120925Smarcel    uint64_t p;
771120925Smarcel    int n;
772120925Smarcel    int regid;
773120925Smarcel
774120925Smarcel    status = UWX_OK;
775120925Smarcel
776120925Smarcel    switch (UWX_GET_DISP_CODE(rstate)) {
777120925Smarcel	case UWX_DISP_SPREL(0):
778120925Smarcel	    p = env->context.special[UWX_REG_SP] +
779120925Smarcel				UWX_GET_DISP_OFFSET(rstate);
780120925Smarcel	    n = COPYIN_MSTACK_16((char *)valp, p);
781120925Smarcel	    if (n != 2*DWORDSZ)
782120925Smarcel		status = UWX_ERR_COPYIN_MSTK;
783120925Smarcel	    *histp = UWX_DISP_MSTK(p);
784120925Smarcel	    break;
785120925Smarcel	case UWX_DISP_PSPREL(0):
786120925Smarcel	    p = env->context.special[UWX_REG_PSP] + 16 -
787120925Smarcel				UWX_GET_DISP_OFFSET(rstate);
788120925Smarcel	    n = COPYIN_MSTACK_16((char *)valp, p);
789120925Smarcel	    if (n != 2*DWORDSZ)
790120925Smarcel		status = UWX_ERR_COPYIN_MSTK;
791120925Smarcel	    *histp = UWX_DISP_MSTK(p);
792120925Smarcel	    break;
793120925Smarcel	case UWX_DISP_REG(0):
794120925Smarcel	    regid = UWX_GET_DISP_REGID(rstate);
795120925Smarcel	    status = uwx_get_reg(env, regid, valp);
796120925Smarcel	    (void) uwx_get_spill_loc(env, regid, histp);
797120925Smarcel	    break;
798120925Smarcel    }
799120925Smarcel    return status;
800120925Smarcel}
801120925Smarcel
802115013Smarcel/* uwx_restore_nat: Returns the saved NaT bit for a preserved GR */
803115013Smarcel
804115013Smarcelint uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat)
805115013Smarcel{
806115013Smarcel    int nat;
807115013Smarcel    uint64_t p;
808115013Smarcel
809115013Smarcel    nat = 0;
810115013Smarcel    switch (UWX_GET_DISP_CODE(rstate)) {
811115013Smarcel	case UWX_DISP_SPREL(0):
812115013Smarcel	    p = env->context.special[UWX_REG_SP] +
813115013Smarcel				UWX_GET_DISP_OFFSET(rstate);
814115013Smarcel	    nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01;
815115013Smarcel	    break;
816115013Smarcel	case UWX_DISP_PSPREL(0):
817115013Smarcel	    p = env->context.special[UWX_REG_PSP] + 16 -
818115013Smarcel				UWX_GET_DISP_OFFSET(rstate);
819115013Smarcel	    nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01;
820115013Smarcel	    break;
821115013Smarcel	case UWX_DISP_REG(0):
822115013Smarcel	    (void) uwx_get_nat(env, UWX_GET_DISP_REGID(rstate), &nat);
823115013Smarcel	    break;
824115013Smarcel    }
825115013Smarcel    return nat;
826115013Smarcel}
827115013Smarcel
828