1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stddef.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include <errno.h> 32 #include <unistd.h> 33 #include <assert.h> 34 #ifdef illumos 35 #include <alloca.h> 36 #endif 37 38 #include <dt_impl.h> 39 #include <dt_oformat.h> 40 #include <dt_program.h> 41 42 static const char _dt_errprog[] = 43 "dtrace:::ERROR" 44 "{" 45 " trace(arg1);" 46 " trace(arg2);" 47 " trace(arg3);" 48 " trace(arg4);" 49 " trace(arg5);" 50 "}"; 51 52 int 53 dtrace_handle_err(dtrace_hdl_t *dtp, dtrace_handle_err_f *hdlr, void *arg) 54 { 55 dtrace_prog_t *pgp = NULL; 56 dt_stmt_t *stp; 57 dtrace_ecbdesc_t *edp; 58 59 /* 60 * We don't currently support multiple error handlers. 61 */ 62 if (dtp->dt_errhdlr != NULL) 63 return (dt_set_errno(dtp, EALREADY)); 64 65 /* 66 * If the DTRACEOPT_GRABANON is enabled, the anonymous enabling will 67 * already have a dtrace:::ERROR probe enabled; save 'hdlr' and 'arg' 68 * but do not bother compiling and enabling _dt_errprog. 69 */ 70 if (dtp->dt_options[DTRACEOPT_GRABANON] != DTRACEOPT_UNSET) 71 goto out; 72 73 if ((pgp = dtrace_program_strcompile(dtp, _dt_errprog, 74 DTRACE_PROBESPEC_NAME, DTRACE_C_ZDEFS, 0, NULL)) == NULL) 75 return (dt_set_errno(dtp, dtrace_errno(dtp))); 76 77 stp = dt_list_next(&pgp->dp_stmts); 78 assert(stp != NULL); 79 80 edp = stp->ds_desc->dtsd_ecbdesc; 81 assert(edp != NULL); 82 edp->dted_uarg = DT_ECB_ERROR; 83 84 out: 85 dtp->dt_errhdlr = hdlr; 86 dtp->dt_errarg = arg; 87 dtp->dt_errprog = pgp; 88 89 return (0); 90 } 91 92 int 93 dtrace_handle_drop(dtrace_hdl_t *dtp, dtrace_handle_drop_f *hdlr, void *arg) 94 { 95 if (dtp->dt_drophdlr != NULL) 96 return (dt_set_errno(dtp, EALREADY)); 97 98 dtp->dt_drophdlr = hdlr; 99 dtp->dt_droparg = arg; 100 101 return (0); 102 } 103 104 int 105 dtrace_handle_proc(dtrace_hdl_t *dtp, dtrace_handle_proc_f *hdlr, void *arg) 106 { 107 if (dtp->dt_prochdlr != NULL) 108 return (dt_set_errno(dtp, EALREADY)); 109 110 dtp->dt_prochdlr = hdlr; 111 dtp->dt_procarg = arg; 112 113 return (0); 114 } 115 116 int 117 dtrace_handle_buffered(dtrace_hdl_t *dtp, dtrace_handle_buffered_f *hdlr, 118 void *arg) 119 { 120 if (dtp->dt_bufhdlr != NULL) 121 return (dt_set_errno(dtp, EALREADY)); 122 123 if (hdlr == NULL) 124 return (dt_set_errno(dtp, EINVAL)); 125 126 dtp->dt_bufhdlr = hdlr; 127 dtp->dt_bufarg = arg; 128 129 return (0); 130 } 131 132 int 133 dtrace_handle_setopt(dtrace_hdl_t *dtp, dtrace_handle_setopt_f *hdlr, 134 void *arg) 135 { 136 if (hdlr == NULL) 137 return (dt_set_errno(dtp, EINVAL)); 138 139 dtp->dt_setopthdlr = hdlr; 140 dtp->dt_setoptarg = arg; 141 142 return (0); 143 } 144 145 #define DT_REC(type, ndx) *((type *)((uintptr_t)data->dtpda_data + \ 146 epd->dtepd_rec[(ndx)].dtrd_offset)) 147 148 static int 149 dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data) 150 { 151 dtrace_eprobedesc_t *epd = data->dtpda_edesc, *errepd; 152 dtrace_probedesc_t *pd = data->dtpda_pdesc, *errpd; 153 dtrace_errdata_t err; 154 dtrace_epid_t epid; 155 156 char where[30]; 157 char details[30]; 158 char offinfo[30]; 159 const int slop = 80; 160 const char *faultstr; 161 char *str; 162 int len; 163 164 assert(epd->dtepd_uarg == DT_ECB_ERROR); 165 166 if (epd->dtepd_nrecs != 5 || strcmp(pd->dtpd_provider, "dtrace") != 0 || 167 strcmp(pd->dtpd_name, "ERROR") != 0) 168 return (dt_set_errno(dtp, EDT_BADERROR)); 169 170 /* 171 * This is an error. We have the following items here: EPID, 172 * faulting action, DIF offset, fault code and faulting address. 173 */ 174 epid = (uint32_t)DT_REC(uint64_t, 0); 175 176 if (dt_epid_lookup(dtp, epid, &errepd, &errpd) != 0) 177 return (dt_set_errno(dtp, EDT_BADERROR)); 178 179 err.dteda_edesc = errepd; 180 err.dteda_pdesc = errpd; 181 err.dteda_cpu = data->dtpda_cpu; 182 err.dteda_action = (int)DT_REC(uint64_t, 1); 183 err.dteda_offset = (int)DT_REC(uint64_t, 2); 184 err.dteda_fault = (int)DT_REC(uint64_t, 3); 185 err.dteda_addr = DT_REC(uint64_t, 4); 186 187 faultstr = dtrace_faultstr(dtp, err.dteda_fault); 188 len = sizeof (where) + sizeof (offinfo) + strlen(faultstr) + 189 strlen(errpd->dtpd_provider) + strlen(errpd->dtpd_mod) + 190 strlen(errpd->dtpd_name) + strlen(errpd->dtpd_func) + 191 slop; 192 193 str = (char *)alloca(len); 194 195 if (err.dteda_action == 0) { 196 (void) sprintf(where, "predicate"); 197 } else { 198 (void) sprintf(where, "action #%d", err.dteda_action); 199 } 200 201 if (err.dteda_offset != -1) { 202 (void) sprintf(offinfo, " at DIF offset %d", err.dteda_offset); 203 } else { 204 offinfo[0] = 0; 205 } 206 207 switch (err.dteda_fault) { 208 case DTRACEFLT_BADADDR: 209 case DTRACEFLT_BADALIGN: 210 case DTRACEFLT_BADSTACK: 211 (void) sprintf(details, " (0x%llx)", 212 (u_longlong_t)err.dteda_addr); 213 break; 214 215 default: 216 details[0] = 0; 217 } 218 219 (void) snprintf(str, len, "error on enabled probe ID %u " 220 "(ID %u: %s:%s:%s:%s): %s%s in %s%s\n", 221 epid, errpd->dtpd_id, errpd->dtpd_provider, 222 errpd->dtpd_mod, errpd->dtpd_func, 223 errpd->dtpd_name, dtrace_faultstr(dtp, err.dteda_fault), 224 details, where, offinfo); 225 226 err.dteda_msg = str; 227 228 if (dtp->dt_errhdlr == NULL) 229 return (dt_set_errno(dtp, EDT_ERRABORT)); 230 231 if ((*dtp->dt_errhdlr)(&err, dtp->dt_errarg) == DTRACE_HANDLE_ABORT) 232 return (dt_set_errno(dtp, EDT_ERRABORT)); 233 234 return (0); 235 } 236 237 int 238 dt_handle_liberr(dtrace_hdl_t *dtp, const dtrace_probedata_t *data, 239 const char *faultstr) 240 { 241 dtrace_probedesc_t *errpd = data->dtpda_pdesc; 242 dtrace_errdata_t err; 243 const int slop = 80; 244 char *str; 245 int len; 246 247 err.dteda_edesc = data->dtpda_edesc; 248 err.dteda_pdesc = errpd; 249 err.dteda_cpu = data->dtpda_cpu; 250 err.dteda_action = -1; 251 err.dteda_offset = -1; 252 err.dteda_fault = DTRACEFLT_LIBRARY; 253 err.dteda_addr = 0; 254 255 len = strlen(faultstr) + 256 strlen(errpd->dtpd_provider) + strlen(errpd->dtpd_mod) + 257 strlen(errpd->dtpd_name) + strlen(errpd->dtpd_func) + 258 slop; 259 260 str = alloca(len); 261 262 (void) snprintf(str, len, "error on enabled probe ID %u " 263 "(ID %u: %s:%s:%s:%s): %s\n", 264 data->dtpda_edesc->dtepd_epid, 265 errpd->dtpd_id, errpd->dtpd_provider, 266 errpd->dtpd_mod, errpd->dtpd_func, 267 errpd->dtpd_name, faultstr); 268 269 err.dteda_msg = str; 270 271 if (dtp->dt_errhdlr == NULL) 272 return (dt_set_errno(dtp, EDT_ERRABORT)); 273 274 if ((*dtp->dt_errhdlr)(&err, dtp->dt_errarg) == DTRACE_HANDLE_ABORT) 275 return (dt_set_errno(dtp, EDT_ERRABORT)); 276 277 return (0); 278 } 279 280 #define DROPTAG(x) x, #x 281 282 static const struct { 283 dtrace_dropkind_t dtdrg_kind; 284 char *dtdrg_tag; 285 } _dt_droptags[] = { 286 { DROPTAG(DTRACEDROP_PRINCIPAL) }, 287 { DROPTAG(DTRACEDROP_AGGREGATION) }, 288 { DROPTAG(DTRACEDROP_DYNAMIC) }, 289 { DROPTAG(DTRACEDROP_DYNRINSE) }, 290 { DROPTAG(DTRACEDROP_DYNDIRTY) }, 291 { DROPTAG(DTRACEDROP_SPEC) }, 292 { DROPTAG(DTRACEDROP_SPECBUSY) }, 293 { DROPTAG(DTRACEDROP_SPECUNAVAIL) }, 294 { DROPTAG(DTRACEDROP_DBLERROR) }, 295 { DROPTAG(DTRACEDROP_STKSTROVERFLOW) }, 296 { 0, NULL } 297 }; 298 299 static const char * 300 dt_droptag(dtrace_dropkind_t kind) 301 { 302 int i; 303 304 for (i = 0; _dt_droptags[i].dtdrg_tag != NULL; i++) { 305 if (_dt_droptags[i].dtdrg_kind == kind) 306 return (_dt_droptags[i].dtdrg_tag); 307 } 308 309 return ("DTRACEDROP_UNKNOWN"); 310 } 311 312 int 313 dt_handle_cpudrop(dtrace_hdl_t *dtp, processorid_t cpu, 314 dtrace_dropkind_t what, uint64_t howmany) 315 { 316 dtrace_dropdata_t drop; 317 char str[80], *s; 318 int size; 319 struct timeval tv; 320 321 assert(what == DTRACEDROP_PRINCIPAL || what == DTRACEDROP_AGGREGATION); 322 323 bzero(&drop, sizeof (drop)); 324 drop.dtdda_handle = dtp; 325 drop.dtdda_cpu = cpu; 326 drop.dtdda_kind = what; 327 drop.dtdda_drops = howmany; 328 drop.dtdda_msg = str; 329 330 if (dtp->dt_droptags) { 331 (void) snprintf(str, sizeof (str), "[%s] ", dt_droptag(what)); 332 s = &str[strlen(str)]; 333 size = sizeof (str) - (s - str); 334 } else { 335 s = str; 336 size = sizeof (str); 337 } 338 339 (void) snprintf(s, size, "%llu %sdrop%s on CPU %d\n", 340 (u_longlong_t)howmany, 341 what == DTRACEDROP_PRINCIPAL ? "" : "aggregation ", 342 howmany > 1 ? "s" : "", cpu); 343 344 if (dtp->dt_oformat) { 345 (void) gettimeofday(&tv, NULL); 346 xo_emit("{:timestamp/%ld.%06ld} {:count/%ju} " 347 "{:total/%ju} {:kind/%d} {:msg/%s}", 348 tv.tv_sec, tv.tv_usec, (uintmax_t)drop.dtdda_drops, 349 (uintmax_t)drop.dtdda_total, drop.dtdda_kind, 350 drop.dtdda_msg); 351 } 352 353 if (dtp->dt_drophdlr == NULL) 354 return (dt_set_errno(dtp, EDT_DROPABORT)); 355 356 if ((*dtp->dt_drophdlr)(&drop, dtp->dt_droparg) == DTRACE_HANDLE_ABORT) 357 return (dt_set_errno(dtp, EDT_DROPABORT)); 358 359 return (0); 360 } 361 362 static const struct { 363 dtrace_dropkind_t dtdrt_kind; 364 uintptr_t dtdrt_offset; 365 const char *dtdrt_str; 366 const char *dtdrt_msg; 367 } _dt_droptab[] = { 368 { DTRACEDROP_DYNAMIC, 369 offsetof(dtrace_status_t, dtst_dyndrops), 370 "dynamic variable drop" }, 371 372 { DTRACEDROP_DYNRINSE, 373 offsetof(dtrace_status_t, dtst_dyndrops_rinsing), 374 "dynamic variable drop", " with non-empty rinsing list" }, 375 376 { DTRACEDROP_DYNDIRTY, 377 offsetof(dtrace_status_t, dtst_dyndrops_dirty), 378 "dynamic variable drop", " with non-empty dirty list" }, 379 380 { DTRACEDROP_SPEC, 381 offsetof(dtrace_status_t, dtst_specdrops), 382 "speculative drop" }, 383 384 { DTRACEDROP_SPECBUSY, 385 offsetof(dtrace_status_t, dtst_specdrops_busy), 386 "failed speculation", " (available buffer(s) still busy)" }, 387 388 { DTRACEDROP_SPECUNAVAIL, 389 offsetof(dtrace_status_t, dtst_specdrops_unavail), 390 "failed speculation", " (no speculative buffer available)" }, 391 392 { DTRACEDROP_STKSTROVERFLOW, 393 offsetof(dtrace_status_t, dtst_stkstroverflows), 394 "jstack()/ustack() string table overflow" }, 395 396 { DTRACEDROP_DBLERROR, 397 offsetof(dtrace_status_t, dtst_dblerrors), 398 "error", " in ERROR probe enabling" }, 399 400 { 0, 0, NULL } 401 }; 402 403 int 404 dt_handle_status(dtrace_hdl_t *dtp, dtrace_status_t *old, dtrace_status_t *new) 405 { 406 dtrace_dropdata_t drop; 407 char str[80], *s; 408 uintptr_t base = (uintptr_t)new, obase = (uintptr_t)old; 409 int i, size; 410 struct timeval tv; 411 412 bzero(&drop, sizeof (drop)); 413 drop.dtdda_handle = dtp; 414 drop.dtdda_cpu = DTRACE_CPUALL; 415 drop.dtdda_msg = str; 416 417 /* 418 * First, check to see if we've been killed -- in which case we abort. 419 */ 420 if (new->dtst_killed && !old->dtst_killed) 421 return (dt_set_errno(dtp, EDT_BRICKED)); 422 423 (void) gettimeofday(&tv, NULL); 424 425 for (i = 0; _dt_droptab[i].dtdrt_str != NULL; i++) { 426 uintptr_t naddr = base + _dt_droptab[i].dtdrt_offset; 427 uintptr_t oaddr = obase + _dt_droptab[i].dtdrt_offset; 428 429 uint64_t nval = *((uint64_t *)naddr); 430 uint64_t oval = *((uint64_t *)oaddr); 431 432 if (nval == oval) 433 continue; 434 435 if (dtp->dt_droptags) { 436 (void) snprintf(str, sizeof (str), "[%s] ", 437 dt_droptag(_dt_droptab[i].dtdrt_kind)); 438 s = &str[strlen(str)]; 439 size = sizeof (str) - (s - str); 440 } else { 441 s = str; 442 size = sizeof (str); 443 } 444 445 (void) snprintf(s, size, "%llu %s%s%s\n", 446 (u_longlong_t)(nval - oval), 447 _dt_droptab[i].dtdrt_str, (nval - oval > 1) ? "s" : "", 448 _dt_droptab[i].dtdrt_msg != NULL ? 449 _dt_droptab[i].dtdrt_msg : ""); 450 451 drop.dtdda_kind = _dt_droptab[i].dtdrt_kind; 452 drop.dtdda_total = nval; 453 drop.dtdda_drops = nval - oval; 454 455 if (dtp->dt_oformat) { 456 xo_open_instance("probes"); 457 dt_oformat_drop(dtp, DTRACE_CPUALL); 458 xo_emit("{:timestamp/%ld.%06ld} {:count/%ju} " 459 "{:total/%ju} {:kind/%d} {:msg/%s}", 460 tv.tv_sec, tv.tv_usec, (uintmax_t)drop.dtdda_drops, 461 (uintmax_t)drop.dtdda_total, drop.dtdda_kind, 462 drop.dtdda_msg); 463 } 464 465 if (dtp->dt_drophdlr == NULL) { 466 if (dtp->dt_oformat) 467 xo_close_instance("probes"); 468 return (dt_set_errno(dtp, EDT_DROPABORT)); 469 } 470 471 if ((*dtp->dt_drophdlr)(&drop, 472 dtp->dt_droparg) == DTRACE_HANDLE_ABORT) { 473 if (dtp->dt_oformat) 474 xo_close_instance("probes"); 475 return (dt_set_errno(dtp, EDT_DROPABORT)); 476 } 477 478 if (dtp->dt_oformat) 479 xo_close_instance("probes"); 480 } 481 482 return (0); 483 } 484 485 int 486 dt_handle_setopt(dtrace_hdl_t *dtp, dtrace_setoptdata_t *data) 487 { 488 void *arg = dtp->dt_setoptarg; 489 490 if (dtp->dt_setopthdlr == NULL) 491 return (0); 492 493 if ((*dtp->dt_setopthdlr)(data, arg) == DTRACE_HANDLE_ABORT) 494 return (dt_set_errno(dtp, EDT_DIRABORT)); 495 496 return (0); 497 } 498 499 int 500 dt_handle(dtrace_hdl_t *dtp, dtrace_probedata_t *data) 501 { 502 dtrace_eprobedesc_t *epd = data->dtpda_edesc; 503 int rval; 504 505 switch (epd->dtepd_uarg) { 506 case DT_ECB_ERROR: 507 rval = dt_handle_err(dtp, data); 508 break; 509 510 default: 511 return (DTRACE_CONSUME_THIS); 512 } 513 514 if (rval == 0) 515 return (DTRACE_CONSUME_NEXT); 516 517 return (DTRACE_CONSUME_ERROR); 518 } 519