1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 0 stevel * Common Development and Distribution License, Version 1.0 only 6 0 stevel * (the "License"). You may not use this file except in compliance 7 0 stevel * with the License. 8 0 stevel * 9 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 0 stevel * or http://www.opensolaris.org/os/licensing. 11 0 stevel * See the License for the specific language governing permissions 12 0 stevel * and limitations under the License. 13 0 stevel * 14 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 15 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 0 stevel * If applicable, add the following below this CDDL HEADER, with the 17 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 18 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 19 0 stevel * 20 0 stevel * CDDL HEADER END 21 0 stevel */ 22 0 stevel /* 23 0 stevel * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel #include <sys/sysmacros.h> 30 0 stevel 31 0 stevel #include <strings.h> 32 0 stevel #include <unistd.h> 33 0 stevel #include <stdarg.h> 34 0 stevel #include <stddef.h> 35 0 stevel #include <stdlib.h> 36 0 stevel #include <stdio.h> 37 0 stevel #include <errno.h> 38 0 stevel #include <ctype.h> 39 0 stevel #include <alloca.h> 40 0 stevel #include <assert.h> 41 0 stevel #include <libgen.h> 42 457 bmc #include <limits.h> 43 0 stevel 44 0 stevel #include <dt_impl.h> 45 0 stevel 46 0 stevel static const struct { 47 0 stevel size_t dtps_offset; 48 0 stevel size_t dtps_len; 49 0 stevel } dtrace_probespecs[] = { 50 0 stevel { offsetof(dtrace_probedesc_t, dtpd_provider), DTRACE_PROVNAMELEN }, 51 0 stevel { offsetof(dtrace_probedesc_t, dtpd_mod), DTRACE_MODNAMELEN }, 52 0 stevel { offsetof(dtrace_probedesc_t, dtpd_func), DTRACE_FUNCNAMELEN }, 53 0 stevel { offsetof(dtrace_probedesc_t, dtpd_name), DTRACE_NAMELEN } 54 0 stevel }; 55 0 stevel 56 0 stevel int 57 0 stevel dtrace_xstr2desc(dtrace_hdl_t *dtp, dtrace_probespec_t spec, 58 0 stevel const char *s, int argc, char *const argv[], dtrace_probedesc_t *pdp) 59 0 stevel { 60 0 stevel size_t off, len, vlen; 61 0 stevel const char *p, *q, *v; 62 0 stevel 63 0 stevel char buf[32]; /* for id_t as %d (see below) */ 64 0 stevel 65 0 stevel if (spec < DTRACE_PROBESPEC_NONE || spec > DTRACE_PROBESPEC_NAME) 66 0 stevel return (dt_set_errno(dtp, EINVAL)); 67 0 stevel 68 0 stevel bzero(pdp, sizeof (dtrace_probedesc_t)); 69 0 stevel p = s + strlen(s) - 1; 70 0 stevel 71 0 stevel do { 72 0 stevel for (len = 0; p >= s && *p != ':'; len++) 73 0 stevel p--; /* move backward until we find a delimiter */ 74 0 stevel 75 0 stevel q = p + 1; 76 0 stevel vlen = 0; 77 0 stevel 78 0 stevel if ((v = strchr(q, '$')) != NULL && v < q + len) { 79 0 stevel /* 80 0 stevel * Set vlen to the length of the variable name and then 81 0 stevel * reset len to the length of the text prior to '$'. If 82 0 stevel * the name begins with a digit, interpret it using the 83 0 stevel * the argv[] array. Otherwise we look in dt_macros. 84 0 stevel * For the moment, all dt_macros variables are of type 85 0 stevel * id_t (see dtrace_update() for more details on that). 86 0 stevel */ 87 0 stevel vlen = (size_t)(q + len - v); 88 0 stevel len = (size_t)(v - q); 89 0 stevel 90 0 stevel /* 91 0 stevel * If the variable string begins with $$, skip past the 92 0 stevel * leading dollar sign since $ and $$ are equivalent 93 0 stevel * macro reference operators in a probe description. 94 0 stevel */ 95 0 stevel if (vlen > 2 && v[1] == '$') { 96 0 stevel vlen--; 97 0 stevel v++; 98 0 stevel } 99 0 stevel 100 0 stevel if (isdigit(v[1])) { 101 0 stevel char *end; 102 0 stevel long i; 103 0 stevel 104 0 stevel errno = 0; 105 0 stevel i = strtol(v + 1, &end, 10); 106 0 stevel 107 0 stevel if (i < 0 || i >= argc || 108 0 stevel errno != 0 || end != v + vlen) 109 0 stevel return (dt_set_errno(dtp, EDT_BADSPCV)); 110 0 stevel 111 0 stevel v = argv[i]; 112 0 stevel vlen = strlen(v); 113 0 stevel 114 0 stevel if (yypcb != NULL && yypcb->pcb_sargv == argv) 115 0 stevel yypcb->pcb_sflagv[i] |= DT_IDFLG_REF; 116 0 stevel 117 0 stevel } else if (vlen > 1) { 118 0 stevel char *vstr = alloca(vlen); 119 0 stevel dt_ident_t *idp; 120 0 stevel 121 0 stevel (void) strncpy(vstr, v + 1, vlen - 1); 122 0 stevel vstr[vlen - 1] = '\0'; 123 0 stevel idp = dt_idhash_lookup(dtp->dt_macros, vstr); 124 0 stevel 125 0 stevel if (idp == NULL) 126 0 stevel return (dt_set_errno(dtp, EDT_BADSPCV)); 127 0 stevel 128 0 stevel v = buf; 129 0 stevel vlen = snprintf(buf, 32, "%d", idp->di_id); 130 0 stevel 131 0 stevel } else 132 0 stevel return (dt_set_errno(dtp, EDT_BADSPCV)); 133 0 stevel } 134 0 stevel 135 0 stevel if (spec == DTRACE_PROBESPEC_NONE) 136 0 stevel return (dt_set_errno(dtp, EDT_BADSPEC)); 137 0 stevel 138 0 stevel if (len + vlen >= dtrace_probespecs[spec].dtps_len) 139 0 stevel return (dt_set_errno(dtp, ENAMETOOLONG)); 140 0 stevel 141 0 stevel off = dtrace_probespecs[spec--].dtps_offset; 142 0 stevel bcopy(q, (char *)pdp + off, len); 143 0 stevel bcopy(v, (char *)pdp + off + len, vlen); 144 0 stevel 145 0 stevel } while (--p >= s); 146 0 stevel 147 0 stevel pdp->dtpd_id = DTRACE_IDNONE; 148 0 stevel return (0); 149 0 stevel } 150 0 stevel 151 0 stevel int 152 0 stevel dtrace_str2desc(dtrace_hdl_t *dtp, dtrace_probespec_t spec, 153 0 stevel const char *s, dtrace_probedesc_t *pdp) 154 0 stevel { 155 0 stevel return (dtrace_xstr2desc(dtp, spec, s, 0, NULL, pdp)); 156 0 stevel } 157 0 stevel 158 0 stevel int 159 0 stevel dtrace_id2desc(dtrace_hdl_t *dtp, dtrace_id_t id, dtrace_probedesc_t *pdp) 160 0 stevel { 161 0 stevel bzero(pdp, sizeof (dtrace_probedesc_t)); 162 0 stevel pdp->dtpd_id = id; 163 0 stevel 164 0 stevel if (dt_ioctl(dtp, DTRACEIOC_PROBES, pdp) == -1 || 165 0 stevel pdp->dtpd_id != id) 166 0 stevel return (dt_set_errno(dtp, EDT_BADID)); 167 0 stevel 168 0 stevel return (0); 169 0 stevel } 170 0 stevel 171 0 stevel char * 172 0 stevel dtrace_desc2str(const dtrace_probedesc_t *pdp, char *buf, size_t len) 173 0 stevel { 174 0 stevel if (pdp->dtpd_id == 0) { 175 0 stevel (void) snprintf(buf, len, "%s:%s:%s:%s", pdp->dtpd_provider, 176 0 stevel pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name); 177 0 stevel } else 178 0 stevel (void) snprintf(buf, len, "%u", pdp->dtpd_id); 179 0 stevel 180 0 stevel return (buf); 181 0 stevel } 182 0 stevel 183 0 stevel char * 184 0 stevel dtrace_attr2str(dtrace_attribute_t attr, char *buf, size_t len) 185 0 stevel { 186 0 stevel const char *name = dtrace_stability_name(attr.dtat_name); 187 0 stevel const char *data = dtrace_stability_name(attr.dtat_data); 188 0 stevel const char *class = dtrace_class_name(attr.dtat_class); 189 0 stevel 190 0 stevel if (name == NULL || data == NULL || class == NULL) 191 0 stevel return (NULL); /* one or more invalid attributes */ 192 0 stevel 193 0 stevel (void) snprintf(buf, len, "%s/%s/%s", name, data, class); 194 0 stevel return (buf); 195 0 stevel } 196 0 stevel 197 0 stevel static char * 198 0 stevel dt_getstrattr(char *p, char **qp) 199 0 stevel { 200 0 stevel char *q; 201 0 stevel 202 0 stevel if (*p == '\0') 203 0 stevel return (NULL); 204 0 stevel 205 0 stevel if ((q = strchr(p, '/')) == NULL) 206 0 stevel q = p + strlen(p); 207 0 stevel else 208 0 stevel *q++ = '\0'; 209 0 stevel 210 0 stevel *qp = q; 211 0 stevel return (p); 212 0 stevel } 213 0 stevel 214 0 stevel int 215 0 stevel dtrace_str2attr(const char *str, dtrace_attribute_t *attr) 216 0 stevel { 217 0 stevel dtrace_stability_t s; 218 0 stevel dtrace_class_t c; 219 0 stevel char *p, *q; 220 0 stevel 221 0 stevel if (str == NULL || attr == NULL) 222 0 stevel return (-1); /* invalid function arguments */ 223 0 stevel 224 0 stevel *attr = _dtrace_maxattr; 225 0 stevel p = alloca(strlen(str) + 1); 226 0 stevel (void) strcpy(p, str); 227 0 stevel 228 0 stevel if ((p = dt_getstrattr(p, &q)) == NULL) 229 0 stevel return (0); 230 0 stevel 231 0 stevel for (s = 0; s <= DTRACE_STABILITY_MAX; s++) { 232 0 stevel if (strcasecmp(p, dtrace_stability_name(s)) == 0) { 233 0 stevel attr->dtat_name = s; 234 0 stevel break; 235 0 stevel } 236 0 stevel } 237 0 stevel 238 0 stevel if (s > DTRACE_STABILITY_MAX) 239 0 stevel return (-1); 240 0 stevel 241 0 stevel if ((p = dt_getstrattr(q, &q)) == NULL) 242 0 stevel return (0); 243 0 stevel 244 0 stevel for (s = 0; s <= DTRACE_STABILITY_MAX; s++) { 245 0 stevel if (strcasecmp(p, dtrace_stability_name(s)) == 0) { 246 0 stevel attr->dtat_data = s; 247 0 stevel break; 248 0 stevel } 249 0 stevel } 250 0 stevel 251 0 stevel if (s > DTRACE_STABILITY_MAX) 252 0 stevel return (-1); 253 0 stevel 254 0 stevel if ((p = dt_getstrattr(q, &q)) == NULL) 255 0 stevel return (0); 256 0 stevel 257 0 stevel for (c = 0; c <= DTRACE_CLASS_MAX; c++) { 258 0 stevel if (strcasecmp(p, dtrace_class_name(c)) == 0) { 259 0 stevel attr->dtat_class = c; 260 0 stevel break; 261 0 stevel } 262 0 stevel } 263 0 stevel 264 0 stevel if (c > DTRACE_CLASS_MAX || (p = dt_getstrattr(q, &q)) != NULL) 265 0 stevel return (-1); 266 0 stevel 267 0 stevel return (0); 268 0 stevel } 269 0 stevel 270 0 stevel const char * 271 0 stevel dtrace_stability_name(dtrace_stability_t s) 272 0 stevel { 273 0 stevel switch (s) { 274 0 stevel case DTRACE_STABILITY_INTERNAL: return ("Internal"); 275 0 stevel case DTRACE_STABILITY_PRIVATE: return ("Private"); 276 0 stevel case DTRACE_STABILITY_OBSOLETE: return ("Obsolete"); 277 0 stevel case DTRACE_STABILITY_EXTERNAL: return ("External"); 278 0 stevel case DTRACE_STABILITY_UNSTABLE: return ("Unstable"); 279 0 stevel case DTRACE_STABILITY_EVOLVING: return ("Evolving"); 280 0 stevel case DTRACE_STABILITY_STABLE: return ("Stable"); 281 0 stevel case DTRACE_STABILITY_STANDARD: return ("Standard"); 282 0 stevel default: return (NULL); 283 0 stevel } 284 0 stevel } 285 0 stevel 286 0 stevel const char * 287 0 stevel dtrace_class_name(dtrace_class_t c) 288 0 stevel { 289 0 stevel switch (c) { 290 0 stevel case DTRACE_CLASS_UNKNOWN: return ("Unknown"); 291 0 stevel case DTRACE_CLASS_CPU: return ("CPU"); 292 0 stevel case DTRACE_CLASS_PLATFORM: return ("Platform"); 293 0 stevel case DTRACE_CLASS_GROUP: return ("Group"); 294 0 stevel case DTRACE_CLASS_ISA: return ("ISA"); 295 0 stevel case DTRACE_CLASS_COMMON: return ("Common"); 296 0 stevel default: return (NULL); 297 0 stevel } 298 0 stevel } 299 0 stevel 300 0 stevel dtrace_attribute_t 301 0 stevel dt_attr_min(dtrace_attribute_t a1, dtrace_attribute_t a2) 302 0 stevel { 303 0 stevel dtrace_attribute_t am; 304 0 stevel 305 0 stevel am.dtat_name = MIN(a1.dtat_name, a2.dtat_name); 306 0 stevel am.dtat_data = MIN(a1.dtat_data, a2.dtat_data); 307 0 stevel am.dtat_class = MIN(a1.dtat_class, a2.dtat_class); 308 0 stevel 309 0 stevel return (am); 310 0 stevel } 311 0 stevel 312 0 stevel dtrace_attribute_t 313 0 stevel dt_attr_max(dtrace_attribute_t a1, dtrace_attribute_t a2) 314 0 stevel { 315 0 stevel dtrace_attribute_t am; 316 0 stevel 317 0 stevel am.dtat_name = MAX(a1.dtat_name, a2.dtat_name); 318 0 stevel am.dtat_data = MAX(a1.dtat_data, a2.dtat_data); 319 0 stevel am.dtat_class = MAX(a1.dtat_class, a2.dtat_class); 320 0 stevel 321 0 stevel return (am); 322 0 stevel } 323 0 stevel 324 0 stevel /* 325 0 stevel * Compare two attributes and return an integer value in the following ranges: 326 0 stevel * 327 0 stevel * <0 if any of a1's attributes are less than a2's attributes 328 0 stevel * =0 if all of a1's attributes are equal to a2's attributes 329 0 stevel * >0 if all of a1's attributes are greater than or equal to a2's attributes 330 0 stevel * 331 0 stevel * To implement this function efficiently, we subtract a2's attributes from 332 0 stevel * a1's to obtain a negative result if an a1 attribute is less than its a2 333 0 stevel * counterpart. We then OR the intermediate results together, relying on the 334 0 stevel * twos-complement property that if any result is negative, the bitwise union 335 0 stevel * will also be negative since the highest bit will be set in the result. 336 0 stevel */ 337 0 stevel int 338 0 stevel dt_attr_cmp(dtrace_attribute_t a1, dtrace_attribute_t a2) 339 0 stevel { 340 0 stevel return (((int)a1.dtat_name - a2.dtat_name) | 341 0 stevel ((int)a1.dtat_data - a2.dtat_data) | 342 0 stevel ((int)a1.dtat_class - a2.dtat_class)); 343 0 stevel } 344 0 stevel 345 0 stevel char * 346 0 stevel dt_attr_str(dtrace_attribute_t a, char *buf, size_t len) 347 0 stevel { 348 0 stevel static const char stability[] = "ipoxuesS"; 349 0 stevel static const char class[] = "uCpgIc"; 350 0 stevel 351 0 stevel if (a.dtat_name < sizeof (stability) && 352 0 stevel a.dtat_data < sizeof (stability) && a.dtat_class < sizeof (class)) { 353 0 stevel (void) snprintf(buf, len, "[%c/%c/%c]", stability[a.dtat_name], 354 0 stevel stability[a.dtat_data], class[a.dtat_class]); 355 0 stevel } else { 356 0 stevel (void) snprintf(buf, len, "[%u/%u/%u]", 357 0 stevel a.dtat_name, a.dtat_data, a.dtat_class); 358 0 stevel } 359 0 stevel 360 0 stevel return (buf); 361 0 stevel } 362 0 stevel 363 0 stevel char * 364 0 stevel dt_version_num2str(dt_version_t v, char *buf, size_t len) 365 0 stevel { 366 0 stevel uint_t M = DT_VERSION_MAJOR(v); 367 0 stevel uint_t m = DT_VERSION_MINOR(v); 368 0 stevel uint_t u = DT_VERSION_MICRO(v); 369 0 stevel 370 0 stevel if (u == 0) 371 0 stevel (void) snprintf(buf, len, "%u.%u", M, m); 372 0 stevel else 373 0 stevel (void) snprintf(buf, len, "%u.%u.%u", M, m, u); 374 0 stevel 375 0 stevel return (buf); 376 0 stevel } 377 0 stevel 378 0 stevel int 379 0 stevel dt_version_str2num(const char *s, dt_version_t *vp) 380 0 stevel { 381 0 stevel int i = 0, n[3] = { 0, 0, 0 }; 382 0 stevel char c; 383 0 stevel 384 0 stevel while ((c = *s++) != '\0') { 385 0 stevel if (isdigit(c)) 386 0 stevel n[i] = n[i] * 10 + c - '0'; 387 0 stevel else if (c != '.' || i++ >= sizeof (n) / sizeof (n[0]) - 1) 388 0 stevel return (-1); 389 0 stevel } 390 0 stevel 391 0 stevel if (n[0] > DT_VERSION_MAJMAX || 392 0 stevel n[1] > DT_VERSION_MINMAX || 393 0 stevel n[2] > DT_VERSION_MICMAX) 394 0 stevel return (-1); 395 0 stevel 396 0 stevel if (vp != NULL) 397 0 stevel *vp = DT_VERSION_NUMBER(n[0], n[1], n[2]); 398 0 stevel 399 0 stevel return (0); 400 0 stevel } 401 0 stevel 402 0 stevel int 403 0 stevel dt_version_defined(dt_version_t v) 404 0 stevel { 405 0 stevel int i; 406 0 stevel 407 0 stevel for (i = 0; _dtrace_versions[i] != 0; i++) { 408 0 stevel if (_dtrace_versions[i] == v) 409 0 stevel return (1); 410 0 stevel } 411 0 stevel 412 0 stevel return (0); 413 0 stevel } 414 0 stevel 415 0 stevel char * 416 0 stevel dt_cpp_add_arg(dtrace_hdl_t *dtp, const char *str) 417 0 stevel { 418 0 stevel char *arg; 419 0 stevel 420 0 stevel if (dtp->dt_cpp_argc == dtp->dt_cpp_args) { 421 0 stevel int olds = dtp->dt_cpp_args; 422 0 stevel int news = olds * 2; 423 0 stevel char **argv = realloc(dtp->dt_cpp_argv, sizeof (char *) * news); 424 0 stevel 425 0 stevel if (argv == NULL) 426 0 stevel return (NULL); 427 0 stevel 428 0 stevel bzero(&argv[olds], sizeof (char *) * olds); 429 0 stevel dtp->dt_cpp_argv = argv; 430 0 stevel dtp->dt_cpp_args = news; 431 0 stevel } 432 0 stevel 433 0 stevel if ((arg = strdup(str)) == NULL) 434 0 stevel return (NULL); 435 0 stevel 436 0 stevel assert(dtp->dt_cpp_argc < dtp->dt_cpp_args); 437 0 stevel dtp->dt_cpp_argv[dtp->dt_cpp_argc++] = arg; 438 0 stevel return (arg); 439 0 stevel } 440 0 stevel 441 0 stevel char * 442 0 stevel dt_cpp_pop_arg(dtrace_hdl_t *dtp) 443 0 stevel { 444 0 stevel char *arg; 445 0 stevel 446 0 stevel if (dtp->dt_cpp_argc <= 1) 447 0 stevel return (NULL); /* dt_cpp_argv[0] cannot be popped */ 448 0 stevel 449 0 stevel arg = dtp->dt_cpp_argv[--dtp->dt_cpp_argc]; 450 0 stevel dtp->dt_cpp_argv[dtp->dt_cpp_argc] = NULL; 451 0 stevel 452 0 stevel return (arg); 453 0 stevel } 454 0 stevel 455 0 stevel /*PRINTFLIKE1*/ 456 0 stevel void 457 0 stevel dt_dprintf(const char *format, ...) 458 0 stevel { 459 0 stevel if (_dtrace_debug) { 460 0 stevel va_list alist; 461 0 stevel 462 0 stevel va_start(alist, format); 463 0 stevel (void) fputs("libdtrace DEBUG: ", stderr); 464 0 stevel (void) vfprintf(stderr, format, alist); 465 0 stevel va_end(alist); 466 0 stevel } 467 0 stevel } 468 0 stevel 469 0 stevel int 470 0 stevel dt_ioctl(dtrace_hdl_t *dtp, int val, void *arg) 471 0 stevel { 472 0 stevel const dtrace_vector_t *v = dtp->dt_vector; 473 0 stevel 474 0 stevel if (v != NULL) 475 0 stevel return (v->dtv_ioctl(dtp->dt_varg, val, arg)); 476 0 stevel 477 0 stevel if (dtp->dt_fd >= 0) 478 0 stevel return (ioctl(dtp->dt_fd, val, arg)); 479 0 stevel 480 0 stevel errno = EBADF; 481 0 stevel return (-1); 482 0 stevel } 483 0 stevel 484 0 stevel int 485 0 stevel dt_status(dtrace_hdl_t *dtp, processorid_t cpu) 486 0 stevel { 487 0 stevel const dtrace_vector_t *v = dtp->dt_vector; 488 0 stevel 489 0 stevel if (v == NULL) 490 0 stevel return (p_online(cpu, P_STATUS)); 491 0 stevel 492 0 stevel return (v->dtv_status(dtp->dt_varg, cpu)); 493 0 stevel } 494 0 stevel 495 0 stevel long 496 0 stevel dt_sysconf(dtrace_hdl_t *dtp, int name) 497 0 stevel { 498 0 stevel const dtrace_vector_t *v = dtp->dt_vector; 499 0 stevel 500 0 stevel if (v == NULL) 501 0 stevel return (sysconf(name)); 502 0 stevel 503 0 stevel return (v->dtv_sysconf(dtp->dt_varg, name)); 504 0 stevel } 505 0 stevel 506 0 stevel /* 507 0 stevel * Wrapper around write(2) to handle partial writes. For maximum safety of 508 0 stevel * output files and proper error reporting, we continuing writing in the 509 0 stevel * face of partial writes until write(2) fails or 'buf' is completely written. 510 0 stevel * We also record any errno in the specified dtrace_hdl_t as well as 'errno'. 511 0 stevel */ 512 0 stevel ssize_t 513 0 stevel dt_write(dtrace_hdl_t *dtp, int fd, const void *buf, size_t n) 514 0 stevel { 515 0 stevel ssize_t resid = n; 516 0 stevel ssize_t len; 517 0 stevel 518 0 stevel while (resid != 0) { 519 0 stevel if ((len = write(fd, buf, resid)) <= 0) 520 0 stevel break; 521 0 stevel 522 0 stevel resid -= len; 523 0 stevel buf = (char *)buf + len; 524 0 stevel } 525 0 stevel 526 0 stevel if (resid == n && n != 0) 527 0 stevel return (dt_set_errno(dtp, errno)); 528 0 stevel 529 0 stevel return (n - resid); 530 0 stevel } 531 0 stevel 532 0 stevel /* 533 0 stevel * This function handles all output from libdtrace, as well as the 534 0 stevel * dtrace_sprintf() case. If we're here due to dtrace_sprintf(), then 535 0 stevel * dt_sprintf_buflen will be non-zero; in this case, we sprintf into the 536 0 stevel * specified buffer and return. Otherwise, if output is buffered (denoted by 537 0 stevel * a NULL fp), we sprintf the desired output into the buffered buffer 538 0 stevel * (expanding the buffer if required). If we don't satisfy either of these 539 0 stevel * conditions (that is, if we are to actually generate output), then we call 540 0 stevel * fprintf with the specified fp. In this case, we need to deal with one of 541 0 stevel * the more annoying peculiarities of libc's printf routines: any failed 542 0 stevel * write persistently sets an error flag inside the FILE causing every 543 0 stevel * subsequent write to fail, but only the caller that initiated the error gets 544 0 stevel * the errno. Since libdtrace clients often intercept SIGINT, this case is 545 0 stevel * particularly frustrating since we don't want the EINTR on one attempt to 546 0 stevel * write to the output file to preclude later attempts to write. This 547 0 stevel * function therefore does a clearerr() if any error occurred, and saves the 548 0 stevel * errno for the caller inside the specified dtrace_hdl_t. 549 0 stevel */ 550 0 stevel /*PRINTFLIKE3*/ 551 0 stevel int 552 0 stevel dt_printf(dtrace_hdl_t *dtp, FILE *fp, const char *format, ...) 553 0 stevel { 554 0 stevel va_list ap; 555 0 stevel int n; 556 0 stevel 557 0 stevel va_start(ap, format); 558 0 stevel 559 0 stevel if (dtp->dt_sprintf_buflen != 0) { 560 0 stevel int len; 561 0 stevel char *buf; 562 0 stevel 563 0 stevel assert(dtp->dt_sprintf_buf != NULL); 564 0 stevel 565 0 stevel buf = &dtp->dt_sprintf_buf[len = strlen(dtp->dt_sprintf_buf)]; 566 0 stevel len = dtp->dt_sprintf_buflen - len; 567 0 stevel assert(len >= 0); 568 0 stevel 569 0 stevel if ((n = vsnprintf(buf, len, format, ap)) < 0) 570 0 stevel n = dt_set_errno(dtp, errno); 571 0 stevel 572 0 stevel va_end(ap); 573 0 stevel 574 0 stevel return (n); 575 0 stevel } 576 0 stevel 577 0 stevel if (fp == NULL) { 578 0 stevel int needed, rval; 579 0 stevel size_t avail; 580 0 stevel 581 0 stevel /* 582 0 stevel * It's not legal to use buffered ouput if there is not a 583 0 stevel * handler for buffered output. 584 0 stevel */ 585 0 stevel if (dtp->dt_bufhdlr == NULL) { 586 0 stevel va_end(ap); 587 0 stevel return (dt_set_errno(dtp, EDT_NOBUFFERED)); 588 0 stevel } 589 0 stevel 590 0 stevel if (dtp->dt_buffered_buf == NULL) { 591 0 stevel assert(dtp->dt_buffered_size == 0); 592 0 stevel dtp->dt_buffered_size = 1; 593 0 stevel dtp->dt_buffered_buf = malloc(dtp->dt_buffered_size); 594 0 stevel 595 0 stevel if (dtp->dt_buffered_buf == NULL) { 596 0 stevel va_end(ap); 597 0 stevel return (dt_set_errno(dtp, EDT_NOMEM)); 598 0 stevel } 599 0 stevel 600 0 stevel dtp->dt_buffered_offs = 0; 601 0 stevel dtp->dt_buffered_buf[0] = '\0'; 602 0 stevel } 603 0 stevel 604 0 stevel if ((needed = vsnprintf(NULL, 0, format, ap)) < 0) { 605 0 stevel rval = dt_set_errno(dtp, errno); 606 0 stevel va_end(ap); 607 0 stevel return (rval); 608 0 stevel } 609 0 stevel 610 0 stevel if (needed == 0) { 611 0 stevel va_end(ap); 612 0 stevel return (0); 613 0 stevel } 614 0 stevel 615 0 stevel for (;;) { 616 0 stevel char *newbuf; 617 0 stevel 618 0 stevel assert(dtp->dt_buffered_offs < dtp->dt_buffered_size); 619 0 stevel avail = dtp->dt_buffered_size - dtp->dt_buffered_offs; 620 0 stevel 621 0 stevel if (needed + 1 < avail) 622 0 stevel break; 623 0 stevel 624 0 stevel if ((newbuf = realloc(dtp->dt_buffered_buf, 625 0 stevel dtp->dt_buffered_size << 1)) == NULL) { 626 0 stevel va_end(ap); 627 0 stevel return (dt_set_errno(dtp, EDT_NOMEM)); 628 0 stevel } 629 0 stevel 630 0 stevel dtp->dt_buffered_buf = newbuf; 631 0 stevel dtp->dt_buffered_size <<= 1; 632 0 stevel } 633 0 stevel 634 0 stevel if (vsnprintf(&dtp->dt_buffered_buf[dtp->dt_buffered_offs], 635 0 stevel avail, format, ap) < 0) { 636 0 stevel rval = dt_set_errno(dtp, errno); 637 0 stevel va_end(ap); 638 0 stevel return (rval); 639 0 stevel } 640 0 stevel 641 0 stevel dtp->dt_buffered_offs += needed; 642 0 stevel assert(dtp->dt_buffered_buf[dtp->dt_buffered_offs] == '\0'); 643 0 stevel return (0); 644 0 stevel } 645 0 stevel 646 0 stevel n = vfprintf(fp, format, ap); 647 0 stevel va_end(ap); 648 0 stevel 649 0 stevel if (n < 0) { 650 0 stevel clearerr(fp); 651 0 stevel return (dt_set_errno(dtp, errno)); 652 0 stevel } 653 0 stevel 654 0 stevel return (n); 655 0 stevel } 656 0 stevel 657 0 stevel int 658 0 stevel dt_buffered_flush(dtrace_hdl_t *dtp, dtrace_probedata_t *pdata, 659 1017 bmc const dtrace_recdesc_t *rec, const dtrace_aggdata_t *agg, uint32_t flags) 660 0 stevel { 661 0 stevel dtrace_bufdata_t data; 662 0 stevel 663 0 stevel if (dtp->dt_buffered_offs == 0) 664 0 stevel return (0); 665 0 stevel 666 0 stevel data.dtbda_handle = dtp; 667 0 stevel data.dtbda_buffered = dtp->dt_buffered_buf; 668 0 stevel data.dtbda_probe = pdata; 669 0 stevel data.dtbda_recdesc = rec; 670 0 stevel data.dtbda_aggdata = agg; 671 1017 bmc data.dtbda_flags = flags; 672 0 stevel 673 0 stevel if ((*dtp->dt_bufhdlr)(&data, dtp->dt_bufarg) == DTRACE_HANDLE_ABORT) 674 0 stevel return (dt_set_errno(dtp, EDT_DIRABORT)); 675 0 stevel 676 0 stevel dtp->dt_buffered_offs = 0; 677 0 stevel dtp->dt_buffered_buf[0] = '\0'; 678 0 stevel 679 0 stevel return (0); 680 0 stevel } 681 0 stevel 682 0 stevel void 683 0 stevel dt_buffered_destroy(dtrace_hdl_t *dtp) 684 0 stevel { 685 0 stevel free(dtp->dt_buffered_buf); 686 0 stevel dtp->dt_buffered_buf = NULL; 687 0 stevel dtp->dt_buffered_offs = 0; 688 0 stevel dtp->dt_buffered_size = 0; 689 0 stevel } 690 0 stevel 691 0 stevel void * 692 0 stevel dt_zalloc(dtrace_hdl_t *dtp, size_t size) 693 0 stevel { 694 0 stevel void *data; 695 0 stevel 696 0 stevel if ((data = malloc(size)) == NULL) 697 0 stevel (void) dt_set_errno(dtp, EDT_NOMEM); 698 0 stevel else 699 0 stevel bzero(data, size); 700 0 stevel 701 0 stevel return (data); 702 0 stevel } 703 0 stevel 704 0 stevel void * 705 0 stevel dt_alloc(dtrace_hdl_t *dtp, size_t size) 706 0 stevel { 707 0 stevel void *data; 708 0 stevel 709 0 stevel if ((data = malloc(size)) == NULL) 710 0 stevel (void) dt_set_errno(dtp, EDT_NOMEM); 711 0 stevel 712 0 stevel return (data); 713 0 stevel } 714 0 stevel 715 0 stevel void 716 0 stevel dt_free(dtrace_hdl_t *dtp, void *data) 717 0 stevel { 718 0 stevel assert(dtp != NULL); /* ensure sane use of this interface */ 719 0 stevel free(data); 720 0 stevel } 721 0 stevel 722 265 mws void 723 265 mws dt_difo_free(dtrace_hdl_t *dtp, dtrace_difo_t *dp) 724 265 mws { 725 265 mws if (dp == NULL) 726 265 mws return; /* simplify caller code */ 727 265 mws 728 265 mws dt_free(dtp, dp->dtdo_buf); 729 265 mws dt_free(dtp, dp->dtdo_inttab); 730 265 mws dt_free(dtp, dp->dtdo_strtab); 731 265 mws dt_free(dtp, dp->dtdo_vartab); 732 265 mws dt_free(dtp, dp->dtdo_kreltab); 733 265 mws dt_free(dtp, dp->dtdo_ureltab); 734 265 mws dt_free(dtp, dp->dtdo_xlmtab); 735 265 mws 736 265 mws dt_free(dtp, dp); 737 265 mws } 738 265 mws 739 0 stevel /* 740 0 stevel * dt_gmatch() is similar to gmatch(3GEN) and dtrace(7D) globbing, but also 741 0 stevel * implements the behavior that an empty pattern matches any string. 742 0 stevel */ 743 0 stevel int 744 0 stevel dt_gmatch(const char *s, const char *p) 745 0 stevel { 746 0 stevel return (p == NULL || *p == '\0' || gmatch(s, p)); 747 0 stevel } 748 0 stevel 749 0 stevel char * 750 0 stevel dt_basename(char *str) 751 0 stevel { 752 0 stevel char *last = strrchr(str, '/'); 753 0 stevel 754 0 stevel if (last == NULL) 755 0 stevel return (str); 756 0 stevel 757 0 stevel return (last + 1); 758 265 mws } 759 265 mws 760 265 mws /* 761 265 mws * dt_popc() is a fast implementation of population count. The algorithm is 762 265 mws * from "Hacker's Delight" by Henry Warren, Jr with a 64-bit equivalent added. 763 265 mws */ 764 265 mws ulong_t 765 265 mws dt_popc(ulong_t x) 766 265 mws { 767 265 mws #ifdef _ILP32 768 265 mws x = x - ((x >> 1) & 0x55555555UL); 769 265 mws x = (x & 0x33333333UL) + ((x >> 2) & 0x33333333UL); 770 265 mws x = (x + (x >> 4)) & 0x0F0F0F0FUL; 771 265 mws x = x + (x >> 8); 772 265 mws x = x + (x >> 16); 773 265 mws return (x & 0x3F); 774 265 mws #endif 775 265 mws #ifdef _LP64 776 265 mws x = x - ((x >> 1) & 0x5555555555555555ULL); 777 265 mws x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); 778 265 mws x = (x + (x >> 4)) & 0x0F0F0F0F0F0F0F0FULL; 779 265 mws x = x + (x >> 8); 780 265 mws x = x + (x >> 16); 781 265 mws x = x + (x >> 32); 782 265 mws return (x & 0x7F); 783 265 mws #endif 784 265 mws } 785 265 mws 786 265 mws /* 787 265 mws * dt_popcb() is a bitmap-based version of population count that returns the 788 265 mws * number of one bits in the specified bitmap 'bp' at bit positions below 'n'. 789 265 mws */ 790 265 mws ulong_t 791 265 mws dt_popcb(const ulong_t *bp, ulong_t n) 792 265 mws { 793 265 mws ulong_t maxb = n & BT_ULMASK; 794 265 mws ulong_t maxw = n >> BT_ULSHIFT; 795 265 mws ulong_t w, popc = 0; 796 265 mws 797 265 mws if (n == 0) 798 265 mws return (0); 799 265 mws 800 265 mws for (w = 0; w < maxw; w++) 801 265 mws popc += dt_popc(bp[w]); 802 265 mws 803 265 mws return (popc + dt_popc(bp[maxw] & ((1UL << maxb) - 1))); 804 0 stevel } 805 0 stevel 806 0 stevel struct _rwlock; 807 0 stevel struct _lwp_mutex; 808 0 stevel 809 0 stevel int 810 0 stevel dt_rw_read_held(pthread_rwlock_t *lock) 811 0 stevel { 812 0 stevel extern int _rw_read_held(struct _rwlock *); 813 0 stevel return (_rw_read_held((struct _rwlock *)lock)); 814 0 stevel } 815 0 stevel 816 0 stevel int 817 0 stevel dt_rw_write_held(pthread_rwlock_t *lock) 818 0 stevel { 819 0 stevel extern int _rw_write_held(struct _rwlock *); 820 0 stevel return (_rw_write_held((struct _rwlock *)lock)); 821 0 stevel } 822 0 stevel 823 0 stevel int 824 0 stevel dt_mutex_held(pthread_mutex_t *lock) 825 0 stevel { 826 0 stevel extern int _mutex_held(struct _lwp_mutex *); 827 0 stevel return (_mutex_held((struct _lwp_mutex *)lock)); 828 0 stevel } 829 457 bmc 830 457 bmc static int 831 457 bmc dt_string2str(char *s, char *str, int nbytes) 832 457 bmc { 833 457 bmc int len = strlen(s); 834 457 bmc 835 457 bmc if (nbytes == 0) { 836 457 bmc /* 837 457 bmc * Like snprintf(3C), we don't check the value of str if the 838 457 bmc * number of bytes is 0. 839 457 bmc */ 840 457 bmc return (len); 841 457 bmc } 842 457 bmc 843 457 bmc if (nbytes <= len) { 844 457 bmc (void) strncpy(str, s, nbytes - 1); 845 457 bmc /* 846 457 bmc * Like snprintf(3C) (and unlike strncpy(3C)), we guarantee 847 457 bmc * that the string is null-terminated. 848 457 bmc */ 849 457 bmc str[nbytes - 1] = '\0'; 850 457 bmc } else { 851 457 bmc (void) strcpy(str, s); 852 457 bmc } 853 457 bmc 854 457 bmc return (len); 855 457 bmc } 856 457 bmc 857 457 bmc int 858 457 bmc dtrace_addr2str(dtrace_hdl_t *dtp, uint64_t addr, char *str, int nbytes) 859 457 bmc { 860 457 bmc dtrace_syminfo_t dts; 861 457 bmc GElf_Sym sym; 862 457 bmc 863 457 bmc size_t n = 20; /* for 0x%llx\0 */ 864 457 bmc char *s; 865 457 bmc int err; 866 457 bmc 867 457 bmc if ((err = dtrace_lookup_by_addr(dtp, addr, &sym, &dts)) == 0) 868 457 bmc n += strlen(dts.dts_object) + strlen(dts.dts_name) + 2; /* +` */ 869 457 bmc 870 457 bmc s = alloca(n); 871 457 bmc 872 457 bmc if (err == 0 && addr != sym.st_value) { 873 457 bmc (void) snprintf(s, n, "%s`%s+0x%llx", dts.dts_object, 874 457 bmc dts.dts_name, (u_longlong_t)addr - sym.st_value); 875 457 bmc } else if (err == 0) { 876 457 bmc (void) snprintf(s, n, "%s`%s", 877 457 bmc dts.dts_object, dts.dts_name); 878 457 bmc } else { 879 457 bmc /* 880 457 bmc * We'll repeat the lookup, but this time we'll specify a NULL 881 457 bmc * GElf_Sym -- indicating that we're only interested in the 882 457 bmc * containing module. 883 457 bmc */ 884 457 bmc if (dtrace_lookup_by_addr(dtp, addr, NULL, &dts) == 0) { 885 457 bmc (void) snprintf(s, n, "%s`0x%llx", dts.dts_object, 886 457 bmc (u_longlong_t)addr); 887 457 bmc } else { 888 457 bmc (void) snprintf(s, n, "0x%llx", (u_longlong_t)addr); 889 457 bmc } 890 457 bmc } 891 457 bmc 892 457 bmc return (dt_string2str(s, str, nbytes)); 893 457 bmc } 894 457 bmc 895 457 bmc int 896 457 bmc dtrace_uaddr2str(dtrace_hdl_t *dtp, pid_t pid, 897 457 bmc uint64_t addr, char *str, int nbytes) 898 457 bmc { 899 457 bmc char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2]; 900 457 bmc struct ps_prochandle *P = NULL; 901 457 bmc GElf_Sym sym; 902 457 bmc char *obj; 903 457 bmc 904 457 bmc if (pid != 0) 905 457 bmc P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 906 457 bmc 907 457 bmc if (P == NULL) { 908 457 bmc (void) snprintf(c, sizeof (c), "0x%llx", addr); 909 457 bmc return (dt_string2str(c, str, nbytes)); 910 457 bmc } 911 457 bmc 912 457 bmc dt_proc_lock(dtp, P); 913 457 bmc 914 457 bmc if (Plookup_by_addr(P, addr, name, sizeof (name), &sym) == 0) { 915 457 bmc (void) Pobjname(P, addr, objname, sizeof (objname)); 916 457 bmc 917 457 bmc obj = dt_basename(objname); 918 457 bmc 919 457 bmc if (addr > sym.st_value) { 920 457 bmc (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", obj, 921 457 bmc name, (u_longlong_t)(addr - sym.st_value)); 922 457 bmc } else { 923 457 bmc (void) snprintf(c, sizeof (c), "%s`%s", obj, name); 924 457 bmc } 925 457 bmc } else if (Pobjname(P, addr, objname, sizeof (objname)) != NULL) { 926 457 bmc (void) snprintf(c, sizeof (c), "%s`0x%llx", 927 457 bmc dt_basename(objname), addr); 928 457 bmc } else { 929 457 bmc (void) snprintf(c, sizeof (c), "0x%llx", addr); 930 457 bmc } 931 457 bmc 932 457 bmc dt_proc_unlock(dtp, P); 933 457 bmc dt_proc_release(dtp, P); 934 457 bmc 935 457 bmc return (dt_string2str(c, str, nbytes)); 936 457 bmc } 937