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