/* For routine name given, return routine header address if rhd not already set */ rhdtyp *op_rhdaddr(mval *name, rhdtyp *rhd) { mval routine; mident_fixed routname; rhdtyp *answer; if (NULL != rhd) answer = rhd; else { MV_FORCE_STR(name); routine = *name; routine.str.len = (MAX_MIDENT_LEN < routine.str.len ? MAX_MIDENT_LEN : routine.str.len); memcpy(&routname.c[0], routine.str.addr, routine.str.len); routine.str.addr = (char *)&routname.c[0]; if ((NULL == rtn_names) || (NULL == (answer = find_rtn_hdr(&routine.str)))) /* Note assignment */ { /* Initial check for rtn_names is so we avoid the call to find_rtn_hdr() if we have just * unlinked all modules as find_rtn_hdr() does not deal well with an empty rtn table. */ op_zlink(&routine, NULL); answer = find_rtn_hdr(&routine.str); if (NULL == answer) rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, name->str.len, name->str.addr, ERR_ZLMODULE, 2, strlen(&zlink_mname.c[0]), &zlink_mname); # if defined (__alpha) && defined (__vms) answer = answer->linkage_ptr; if (NULL == answer) rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, name->str.len, name->str.addr, ERR_ZLMODULE, 2, strlen(&zlink_mname.c[0]), zlink_mname.c); # endif } } return answer; }
void job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr) { rhdtyp *rt_hdr; int4 *lp; error_def (ERR_JOBLABOFF); if ((rt_hdr = find_rtn_hdr(rtn)) == 0) { mval rt; rt.mvtype = MV_STR; rt.str = *rtn; op_zlink(&rt,0); if ((rt_hdr = find_rtn_hdr (rtn)) == 0) GTMASSERT; } lp = NULL; if ((rt_hdr->compiler_qlf & CQ_LINE_ENTRY) || 0 == offset) { /* label offset with routine compiled with NOLINE_ENTRY should cause error */ lp = find_line_addr(rt_hdr, label, offset, NULL); } if (!lp) rts_error(VARLSTCNT(1) ERR_JOBLABOFF); *labaddr = (char *) LINE_NUMBER_ADDR(rt_hdr, lp); *hdr = (char *)rt_hdr; }
/* Routine to locate the entry being linked from generated code and link it in and return to the glue code * code to drive it. * * Arguments: * * rtnhdridx - Index into linkage table for the routine that needs linking. */ void auto_zlink(int rtnhdridx) { mstr rname; mident_fixed rname_buff; mval rtn; rhdtyp *rhd; assert(0 <= rtnhdridx); /* rtnhdridx must never be negative */ assert(rtnhdridx <= frame_pointer->rvector->linkage_len); assert(NULL == frame_pointer->rvector->linkage_adr[rtnhdridx].ext_ref); rname = frame_pointer->rvector->linkage_names[rtnhdridx]; rname.addr += (INTPTR_T)frame_pointer->rvector->literal_text_adr; /* Perform relocation on name */ memcpy(rname_buff.c, rname.addr, rname.len); memset(rname_buff.c + rname.len, 0, SIZEOF(rname_buff) - rname.len); /* Clear rest of mident_fixed */ rname.addr = rname_buff.c; assert(rname.len <= MAX_MIDENT_LEN); assert(NULL == find_rtn_hdr(&rname)); rtn.mvtype = MV_STR; rtn.str.len = rname.len; rtn.str.addr = rname.addr; op_zlink(&rtn, NULL); /* op_zlink() takes care of '%' -> '_' translation of routine name */ DEBUG_ONLY(if ('_' == rname_buff.c[0]) rname_buff.c[0] = '%'); assert(NULL != (rhd = find_rtn_hdr(&rname))); DBGARLNK((stderr, "auto_zlink: Linked in rtn %.*s to "lvaddr"\n", rname.len, rname.addr, find_rtn_hdr(&rname))); return; }
boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr, boolean_t *need_rtnobj_shm_free) { rhdtyp *rt_hdr; int4 *lp; mval rt; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (NULL == (rt_hdr = find_rtn_hdr(rtn))) { rt.mvtype = MV_STR; rt.str = *rtn; op_zlink(&rt, NULL); rt_hdr = find_rtn_hdr(rtn); if (NULL == rt_hdr) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, rtn->len, rtn->addr, ERR_ZLMODULE, 2, STRLEN(&zlink_mname.c[0]), &zlink_mname); *need_rtnobj_shm_free = ARLINK_ONLY(rt_hdr->shared_object) NON_ARLINK_ONLY(FALSE); *hdr = (char *)rt_hdr; } else *need_rtnobj_shm_free = FALSE; lp = NULL; if ((rt_hdr->compiler_qlf & CQ_LINE_ENTRY) || (0 == offset)) /* Label offset with routine compiled with NOLINE_ENTRY should cause error. */ lp = find_line_addr(rt_hdr, label, offset, NULL); if (!lp) return (FALSE); /* Set the pointer to address / offset for line number entry storage in TABENT_PROXY. */ # ifdef USHBIN_SUPPORTED ARLINK_ONLY((TABENT_PROXY).rtnhdr_adr = rt_hdr); (TABENT_PROXY).lnr_adr = lp; # else /* On non-shared-binary, calculcate the offset to the corresponding lnr_tabent record by subtracting * the base address (routine header) from line number entry's address, and save the result in * lab_ln_ptr field of TABENT_PROXY structure. */ (TABENT_PROXY).lab_ln_ptr = ((int4)lp - (int4)rt_hdr); # endif if (NULL != labaddr) *labaddr = (char *)LINE_NUMBER_ADDR(rt_hdr, lp); *hdr = (char *)rt_hdr; return (TRUE); }
void job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr) { rhdtyp *rt_hdr; int4 *lp; mval rt; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (NULL == (rt_hdr = find_rtn_hdr(rtn))) { rt.mvtype = MV_STR; rt.str = *rtn; op_zlink(&rt, NULL); assertpro(NULL != (rt_hdr = find_rtn_hdr(rtn))); } lp = NULL; if ((rt_hdr->compiler_qlf & CQ_LINE_ENTRY) || (0 == offset)) /* Label offset with routine compiled with NOLINE_ENTRY should cause error. */ lp = find_line_addr(rt_hdr, label, offset, NULL); if (!lp) rts_error(VARLSTCNT(1) ERR_JOBLABOFF); /* Set the pointer to address / offset for line number entry storage in lab_proxy. */ USHBIN_ONLY((TREF(lab_proxy)).lnr_adr = lp;)
void job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr) { rhdtyp *rt_hdr; int4 *lp; error_def (ERR_JOBLABOFF); if ((rt_hdr = find_rtn_hdr(rtn)) == 0) { mval rt; rt.mvtype = MV_STR; rt.str = *rtn; op_zlink(&rt,0); if ((rt_hdr = find_rtn_hdr (rtn)) == 0) GTMASSERT; } lp = NULL; if (!rt_hdr->label_only || 0 == offset) /* If label_only and offset != 0 should cause error */ lp = find_line_addr (rt_hdr, label, offset); if (!lp) rts_error(VARLSTCNT(1) ERR_JOBLABOFF); *labaddr = (char *) LINE_NUMBER_ADDR(rt_hdr, lp); *hdr = (char *)rt_hdr; }
void op_zprint(mval *rtn, mval *start_label, int start_int_exp, mval *end_label, int end_int_exp) /* contains label to be located or null string */ /* contains label offset or line number to reference */ /* contains routine to look in or null string */ /* NOTE: If only the first label is specified, the */ /* parser makes the second label the duplicate */ /* of the first. (not so vice versa) */ { mval print_line, null_str; mstr *src1, *src2; uint4 stat1, stat2; rhdtyp *rtn_vector; error_def(ERR_FILENOTFND); error_def(ERR_TXTSRCMAT); error_def(ERR_ZPRTLABNOTFND); error_def(ERR_ZLINKFILE); error_def(ERR_ZLMODULE); MV_FORCE_STR(start_label); MV_FORCE_STR(end_label); MV_FORCE_STR(rtn); if (NULL == (rtn_vector = find_rtn_hdr(&rtn->str))) { op_zlink(rtn, NULL); rtn_vector = find_rtn_hdr(&rtn->str); if (NULL == rtn_vector) rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, rtn->str.len, rtn->str.addr, ERR_ZLMODULE, 2, mid_len(&zlink_mname), &zlink_mname.c[0]); } stat1 = get_src_line(rtn, start_label, start_int_exp, &src1); if (stat1 & LABELNOTFOUND) rts_error(VARLSTCNT(1) ERR_ZPRTLABNOTFND); if (stat1 & SRCNOTFND) rts_error(VARLSTCNT(4) ERR_FILENOTFND, 2, rtn_vector->src_full_name.len, rtn_vector->src_full_name.addr); if (stat1 & (SRCNOTAVAIL | AFTERLASTLINE)) return; if (stat1 & (ZEROLINE | NEGATIVELINE)) { null_str.mvtype = MV_STR; null_str.str.len = 0; stat1 = get_src_line(rtn, &null_str, 1, &src1); if (stat1 & AFTERLASTLINE) /* the "null" file */ return; } if (end_int_exp == 0 && (end_label->str.len == 0 || *end_label->str.addr == 0)) stat2 = AFTERLASTLINE; else if ((stat2 = get_src_line(rtn, end_label, end_int_exp, &src2)) & LABELNOTFOUND) rts_error(VARLSTCNT(1) ERR_ZPRTLABNOTFND); if (stat2 & (ZEROLINE | NEGATIVELINE)) return; if (stat2 & AFTERLASTLINE) { null_str.mvtype = MV_STR; null_str.str.len = 0; stat2 = get_src_line(rtn, &null_str, 1, &src2); /* number of lines less one for duplicated zero'th line and one due to termination condition being <= */ assert((INTPTR_T)src2 > 0); src2 += rtn_vector->lnrtab_len - 2; } if (stat1 & CHECKSUMFAIL) { rts_error(VARLSTCNT(1) INFO_MSK(ERR_TXTSRCMAT)); op_wteol(1); } print_line.mvtype = MV_STR; for ( ; src1 <= src2 ; src1++) { if (outofband) outofband_action(FALSE); print_line.str.addr = src1->addr; print_line.str.len = src1->len; op_write(&print_line); op_wteol(1); } return; }
void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret) /* label contains label to be located or null string */ /* int_exp contains label offset or line number to reference */ /* ret is used to return the correct string to caller */ { char *cp, *ctop; int i, lbl, letter; mval *temp_rtn, temp_mval; mstr *sld; uint4 stat; rhdtyp *rtn_vector; error_def(ERR_TXTNEGLIN); error_def(ERR_TXTSRCMAT); error_def(ERR_ZLINKFILE); error_def(ERR_ZLMODULE); MV_FORCE_STR(label); MV_FORCE_STR(rtn); temp_rtn = &temp_mval; *temp_rtn = *rtn; /* make a copy of the routine in case the caller used the same mval for rtn and ret */ ret->str.len = 0; /* make ret an emptystring in case the return is by way of the condition handler */ ret->mvtype = MV_STR; sld = (mstr *)NULL; ESTABLISH(fntext_ch); /* to swallow errors and permit an emptystring result */ if ((int_exp == 0) && ((label->str.len == 0) || (*label->str.addr == 0))) stat = ZEROLINE; else stat = get_src_line(temp_rtn, label, int_exp, &sld); if ((FALSE == (stat & CHECKSUMFAIL)) && (FALSE == (stat & NEGATIVELINE))) { if (stat & ZEROLINE) { if (NULL == (rtn_vector = find_rtn_hdr(&temp_rtn->str))) { /* not here, so try to bring it in */ op_zlink(temp_rtn, 0); rtn_vector = find_rtn_hdr(&temp_rtn->str); } if (NULL != rtn_vector) { ret->str.addr = cp = (char *)&rtn_vector->routine_name; for (ctop = cp + sizeof(mident); *cp && cp < ctop; cp++) ; ret->str.len = cp - ret->str.addr; } } else if (NULL != sld) ret->str = *sld; } REVERT; /* If non-empty, copy result to stringpool and * convert any tabs in linestart to spaces */ if (ret->str.len) { if (stringpool.free + ret->str.len > stringpool.top) stp_gcol(ret->str.len); cp = stringpool.free; for (i = 0, lbl = 1; i < ret->str.len; i++) { letter = ret->str.addr[i]; if (lbl) { if ((' ' == letter) || ('\t' == letter)) { letter = ' '; lbl = 0; } *cp++ = letter; } else { if ((' ' != letter) && ('\t' != letter)) { memcpy(cp, &ret->str.addr[i], ret->str.len - i); break; } else *cp++ = ' '; } } ret->str.addr=stringpool.free; stringpool.free += ret->str.len; } return; }
rhdtyp *auto_zlink (unsigned char *pc, int4 **line) { char *adj_pc; /* address of PEA rtnref offset */ mstr rname; mident_fixed rname_local; urx_rtnref *rtnurx; mval rtn; rhdtyp *rhead; union { ModR_M modrm; unsigned char byte; } modrm_byte_byte, modrm_byte_long; /* ASSUMPTION -- The instruction previous to the current mpc is a transfer table jump. * This is either a byte or a int4 displacement off of ebx, instruction * size either 3 or 6 (prefix byte, ModR/M byte, 8- or 32-bit offset). */ modrm_byte_byte.modrm.reg_opcode = I386_INS_CALL_Ev; modrm_byte_byte.modrm.mod = I386_MOD32_BASE_DISP_8; modrm_byte_byte.modrm.r_m = I386_REG_EBX; modrm_byte_long.modrm.reg_opcode = I386_INS_CALL_Ev; modrm_byte_long.modrm.mod = I386_MOD32_BASE_DISP_32; modrm_byte_long.modrm.r_m = I386_REG_EBX; if ((*(pc - XFER_BYTE_SZ) == I386_INS_Grp5_Prefix) && (*(pc - XFER_BYTE_SZ + 1) == modrm_byte_byte.byte)) { assert(*(pc - XFER_BYTE_SZ - PEA_SZ) == I386_INS_PUSH_Iv); adj_pc = (char *)pc - XFER_BYTE_SZ - PEA_SZ; } else if ((*(pc - XFER_LONG_SZ) == I386_INS_Grp5_Prefix) && (*(pc - XFER_LONG_SZ + 1) == modrm_byte_long.byte)) { assert(*(pc - XFER_LONG_SZ - PEA_SZ) == I386_INS_PUSH_Iv); adj_pc = (char *)pc - XFER_LONG_SZ - PEA_SZ; } else GTMASSERT; if (azl_geturxrtn(adj_pc + INST_SZ, &rname, &rtnurx)) { assert((0 <= rname.len) && (MAX_MIDENT_LEN >= rname.len)); assert(rname.addr); /* Copy rname into local storage because azl_geturxrtn sets rname.addr to an address that is * freed during op_zlink and before the call to find_rtn_hdr. */ memcpy(rname_local.c, rname.addr, rname.len); rname.addr = rname_local.c; assert(rtnurx); assert(*(adj_pc - PEA_SZ) == I386_INS_PUSH_Iv); assert(azl_geturxlab(adj_pc - PEA_SZ + INST_SZ, rtnurx)); assert(!find_rtn_hdr(&rname)); rtn.mvtype = MV_STR; rtn.str.len = rname.len; rtn.str.addr = rname.addr; op_zlink (&rtn, 0); if (0 != (rhead = find_rtn_hdr(&rname))) /* note the assignment */ { *line = *(int4 **)(adj_pc - PEA_SZ + INST_SZ); if (!(*line)) rts_error(VARLSTCNT(1) ERR_LABELUNKNOWN); return rhead; } } rts_error(VARLSTCNT(1) ERR_ROUTINEUNKNOWN); return NULL; }
int gtm_trigger_complink(gv_trigger_t *trigdsc, boolean_t dolink) { char rtnname[GTM_PATH_MAX + 1], rtnname_template[GTM_PATH_MAX + 1]; char objname[GTM_PATH_MAX + 1]; char zcomp_parms[(GTM_PATH_MAX * 2) + SIZEOF(mident_fixed) + SIZEOF(OBJECT_PARM) + SIZEOF(NAMEOFRTN_PARM)]; mstr save_zsource; int rtnfd, rc, lenrtnname, lenobjname, len, alphnum_len, retry, save_errno; char *mident_suffix_p1, *mident_suffix_p2, *mident_suffix_top, *namesub1, *namesub2, *zcomp_parms_ptr; mval zlfile, zcompprm; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; DBGTRIGR_ONLY(memcpy(rtnname, trigdsc->rtn_desc.rt_name.addr, trigdsc->rtn_desc.rt_name.len)); DBGTRIGR_ONLY(rtnname[trigdsc->rtn_desc.rt_name.len] = 0); DBGTRIGR((stderr, "gtm_trigger_complink: (Re)compiling trigger %s\n", rtnname)); ESTABLISH_RET(gtm_trigger_complink_ch, ((0 == error_condition) ? TREF(dollar_zcstatus) : error_condition )); /* Verify there are 2 available chars for uniqueness */ assert((MAX_MIDENT_LEN - TRIGGER_NAME_RESERVED_SPACE) >= (trigdsc->rtn_desc.rt_name.len)); assert(NULL == trigdsc->rtn_desc.rt_adr); gtm_trigger_comp_prev_run_time = run_time; run_time = TRUE; /* Required by compiler */ /* Verify the routine name set by MUPIP TRIGGER and read by gvtr_db_read_hasht() is not in use */ if (NULL != find_rtn_hdr(&trigdsc->rtn_desc.rt_name)) { /* Ooops .. need name to be more unique.. */ /* Though variable definitions are conventionally done at the function entry, the reason alphanumeric_table * definition is done here is to minimize the time taken to initialize the below table in the most common case * (i.e. no trigger name collisions). */ char alphanumeric_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\0'}; alphnum_len = STR_LIT_LEN(alphanumeric_table); namesub1 = trigdsc->rtn_desc.rt_name.addr + trigdsc->rtn_desc.rt_name.len++; /* If WBTEST_HELPOUT_TRIGNAMEUNIQ is defined, set alphnum_len to 1. This way, we make the maximum * possible combinations for the uniqe trigger names to be 3 which is significantly lesser than * the actual number of combinations (62x62 = 3844). For eg., if ^a is a global having triggers defined * in 4 global directories, then the possible unique trigger names are a#1# ; a#1#A ; a#1#AA. */ GTM_WHITE_BOX_TEST(WBTEST_HELPOUT_TRIGNAMEUNIQ, alphnum_len, 1); mident_suffix_top = (char *)alphanumeric_table + alphnum_len; /* Phase 1. See if any single character can add uniqueness */ for (mident_suffix_p1 = (char *)alphanumeric_table; mident_suffix_p1 < mident_suffix_top; mident_suffix_p1++) { *namesub1 = *mident_suffix_p1; if (NULL == find_rtn_hdr(&trigdsc->rtn_desc.rt_name)) break; } if (mident_suffix_p1 == mident_suffix_top) { /* Phase 2. Phase 1 could not find uniqueness .. Find it with 2 char variations */ namesub2 = trigdsc->rtn_desc.rt_name.addr + trigdsc->rtn_desc.rt_name.len++; for (mident_suffix_p1 = (char *)alphanumeric_table; mident_suffix_p1 < mident_suffix_top; mident_suffix_p1++) { /* First char loop */ for (mident_suffix_p2 = (char *)alphanumeric_table; mident_suffix_p2 < mident_suffix_top; mident_suffix_p2++) { /* 2nd char loop */ *namesub1 = *mident_suffix_p1; *namesub2 = *mident_suffix_p2; if (NULL == find_rtn_hdr(&trigdsc->rtn_desc.rt_name)) { mident_suffix_p1 = mident_suffix_top + 1; /* Break out of both loops */ break; } } } if (mident_suffix_p1 == mident_suffix_top) { /* Phase 3: Punt */ assert(WBTEST_HELPOUT_TRIGNAMEUNIQ == gtm_white_box_test_case_number); rts_error(VARLSTCNT(5) ERR_TRIGNAMEUNIQ, 3, trigdsc->rtn_desc.rt_name.len - 2, trigdsc->rtn_desc.rt_name.addr, alphnum_len * alphnum_len); } } } /* Write trigger execute string out to temporary file and compile it */ assert(MAX_XECUTE_LEN >= trigdsc->xecute_str.str.len); rc = SNPRINTF(rtnname_template, GTM_PATH_MAX, "%s/trgtmpXXXXXX", DEFAULT_GTM_TMP); assert(0 < rc); /* Note rc is return code aka length - we expect a non-zero length */ assert(GTM_PATH_MAX >= rc); /* The mkstemp() routine is known to bogus-fail for no apparent reason at all especially on AIX 6.1. In the event * this shortcoming plagues other platforms as well, we add a low-cost retry wrapper. */ retry = MAX_MKSTEMP_RETRIES; do { strcpy(rtnname, rtnname_template); rtnfd = mkstemp(rtnname); } while ((-1 == rtnfd) && (EEXIST == errno) && (0 < --retry)); if (-1 == rtnfd) { save_errno = errno; assert(FALSE); rts_error(VARLSTCNT(12) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("mkstemp()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_TEXT(rtnname), save_errno); } assert(0 < rtnfd); /* Verify file descriptor */ rc = 0; # ifdef GEN_TRIGCOMPFAIL_ERROR { /* Used ONLY to generate an error in a trigger compile by adding some junk in a previous line */ DOWRITERC(rtnfd, ERROR_CAUSING_JUNK, strlen(ERROR_CAUSING_JUNK), rc); /* BYPASSOK */ if (0 != rc) { UNLINK(rtnname); rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("write()"), CALLFROM, rc); } } # endif DOWRITERC(rtnfd, trigdsc->xecute_str.str.addr, trigdsc->xecute_str.str.len, rc); if (0 != rc) { UNLINK(rtnname); rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("write()"), CALLFROM, rc); } if (NULL == memchr(trigdsc->xecute_str.str.addr, '\n', trigdsc->xecute_str.str.len)) { DOWRITERC(rtnfd, NEWLINE, strlen(NEWLINE), rc); /* BYPASSOK */ if (0 != rc) { UNLINK(rtnname); rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("write()"), CALLFROM, rc); } } CLOSEFILE(rtnfd, rc); if (0 != rc) { UNLINK(rtnname); rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, rc); } assert(MAX_MIDENT_LEN > trigdsc->rtn_desc.rt_name.len); zcomp_parms_ptr = zcomp_parms; lenrtnname = STRLEN(rtnname); MEMCPY_LIT(zcomp_parms_ptr, NAMEOFRTN_PARM); zcomp_parms_ptr += STRLEN(NAMEOFRTN_PARM); memcpy(zcomp_parms_ptr, trigdsc->rtn_desc.rt_name.addr, trigdsc->rtn_desc.rt_name.len); zcomp_parms_ptr += trigdsc->rtn_desc.rt_name.len; MEMCPY_LIT(zcomp_parms_ptr, OBJECT_PARM); zcomp_parms_ptr += STRLEN(OBJECT_PARM); strcpy(objname, rtnname); /* Make copy of rtnname to become object name */ strcat(objname, OBJECT_FTYPE); /* Turn into object file reference */ lenobjname = lenrtnname + STRLEN(OBJECT_FTYPE); memcpy(zcomp_parms_ptr, objname, lenobjname); zcomp_parms_ptr += lenobjname; *zcomp_parms_ptr++ = ' '; memcpy(zcomp_parms_ptr, rtnname, lenrtnname); zcomp_parms_ptr += lenrtnname; *zcomp_parms_ptr = '\0'; /* Null tail */ len = INTCAST(zcomp_parms_ptr - zcomp_parms); assert((SIZEOF(zcomp_parms) - 1) > len); /* Verify no overflow */ zcompprm.mvtype = MV_STR; zcompprm.str.addr = zcomp_parms; zcompprm.str.len = len; /* Backup dollar_zsource so trigger doesn't show */ PUSH_MV_STENT(MVST_MSAV); mv_chain->mv_st_cont.mvs_msav.v = dollar_zsource; mv_chain->mv_st_cont.mvs_msav.addr = &dollar_zsource; TREF(trigger_compile) = TRUE; /* Set flag so compiler knows this is a special trigger compile */ op_zcompile(&zcompprm, FALSE); /* Compile but don't require a .m file extension */ TREF(trigger_compile) = FALSE; /* compile_source_file() establishes handler so always returns */ if (0 != TREF(dollar_zcstatus)) { /* Someone err'd.. */ run_time = gtm_trigger_comp_prev_run_time; REVERT; UNLINK(objname); /* Remove files before return error */ UNLINK(rtnname); return ERR_TRIGCOMPFAIL; } if (dolink) { /* Link is optional as MUPIP TRIGGER doesn't need link */ zlfile.mvtype = MV_STR; zlfile.str.addr = objname; zlfile.str.len = lenobjname; /* Specifying literal_null for a second arg (as opposed to NULL or 0) allows us to specify * linking the object file (no compilation or looking for source). The 2nd arg is parms for * recompilation and is non-null in an explicit zlink which we need to emulate. */ # ifdef GEN_TRIGLINKFAIL_ERROR UNLINK(objname); /* delete object before it can be used */ # endif op_zlink(&zlfile, (mval *)&literal_null); /* need cast due to "extern const" attributes */ /* No return here if link fails for some reason */ trigdsc->rtn_desc.rt_adr = find_rtn_hdr(&trigdsc->rtn_desc.rt_name); if (NULL == trigdsc->rtn_desc.rt_adr) GTMASSERT; /* Can't find routine we just put there? Catastrophic if happens */ /* Replace the randomly generated source name with the constant "GTM Trigger" */ trigdsc->rtn_desc.rt_adr->src_full_name.addr = GTM_TRIGGER_SOURCE_NAME; trigdsc->rtn_desc.rt_adr->src_full_name.len = STRLEN(GTM_TRIGGER_SOURCE_NAME); trigdsc->rtn_desc.rt_adr->trigr_handle = trigdsc; /* Back pointer to trig def */ } if (MVST_MSAV == mv_chain->mv_st_type && &dollar_zsource == mv_chain->mv_st_cont.mvs_msav.addr) { /* Top mv_stent is one we pushed on there - restore dollar_zsource and get rid of it */ dollar_zsource = mv_chain->mv_st_cont.mvs_msav.v; POP_MV_STENT(); } else assert(FALSE); /* This mv_stent should be the one we just pushed */ /* Remove temporary files created */ UNLINK(objname); /* Delete the object file first since rtnname is the unique key */ UNLINK(rtnname); /* Delete the source file */ run_time = gtm_trigger_comp_prev_run_time; REVERT; return 0; }