Exemplo n.º 1
0
void urx_resolve(rhdtyp *rtn, lab_tabent *lbl_tab, lab_tabent *lbl_top)
{
	urx_rtnref	*rp0, *rp1;
	urx_labref	*lp0, *lp1;
	urx_addr	*ap;

	if (!urx_getrtn(rtn->routine_name.addr, rtn->routine_name.len, &rp0, &rp1, &urx_anchor))
		return;
	while ((ap = rp1->addr) != 0)
	{
		assert(0 == *ap->addr);
#ifdef VMS
		*ap->addr = (int4)rtn->linkage_ptr;
#else
		*ap->addr = (UINTPTR_T)rtn;
#endif
		rp1->addr = ap->next;
		free(ap);
	}
	while (lbl_tab < lbl_top)
	{
		if (urx_getlab(lbl_tab->lab_name.addr, lbl_tab->lab_name.len, rp1, &lp0, &lp1))
		{
			while (0 != (ap = lp1->addr))	/* note the assignment! */
			{
				assert(0 == *ap->addr);
				*ap->addr =
					USHBIN_ONLY((INTPTR_T)&lbl_tab->lnr_adr)
					/* on non-shared binary resolve this address by adding the offset stored at lbl_tab address
					 * to the routine header, to arrive at the address at which the current line number entry is
					 * stored
					 */
					NON_USHBIN_ONLY((INTPTR_T)&lbl_tab->lab_ln_ptr);
				lp1->addr = ap->next;
				free(ap);
			}
			assert(0 == lp1->addr);
			if (lp0 == (urx_labref *)rp1)
				((urx_rtnref *)lp0)->lab = lp1->next;
			else
				lp0->next = lp1->next;
			free(lp1);
		}
		lbl_tab++;
	}
	if (0 == rp1->lab)
	{
		rp0->next = rp1->next;
		free(rp1);
	}
}
Exemplo 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, 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;
}
Exemplo n.º 3
0
/* Routine to eliminate the zlinked trigger code for a given trigger about to be deleted. Operations performed
 * differ depending on platform type (shared binary or not).
 */
void gtm_trigger_cleanup(gv_trigger_t *trigdsc)
{
	rtn_tabent	*rbot, *mid, *rtop;
	mident		*rtnname;
	rhdtyp		*rtnhdr;
	textElem	*telem;
	int		comp, size;
	stack_frame	*fp, *fpprev;
	mname_entry	key;
	ht_ent_mname    *tabent;
	routine_source	*src_tbl;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	/* First thing to do is release trigger source field if it exists */
	if (0 < trigdsc->xecute_str.str.len)
	{
		free(trigdsc->xecute_str.str.addr);
		trigdsc->xecute_str.str.len = 0;
		trigdsc->xecute_str.str.addr = NULL;
	}
	/* Next thing to do is find the routine header in the rtn_names list so we can remove it. */
	rtnname = &trigdsc->rtn_desc.rt_name;
	rtnhdr = trigdsc->rtn_desc.rt_adr;
	rbot = rtn_names;
	rtop = rtn_names_end;
	for (;;)
	{	/* See if routine exists in list via a binary search which reverts to serial
		   search when # of items drops below the threshold S_CUTOFF.
		*/
		if ((rtop - rbot) < S_CUTOFF)
		{
			comp = -1;
			for (mid = rbot; mid <= rtop ; mid++)
			{
				MIDENT_CMP(&mid->rt_name, rtnname, comp);
				if (0 == comp)
					break;
				if (0 < comp)
					GTMASSERT;	/* Routine should be found */
			}
			break;
		} else
		{	mid = rbot + (rtop - rbot)/2;
			MIDENT_CMP(&mid->rt_name, rtnname, comp);
			if (0 == comp)
				break;
			else if (0 > comp)
			{
				rbot = mid + 1;
				continue;
			} else
			{
				rtop = mid - 1;
				continue;
			}
		}
	}
#	ifdef DEBUG
	assert(rtnhdr == mid->rt_adr);
	/* Verify trigger routine we want to remove is not currently active. If it is, we need to GTMASSERT.
	 * Triggers are not like regular routines since they should only ever be referenced from the stack during a
	 * transaction. Likewise, we should only ever load the triggers as the first action in that transaction.
	 */
	for (fp = frame_pointer; fp ; fp = fpprev)
	{
		fpprev = fp->old_frame_pointer;
#		ifdef GTM_TRIGGER
		if (NULL != fpprev && SFT_TRIGR & fpprev->type)
			fpprev = *(stack_frame **)(fpprev + 1);
#		endif
		/* Only one possible version of a trigger routine */
		assert(USHBIN_ONLY(NULL) NON_USHBIN_ONLY(fp->rvector) == OLD_RHEAD_ADR(CURRENT_RHEAD_ADR(fp->rvector)));
		assert(fp->rvector != rtnhdr);
	}
#	endif
	/* Remove break points in this routine before rmv from rtntbl */
	zr_remove(rtnhdr, BREAKMSG);
	/* Release any $TEXT() info this trigger has loaded */
	if (NULL != (TREF(rt_name_tbl)).base)
	{
		key.var_name = mid->rt_name;
		COMPUTE_HASH_MNAME(&key);
		if (NULL != (tabent = lookup_hashtab_mname(TADR(rt_name_tbl), &key)))	/* note assignment */
		{	/* We have a hash entry. Whether it has a value or not, it has a key name (if this is
			 * the first time this trigger is being deleted) that may be pointing into the routine we
			 * are about to remove. Migrate this key name to the stringpool.
			 */
			s2pool(&tabent->key.var_name);
			if (NULL != tabent->value)
			{	/* Has value, release the source. Entries and source are malloc'd in two blocks on UNIX */
				src_tbl = (routine_source *)tabent->value;
				if (NULL != src_tbl->srcbuff)
					free(src_tbl->srcbuff);
				free(src_tbl);
				tabent->value = NULL;
			}
		}
	}
	/* Remove the routine from the rtn_table */
	size = INTCAST((char *)rtn_names_end - (char *)mid);
	if (0 < size)
		memmove((char *)mid, (char *)(mid + 1), size);	/* Remove this routine name from sorted table */
	rtn_names_end--;
	urx_remove(rtnhdr);					/* Remove any unresolved entries */
#	ifdef USHBIN_SUPPORTED
	stp_move((char *)rtnhdr->literal_text_adr,
		 (char *)(rtnhdr->literal_text_adr + rtnhdr->literal_text_len));
	GTM_TEXT_FREE(rtnhdr->ptext_adr);			/* R/O releasable section */
	free(rtnhdr->literal_adr);				/* R/W releasable section part 1 */
	free(rtnhdr->linkage_adr);				/* R/W releasable section part 2 */
	free(rtnhdr->labtab_adr);				/* Usually non-releasable but triggers don't have labels so
								 * this is just cleaning up a dangling null malloc
								 */
	free(rtnhdr);
#	else
#		if (!defined(__linux__) && !defined(__CYGWIN__)) || !defined(__i386) || !defined(COMP_GTA)
#			error Unsupported NON-USHBIN platform
#		endif
	/* For a non-shared binary platform we need to get an approximate addr range for stp_move. This is not
	 * done when a routine is replaced on these platforms but in this case we are able to due to the isolated
	 * environment if we only take the precautions of migrating potential literal text which may have been
	 * pointed to by any set environment variables.
	 * In this format, the only platform we support currently is Linux-x86 (i386) which uses GTM_TEXT_ALLOC
	 * to allocate special storage for it to put executable code in. We can access the storage header for
	 * this storage and find out how big it is and use that information to give stp_move a good range since
	 * the literal segment occurs right at the end of allocated storage (for which there is no pointer
	 * in the fileheader).
	 */
	telem = (textElem *)((char *)rtnhdr - offsetof(textElem, userStorage));
	assert(TextAllocated == telem->state);
	stp_move((char *)LNRTAB_ADR(rtnhdr) + (rtnhdr->lnrtab_len * SIZEOF(lnr_tabent)),
		 (char *)rtnhdr + telem->realLen);
	GTM_TEXT_FREE(rtnhdr);
#	endif
}