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