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); }
/* Routine to parse the value of $ZROUTINES and create the list of structures that define the (new) routine * search list order and define which (if any) directories can use auto-relink. * * Parameter: * str - string to parse (usually dollar_zroutines) * * Return code: * none */ void zro_load(mstr *str) { unsigned toktyp, status; boolean_t enable_autorelink; mstr tok, transtr; char *lp, *top; zro_ent array[ZRO_MAX_ENTS], *op; int oi, si, total_ents; struct stat outbuf; int stat_res; char tranbuf[MAX_FBUFF + 1]; parse_blk pblk; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ARLINK_ONLY(TREF(arlink_enabled) = FALSE); /* Set if any zro entry is enabled for autorelink */ memset(array, 0, SIZEOF(array)); lp = str->addr; top = lp + str->len; while ((lp < top) && (ZRO_DEL == *lp)) /* Bypass leading blanks */ lp++; array[0].type = ZRO_TYPE_COUNT; array[0].count = 0; memset(&pblk, 0, SIZEOF(pblk)); pblk.buffer = tranbuf; toktyp = GETTOK; if (ZRO_EOL == toktyp) { /* Null string - set default - implies current working directory only */ array[0].count = 1; array[1].type = ZRO_TYPE_OBJECT; array[1].str.len = 0; array[2].type = ZRO_TYPE_COUNT; array[2].count = 1; array[3].type = ZRO_TYPE_SOURCE; array[3].str.len = 0; si = 4; } else { /* String supplied - parse it */ for (oi = 1;;) { if (ZRO_IDN != toktyp) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FSEXP); if (ZRO_MAX_ENTS <= (oi + 1)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_MAXARGCNT, 1, ZRO_MAX_ENTS); /* We have type ZRO_IDN (an identifier/name of some sort). See if token has a "*" (ZRO_ALF) at the end * of it indicating that it is supposed to (1) be a directory and not a shared library and (2) that the * user desires this directory to have auto-relink capability. */ enable_autorelink = FALSE; /* All platforms allow the auto-relink indicator on object directories but only autorelink able platforms * (#ifdef AUTORELINK_SUPPORTED is set) do anything with it. Other platforms just ignore it. Specifying * "*" at end of non-object directories causes an error further downstream (FILEPARSE) when the "*" is * not stripped off the file name - unless someone has managed to create a directory with a "*" suffix. */ if (ZRO_ALF == *(tok.addr + tok.len - 1)) { /* Auto-relink is indicated */ enable_autorelink = TRUE; TREF(arlink_enabled) = TRUE; --tok.len; /* Remove indicator from name so we can use it */ assert(0 <= tok.len); } if (SIZEOF(tranbuf) <= tok.len) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr); /* Run specified directory through parse_file to fill in any missing pieces and get some info on it */ pblk.buff_size = MAX_FBUFF; /* Don't count null terminator here */ pblk.fnb = 0; status = parse_file(&tok, &pblk); if (!(status & 1)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr, status); tranbuf[pblk.b_esl] = 0; /* Needed for some subsequent STAT_FILE */ STAT_FILE(tranbuf, &outbuf, stat_res); if (-1 == stat_res) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr, errno); if (S_ISREG(outbuf.st_mode)) { /* Regular file - a shared library file */ if (enable_autorelink) /* Auto-relink indicator on shared library not permitted */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr); array[oi].shrlib = zro_shlibs_find(tranbuf); array[oi].type = ZRO_TYPE_OBJLIB; si = oi + 1; } else { if (!S_ISDIR(outbuf.st_mode)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_INVZROENT, 2, tok.len, tok.addr); array[oi].type = ZRO_TYPE_OBJECT; array[oi + 1].type = ZRO_TYPE_COUNT; si = oi + 2; # ifdef AUTORELINK_SUPPORTED # ifdef DEBUG /* If env var gtm_test_autorelink_always is set in dbg version, treat every * object directory specified in $zroutines as if * has been additionally specified. */ if (TREF(gtm_test_autorelink_always)) { enable_autorelink = TRUE; TREF(arlink_enabled) = TRUE; } # endif if (enable_autorelink) { /* Only setup autorelink struct if it is enabled */ if (!TREF(is_mu_rndwn_rlnkctl)) { transtr.addr = tranbuf; transtr.len = pblk.b_esl; array[oi].relinkctl_sgmaddr = (void_ptr_t)relinkctl_attach(&transtr, NULL, 0); } else { /* If zro_load() is called as a part of MUPIP RUNDOWN -RELINKCTL, then we do not * want to do relinkctl_attach() on all relinkctl files at once because we leave * the function holding the linkctl lock, which might potentially cause a deadlock * if multiple processes are run concurrently with different $gtmroutines. However, * we need a way to tell mu_rndwn_rlnkctl() which object directories are autorelink- * enabled. For that we set a negative number to the presently unused count field of * object directory entries in the zro_ent linked list. If we ever decide to make * that value meaningful, then, perhaps, ensuring that this count remains negative * in case of MUPIP RUNDOWN -RELINKCTL but has the correct absolute value would do * the trick. */ array[oi].count = ZRO_DIR_ENABLE_AR; } } # endif } array[0].count++; array[oi].str = tok; toktyp = GETTOK; if (ZRO_LBR == toktyp) { if (ZRO_TYPE_OBJLIB == array[oi].type) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_NOLBRSRC); toktyp = GETTOK; if (ZRO_DEL == toktyp) toktyp = GETTOK; if ((ZRO_IDN != toktyp) && (ZRO_RBR != toktyp)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_QUALEXP); array[oi + 1].count = 0; for (;;) { if (ZRO_RBR == toktyp) break; if (ZRO_IDN != toktyp) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FSEXP); if (ZRO_MAX_ENTS <= si) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_MAXARGCNT, 1, ZRO_MAX_ENTS); if (SIZEOF(tranbuf) <= tok.len) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr); pblk.buff_size = MAX_FBUFF; pblk.fnb = 0; status = parse_file(&tok, &pblk); if (!(status & 1)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr, status); tranbuf[pblk.b_esl] = 0; STAT_FILE(tranbuf, &outbuf, stat_res); if (-1 == stat_res) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr, errno); if (!S_ISDIR(outbuf.st_mode)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_DIRONLY, 2, tok.len, tok.addr); array[oi + 1].count++; array[si].type = ZRO_TYPE_SOURCE; array[si].str = tok; si++; toktyp = GETTOK; if (ZRO_DEL == toktyp) toktyp = GETTOK; } toktyp = GETTOK; } else { if ((ZRO_TYPE_OBJLIB != array[oi].type) && ((ZRO_DEL == toktyp) || (ZRO_EOL == toktyp))) { if (ZRO_MAX_ENTS <= si) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_MAXARGCNT, 1, ZRO_MAX_ENTS); array[oi + 1].count = 1; array[si] = array[oi]; array[si].type = ZRO_TYPE_SOURCE; si++; } } if (ZRO_EOL == toktyp) break; if (ZRO_DEL == toktyp) toktyp = GETTOK; else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZROSYNTAX, 2, str->len, str->addr); oi = si; } } total_ents = si; if (TREF(zro_root)) { assert((TREF(zro_root))->type == ZRO_TYPE_COUNT); oi = (TREF(zro_root))->count; assert(oi); for (op = TREF(zro_root) + 1; 0 < oi--;) { /* Release space held by translated entries */ assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type)); if (op->str.len) free(op->str.addr); if (ZRO_TYPE_OBJLIB == (op++)->type) continue; /* i.e. no sources for shared library */ assert(ZRO_TYPE_COUNT == op->type); si = (op++)->count; for (; si-- > 0; op++) { assert(ZRO_TYPE_SOURCE == op->type); if (op->str.len) free(op->str.addr); } } free(TREF(zro_root)); } TREF(zro_root) = (zro_ent *)malloc(total_ents * SIZEOF(zro_ent)); memcpy((uchar_ptr_t)TREF(zro_root), (uchar_ptr_t)array, total_ents * SIZEOF(zro_ent)); assert(ZRO_TYPE_COUNT == (TREF(zro_root))->type); oi = (TREF(zro_root))->count; assert(oi); for (op = TREF(zro_root) + 1; 0 < oi--;) { assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type)); if (op->str.len) { pblk.buff_size = MAX_FBUFF; pblk.fnb = 0; status = parse_file(&op->str, &pblk); if (!(status & 1)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, op->str.len, op->str.addr, status); op->str.addr = (char *)malloc(pblk.b_esl); op->str.len = pblk.b_esl; memcpy(op->str.addr, pblk.buffer, pblk.b_esl); } if (ZRO_TYPE_OBJLIB == (op++)->type) continue; assert(ZRO_TYPE_COUNT == op->type); si = (op++)->count; for (; 0 < si--; op++) { assert(ZRO_TYPE_SOURCE == op->type); if (op->str.len) { pblk.buff_size = MAX_FBUFF; pblk.fnb = 0; status = parse_file(&op->str, &pblk); if (!(status & 1)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, op->str.len, op->str.addr, status); op->str.addr = (char *)malloc(pblk.b_esl); op->str.len = pblk.b_esl; memcpy(op->str.addr, pblk.buffer, pblk.b_esl); } } } (TREF(set_zroutines_cycle))++; /* Signal need to recompute zroutines histories for each linked routine */ }
void op_zshow(mval *func, int type, lv_val *lvn) { const char *ptr; boolean_t do_all = FALSE, done_a = FALSE, done_b = FALSE, done_c = FALSE, done_d = FALSE, done_g = FALSE, done_i = FALSE, done_l = FALSE, done_r = FALSE, done_s = FALSE, done_v = FALSE; int i; zshow_out output; MAXSTR_BUFF_DECL(buff); MV_FORCE_STR(func); for (i = 0, ptr = func->str.addr; i < func->str.len; i++, ptr++) { switch (*ptr) { case 'A': case 'a': case 'B': case 'b': case 'C': case 'c': case 'D': case 'd': case 'G': case 'g': case 'I': case 'i': case 'L': case 'l': case 'R': case 'r': case 'S': case 's': case 'V': case 'v': continue; case '*': do_all = TRUE; break; default: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZSHOWBADFUNC); } } if (do_all) { ptr = ZSHOW_ALL; i = STR_LIT_LEN(ZSHOW_ALL); } else { ptr = func->str.addr; i = func->str.len; } memset(&output, 0, SIZEOF(output)); if (type == ZSHOW_LOCAL) output.out_var.lv.lvar = lvn; else if (type == ZSHOW_GLOBAL) { output.out_var.gv.end = gv_currkey->end; output.out_var.gv.prev = gv_currkey->prev; } MAXSTR_BUFF_INIT; output.type = type; output.buff = &buff[0]; output.size = SIZEOF(buff); output.ptr = output.buff; for ( ; i ; i--, ptr++) { output.line_num = 1; switch (*ptr) { case 'A': case 'a': if (done_a) break; done_a = TRUE; output.code = 'A'; ARLINK_ONLY(zshow_rctldump(&output)); break; case 'B': case 'b': if (done_b) break; done_b = TRUE; output.code = 'B'; zshow_zbreaks(&output); break; case 'C': case 'c': if (done_c) break; done_c = TRUE; output.code = 'C'; zshow_zcalls(&output); break; case 'D': case 'd': if (done_d) break; done_d = TRUE; output.code = 'D'; zshow_devices(&output); break; case 'G': case 'g': if (done_g) break; done_g = TRUE; output.code = 'G'; output.line_num = 0; /* G statistics start at 0 for <*,*> output and not 1 like the others */ zshow_gvstats(&output); break; case 'I': case 'i': if (done_i) break; done_i = TRUE; output.code = 'I'; zshow_svn(&output, SV_ALL); break; case 'L': case 'l': if (done_l) break; done_l = TRUE; output.code = 'L'; output.line_num = 0; /* L statistics start at 0 for <LUS,LUF> output and not 1 like the others */ zshow_locks(&output); break; case 'R': case 'r': if (done_r) break; done_r = TRUE; output.code = 'R'; zshow_stack(&output, TRUE); /* show_checksum = TRUE */ break; case 'S': case 's': if (done_s) break; done_s = TRUE; output.code = 'S'; zshow_stack(&output, FALSE); /* show_checksum = FALSE */ break; case 'V': case 'v': if (done_v) break; done_v = TRUE; output.code = 'V'; zshow_zwrite(&output); break; } } output.code = 0; output.flush = TRUE; zshow_output(&output,0); MAXSTR_BUFF_FINI; /* If ZSHOW was done onto a subscripted lvn but no zshow records got dumped in that lvn, it might have $data = 0. * Kill it in that case as otherwise it will create an out-of-design situation for $query(lvn). */ if ((type == ZSHOW_LOCAL) && (NULL != active_lv) && lcl_arg1_is_desc_of_arg2(active_lv, lvn)) UNDO_ACTIVE_LV(actlv_op_zshow); }