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