void release_private_code_copy(rhdtyp *rtn) { # ifdef USHBIN_SUPPORTED assert(NULL != rtn->shared_ptext_adr); assert(rtn->shared_ptext_adr != rtn->ptext_adr); DBGARLNK((stderr, "release_private_code_copy: Releasing private code copy at 0x"lvaddr" for rtnhdr 0x"lvaddr"\n", rtn->ptext_adr, rtn)); adjust_frames(rtn->ptext_adr, rtn->ptext_end_adr, rtn->shared_ptext_adr); GTM_TEXT_FREE(rtn->ptext_adr); do { /* Since more than one version of a module may exist at a given time, run the routine * header chain and check all versions - releasing the private copy if it exists. */ DBGARLNK((stderr, "release_private_code_copy: rtnhdr 0x"lvaddr" Previous values - ptext_adr: 0x"lvaddr " ptext_end_adr: 0x"lvaddr"\n", rtn, rtn->ptext_adr, rtn->ptext_end_adr)); rtn->ptext_end_adr = rtn->shared_ptext_adr + (rtn->ptext_end_adr - rtn->ptext_adr); rtn->ptext_adr = rtn->shared_ptext_adr; DBGARLNK((stderr, "release_private_code_copy: rtnhdr 0x"lvaddr" New values - ptext_adr: 0x"lvaddr " ptext_end_adr: 0x"lvaddr"\n", rtn, rtn->ptext_adr, rtn->ptext_end_adr)); /* Check for special case loop terminator. If this was a routine copy created when a routine in use was * recursively relinked, we do not want to follow its backchain and change those modules because this * routine copy is not part of that chain. The backpointer is only to find the original routine header * when this routine terminates. So if this routine is a recursive copy, stop the loop now. */ rtn = ((NULL != rtn->old_rhead_adr) && (rtn != rtn->old_rhead_adr->active_rhead_adr)) ? (rhdtyp *)rtn->old_rhead_adr : NULL; } while (NULL != rtn); DBGARLNK((stderr, "release_private_code_copy: Complete\n")); # endif return; }
void release_private_code_copy(rhdtyp *rtn) { #ifdef USHBIN_SUPPORTED assert(NULL != rtn->shlib_handle); assert(NULL != rtn->shared_ptext_adr); adjust_frames(rtn->ptext_adr, rtn->ptext_end_adr, rtn->shared_ptext_adr); GTM_TEXT_FREE(rtn->ptext_adr); rtn->ptext_end_adr = rtn->shared_ptext_adr + (rtn->ptext_end_adr - rtn->ptext_adr); rtn->ptext_adr = rtn->shared_ptext_adr; rtn->shared_ptext_adr = NULL; #endif return; }
void release_private_code_copy(rhdtyp *rtn) { # ifdef USHBIN_SUPPORTED assert(NULL != rtn->shared_ptext_adr); assert(rtn->shared_ptext_adr != rtn->ptext_adr); adjust_frames(rtn->ptext_adr, rtn->ptext_end_adr, rtn->shared_ptext_adr); GTM_TEXT_FREE(rtn->ptext_adr); do { /* Since more than one version of a module may exist at a given time, run the routine * header chain and check all versions - releasing the private copy if it exists. */ rtn->ptext_end_adr = rtn->shared_ptext_adr + (rtn->ptext_end_adr - rtn->ptext_adr); rtn->ptext_adr = rtn->shared_ptext_adr; rtn = (rhdtyp *)rtn->old_rhead_adr; } while (NULL != rtn); # endif return; }
/* 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 }