/* * Common code for cooking an identifier that uses a typed signature list (we * use this for associative arrays and functions). If the argument list is * of the same length and types, then return the return type. Otherwise * print an appropriate compiler error message and abort the compile. */ static void dt_idcook_sign(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args, const char *prefix, const char *suffix) { dt_idsig_t *isp = idp->di_data; int i, compat, mismatch, arglimit, iskey; char n1[DT_TYPE_NAMELEN]; char n2[DT_TYPE_NAMELEN]; iskey = idp->di_kind == DT_IDENT_ARRAY || idp->di_kind == DT_IDENT_AGG; if (isp->dis_varargs >= 0) { mismatch = argc < isp->dis_varargs; arglimit = isp->dis_varargs; } else if (isp->dis_optargs >= 0) { mismatch = (argc < isp->dis_optargs || argc > isp->dis_argc); arglimit = argc; } else { mismatch = argc != isp->dis_argc; arglimit = isp->dis_argc; } if (mismatch) { xyerror(D_PROTO_LEN, "%s%s%s prototype mismatch: %d %s%s" "passed, %s%d expected\n", prefix, idp->di_name, suffix, argc, iskey ? "key" : "arg", argc == 1 ? " " : "s ", isp->dis_optargs >= 0 ? "at least " : "", isp->dis_optargs >= 0 ? isp->dis_optargs : arglimit); } for (i = 0; i < arglimit; i++, args = args->dn_list) { if (isp->dis_args[i].dn_ctfp != NULL) compat = dt_node_is_argcompat(&isp->dis_args[i], args); else compat = 1; /* "@" matches any type */ if (!compat) { xyerror(D_PROTO_ARG, "%s%s%s %s #%d is incompatible with " "prototype:\n\tprototype: %s\n\t%9s: %s\n", prefix, idp->di_name, suffix, iskey ? "key" : "argument", i + 1, dt_node_type_name(&isp->dis_args[i], n1, sizeof (n1)), iskey ? "key" : "argument", dt_node_type_name(args, n2, sizeof (n2))); } } dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); }
/* * Cook an associative array identifier. If this is the first time we are * cooking this array, create its signature based on the argument list. * Otherwise validate the argument list against the existing signature. */ static void dt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) { if (idp->di_data == NULL) { dt_idsig_t *isp = idp->di_data = malloc(sizeof (dt_idsig_t)); char n[DT_TYPE_NAMELEN]; int i; if (isp == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); isp->dis_varargs = -1; isp->dis_optargs = -1; isp->dis_argc = argc; isp->dis_args = NULL; isp->dis_auxinfo = 0; if (argc != 0 && (isp->dis_args = calloc(argc, sizeof (dt_node_t))) == NULL) { idp->di_data = NULL; free(isp); longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); } /* * If this identifier has not been explicitly declared earlier, * set the identifier's base type to be our special type <DYN>. * If this ident is an aggregation, it will remain as is. If * this ident is an associative array, it will be reassigned * based on the result type of the first assignment statement. */ if (!(idp->di_flags & DT_IDFLG_DECL)) { idp->di_ctfp = DT_DYN_CTFP(yypcb->pcb_hdl); idp->di_type = DT_DYN_TYPE(yypcb->pcb_hdl); } for (i = 0; i < argc; i++, args = args->dn_list) { if (dt_node_is_dynamic(args) || dt_node_is_void(args)) { xyerror(D_KEY_TYPE, "%s expression may not be " "used as %s index: key #%d\n", dt_node_type_name(args, n, sizeof (n)), dt_idkind_name(idp->di_kind), i + 1); } dt_node_type_propagate(args, &isp->dis_args[i]); isp->dis_args[i].dn_list = &isp->dis_args[i + 1]; } if (argc != 0) isp->dis_args[argc - 1].dn_list = NULL; dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); } else { dt_idcook_sign(dnp, idp, argc, args, idp->di_kind == DT_IDENT_AGG ? "@" : "", "[ ]"); } }
void dt_dis(const dtrace_difo_t *dp, FILE *fp) { static const struct opent { const char *op_name; void (*op_func)(const dtrace_difo_t *, const char *, dif_instr_t, FILE *); } optab[] = { { "(illegal opcode)", dt_dis_str }, { "or", dt_dis_log }, /* DIF_OP_OR */ { "xor", dt_dis_log }, /* DIF_OP_XOR */ { "and", dt_dis_log }, /* DIF_OP_AND */ { "sll", dt_dis_log }, /* DIF_OP_SLL */ { "srl", dt_dis_log }, /* DIF_OP_SRL */ { "sub", dt_dis_log }, /* DIF_OP_SUB */ { "add", dt_dis_log }, /* DIF_OP_ADD */ { "mul", dt_dis_log }, /* DIF_OP_MUL */ { "sdiv", dt_dis_log }, /* DIF_OP_SDIV */ { "udiv", dt_dis_log }, /* DIF_OP_UDIV */ { "srem", dt_dis_log }, /* DIF_OP_SREM */ { "urem", dt_dis_log }, /* DIF_OP_UREM */ { "not", dt_dis_r1rd }, /* DIF_OP_NOT */ { "mov", dt_dis_r1rd }, /* DIF_OP_MOV */ { "cmp", dt_dis_cmp }, /* DIF_OP_CMP */ { "tst", dt_dis_tst }, /* DIF_OP_TST */ { "ba", dt_dis_branch }, /* DIF_OP_BA */ { "be", dt_dis_branch }, /* DIF_OP_BE */ { "bne", dt_dis_branch }, /* DIF_OP_BNE */ { "bg", dt_dis_branch }, /* DIF_OP_BG */ { "bgu", dt_dis_branch }, /* DIF_OP_BGU */ { "bge", dt_dis_branch }, /* DIF_OP_BGE */ { "bgeu", dt_dis_branch }, /* DIF_OP_BGEU */ { "bl", dt_dis_branch }, /* DIF_OP_BL */ { "blu", dt_dis_branch }, /* DIF_OP_BLU */ { "ble", dt_dis_branch }, /* DIF_OP_BLE */ { "bleu", dt_dis_branch }, /* DIF_OP_BLEU */ { "ldsb", dt_dis_load }, /* DIF_OP_LDSB */ { "ldsh", dt_dis_load }, /* DIF_OP_LDSH */ { "ldsw", dt_dis_load }, /* DIF_OP_LDSW */ { "ldub", dt_dis_load }, /* DIF_OP_LDUB */ { "lduh", dt_dis_load }, /* DIF_OP_LDUH */ { "lduw", dt_dis_load }, /* DIF_OP_LDUW */ { "ldx", dt_dis_load }, /* DIF_OP_LDX */ { "ret", dt_dis_ret }, /* DIF_OP_RET */ { "nop", dt_dis_str }, /* DIF_OP_NOP */ { "setx", dt_dis_setx }, /* DIF_OP_SETX */ { "sets", dt_dis_sets }, /* DIF_OP_SETS */ { "scmp", dt_dis_cmp }, /* DIF_OP_SCMP */ { "ldga", dt_dis_lda }, /* DIF_OP_LDGA */ { "ldgs", dt_dis_ldv }, /* DIF_OP_LDGS */ { "stgs", dt_dis_stv }, /* DIF_OP_STGS */ { "ldta", dt_dis_lda }, /* DIF_OP_LDTA */ { "ldts", dt_dis_ldv }, /* DIF_OP_LDTS */ { "stts", dt_dis_stv }, /* DIF_OP_STTS */ { "sra", dt_dis_log }, /* DIF_OP_SRA */ { "call", dt_dis_call }, /* DIF_OP_CALL */ { "pushtr", dt_dis_pushts }, /* DIF_OP_PUSHTR */ { "pushtv", dt_dis_pushts }, /* DIF_OP_PUSHTV */ { "popts", dt_dis_str }, /* DIF_OP_POPTS */ { "flushts", dt_dis_str }, /* DIF_OP_FLUSHTS */ { "ldgaa", dt_dis_ldv }, /* DIF_OP_LDGAA */ { "ldtaa", dt_dis_ldv }, /* DIF_OP_LDTAA */ { "stgaa", dt_dis_stv }, /* DIF_OP_STGAA */ { "sttaa", dt_dis_stv }, /* DIF_OP_STTAA */ { "ldls", dt_dis_ldv }, /* DIF_OP_LDLS */ { "stls", dt_dis_stv }, /* DIF_OP_STLS */ { "allocs", dt_dis_r1rd }, /* DIF_OP_ALLOCS */ { "copys", dt_dis_log }, /* DIF_OP_COPYS */ { "stb", dt_dis_store }, /* DIF_OP_STB */ { "sth", dt_dis_store }, /* DIF_OP_STH */ { "stw", dt_dis_store }, /* DIF_OP_STW */ { "stx", dt_dis_store }, /* DIF_OP_STX */ { "uldsb", dt_dis_load }, /* DIF_OP_ULDSB */ { "uldsh", dt_dis_load }, /* DIF_OP_ULDSH */ { "uldsw", dt_dis_load }, /* DIF_OP_ULDSW */ { "uldub", dt_dis_load }, /* DIF_OP_ULDUB */ { "ulduh", dt_dis_load }, /* DIF_OP_ULDUH */ { "ulduw", dt_dis_load }, /* DIF_OP_ULDUW */ { "uldx", dt_dis_load }, /* DIF_OP_ULDX */ { "rldsb", dt_dis_load }, /* DIF_OP_RLDSB */ { "rldsh", dt_dis_load }, /* DIF_OP_RLDSH */ { "rldsw", dt_dis_load }, /* DIF_OP_RLDSW */ { "rldub", dt_dis_load }, /* DIF_OP_RLDUB */ { "rlduh", dt_dis_load }, /* DIF_OP_RLDUH */ { "rlduw", dt_dis_load }, /* DIF_OP_RLDUW */ { "rldx", dt_dis_load }, /* DIF_OP_RLDX */ { "xlate", dt_dis_xlate }, /* DIF_OP_XLATE */ { "xlarg", dt_dis_xlate }, /* DIF_OP_XLARG */ }; const struct opent *op; ulong_t i = 0; char type[DT_TYPE_NAMELEN]; (void) fprintf(fp, "\nDIFO 0x%p returns %s\n", (void *)dp, dt_dis_typestr(&dp->dtdo_rtype, type, sizeof (type))); (void) fprintf(fp, "%-3s %-8s %s\n", "OFF", "OPCODE", "INSTRUCTION"); for (i = 0; i < dp->dtdo_len; i++) { dif_instr_t instr = dp->dtdo_buf[i]; dif_instr_t opcode = DIF_INSTR_OP(instr); if (opcode >= sizeof (optab) / sizeof (optab[0])) opcode = 0; /* force invalid opcode message */ op = &optab[opcode]; (void) fprintf(fp, "%02lu: %08x ", i, instr); op->op_func(dp, op->op_name, instr, fp); (void) fprintf(fp, "\n"); } if (dp->dtdo_varlen != 0) { (void) fprintf(fp, "\n%-16s %-4s %-3s %-3s %-4s %s\n", "NAME", "ID", "KND", "SCP", "FLAG", "TYPE"); } for (i = 0; i < dp->dtdo_varlen; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i]; char kind[4], scope[4], flags[16] = { 0 }; switch (v->dtdv_kind) { case DIFV_KIND_ARRAY: (void) strcpy(kind, "arr"); break; case DIFV_KIND_SCALAR: (void) strcpy(kind, "scl"); break; default: (void) snprintf(kind, sizeof (kind), "%u", v->dtdv_kind); } switch (v->dtdv_scope) { case DIFV_SCOPE_GLOBAL: (void) strcpy(scope, "glb"); break; case DIFV_SCOPE_THREAD: (void) strcpy(scope, "tls"); break; case DIFV_SCOPE_LOCAL: (void) strcpy(scope, "loc"); break; default: (void) snprintf(scope, sizeof (scope), "%u", v->dtdv_scope); } if (v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)) { (void) snprintf(flags, sizeof (flags), "/0x%x", v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)); } if (v->dtdv_flags & DIFV_F_REF) (void) strcat(flags, "/r"); if (v->dtdv_flags & DIFV_F_MOD) (void) strcat(flags, "/w"); (void) fprintf(fp, "%-16s %-4x %-3s %-3s %-4s %s\n", &dp->dtdo_strtab[v->dtdv_name], v->dtdv_id, kind, scope, flags + 1, dt_dis_typestr(&v->dtdv_type, type, sizeof (type))); } if (dp->dtdo_xlmlen != 0) { (void) fprintf(fp, "\n%-4s %-3s %-12s %s\n", "XLID", "ARG", "MEMBER", "TYPE"); } for (i = 0; i < dp->dtdo_xlmlen; i++) { dt_node_t *dnp = dp->dtdo_xlmtab[i]; dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator; (void) fprintf(fp, "%-4u %-3d %-12s %s\n", (uint_t)dxp->dx_id, dxp->dx_arg, dnp->dn_membname, dt_node_type_name(dnp, type, sizeof (type))); } if (dp->dtdo_krelen != 0) dt_dis_rtab("KREL", dp, fp, dp->dtdo_kreltab, dp->dtdo_krelen); if (dp->dtdo_urelen != 0) dt_dis_rtab("UREL", dp, fp, dp->dtdo_ureltab, dp->dtdo_urelen); }
/* * Cook a reference to the dynamically typed args[] array. We verify that the * reference is using a single integer constant, and then construct a new ident * representing the appropriate type or translation specifically for this node. */ static void dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_probe_t *prp = yypcb->pcb_probe; dt_node_t tag, *nnp, *xnp; dt_xlator_t *dxp; dt_ident_t *xidp; char n1[DT_TYPE_NAMELEN]; char n2[DT_TYPE_NAMELEN]; if (argc != 1) { xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s" "passed, 1 expected\n", idp->di_name, argc, argc == 1 ? " " : "s "); } if (ap->dn_kind != DT_NODE_INT) { xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with " "prototype:\n\tprototype: %s\n\t argument: %s\n", idp->di_name, "integer constant", dt_type_name(ap->dn_ctfp, ap->dn_type, n1, sizeof (n1))); } if (yypcb->pcb_pdesc == NULL) { xyerror(D_ARGS_NONE, "%s[ ] may not be referenced outside " "of a probe clause\n", idp->di_name); } if (prp == NULL) { xyerror(D_ARGS_MULTI, "%s[ ] may not be referenced because probe description %s " "matches an unstable set of probes\n", idp->di_name, dtrace_desc2str(yypcb->pcb_pdesc, n1, sizeof (n1))); } if (ap->dn_value >= prp->pr_argc) { xyerror(D_ARGS_IDX, "index %lld is out of range for %s %s[ ]\n", (longlong_t)ap->dn_value, dtrace_desc2str(yypcb->pcb_pdesc, n1, sizeof (n1)), idp->di_name); } /* * Look up the native and translated argument types for the probe. * If no translation is needed, these will be the same underlying node. * If translation is needed, look up the appropriate translator. Once * we have the appropriate node, create a new dt_ident_t for this node, * assign it the appropriate attributes, and set the type of 'dnp'. */ xnp = prp->pr_xargv[ap->dn_value]; nnp = prp->pr_nargv[prp->pr_mapping[ap->dn_value]]; if (xnp->dn_type == CTF_ERR) { xyerror(D_ARGS_TYPE, "failed to resolve translated type for " "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value); } if (nnp->dn_type == CTF_ERR) { xyerror(D_ARGS_TYPE, "failed to resolve native type for " "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value); } if (dtp->dt_xlatemode == DT_XL_STATIC && ( nnp == xnp || dt_node_is_argcompat(nnp, xnp))) { dnp->dn_ident = dt_ident_create(idp->di_name, idp->di_kind, idp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr, idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen); if (dnp->dn_ident == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); dt_node_type_assign(dnp, prp->pr_argv[ap->dn_value].dtt_ctfp, prp->pr_argv[ap->dn_value].dtt_type); } else if ((dxp = dt_xlator_lookup(dtp, nnp, xnp, DT_XLATE_FUZZY)) != NULL || ( dxp = dt_xlator_lookup(dtp, dt_probe_tag(prp, ap->dn_value, &tag), xnp, DT_XLATE_EXACT | DT_XLATE_EXTERN)) != NULL) { xidp = dt_xlator_ident(dxp, xnp->dn_ctfp, xnp->dn_type); dnp->dn_ident = dt_ident_create(idp->di_name, xidp->di_kind, xidp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr, idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen); if (dnp->dn_ident == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); if (dt_xlator_dynamic(dxp)) dxp->dx_arg = (int)ap->dn_value; /* * Propagate relevant members from the translator's internal * dt_ident_t. This code must be kept in sync with the state * that is initialized for idents in dt_xlator_create(). */ dnp->dn_ident->di_data = xidp->di_data; dnp->dn_ident->di_ctfp = xidp->di_ctfp; dnp->dn_ident->di_type = xidp->di_type; dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp)); } else { xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s " "is not defined\n", idp->di_name, (longlong_t)ap->dn_value, dt_node_type_name(nnp, n1, sizeof (n1)), dt_node_type_name(xnp, n2, sizeof (n2))); } assert(dnp->dn_ident->di_flags & DT_IDFLG_ORPHAN); assert(dnp->dn_ident->di_id == idp->di_id); }