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