diff options
Diffstat (limited to 'sys/contrib/ia64/libuwx/src/uwx_step.c')
-rw-r--r-- | sys/contrib/ia64/libuwx/src/uwx_step.c | 827 |
1 files changed, 827 insertions, 0 deletions
diff --git a/sys/contrib/ia64/libuwx/src/uwx_step.c b/sys/contrib/ia64/libuwx/src/uwx_step.c new file mode 100644 index 0000000..42b8c93 --- /dev/null +++ b/sys/contrib/ia64/libuwx/src/uwx_step.c @@ -0,0 +1,827 @@ +/* +Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P. +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "uwx_env.h" +#include "uwx_utable.h" +#include "uwx_uinfo.h" +#include "uwx_scoreboard.h" +#include "uwx_str.h" +#include "uwx_step.h" +#include "uwx_trace.h" + +/* + * uwx_step.c + * + * This file contains the routines for stepping from one frame + * into its callers frame. The context for the current frame + * is maintained inside the current unwind environment + * (struct uwx_env), and is updated with each call to + * uwx_step() to refer to the previous frame. + */ + + +/* Forward Declarations */ + +int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate); +int uwx_restore_reg(struct uwx_env *env, uint64_t rstate, + uint64_t *valp, uint64_t *histp); +int uwx_restore_freg(struct uwx_env *env, uint64_t rstate, + uint64_t *valp, uint64_t *histp); +int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat); + + +/* uwx_lookupip_hook: Hook routine so dynamic instrumentation */ +/* tools can intercept Lookup IP events. When not */ +/* intercepted, it just returns "Not found", so that */ +/* the callback routine is invoked. */ + +/*ARGSUSED*/ +int uwx_lookupip_hook(int request, uint64_t ip, intptr_t tok, uint64_t **vecp, + size_t uvecsize) +{ + return UWX_LKUP_NOTFOUND; +} + + +/* uwx_get_frame_info: Gets unwind info for current frame */ +static +int uwx_get_frame_info(struct uwx_env *env) +{ + int i; + int status; + int cbstatus; + int cbcalled = 0; + uint64_t ip; + uint64_t *uvec; + uint64_t *rstate; + struct uwx_utable_entry uentry; + uint64_t uvecout[UVECSIZE]; + + if (env->copyin == 0 || env->lookupip == 0) + return UWX_ERR_NOCALLBACKS; + + env->ptr_size = DWORDSZ; + env->code_start = 0; + env->function_offset = -1LL; + env->function_name = 0; + env->module_name = 0; + env->abi_context = 0; + uwx_reset_str_pool(env); + + /* Use the lookup IP callback routine to find out about the */ + /* current IP. If the predicate registers are valid, pass them */ + /* in the uvec. */ + + /* When self-unwinding, we call a hook routine before the */ + /* callback. If the application is running under control of */ + /* a dynamic instrumentation tool, that tool will have an */ + /* opportunity to intercept lookup IP requests. */ + + i = 0; + uvecout[i++] = UWX_KEY_VERSION; + uvecout[i++] = UWX_VERSION; + if (env->context.valid_regs & (1 << UWX_REG_PREDS)) { + uvecout[i++] = UWX_KEY_PREDS; + uvecout[i++] = env->context.special[UWX_REG_PREDS]; + } + uvecout[i++] = UWX_KEY_END; + uvecout[i++] = 0; + uvec = uvecout; + cbstatus = UWX_LKUP_NOTFOUND; + ip = env->context.special[UWX_REG_IP]; + env->remapped_ip = ip; + + /* Call the hook routine. */ + + if (env->remote == 0) + cbstatus = uwx_lookupip_hook(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec, + sizeof(uvecout)); + + /* If the hook routine remapped the IP, use the new IP for */ + /* the callback instead of the original IP. */ + + if (cbstatus == UWX_LKUP_REMAP) { + for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { + switch ((int)uvec[i]) { + case UWX_KEY_NEWIP: + ip = uvec[i+1]; + break; + } + } + env->remapped_ip = ip; + } + + /* Now call the callback routine unless the hook routine gave */ + /* us all the info. */ + + if (cbstatus == UWX_LKUP_NOTFOUND || cbstatus == UWX_LKUP_REMAP) { + cbcalled = 1; + cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec); + } + + /* If the callback routine remapped the IP, call it one more time */ + /* with the new IP. */ + + if (cbstatus == UWX_LKUP_REMAP) { + for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { + switch ((int)uvec[i]) { + case UWX_KEY_NEWIP: + ip = uvec[i+1]; + break; + } + } + env->remapped_ip = ip; + cbstatus = (*env->lookupip)(UWX_LKUP_LOOKUP, ip, env->cb_token, &uvec); + } + + /* If NOTFOUND, there's nothing we can do but return an error. */ + + if (cbstatus == UWX_LKUP_NOTFOUND) { + status = UWX_ERR_IPNOTFOUND; + } + + /* If the callback returns an unwind table, we need to */ + /* search the table for an unwind entry that describes the */ + /* code region of interest, then decode the unwind information */ + /* associated with that unwind table entry, and store the */ + /* resulting register state array in the unwind environment */ + /* block. */ + + else if (cbstatus == UWX_LKUP_UTABLE) { + status = uwx_search_utable(env, ip, uvec, &uentry); + if (cbcalled) + (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); + if (status == UWX_OK) { + env->ptr_size = uentry.ptr_size; + env->code_start = uentry.code_start; + status = uwx_decode_uinfo(env, &uentry, &rstate); + } + if (status == UWX_ERR_NOUENTRY || status == UWX_ERR_NOUDESC) + status = uwx_default_rstate(env, &rstate); + if (status == UWX_OK) + env->rstate = rstate; + } + + /* If the callback returns an unwind info block, we can */ + /* proceed directly to decoding the unwind information. */ + + else if (cbstatus == UWX_LKUP_UINFO) { + uentry.ptr_size = DWORDSZ; + uentry.code_start = 0; + uentry.code_end = 0; + uentry.unwind_info = 0; + uentry.unwind_flags = 0; + for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { + switch ((int)uvec[i]) { + case UWX_KEY_UFLAGS: + uentry.unwind_flags = uvec[i+1]; + if (uentry.unwind_flags & UNWIND_TBL_32BIT) + uentry.ptr_size = WORDSZ; + break; + case UWX_KEY_UINFO: + uentry.unwind_info = uvec[i+1]; + break; + case UWX_KEY_GP: + uwx_set_reg(env, UWX_REG_GP, uvec[i+1]); + break; + case UWX_KEY_MODULE: + env->module_name = + uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); + break; + case UWX_KEY_FUNC: + env->function_name = + uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); + break; + case UWX_KEY_FUNCSTART: + uentry.code_start = uvec[i+1]; + env->code_start = uentry.code_start; + break; + } + } + env->ptr_size = uentry.ptr_size; + if (cbcalled) + (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); + status = uwx_decode_uinfo(env, &uentry, &rstate); + if (status == UWX_ERR_NOUDESC) + status = uwx_default_rstate(env, &rstate); + if (status == UWX_OK) + env->rstate = rstate; + } + + /* If the callback returns a frame description (in the form */ + /* of an update vector), convert the update vector into a */ + /* register state array, then invoke the callback again to */ + /* let it free any memory it allocated. */ + + else if (cbstatus == UWX_LKUP_FDESC) { + status = uwx_decode_uvec(env, uvec, &rstate); + if (cbcalled) + (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); + if (status == UWX_OK) + env->rstate = rstate; + } + + /* Any other return from the callback is an error. */ + + else { + status = UWX_ERR_LOOKUPERR; + } + return status; +} + + +/* uwx_restore_markers: Restores the stack markers -- PSP, RP, PFS */ + +int uwx_restore_markers(struct uwx_env *env) +{ + int status; + uint64_t val; + uint64_t hist; + + if ((env->context.valid_regs & VALID_BASIC4) != VALID_BASIC4) + return UWX_ERR_NOCONTEXT; + + /* If we haven't already obtained the frame info for the */ + /* current frame, get it now. */ + + if (env->rstate == 0) { + status = uwx_get_frame_info(env); + if (status != UWX_OK) + return status; + } + + TRACE_S_STEP(env->rstate) + + if (env->rstate[SBREG_PSP] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, env->rstate[SBREG_PSP], &val, &hist); + if (status != UWX_OK) + return status; + env->context.special[UWX_REG_PSP] = val; + env->history.special[UWX_REG_PSP] = hist; + env->context.valid_regs |= 1 << UWX_REG_PSP; + TRACE_S_RESTORE_REG("PSP", env->rstate[SBREG_PSP], val) + } + + if (env->rstate[SBREG_RP] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, env->rstate[SBREG_RP], &val, &hist); + if (status != UWX_OK) + return status; + env->context.special[UWX_REG_RP] = val; + env->history.special[UWX_REG_RP] = hist; + env->context.valid_regs |= 1 << UWX_REG_RP; + TRACE_S_RESTORE_REG("RP", env->rstate[SBREG_RP], val) + } + + if (env->rstate[SBREG_PFS] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, env->rstate[SBREG_PFS], &val, &hist); + if (status != UWX_OK) + return status; + env->context.special[UWX_REG_PFS] = val; + env->history.special[UWX_REG_PFS] = hist; + env->context.valid_regs |= 1 << UWX_REG_PFS; + TRACE_S_RESTORE_REG("PFS", env->rstate[SBREG_PFS], val) + } + + return UWX_OK; +} + +/* uwx_get_module_info: Gets module name and text base for current frame */ + +int uwx_get_module_info( + struct uwx_env *env, + char **modp, + uint64_t *text_base) +{ + int i; + int status; + int cbstatus; + uint64_t ip; + uint64_t *uvec; + uint64_t uvecout[UVECSIZE]; + + if (env == 0) + return UWX_ERR_NOENV; + + /* If we haven't already obtained the frame info for the */ + /* current frame, get it now. */ + + if (env->rstate == 0) { + status = uwx_get_frame_info(env); + if (status != UWX_OK) + return status; + } + + /* Get the module name from the lookup IP callback. */ + if (env->module_name == 0) { + ip = env->remapped_ip; + i = 0; + if (env->function_offset >= 0) { + uvecout[i++] = UWX_KEY_FUNCSTART; + uvecout[i++] = ip - env->function_offset; + } + uvecout[i++] = UWX_KEY_END; + uvecout[i++] = 0; + uvec = uvecout; + cbstatus = (*env->lookupip)(UWX_LKUP_MODULE, ip, env->cb_token, &uvec); + + if (cbstatus == UWX_LKUP_SYMINFO) { + for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { + switch ((int)uvec[i]) { + case UWX_KEY_TBASE: + env->text_base = uvec[i+1]; + break; + case UWX_KEY_MODULE: + env->module_name = + uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); + break; + case UWX_KEY_FUNC: + env->function_name = + uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); + break; + case UWX_KEY_FUNCSTART: + env->function_offset = ip - uvec[i+1]; + break; + } + } + (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); + } + } + + *modp = env->module_name; + *text_base = env->text_base; + + return UWX_OK; +} + +/* uwx_get_funcstart: Gets start address of function from current frame */ + +int uwx_get_funcstart( + struct uwx_env *env, + uint64_t *funcstart) +{ + int status; + + if (env == 0) + return UWX_ERR_NOENV; + + /* If we haven't already obtained the frame info for the */ + /* current frame, get it now. */ + + if (env->rstate == 0) { + status = uwx_get_frame_info(env); + if (status != UWX_OK) + return status; + } + + *funcstart = env->remapped_ip - env->function_offset; + + return UWX_OK; +} + +/* uwx_get_sym_info: Gets symbolic info from current frame */ +/* (Will make a UWX_LKUP_SYMBOLS callback if info */ +/* was not provided by UWX_LKUP_LOOKUP callback) */ + +int uwx_get_sym_info( + struct uwx_env *env, + char **modp, + char **symp, + uint64_t *offsetp) +{ + int status; + int cbstatus; + uint64_t ip; + uint64_t *uvec; + uint64_t uvecout[UVECSIZE]; + int i; + + if (env == 0) + return UWX_ERR_NOENV; + + /* If we haven't already obtained the frame info for the */ + /* current frame, get it now. */ + + if (env->rstate == 0) { + status = uwx_get_frame_info(env); + if (status != UWX_OK) + return status; + } + + /* Get the symbolic information from the lookup IP callback. */ + if (env->function_name == 0) { + ip = env->remapped_ip; + i = 0; + if (env->function_offset >= 0) { + uvecout[i++] = UWX_KEY_FUNCSTART; + uvecout[i++] = ip - env->function_offset; + } + uvecout[i++] = UWX_KEY_END; + uvecout[i++] = 0; + uvec = uvecout; + cbstatus = (*env->lookupip)(UWX_LKUP_SYMBOLS, ip, env->cb_token, &uvec); + + if (cbstatus == UWX_LKUP_SYMINFO) { + for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { + switch ((int)uvec[i]) { + case UWX_KEY_MODULE: + env->module_name = + uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); + break; + case UWX_KEY_FUNC: + env->function_name = + uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); + break; + case UWX_KEY_FUNCSTART: + env->function_offset = ip - uvec[i+1]; + break; + } + } + (void) (*env->lookupip)(UWX_LKUP_FREE, 0, env->cb_token, &uvec); + } + } + + *modp = env->module_name; + *symp = env->function_name; + *offsetp = env->function_offset; + + return UWX_OK; +} + + +/* uwx_step: Steps from the current frame to the previous frame */ + +int uwx_step(struct uwx_env *env) +{ + int i; + int status; + int pfs_sol; + int dispcode; + uint64_t val; + uint64_t fval[2]; + uint64_t hist; + uint64_t tempgr[NPRESERVEDGR]; + int needpriunat; + int unat; + int tempnat; + + if (env == 0) + return UWX_ERR_NOENV; + + /* Complete the current context by restoring the current values */ + /* of psp, rp, and pfs. */ + + if (env->rstate == 0 || + (env->context.valid_regs & VALID_MARKERS) != VALID_MARKERS) { + status = uwx_restore_markers(env); + if (status != UWX_OK) + return status; + } + + /* Check for bottom of stack (rp == 0). */ + + if (env->context.special[UWX_REG_RP] == 0) + return UWX_BOTTOM; + + /* Find where the primary unat is saved, get a copy. */ + /* Then, as we restore the GRs, we'll merge the NaT bits into the */ + /* priunat register in the context. */ + /* (Make sure we need it, though, before we try to get it, */ + /* because the attempt to get it might invoke the copy-in callback. */ + /* We don't need the priunat unless one of GR 4-7 was */ + /* saved to the memory stack.) */ + + needpriunat = 0; + for (i = 0; i < NSB_GR; i++) { + dispcode = UWX_GET_DISP_CODE(env->rstate[SBREG_GR + i]); + if (dispcode == UWX_DISP_SPREL(0) || dispcode == UWX_DISP_PSPREL(0)) + needpriunat = 1; + } + unat = 0; + if (needpriunat && env->rstate[SBREG_PRIUNAT] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, env->rstate[SBREG_PRIUNAT], &val, &hist); + if (status != UWX_OK) + return status; + unat = (int) val; + env->history.special[UWX_REG_PRIUNAT] = hist; + TRACE_S_RESTORE_REG("PRIUNAT", env->rstate[SBREG_PRIUNAT], val) + } + + /* Retrieve saved values of the preserved GRs into temporaries. */ + + tempnat = (int) env->context.special[UWX_REG_PRIUNAT]; + for (i = 0; i < NSB_GR; i++) { + if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, + env->rstate[SBREG_GR + i], &val, &hist); + if (status != UWX_OK) + return status; + tempgr[i] = val; + if (uwx_restore_nat(env, env->rstate[SBREG_GR + i], unat)) + tempnat |= 1 << i; + else + tempnat &= ~(1 << i); + env->history.gr[i] = hist; + env->context.valid_regs |= 1 << (i + VALID_GR_SHIFT); + TRACE_S_RESTORE_GR(i, env->rstate[SBREG_GR + i], val) + } + } + + /* Now we have everything we need to step back to the previous frame. */ + + /* Restore preserved BRs. */ + + for (i = 0; i < NSB_BR; i++) { + if (env->rstate[SBREG_BR + i] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, + env->rstate[SBREG_BR + i], &val, &hist); + if (status != UWX_OK) + return status; + env->context.br[i] = val; + env->history.br[i] = hist; + env->context.valid_regs |= 1 << (i + VALID_BR_SHIFT); + TRACE_S_RESTORE_BR(i, env->rstate[SBREG_BR + i], val) + } + } + + /* Restore preserved FRs. */ + + if (env->nsbreg == NSBREG) { + for (i = 0; i < NSB_FR; i++) { + if (env->rstate[SBREG_FR + i] != UWX_DISP_NONE) { + status = uwx_restore_freg(env, + env->rstate[SBREG_FR + i], fval, &hist); + if (status != UWX_OK) + return status; + env->context.fr[i].part0 = fval[0]; + env->context.fr[i].part1 = fval[1]; + env->history.fr[i] = hist; + env->context.valid_frs |= 1 << i; + TRACE_S_RESTORE_FR(i, env->rstate[SBREG_FR + i], fval) + } + } + } + + /* Restore other preserved regs. */ + + if (env->rstate[SBREG_PREDS] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, env->rstate[SBREG_PREDS], &val, &hist); + if (status != UWX_OK) + return status; + env->context.special[UWX_REG_PREDS] = val; + env->history.special[UWX_REG_PREDS] = hist; + env->context.valid_regs |= 1 << UWX_REG_PREDS; + TRACE_S_RESTORE_REG("PREDS", env->rstate[SBREG_PREDS], val) + } + if (env->rstate[SBREG_RNAT] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, env->rstate[SBREG_RNAT], &val, &hist); + if (status != UWX_OK) + return status; + env->context.special[UWX_REG_AR_RNAT] = val; + env->history.special[UWX_REG_AR_RNAT] = hist; + env->context.valid_regs |= 1 << UWX_REG_AR_RNAT; + TRACE_S_RESTORE_REG("RNAT", env->rstate[SBREG_RNAT], val) + } + if (env->rstate[SBREG_UNAT] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, env->rstate[SBREG_UNAT], &val, &hist); + if (status != UWX_OK) + return status; + env->context.special[UWX_REG_AR_UNAT] = val; + env->history.special[UWX_REG_AR_UNAT] = hist; + env->context.valid_regs |= 1 << UWX_REG_AR_UNAT; + TRACE_S_RESTORE_REG("UNAT", env->rstate[SBREG_UNAT], val) + } + if (env->rstate[SBREG_FPSR] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, env->rstate[SBREG_FPSR], &val, &hist); + if (status != UWX_OK) + return status; + env->context.special[UWX_REG_AR_FPSR] = val; + env->history.special[UWX_REG_AR_FPSR] = hist; + env->context.valid_regs |= 1 << UWX_REG_AR_FPSR; + TRACE_S_RESTORE_REG("FPSR", env->rstate[SBREG_FPSR], val) + } + if (env->rstate[SBREG_LC] != UWX_DISP_NONE) { + status = uwx_restore_reg(env, env->rstate[SBREG_LC], &val, &hist); + if (status != UWX_OK) + return status; + env->context.special[UWX_REG_AR_LC] = val; + env->history.special[UWX_REG_AR_LC] = hist; + env->context.valid_regs |= 1 << UWX_REG_AR_LC; + TRACE_S_RESTORE_REG("LC", env->rstate[SBREG_LC], val) + } + + /* Restore preserved GRs from temporaries. */ + + for (i = 0; i < NSB_GR; i++) { + if (env->rstate[SBREG_GR + i] != UWX_DISP_NONE) + env->context.gr[i] = tempgr[i]; + } + env->context.special[UWX_REG_PRIUNAT] = tempnat; + + /* Restore the frame markers. */ + + env->context.special[UWX_REG_IP] = env->context.special[UWX_REG_RP]; + env->history.special[UWX_REG_IP] = env->history.special[UWX_REG_RP]; + + env->context.special[UWX_REG_SP] = env->context.special[UWX_REG_PSP]; + env->history.special[UWX_REG_SP] = env->history.special[UWX_REG_PSP]; + + pfs_sol = ((unsigned int)env->context.special[UWX_REG_PFS] >> 7) & 0x7f; + env->context.special[UWX_REG_BSP] = uwx_add_to_bsp( + env->context.special[UWX_REG_BSP], + -pfs_sol); + + env->context.special[UWX_REG_CFM] = env->context.special[UWX_REG_PFS]; + env->history.special[UWX_REG_CFM] = env->history.special[UWX_REG_PFS]; + + env->context.special[UWX_REG_RP] = 0; + + /* The frame info for the new frame isn't yet available. */ + + env->rstate = 0; + env->context.valid_regs &= ~VALID_MARKERS; + + return UWX_OK; +} + + +/* uwx_decode_uvec: Converts the update vector into a register state array */ + +int uwx_decode_uvec(struct uwx_env *env, uint64_t *uvec, uint64_t **rstate) +{ + int i; + int status; + + status = uwx_default_rstate(env, rstate); + if (status != UWX_OK) + return status; + + for (i = 0; uvec[i] != UWX_KEY_END; i += 2) { + switch ((int)uvec[i]) { + case UWX_KEY_CONTEXT: + env->abi_context = (int)(uvec[i+1]); + status = UWX_ABI_FRAME; + break; + case UWX_KEY_GP: + uwx_set_reg(env, UWX_REG_GP, uvec[i+1]); + break; + case UWX_KEY_MODULE: + env->module_name = + uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); + break; + case UWX_KEY_FUNC: + env->function_name = + uwx_alloc_str(env, (char *)(intptr_t)(uvec[i+1])); + break; + case UWX_KEY_FUNCSTART: + env->function_offset = env->remapped_ip - uvec[i+1]; + break; + default: + return UWX_ERR_CANTUNWIND; + } + } + return status; +} + + +/* uwx_restore_reg: Restores a register according to the scoreboard */ + +#define COPYIN_MSTACK_8(dest, src) \ + (env->remote? \ + (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \ + DWORDSZ, env->cb_token) : \ + (*(uint64_t *)(intptr_t)(dest) = \ + *(uint64_t *)(intptr_t)(src), DWORDSZ) ) + +int uwx_restore_reg(struct uwx_env *env, uint64_t rstate, + uint64_t *valp, uint64_t *histp) +{ + int status; + uint64_t p; + int n; + int regid; + + status = UWX_OK; + + switch (UWX_GET_DISP_CODE(rstate)) { + case UWX_DISP_SPPLUS(0): + *valp = env->context.special[UWX_REG_SP] + + UWX_GET_DISP_OFFSET(rstate); + *histp = UWX_DISP_NONE; + break; + case UWX_DISP_SPREL(0): + p = env->context.special[UWX_REG_SP] + + UWX_GET_DISP_OFFSET(rstate); + n = COPYIN_MSTACK_8((char *)valp, p); + if (n != DWORDSZ) + status = UWX_ERR_COPYIN_MSTK; + *histp = UWX_DISP_MSTK(p); + break; + case UWX_DISP_PSPREL(0): + p = env->context.special[UWX_REG_PSP] + 16 - + UWX_GET_DISP_OFFSET(rstate); + n = COPYIN_MSTACK_8((char *)valp, p); + if (n != DWORDSZ) + status = UWX_ERR_COPYIN_MSTK; + *histp = UWX_DISP_MSTK(p); + break; + case UWX_DISP_REG(0): + regid = UWX_GET_DISP_REGID(rstate); + status = uwx_get_reg(env, regid, valp); + (void) uwx_get_spill_loc(env, regid, histp); + break; + } + return status; +} + +#define COPYIN_MSTACK_16(dest, src) \ + (env->remote? \ + (*env->copyin)(UWX_COPYIN_MSTACK, (dest), (src), \ + 2*DWORDSZ, env->cb_token) : \ + (*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), \ + *(uint64_t *)(intptr_t)((dest)+8) = \ + *(uint64_t *)(intptr_t)((src)+8), \ + 2*DWORDSZ) ) + +int uwx_restore_freg(struct uwx_env *env, uint64_t rstate, + uint64_t *valp, uint64_t *histp) +{ + int status; + uint64_t p; + int n; + int regid; + + status = UWX_OK; + + switch (UWX_GET_DISP_CODE(rstate)) { + case UWX_DISP_SPREL(0): + p = env->context.special[UWX_REG_SP] + + UWX_GET_DISP_OFFSET(rstate); + n = COPYIN_MSTACK_16((char *)valp, p); + if (n != 2*DWORDSZ) + status = UWX_ERR_COPYIN_MSTK; + *histp = UWX_DISP_MSTK(p); + break; + case UWX_DISP_PSPREL(0): + p = env->context.special[UWX_REG_PSP] + 16 - + UWX_GET_DISP_OFFSET(rstate); + n = COPYIN_MSTACK_16((char *)valp, p); + if (n != 2*DWORDSZ) + status = UWX_ERR_COPYIN_MSTK; + *histp = UWX_DISP_MSTK(p); + break; + case UWX_DISP_REG(0): + regid = UWX_GET_DISP_REGID(rstate); + status = uwx_get_reg(env, regid, valp); + (void) uwx_get_spill_loc(env, regid, histp); + break; + } + return status; +} + +/* uwx_restore_nat: Returns the saved NaT bit for a preserved GR */ + +int uwx_restore_nat(struct uwx_env *env, uint64_t rstate, int unat) +{ + int nat; + uint64_t p; + + nat = 0; + switch (UWX_GET_DISP_CODE(rstate)) { + case UWX_DISP_SPREL(0): + p = env->context.special[UWX_REG_SP] + + UWX_GET_DISP_OFFSET(rstate); + nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01; + break; + case UWX_DISP_PSPREL(0): + p = env->context.special[UWX_REG_PSP] + 16 - + UWX_GET_DISP_OFFSET(rstate); + nat = (unat >> (((int)p >> 3) & 0x3f)) & 0x01; + break; + case UWX_DISP_REG(0): + (void) uwx_get_nat(env, UWX_GET_DISP_REGID(rstate), &nat); + break; + } + return nat; +} + |