summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ia64/libuwx/src/uwx_step.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/ia64/libuwx/src/uwx_step.c')
-rw-r--r--sys/contrib/ia64/libuwx/src/uwx_step.c827
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;
+}
+
OpenPOWER on IntegriCloud