Ejemplo n.º 1
0
void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfer_addr)
{
	mv_stent	*mv_st_ent, *mv_st_prev;
	char		*top;
	unsigned char	*msp_save;
	int4		shift, size, mv_st_type;
	rhdtyp		*old_rtnhdr;

	unwind_nocounts();
	/* We are going to mutate the current frame from the program it was running to the program we want it to run.
	 * If the current frame is marked for indr cache cleanup, do that cleanup now and unmark the frame.
	 */
	IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(frame_pointer);

	DBGEHND((stderr, "flush_jmp: Retargetting stack frame 0x"lvaddr" for transfer address 0x"lvaddr"\n", frame_pointer,
		 transfer_addr));
	/* Also unmark the SFF_ETRAP_ERR bit in case it is set. This way we ensure control gets transferred to
	 * the mpc below instead of "error_return" (which is what getframe will do in case the bit is set).
	 * It is ok to clear this bit because the global variable "error_frame" will still be set to point to
	 * this frame so whenever we unwind out of this, we will rethrow the error at the parent frame.
	 */
	assert(!(frame_pointer->flags & SFF_ETRAP_ERR) || (NULL == error_frame) || (error_frame == frame_pointer));
	assert(!(SFT_TRIGR & frame_pointer->type));
	frame_pointer->flags &= SFF_ETRAP_ERR_OFF;	  /* clear SFF_ETRAP_ERR bit */
	frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* clear SFF_IMPLTSTART_CALLD bit since this frame is being rewritten */
	GTMTRIG_ONLY(DBGTRIGR((stderr, "flush_jmp: Turrning off SFF_IMPLTSTART_CALLD_OFF in frame 0x"lvaddr"\n", frame_pointer)));
	old_rtnhdr = frame_pointer->rvector;
	frame_pointer->rvector = rtn_base;
	/* Now that fp->rvector has been overwritten to new routine, check if the older routine had a "rtn_relinked" flag set
	 * and if so that cleanup can be performed now.
	 */
	USHBIN_ONLY(CLEANUP_COPIED_RECURSIVE_RTN(old_rtnhdr));	/* cleanup if needed */
	frame_pointer->vartab_ptr = (char *)VARTAB_ADR(rtn_base);
	frame_pointer->vartab_len = frame_pointer->rvector->vartab_len;
	frame_pointer->mpc = transfer_addr;
	frame_pointer->ctxt = context;
#ifdef HAS_LITERAL_SECT
	frame_pointer->literal_ptr = (int4 *)LITERAL_ADR(rtn_base);
#endif
	frame_pointer->temp_mvals = frame_pointer->rvector->temp_mvals;
	size = rtn_base->temp_size;
	frame_pointer->temps_ptr = (unsigned char *)frame_pointer - size;
	size += rtn_base->vartab_len * SIZEOF(ht_ent_mname *);
	frame_pointer->l_symtab = (ht_ent_mname **)((char *)frame_pointer - size);
	assert(frame_pointer->type & SFT_COUNT);
	assert((unsigned char *)mv_chain > stacktop && (unsigned char *)mv_chain <= stackbase);
	while (((char *)mv_chain < (char *)frame_pointer) && !mvs_save[mv_chain->mv_st_type])
	{
		assert(MVST_TRIGR != mv_chain->mv_st_type);	/* Should never unwind a trigger frame here */
		msp = (unsigned char *)mv_chain;
		op_oldvar();
	}
	if ((char *)mv_chain > (char *)frame_pointer)
	{
		msp_save = msp;
		msp = (unsigned char *)frame_pointer->l_symtab;
	   	if (msp <= stackwarn)
	   	{
			if (msp <= stacktop)
			{
				msp = msp_save;
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW);
	   		} else
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT);
	   	}
		memset(msp, 0, size);
		DBGEHND((stderr, "flush_jmp: Old msp: 0x"lvaddr"  New msp: 0x"lvaddr"\n", msp_save, msp));
		return;
	}
	/* We kept one or more mv_stents for this frame. We may need to shift the stack to get room to create an l_symtab
	 * for this re-purposed frame. In the above loop, we stopped searching the mv_stent chain at the first mv_stent we
	 * knew we had to keep. Since we are moving things around anyway, see if there are any mv_stents associated
	 * with this frame which don't need to be kept and can reclaim.
	 */
	mv_st_ent = mv_chain;
	mv_st_prev = (mv_stent *)((char *)mv_st_ent + mv_st_ent->mv_st_next);
	top = (char *)mv_st_ent + mvs_size[mv_st_ent->mv_st_type];
	while ((char *)mv_st_prev < (char *)frame_pointer)
	{
		mv_st_type = mv_st_prev->mv_st_type;
		assert(MVST_TRIGR != mv_st_type);	/* Should never unwind a trigger frame here */
		if (!mvs_save[mv_st_type])
		{	/* Don't need to keep this mv_stent. Remove it from the chain */
			DBGEHND((stderr, "flush_jmp: Removing no-save mv_stent addr 0x"lvaddr" and type %d\n",
				 mv_st_prev, mv_st_type));
			unw_mv_ent(mv_st_prev);
			mv_st_ent->mv_st_next += mv_st_prev->mv_st_next;
			mv_st_prev = (mv_stent *)((char *)mv_st_prev + mv_st_prev->mv_st_next);
			continue;
		}
		/* We found a previous mv_stent we need to keep. If we had an interveening mv_stent we don't need to
		 * keep, migrate the new keeper mv_stent adjacent to the previous keeper. */
		if (mv_st_prev != (mv_stent *)top)
		{
			DBGEHND((stderr, "flush_jmp: Migrating keeper mv_stent from 0x"lvaddr" to 0x"lvaddr" type %d\n",
				 mv_st_prev, top, mv_st_type));
			if (MVST_TPHOLD == mv_st_type)
			{	/* If we are moving an MVST_TPHOLD mv_stent, find it in the tpstack and fix its
				 * address there too. Else we won't unwind to the correct place on a restart. */
				fix_tphold_mvc(top, (char *)mv_st_prev, ((char *)mv_st_prev + mvs_size[MVST_TPHOLD]));
			}
			memmove(top, mv_st_prev, mvs_size[mv_st_type]);
		}
		DBGEHND((stderr, "flush_jmp: Updating offsets for mv_stent at addr 0x"lvaddr" type %d\n",
			 mv_st_ent, mv_st_ent->mv_st_type));
		mv_st_ent->mv_st_next = mvs_size[mv_st_ent->mv_st_type];
		mv_st_ent = (mv_stent *)top;
		mv_st_ent->mv_st_next += (unsigned int)((char *)mv_st_prev - top);
		top += mvs_size[mv_st_ent->mv_st_type];
		mv_st_prev = (mv_stent *)((char *)mv_st_ent + mv_st_ent->mv_st_next);
	}
	shift = (int4)((char *)frame_pointer - top - size);
	DBGEHND_ONLY(msp_save = msp);
	if (shift)
	{
   		if ((unsigned char *)mv_chain + shift <= stackwarn)
   		{
			if ((unsigned char *)mv_chain + shift <= stacktop)
   				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW);
   			else
   				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT);
      		}
		DBGEHND((stderr, "flush_jmp: Shifting %d bytes of stack from 0x"lvaddr" to 0x"lvaddr" by %d bytes\n",
			 INTCAST(top - (char *)mv_chain), mv_chain, (mv_chain + shift), shift));
		/* Since we are moving one or more mv_stents, it is no more difficult to check the range against the
		 * tp_frame chain than it is to loop through the mv_stents checking each one since the tp_frame stack
		 * is usually no more than 1-3 deep.
		 */
		fix_tphold_mvc(((char *)mv_chain + shift), (char *)mv_chain, ((char *)mv_chain + (top - (char *)mv_chain)));
		memmove((char *)mv_chain + shift, mv_chain, top - (char *)mv_chain);
		mv_chain = (mv_stent *)((char *)mv_chain + shift);
		mv_st_ent = (mv_stent *)((char *)mv_st_ent + shift);
		mv_st_ent->mv_st_next -= shift;
		msp = (unsigned char *)mv_chain;
	}
	memset(frame_pointer->l_symtab, 0, size);
	DBGEHND((stderr, "flush_jmp: Old msp: 0x"lvaddr"  New msp: 0x"lvaddr"\n", msp_save, msp));
	return;
}
Ejemplo n.º 2
0
void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfer_addr)
{

	mv_stent	*mv_st_ent, *mv_st_prev;
	char		*top;
	unsigned char	*msp_save;
	int4		shift, size;
	error_def(ERR_STACKOFLOW);
	error_def(ERR_STACKCRIT);

	unwind_nocounts();
	/* We are going to mutate the current frame from the program it was running to the program we want it to run.
	 * If the current frame is marked for indr cache cleanup, do that cleanup now and unmark the frame.
	 */
	IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(frame_pointer);

	frame_pointer->rvector = rtn_base;
	frame_pointer->vartab_ptr = (char *)VARTAB_ADR(rtn_base);
	frame_pointer->vartab_len = frame_pointer->rvector->vartab_len;
	frame_pointer->mpc = transfer_addr;
	frame_pointer->ctxt = context;
#ifdef HAS_LITERAL_SECT
	frame_pointer->literal_ptr = (int4 *)0;
#endif
	frame_pointer->temp_mvals = frame_pointer->rvector->temp_mvals;
	size = rtn_base->temp_size;
	frame_pointer->temps_ptr = (unsigned char *) frame_pointer - size;
	size += rtn_base->vartab_len * sizeof(mval *);
	frame_pointer->l_symtab = (mval **)((char *) frame_pointer - size);
	assert(frame_pointer->type & SFT_COUNT);
	assert((unsigned char *) mv_chain > stacktop && (unsigned char *) mv_chain <= stackbase);

	while ((char *) mv_chain < (char *) frame_pointer && !mvs_save[mv_chain->mv_st_type])
	{
		msp = (unsigned char *)mv_chain;
		op_oldvar();
	}
	if ((char *) mv_chain > (char *) frame_pointer)
	{
		msp_save = msp;
		msp = (unsigned char *)frame_pointer->l_symtab;
	   	if (msp <= stackwarn)
	   	{
			if (msp <= stacktop)
			{
				msp = msp_save;
				rts_error(VARLSTCNT(1) ERR_STACKOFLOW);
	   		} else
				rts_error(VARLSTCNT(1) ERR_STACKCRIT);
	   	}
		memset(msp, 0, size);
		return;
	}
	mv_st_ent = mv_chain;
	mv_st_prev = (mv_stent *)((char *) mv_st_ent + mv_st_ent->mv_st_next);
	top = (char *) mv_st_ent + mvs_size[mv_st_ent->mv_st_type];
	while ((char *) mv_st_prev < (char *) frame_pointer)
	{
		if ( !mvs_save[mv_st_prev->mv_st_type] )
		{
			unw_mv_ent(mv_st_prev);
			mv_st_ent->mv_st_next += mv_st_prev->mv_st_next;
			mv_st_prev = (mv_stent *)((char *) mv_st_prev + mv_st_prev->mv_st_next);
			continue;
		}
		if (mv_st_prev != (mv_stent *)top)
			memmove(top, mv_st_prev, mvs_size[mv_st_prev->mv_st_type]);
		mv_st_ent->mv_st_next = mvs_size[mv_st_ent->mv_st_type];
		mv_st_ent = (mv_stent *)top;
		mv_st_ent->mv_st_next += (char *) mv_st_prev - top;
		top += mvs_size[mv_st_ent->mv_st_type];
		mv_st_prev = (mv_stent *)((char *) mv_st_ent + mv_st_ent->mv_st_next);
	}
	shift = (char *) frame_pointer - top - size;
	if (shift)
	{
   		if ((unsigned char *)mv_chain + shift <= stackwarn)
   		{
			if ((unsigned char *)mv_chain + shift <= stacktop)
   				rts_error(VARLSTCNT(1) ERR_STACKOFLOW);
   			else
   				rts_error(VARLSTCNT(1) ERR_STACKCRIT);
      		}
		memmove((char *) mv_chain + shift, mv_chain, top - (char *) mv_chain);
		mv_chain = (mv_stent *)((char *) mv_chain + shift);
		mv_st_ent = (mv_stent *)((char *) mv_st_ent + shift);
		mv_st_ent->mv_st_next -= shift;
		msp = (unsigned char *) mv_chain;
	}
	memset(frame_pointer->l_symtab, 0, size);
	return;
}
Ejemplo n.º 3
0
void trans_code_cleanup(void)
{
    stack_frame	*fp;
    uint4		err;

    error_def(ERR_STACKCRIT);
    error_def(ERR_ERRWZTRAP);
    error_def(ERR_ERRWETRAP);
    error_def(ERR_ERRWIOEXC);

    assert(!(SFT_ZINTR & proc_act_type));
    /* With no extra ztrap frame being pushed onto stack, we may miss error(s)
     * during trans_code if we don't check proc_act_type in addition to
     * frame_pointer->type below.
     */
    if (SFT_ZTRAP == proc_act_type)
    {
        if (0 < dollar_ztrap.str.len)
            err = (int)ERR_ERRWZTRAP;
        else
        {
            assert(0 < dollar_etrap.str.len);
            err = (int)ERR_ERRWETRAP;
        }
        frame_pointer->flags |= SFF_ZTRAP_ERR;
    } else if (SFT_DEV_ACT == proc_act_type)
    {
        err = ERR_ERRWIOEXC;
        frame_pointer->flags |= SFF_DEV_ACT_ERR;
    } else
        err = 0;

    proc_act_type = 0;
    if (compile_time)
    {
        compile_time = FALSE;
        if (stringpool.base != rts_stringpool.base)
            stringpool = rts_stringpool;
    }
    for (fp = frame_pointer; fp; fp = fp->old_frame_pointer)
    {
        if (fp->type & SFT_DM)
            break;
        if (fp->type & SFT_COUNT)
        {
            assert(NULL != err_act);
            if (!IS_ETRAP)
                dm_setup();
            break;
        }
        if (fp->type)
        {
            SET_ERR_CODE(fp, err);
        }
        /* If this frame is indicated for cache cleanup, do that cleanup
           now before we get rid of the pointers used by that cleanup.
        */
        IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(fp);
        fp->mpc = CODE_ADDRESS(pseudo_ret);
        fp->ctxt = CONTEXT(pseudo_ret);
    }
    transform = TRUE;
    if (err)
        dec_err(VARLSTCNT(1) err);
}
Ejemplo n.º 4
0
void trans_code_cleanup(void)
{
	stack_frame	*fp, *fpprev;
	uint4		errmsg;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(!(SFT_ZINTR & proc_act_type));
	/* With no extra ztrap frame being pushed onto stack, we may miss error(s)
	 * during trans_code if we don't check proc_act_type in addition to
	 * frame_pointer->type below.
	 */
	if (SFT_ZTRAP == proc_act_type)
	{
		if (0 < dollar_ztrap.str.len)
			errmsg = ERR_ERRWZTRAP;
		else
			errmsg = ERR_ERRWETRAP;
	} else if (SFT_DEV_ACT == proc_act_type)
		errmsg = ERR_ERRWIOEXC;
	else
		errmsg = 0;
	proc_act_type = 0;
	if (TREF(compile_time))
	{
		TREF(compile_time) = FALSE;
		if (stringpool.base != rts_stringpool.base)
			stringpool = rts_stringpool;
	}
	for (fp = frame_pointer; fp; fp = fpprev)
	{
		fpprev = fp->old_frame_pointer;
#		ifdef GTM_TRIGGER
		if (SFT_TRIGR & fpprev->type)
			fpprev = *(stack_frame **)(fpprev + 1);
#		endif
		if (fp->type & SFT_DM)
			break;
		if (fp->type & SFT_COUNT)
		{
			if ((ERR_ERRWZTRAP == errmsg) || (ERR_ERRWETRAP == errmsg))
			{	/* Whether ETRAP or ZTRAP we want to rethrow the error at one level down */
				SET_ERROR_FRAME(fp);	/* reset error_frame to point to the closest counted frame */
				assert(fp->flags & SFF_ETRAP_ERR);
				/* Turn off any device exception related flags now that we are going to handle errors using
				 * $ETRAP or $ZTRAP AT THE PARENT LEVEL only (no more device exceptions).
				 */
				dollar_ztrap.str.len = 0;
				ztrap_explicit_null = FALSE;
				fp->flags &= SFF_DEV_ACT_ERR_OFF;
				fp->flags &= SFF_ZTRAP_ERR_OFF;
				err_act = &dollar_etrap.str;
				break;
			} else if (ERR_ERRWIOEXC == errmsg)
			{	/* Error while compiling device exception. Set SFF_ETRAP_ERR bit so control is transferred to
				 * error_return() which in turn will rethrow the error AT THE SAME LEVEL in order to try and
				 * use $ZTRAP or $ETRAP whichever is active. Also set the SFF_DEV_ACT_ERR bit to signify this
				 * is a device exception that is rethrown instead of a ztrap/etrap error. Also assert that
				 * the rethrow will not use IO exception again (thereby ensuring error processing will
				 * eventually terminate instead of indefinitely recursing).
				 */
				fp->flags |= (SFF_DEV_ACT_ERR | SFF_ETRAP_ERR);
				assert(NULL == active_device);	/* mdb_condition_handler should have reset it */
				break;
			} else if ((ERR_ERRWZBRK == errmsg) || (ERR_ERRWEXC == errmsg))
			{	/* For typical exceptions in ZBREAK and ZSTEP, get back to direct mode */
				dm_setup();
				break;
			} else
			{	/* The only known way to be here is if the command is a command given in direct mode as
				 * mdb_condition_handler won't drive an error handler in that case which would be caught in
				 * one of the above conditions. Not breaking out of the loop here means the frame will just
				 * unwind and we'll break on the direct mode frame which will be redriven. If the parent frame
				 * is not a direct mode frame, we'll assert in debug or break in pro and just continue.
				 * to direct mode.
				 */
				assert(fp->flags && (SFF_INDCE));
				if (!fp->old_frame_pointer || !(fp->old_frame_pointer->type & SFT_DM))
				{
					assert(FALSE);
					break;
				}
			}
		}
		if (fp->type)
		{
			SET_ERR_CODE(fp, errmsg);
		}
		/* If this frame is indicated for cache cleanup, do that cleanup
		 * now before we get rid of the pointers used by that cleanup.
		 */
		IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(fp);
		fp->mpc = CODE_ADDRESS(pseudo_ret);
		fp->ctxt = GTM_CONTEXT(pseudo_ret);
		fp->flags &= SFF_IMPLTSTART_CALLD_OFF;	/* Frame enterable now with mpc reset */
		GTMTRIG_ONLY(DBGTRIGR((stderr, "trans_code_cleanup: turning off SFF_IMPLTSTART_CALLD in frame 0x"lvaddr"\n",
				       frame_pointer)));
	}
	TREF(transform) = TRUE;
	if (0 != errmsg)
		dec_err(VARLSTCNT(1) errmsg);
}