📄 dt_printf.c
字号:
return (dt_set_errno(dtp, EDT_DMISMATCH)); } return (pfprint_estr(dtp, fp, format, pfd, &c, 1, normal));}/*ARGSUSED*/static intpfprint_pct(dtrace_hdl_t *dtp, FILE *fp, const char *format, const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal){ return (dt_printf(dtp, fp, "%%"));}static const char pfproto_xint[] = "char, short, int, long, or long long";static const char pfproto_csi[] = "char, short, or int";static const char pfproto_fp[] = "float, double, or long double";static const char pfproto_addr[] = "pointer or integer";static const char pfproto_cstr[] = "char [] or string (or use stringof)";static const char pfproto_wstr[] = "wchar_t []";/* * Printf format conversion dictionary. This table should match the set of * conversions offered by printf(3C), as well as some additional extensions. * The second parameter is an ASCII string which is either an actual type * name we should look up (if pfcheck_type is specified), or just a descriptive * string of the types expected for use in error messages. */static const dt_pfconv_t _dtrace_conversions[] = {{ "a", "s", pfproto_addr, pfcheck_addr, pfprint_addr },{ "A", "s", pfproto_addr, pfcheck_addr, pfprint_uaddr },{ "c", "c", pfproto_csi, pfcheck_csi, pfprint_sint },{ "C", "s", pfproto_csi, pfcheck_csi, pfprint_echr },{ "d", "d", pfproto_xint, pfcheck_dint, pfprint_dint },{ "e", "e", pfproto_fp, pfcheck_fp, pfprint_fp },{ "E", "E", pfproto_fp, pfcheck_fp, pfprint_fp },{ "f", "f", pfproto_fp, pfcheck_fp, pfprint_fp },{ "g", "g", pfproto_fp, pfcheck_fp, pfprint_fp },{ "G", "G", pfproto_fp, pfcheck_fp, pfprint_fp },{ "hd", "d", "short", pfcheck_type, pfprint_sint },{ "hi", "i", "short", pfcheck_type, pfprint_sint },{ "ho", "o", "unsigned short", pfcheck_type, pfprint_uint },{ "hu", "u", "unsigned short", pfcheck_type, pfprint_uint },{ "hx", "x", "short", pfcheck_xshort, pfprint_uint },{ "hX", "X", "short", pfcheck_xshort, pfprint_uint },{ "i", "i", pfproto_xint, pfcheck_dint, pfprint_dint },{ "k", "s", "stack", pfcheck_type, pfprint_stack },{ "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */{ "ld", "d", "long", pfcheck_type, pfprint_sint },{ "li", "i", "long", pfcheck_type, pfprint_sint },{ "lo", "o", "unsigned long", pfcheck_type, pfprint_uint },{ "lu", "u", "unsigned long", pfcheck_type, pfprint_uint },{ "ls", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },{ "lx", "x", "long", pfcheck_xlong, pfprint_uint },{ "lX", "X", "long", pfcheck_xlong, pfprint_uint },{ "lld", "d", "long long", pfcheck_type, pfprint_sint },{ "lli", "i", "long long", pfcheck_type, pfprint_sint },{ "llo", "o", "unsigned long long", pfcheck_type, pfprint_uint },{ "llu", "u", "unsigned long long", pfcheck_type, pfprint_uint },{ "llx", "x", "long long", pfcheck_xlonglong, pfprint_uint },{ "llX", "X", "long long", pfcheck_xlonglong, pfprint_uint },{ "Le", "e", "long double", pfcheck_type, pfprint_fp },{ "LE", "E", "long double", pfcheck_type, pfprint_fp },{ "Lf", "f", "long double", pfcheck_type, pfprint_fp },{ "Lg", "g", "long double", pfcheck_type, pfprint_fp },{ "LG", "G", "long double", pfcheck_type, pfprint_fp },{ "o", "o", pfproto_xint, pfcheck_xint, pfprint_uint },{ "p", "x", pfproto_addr, pfcheck_addr, pfprint_uint },{ "s", "s", "char [] or string (or use stringof)", pfcheck_str, pfprint_cstr },{ "S", "s", pfproto_cstr, pfcheck_str, pfprint_estr },{ "T", "s", "uint64_t", pfcheck_type, pfprint_time822 },{ "u", "u", pfproto_xint, pfcheck_xint, pfprint_uint },{ "wc", "wc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */{ "ws", "ws", pfproto_wstr, pfcheck_wstr, pfprint_wstr },{ "x", "x", pfproto_xint, pfcheck_xint, pfprint_uint },{ "X", "X", pfproto_xint, pfcheck_xint, pfprint_uint },{ "Y", "s", "uint64_t", pfcheck_type, pfprint_time },{ "%", "%", "void", pfcheck_type, pfprint_pct },{ NULL, NULL, NULL, NULL, NULL }};intdt_pfdict_create(dtrace_hdl_t *dtp){ uint_t n = _dtrace_strbuckets; const dt_pfconv_t *pfd; dt_pfdict_t *pdi; if ((pdi = malloc(sizeof (dt_pfdict_t))) == NULL || (pdi->pdi_buckets = malloc(sizeof (dt_pfconv_t *) * n)) == NULL) { free(pdi); return (dt_set_errno(dtp, EDT_NOMEM)); } dtp->dt_pfdict = pdi; bzero(pdi->pdi_buckets, sizeof (dt_pfconv_t *) * n); pdi->pdi_nbuckets = n; for (pfd = _dtrace_conversions; pfd->pfc_name != NULL; pfd++) { dtrace_typeinfo_t dtt; dt_pfconv_t *pfc; uint_t h; if ((pfc = malloc(sizeof (dt_pfconv_t))) == NULL) { dt_pfdict_destroy(dtp); return (dt_set_errno(dtp, EDT_NOMEM)); } bcopy(pfd, pfc, sizeof (dt_pfconv_t)); h = dt_strtab_hash(pfc->pfc_name, NULL) % n; pfc->pfc_next = pdi->pdi_buckets[h]; pdi->pdi_buckets[h] = pfc; dtt.dtt_ctfp = NULL; dtt.dtt_type = CTF_ERR; /* * The "D" container or its parent must contain a definition of * any type referenced by a printf conversion. If none can be * found, we fail to initialize the printf dictionary. */ if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type( dtp, DTRACE_OBJ_DDEFS, pfc->pfc_tstr, &dtt) != 0) { dt_pfdict_destroy(dtp); return (dt_set_errno(dtp, EDT_NOCONV)); } pfc->pfc_dctfp = dtt.dtt_ctfp; pfc->pfc_dtype = dtt.dtt_type; /* * The "C" container may contain an alternate definition of an * explicit conversion type. If it does, use it; otherwise * just set pfc_ctype to pfc_dtype so it is always valid. */ if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type( dtp, DTRACE_OBJ_CDEFS, pfc->pfc_tstr, &dtt) == 0) { pfc->pfc_cctfp = dtt.dtt_ctfp; pfc->pfc_ctype = dtt.dtt_type; } else { pfc->pfc_cctfp = pfc->pfc_dctfp; pfc->pfc_ctype = pfc->pfc_dtype; } if (pfc->pfc_check == NULL || pfc->pfc_print == NULL || pfc->pfc_ofmt == NULL || pfc->pfc_tstr == NULL) { dt_pfdict_destroy(dtp); return (dt_set_errno(dtp, EDT_BADCONV)); } dt_dprintf("loaded printf conversion %%%s\n", pfc->pfc_name); } return (0);}voiddt_pfdict_destroy(dtrace_hdl_t *dtp){ dt_pfdict_t *pdi = dtp->dt_pfdict; dt_pfconv_t *pfc, *nfc; uint_t i; if (pdi == NULL) return; for (i = 0; i < pdi->pdi_nbuckets; i++) { for (pfc = pdi->pdi_buckets[i]; pfc != NULL; pfc = nfc) { nfc = pfc->pfc_next; free(pfc); } } free(pdi->pdi_buckets); free(pdi); dtp->dt_pfdict = NULL;}static const dt_pfconv_t *dt_pfdict_lookup(dtrace_hdl_t *dtp, const char *name){ dt_pfdict_t *pdi = dtp->dt_pfdict; uint_t h = dt_strtab_hash(name, NULL) % pdi->pdi_nbuckets; const dt_pfconv_t *pfc; for (pfc = pdi->pdi_buckets[h]; pfc != NULL; pfc = pfc->pfc_next) { if (strcmp(pfc->pfc_name, name) == 0) break; } return (pfc);}static dt_pfargv_t *dt_printf_error(dtrace_hdl_t *dtp, int err){ if (yypcb != NULL) longjmp(yypcb->pcb_jmpbuf, err); (void) dt_set_errno(dtp, err); return (NULL);}dt_pfargv_t *dt_printf_create(dtrace_hdl_t *dtp, const char *s){ dt_pfargd_t *pfd, *nfd = NULL; dt_pfargv_t *pfv; const char *p, *q; char *format; if ((pfv = malloc(sizeof (dt_pfargv_t))) == NULL || (format = strdup(s)) == NULL) { free(pfv); return (dt_printf_error(dtp, EDT_NOMEM)); } pfv->pfv_format = format; pfv->pfv_argv = NULL; pfv->pfv_argc = 0; pfv->pfv_flags = 0; for (q = format; (p = strchr(q, '%')) != NULL; q = *p ? p + 1 : p) { uint_t namelen = 0; int digits = 0; int dot = 0; char name[8]; char c; int n; if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) { dt_printf_destroy(pfv); return (dt_printf_error(dtp, EDT_NOMEM)); } if (pfv->pfv_argv != NULL) nfd->pfd_next = pfd; else pfv->pfv_argv = pfd; bzero(pfd, sizeof (dt_pfargd_t)); pfv->pfv_argc++; nfd = pfd; if (p > q) { pfd->pfd_preflen = (size_t)(p - q); pfd->pfd_prefix = q; } fmt_switch: switch (c = *++p) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (dot == 0 && digits == 0 && c == '0') { pfd->pfd_flags |= DT_PFCONV_ZPAD; pfd->pfd_flags &= ~DT_PFCONV_LEFT; goto fmt_switch; } for (n = 0; isdigit(c); c = *++p) n = n * 10 + c - '0'; if (dot) pfd->pfd_prec = n; else pfd->pfd_width = n; p--; digits++; goto fmt_switch; case '#': pfd->pfd_flags |= DT_PFCONV_ALT; goto fmt_switch; case '*': n = dot ? DT_PFCONV_DYNPREC : DT_PFCONV_DYNWIDTH; if (pfd->pfd_flags & n) { yywarn("format conversion #%u has more than " "one '*' specified for the output %s\n", pfv->pfv_argc, n ? "precision" : "width"); dt_printf_destroy(pfv); return (dt_printf_error(dtp, EDT_COMPILER)); } pfd->pfd_flags |= n; goto fmt_switch; case '+': pfd->pfd_flags |= DT_PFCONV_SPOS; goto fmt_switch; case '-': pfd->pfd_flags |= DT_PFCONV_LEFT; pfd->pfd_flags &= ~DT_PFCONV_ZPAD; goto fmt_switch; case '.': if (dot++ != 0) { yywarn("format conversion #%u has more than " "one '.' specified\n", pfv->pfv_argc); dt_printf_destroy(pfv); return (dt_printf_error(dtp, EDT_COMPILER)); } digits = 0; goto fmt_switch; case '?': if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) pfd->pfd_width = 16; else pfd->pfd_width = 8; goto fmt_switch; case '@': pfd->pfd_flags |= DT_PFCONV_AGG; goto fmt_switch; case '\'': pfd->pfd_flags |= DT_PFCONV_GROUP; goto fmt_switch; case ' ': pfd->pfd_flags |= DT_PFCONV_SPACE; goto fmt_switch; case '$': yywarn("format conversion #%u uses unsupported " "positional format (%%n$)\n", pfv->pfv_argc); dt_printf_destroy(pfv); return (dt_printf_error(dtp, EDT_COMPILER)); case '%': if (p[-1] == '%') goto default_lbl; /* if %% then use "%" conv */ yywarn("format conversion #%u cannot be combined " "with other format flags: %%%%\n", pfv->pfv_argc); dt_printf_destroy(pfv); return (dt_printf_error(dtp, EDT_COMPILER)); case '\0': yywarn("format conversion #%u name expected before " "end of format string\n", pfv->pfv_argc); dt_printf_destroy(pfv); return (dt_printf_error(dtp, EDT_COMPILER)); case 'h': case 'l': case 'L': case 'w': if (namelen < sizeof (name) - 2) name[namelen++] = c; goto fmt_switch; default_lbl: default: name[namelen++] = c; name[namelen] = '\0'; } if (strcmp(name, "A") == 0) { dt_ident_t *idp; idp = dt_idhash_lookup(dtp->dt_macros, "target"); if (idp == NULL || idp->di_id == 0) { yywarn("format conversion #%u only " "valid when target process is specified\n", pfv->pfv_argc); dt_printf_destroy(pfv); return (dt_printf_error(dtp, EDT_COMPILER)); } } pfd->pfd_conv = dt_pfdict_lookup(dtp, name); if (pfd->pfd_conv == NULL) { yywarn("format conversion #%u is undefined: %%%s\n", pfv->pfv_argc, name); dt_printf_destroy(pfv); return (dt_printf_error(dtp, EDT_COMPILER)); } } if (*q != '\0' || *format == '\0') { if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) { dt_printf_destroy(pfv); return (dt_printf_error(dtp, EDT_NOMEM)); } if (pfv->pfv_argv != NULL) nfd->pfd_next = pfd; else pfv->pfv_argv = pfd; bzero(pfd, sizeof (dt_pfargd_t)); pfv->pfv_argc++; pfd->pfd_prefix = q; pfd->pfd_preflen = strlen(q); } return (pfv);}voiddt_printf_destroy(dt_pfargv_t *pfv){ dt_pfargd_t *pfd, *nfd; for (pfd = pfv->pfv_argv; pfd != NULL; pfd = nfd) { nfd = pfd->pfd_next; free(pfd); } free(pfv->pfv_format); free(pfv);}voiddt_printf_validate(dt_pfargv_t *pfv, uint_t flags, dt_ident_t *idp, int foff, dtrace_actkind_t kind, dt_node_t *dnp){ dt_pfargd_t *pfd = pfv->pfv_argv; const char *func = idp->di_name; char n[DT_TYPE_NAMELEN]; dtrace_typeinfo_t dtt; const char *aggtype; dt_node_t aggnode; int i, j; if (pfv->pfv_format[0] == '\0') { xyerror(D_PRINTF_FMT_EMPTY, "%s( ) format string is empty\n", func); } /* * We fake up a parse node representing the type that can be used with * an aggregation result conversion. For now we hardcode the signed * aggregations; this will be fixed later when sign issues are fixed. */ if (kind == DTRACEAGG_QUANTIZE || kind == DTRACEAGG_LQUANTIZE) aggtype = "int64_t"; else aggtype = "uint64_t"; if (dt_type_lookup(aggtype, &dtt) != 0) xyerror(D_TYPE_ERR, "failed to lookup agg type %s\n", aggtype); bzero(&aggnode, sizeof (aggnode)); dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type); for (i = 0, j = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { const dt_pfconv_t *pfc = pfd->pfd_conv; const char *dyns[2]; int dync = 0; char vname[64]; dt_node_t *vnp; if (pfc == NULL) continue; /* no checking if argd is just a prefix */ if (pfc->pfc_print == &pfprint_pct) { (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt); continue; } if (pfd->pfd_flags & DT_PFCONV_DYNPREC) dyns[dync++] = ".*"; if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) dyns[dync++] = "*"; for (; dync != 0; dync--) { if (dnp == NULL) { xyerror(D_PRINTF_DYN_PROTO, "%s( ) prototype mismatch: conversion " "#%d (%%%s) is missing a corresponding " "\"%s\" argument\n", func, i + 1, pfc->pfc_name, dyns[dync - 1]); } if (dt_node_is_integer(dnp) == 0) { xyerror(D_PRINTF_DYN_TYPE, "%s( ) argument #%d is incompatible " "with conversion #%d prototype:\n" "\tconversion: %% %s %s\n" "\t prototype: int\n\t argument: %s\n", func, j + foff + 1, i + 1, dyns[dync - 1], pfc->pfc_name, dt_node_type_name(dnp, n, sizeof (n))); } dnp = dnp->dn_list; j++; } /* * If this conversion is consuming the aggregation data, set * the value node pointer (vnp) to a fake node based on the * aggregating function result type. Otherwise assign vnp to * the next parse node in the argument list, if there is one. */ if (pfd->pfd_flags & DT_PFCONV_AGG) { if (!(flags & DT_PRINTF_AGGREGATION)) { xyerror(D_PRINTF_AGG_CONV, "%%@ conversion requires an aggregation" " and is not for use with %s( )\n", func); } (void) strlcpy(vname, "aggregating action", sizeof (vname));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -