📄 dt_ident.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)dt_ident.c 1.8 04/11/13 SMI"#include <sys/sysmacros.h>#include <strings.h>#include <stdlib.h>#include <alloca.h>#include <assert.h>#include <errno.h>#include <ctype.h>#include <sys/procfs_isa.h>#include <limits.h>#include <dt_ident.h>#include <dt_parser.h>#include <dt_provider.h>#include <dt_strtab.h>#include <dt_impl.h>/* * 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 voiddt_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; char n1[DT_TYPE_NAMELEN]; char n2[DT_TYPE_NAMELEN]; if (isp->dis_varargs >= 0) { mismatch = argc < isp->dis_varargs; arglimit = isp->dis_varargs; } else { mismatch = argc != isp->dis_argc; arglimit = isp->dis_argc; } if (mismatch) { xyerror(D_PROTO_LEN, "%s%s%s prototype mismatch: %d arg%s" "passed, %d expected\n", prefix, idp->di_name, suffix, argc, argc == 1 ? " " : "s ", 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 argument #%d is incompatible with " "prototype:\n\tprototype: %s\n\t argument: %s\n", prefix, idp->di_name, suffix, i + 1, dt_node_type_name(&isp->dis_args[i], n1, sizeof (n1)), 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 voiddt_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_argc = argc; isp->dis_args = NULL; 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 ? "@" : "", "[ ]"); }}/* * Cook a function call. If this is the first time we are cooking this * identifier, create its type signature based on predefined prototype stored * in di_iarg. We then validate the argument list against this signature. */static voiddt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args){ if (idp->di_data == NULL) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dtrace_typeinfo_t dtt; dt_idsig_t *isp; char *s, *p1, *p2; int i = 0; assert(idp->di_iarg != NULL); s = alloca(strlen(idp->di_iarg) + 1); (void) strcpy(s, idp->di_iarg); if ((p2 = strrchr(s, ')')) != NULL) *p2 = '\0'; /* mark end of parameter list string */ if ((p1 = strchr(s, '(')) != NULL) *p1++ = '\0'; /* mark end of return type string */ if (p1 == NULL || p2 == NULL) { xyerror(D_UNKNOWN, "internal error: malformed entry " "for built-in function %s\n", idp->di_name); } for (p2 = p1; *p2 != '\0'; p2++) { if (!isspace(*p2)) { i++; break; } } for (p2 = strchr(p2, ','); p2++ != NULL; i++) p2 = strchr(p2, ','); /* * We first allocate a new ident signature structure with the * appropriate number of argument entries, and then look up * the return type and store its CTF data in di_ctfp/type. */ if ((isp = idp->di_data = malloc(sizeof (dt_idsig_t))) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); isp->dis_varargs = -1; isp->dis_argc = i; isp->dis_args = NULL; if (i != 0 && (isp->dis_args = calloc(i, sizeof (dt_node_t))) == NULL) { idp->di_data = NULL; free(isp); longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); } if (dt_type_lookup(s, &dtt) == -1) { xyerror(D_UNKNOWN, "failed to resolve type of %s (%s):" " %s\n", idp->di_name, s, dtrace_errmsg(dtp, dtrace_errno(dtp))); } if (idp->di_kind == DT_IDENT_AGGFUNC) { idp->di_ctfp = DT_DYN_CTFP(dtp); idp->di_type = DT_DYN_TYPE(dtp); } else { idp->di_ctfp = dtt.dtt_ctfp; idp->di_type = dtt.dtt_type; } /* * For each comma-delimited parameter in the prototype string, * we look up the corresponding type and store its CTF data in * the corresponding location in dis_args[]. We also recognize * the special type string "@" to indicate that the specified * parameter may be a D expression of *any* type (represented * as a dis_args[] element with ctfp = NULL, type == CTF_ERR). * If a varargs "..." is present, we record the argument index * in dis_varargs for the benefit of dt_idcook_sign(), above. */ for (i = 0; i < isp->dis_argc; i++, p1 = p2) { while (isspace(*p1)) p1++; /* skip leading whitespace */ if ((p2 = strchr(p1, ',')) == NULL) p2 = p1 + strlen(p1); else *p2++ = '\0'; if (strcmp(p1, "@") == 0 || strcmp(p1, "...") == 0) { isp->dis_args[i].dn_ctfp = NULL; isp->dis_args[i].dn_type = CTF_ERR; if (*p1 == '.') isp->dis_varargs = i; continue; } if (dt_type_lookup(p1, &dtt) == -1) { xyerror(D_UNKNOWN, "failed to resolve type of " "%s arg#%d (%s): %s\n", idp->di_name, i + 1, p1, dtrace_errmsg(dtp, dtrace_errno(dtp))); } dt_node_type_assign(&isp->dis_args[i], dtt.dtt_ctfp, dtt.dtt_type); } } dt_idcook_sign(dnp, idp, argc, args, "", "( )");}/* * Cook a reference to the dynamically typed args[] array. We verify that the * reference is using a single integer constant, and then return the type found * at the corresponding location in yypcb->pcb_pargv[]. */static voiddt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap){ char n[DT_TYPE_NAMELEN]; dt_ident_t *xidp; dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_arg_t *argp; 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, n, sizeof (n))); } if (yypcb->pcb_pdesc == NULL) { xyerror(D_ARGS_NONE, "%s[ ] may not be referenced outside " "of a probe clause\n", idp->di_name); } if (yypcb->pcb_pargs == NULL) { if (yypcb->pcb_nprobes > 1) { xyerror(D_ARGS_MULTI, "%s[ ] may not be referenced " "because probe description %s matches more than " "one probe\n", idp->di_name, dtrace_desc2str(yypcb->pcb_pdesc, n, sizeof (n))); } xyerror(D_ARGS_NONE, "no %s[ ] are available for probe %s\n", idp->di_name, dtrace_desc2str(yypcb->pcb_pdesc, n, sizeof (n))); } for (argp = yypcb->pcb_pargs; argp != NULL; argp = argp->da_next) { if (argp->da_ndx == ap->dn_value) break; } if (((ap->dn_flags & DT_NF_SIGNED) && (int64_t)ap->dn_value < 0) || argp == NULL) { xyerror(D_ARGS_IDX, "index %lld is out of range for probe %s " "%s[ ]\n", (longlong_t)ap->dn_value, dtrace_desc2str(yypcb->pcb_pdesc, n, sizeof (n)), idp->di_name); } if ((xidp = argp->da_xlator) != NULL) { /* * If we have an argument translator, we need to transform the * ident for the node based on the ident of the translator. * We perform just enough transformation such that the node * appears to be a translator when looked at as a translator, * but not so much that it doesn't look like an array when it * needs to be viewed as an array. */ idp->di_kind = xidp->di_kind; idp->di_data = xidp->di_data; idp->di_ctfp = xidp->di_ctfp; idp->di_type = xidp->di_type; dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp)); } else { idp->di_kind = DT_IDENT_ARRAY; idp->di_data = NULL; idp->di_ctfp = DT_DYN_CTFP(yypcb->pcb_hdl); idp->di_type = DT_DYN_TYPE(yypcb->pcb_hdl); dt_node_type_assign(dnp, argp->da_ctfp, argp->da_type); }}static voiddt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap){ dtrace_typeinfo_t dtt; dtrace_hdl_t *dtp = yypcb->pcb_hdl; char n[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, n, sizeof (n))); } if ((ap->dn_flags & DT_NF_SIGNED) && (int64_t)ap->dn_value < 0) { xyerror(D_REGS_IDX, "index %lld is out of range for array %s\n", (longlong_t)ap->dn_value, idp->di_name); } if (dt_type_lookup("uint64_t", &dtt) == -1) { xyerror(D_UNKNOWN, "failed to resolve type of %s: %s\n", idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp))); } idp->di_ctfp = dtt.dtt_ctfp; idp->di_type = dtt.dtt_type; dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);}/*ARGSUSED*/static voiddt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args){ if (idp->di_type == CTF_ERR) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dtrace_typeinfo_t dtt; if (dt_type_lookup(idp->di_iarg, &dtt) == -1) { xyerror(D_UNKNOWN, "failed to resolve type %s for identifier %s: %s\n", (const char *)idp->di_iarg, idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp))); } idp->di_ctfp = dtt.dtt_ctfp; idp->di_type = dtt.dtt_type; } dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);}/*ARGSUSED*/static voiddt_idcook_thaw(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args){ if (idp->di_ctfp != NULL && idp->di_type != CTF_ERR) dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);}/*ARGSUSED*/static dt_ident_t *dt_idctor_default(dt_node_t *dnp, int argc, dt_node_t *ap){ return (dnp->dn_ident);}static dt_ident_t *dt_idctor_args(dt_node_t *dnp, int argc, dt_node_t *ap){ dt_ident_t *idp = dnp->dn_ident; char n[DT_TYPE_NAMELEN], *name; int len; /* * The args[] array is special because two identifiers with different * indices will have different ident attributes. To support this, * we create an ident for each index. The di_data field of the "args" * ident in the hash points to a list of indexed idents; each of the * indexed args[] idents has DT_IDFLG_ARGNDX set in its di_flags field. */ if (idp->di_flags & DT_IDFLG_ARGNDX) return (idp); 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, n, sizeof (n))); } if (ap->dn_value > UCHAR_MAX) { xyerror(D_ARGS_IDX, "index %lld is out of range for probe %s " "%s[ ]\n", (longlong_t)ap->dn_value, dtrace_desc2str(yypcb->pcb_pdesc, n, sizeof (n)), idp->di_name); } len = strlen(idp->di_name) + 1; for (idp = idp->di_data; idp != NULL; idp = idp->di_next) { if (idp->di_name[len] == ap->dn_value) return (idp); } /* * We need to create a new ident using the existing one as a template. */ idp = dnp->dn_ident; if ((name = malloc(strlen(idp->di_name) + 2)) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); (void) strcpy(name, idp->di_name); name[len] = ap->dn_value; idp = dt_ident_create(NULL, idp->di_kind, idp->di_flags, idp->di_id, idp->di_attr, idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen); idp->di_next = dnp->dn_ident->di_data; dnp->dn_ident->di_data = idp; idp->di_flags |= DT_IDFLG_ARGNDX; idp->di_name = name; return (idp);}static voiddt_iddtor_sign(dt_ident_t *idp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -