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