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.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
36 #include <dt_program.h>
38 static const char _dt_errprog
[] =
49 dtrace_handle_err(dtrace_hdl_t
*dtp
, dtrace_handle_err_f
*hdlr
, void *arg
)
51 dtrace_prog_t
*pgp
= NULL
;
53 dtrace_ecbdesc_t
*edp
;
56 * We don't currently support multiple error handlers.
58 if (dtp
->dt_errhdlr
!= NULL
)
59 return (dt_set_errno(dtp
, EALREADY
));
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.
66 if (dtp
->dt_options
[DTRACEOPT_GRABANON
] != DTRACEOPT_UNSET
)
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
)));
73 stp
= dt_list_next(&pgp
->dp_stmts
);
76 edp
= stp
->ds_desc
->dtsd_ecbdesc
;
78 edp
->dted_uarg
= DT_ECB_ERROR
;
81 dtp
->dt_errhdlr
= hdlr
;
83 dtp
->dt_errprog
= pgp
;
89 dtrace_handle_drop(dtrace_hdl_t
*dtp
, dtrace_handle_drop_f
*hdlr
, void *arg
)
91 if (dtp
->dt_drophdlr
!= NULL
)
92 return (dt_set_errno(dtp
, EALREADY
));
94 dtp
->dt_drophdlr
= hdlr
;
95 dtp
->dt_droparg
= arg
;
101 dtrace_handle_proc(dtrace_hdl_t
*dtp
, dtrace_handle_proc_f
*hdlr
, void *arg
)
103 if (dtp
->dt_prochdlr
!= NULL
)
104 return (dt_set_errno(dtp
, EALREADY
));
106 dtp
->dt_prochdlr
= hdlr
;
107 dtp
->dt_procarg
= arg
;
113 dtrace_handle_buffered(dtrace_hdl_t
*dtp
, dtrace_handle_buffered_f
*hdlr
,
116 if (dtp
->dt_bufhdlr
!= NULL
)
117 return (dt_set_errno(dtp
, EALREADY
));
120 return (dt_set_errno(dtp
, EINVAL
));
122 dtp
->dt_bufhdlr
= hdlr
;
123 dtp
->dt_bufarg
= arg
;
129 dtrace_handle_setopt(dtrace_hdl_t
*dtp
, dtrace_handle_setopt_f
*hdlr
,
133 return (dt_set_errno(dtp
, EINVAL
));
135 dtp
->dt_setopthdlr
= hdlr
;
136 dtp
->dt_setoptarg
= arg
;
141 #define DT_REC(type, ndx) *((type *)((uintptr_t)data->dtpda_data + \
142 epd->dtepd_rec[(ndx)].dtrd_offset))
145 dt_handle_err(dtrace_hdl_t
*dtp
, dtrace_probedata_t
*data
)
147 dtrace_eprobedesc_t
*epd
= data
->dtpda_edesc
, *errepd
;
148 dtrace_probedesc_t
*pd
= data
->dtpda_pdesc
, *errpd
;
149 dtrace_errdata_t err
;
156 const char *faultstr
;
160 assert(epd
->dtepd_uarg
== DT_ECB_ERROR
);
162 if (epd
->dtepd_nrecs
!= 5 || strcmp(pd
->dtpd_provider
, "dtrace") != 0 ||
163 strcmp(pd
->dtpd_name
, "ERROR") != 0)
164 return (dt_set_errno(dtp
, EDT_BADERROR
));
167 * This is an error. We have the following items here: EPID,
168 * faulting action, DIF offset, fault code and faulting address.
170 epid
= (uint32_t)DT_REC(uint64_t, 0);
172 if (dt_epid_lookup(dtp
, epid
, &errepd
, &errpd
) != 0)
173 return (dt_set_errno(dtp
, EDT_BADERROR
));
175 err
.dteda_edesc
= errepd
;
176 err
.dteda_pdesc
= errpd
;
177 err
.dteda_cpu
= data
->dtpda_cpu
;
178 err
.dteda_action
= (int)DT_REC(uint64_t, 1);
179 err
.dteda_offset
= (int)DT_REC(uint64_t, 2);
180 err
.dteda_fault
= (int)DT_REC(uint64_t, 3);
181 err
.dteda_addr
= DT_REC(uint64_t, 4);
183 faultstr
= dtrace_faultstr(dtp
, err
.dteda_fault
);
184 len
= sizeof (where
) + sizeof (offinfo
) + strlen(faultstr
) +
185 strlen(errpd
->dtpd_provider
) + strlen(errpd
->dtpd_mod
) +
186 strlen(errpd
->dtpd_name
) + strlen(errpd
->dtpd_func
) +
189 str
= (char *)alloca(len
);
191 if (err
.dteda_action
== 0) {
192 (void) sprintf(where
, "predicate");
194 (void) sprintf(where
, "action #%d", err
.dteda_action
);
197 if (err
.dteda_offset
!= -1) {
198 (void) sprintf(offinfo
, " at DIF offset %d", err
.dteda_offset
);
203 switch (err
.dteda_fault
) {
204 case DTRACEFLT_BADADDR
:
205 case DTRACEFLT_BADALIGN
:
206 case DTRACEFLT_BADSTACK
:
207 (void) sprintf(details
, " (0x%llx)",
208 (u_longlong_t
)err
.dteda_addr
);
215 (void) snprintf(str
, len
, "error on enabled probe ID %u "
216 "(ID %u: %s:%s:%s:%s): %s%s in %s%s\n",
217 epid
, errpd
->dtpd_id
, errpd
->dtpd_provider
,
218 errpd
->dtpd_mod
, errpd
->dtpd_func
,
219 errpd
->dtpd_name
, dtrace_faultstr(dtp
, err
.dteda_fault
),
220 details
, where
, offinfo
);
224 if (dtp
->dt_errhdlr
== NULL
)
225 return (dt_set_errno(dtp
, EDT_ERRABORT
));
227 if ((*dtp
->dt_errhdlr
)(&err
, dtp
->dt_errarg
) == DTRACE_HANDLE_ABORT
)
228 return (dt_set_errno(dtp
, EDT_ERRABORT
));
234 dt_handle_liberr(dtrace_hdl_t
*dtp
, const dtrace_probedata_t
*data
,
235 const char *faultstr
)
237 dtrace_probedesc_t
*errpd
= data
->dtpda_pdesc
;
238 dtrace_errdata_t err
;
243 err
.dteda_edesc
= data
->dtpda_edesc
;
244 err
.dteda_pdesc
= errpd
;
245 err
.dteda_cpu
= data
->dtpda_cpu
;
246 err
.dteda_action
= -1;
247 err
.dteda_offset
= -1;
248 err
.dteda_fault
= DTRACEFLT_LIBRARY
;
249 err
.dteda_addr
= (uintptr_t)NULL
;
251 len
= strlen(faultstr
) +
252 strlen(errpd
->dtpd_provider
) + strlen(errpd
->dtpd_mod
) +
253 strlen(errpd
->dtpd_name
) + strlen(errpd
->dtpd_func
) +
258 (void) snprintf(str
, len
, "error on enabled probe ID %u "
259 "(ID %u: %s:%s:%s:%s): %s\n",
260 data
->dtpda_edesc
->dtepd_epid
,
261 errpd
->dtpd_id
, errpd
->dtpd_provider
,
262 errpd
->dtpd_mod
, errpd
->dtpd_func
,
263 errpd
->dtpd_name
, faultstr
);
267 if (dtp
->dt_errhdlr
== NULL
)
268 return (dt_set_errno(dtp
, EDT_ERRABORT
));
270 if ((*dtp
->dt_errhdlr
)(&err
, dtp
->dt_errarg
) == DTRACE_HANDLE_ABORT
)
271 return (dt_set_errno(dtp
, EDT_ERRABORT
));
276 #define DROPTAG(x) x, #x
278 static const struct {
279 dtrace_dropkind_t dtdrg_kind
;
282 { DROPTAG(DTRACEDROP_PRINCIPAL
) },
283 { DROPTAG(DTRACEDROP_AGGREGATION
) },
284 { DROPTAG(DTRACEDROP_DYNAMIC
) },
285 { DROPTAG(DTRACEDROP_DYNRINSE
) },
286 { DROPTAG(DTRACEDROP_DYNDIRTY
) },
287 { DROPTAG(DTRACEDROP_SPEC
) },
288 { DROPTAG(DTRACEDROP_SPECBUSY
) },
289 { DROPTAG(DTRACEDROP_SPECUNAVAIL
) },
290 { DROPTAG(DTRACEDROP_DBLERROR
) },
291 { DROPTAG(DTRACEDROP_STKSTROVERFLOW
) },
296 dt_droptag(dtrace_dropkind_t kind
)
300 for (i
= 0; _dt_droptags
[i
].dtdrg_tag
!= NULL
; i
++) {
301 if (_dt_droptags
[i
].dtdrg_kind
== kind
)
302 return (_dt_droptags
[i
].dtdrg_tag
);
305 return ("DTRACEDROP_UNKNOWN");
309 dt_handle_cpudrop(dtrace_hdl_t
*dtp
, processorid_t cpu
,
310 dtrace_dropkind_t what
, uint64_t howmany
)
312 dtrace_dropdata_t drop
;
316 assert(what
== DTRACEDROP_PRINCIPAL
|| what
== DTRACEDROP_AGGREGATION
);
318 bzero(&drop
, sizeof (drop
));
319 drop
.dtdda_handle
= dtp
;
320 drop
.dtdda_cpu
= cpu
;
321 drop
.dtdda_kind
= what
;
322 drop
.dtdda_drops
= howmany
;
323 drop
.dtdda_msg
= str
;
325 if (dtp
->dt_droptags
) {
326 (void) snprintf(str
, sizeof (str
), "[%s] ", dt_droptag(what
));
327 s
= &str
[strlen(str
)];
328 size
= sizeof (str
) - (s
- str
);
334 (void) snprintf(s
, size
, "%llu %sdrop%s on CPU %d\n",
335 howmany
, what
== DTRACEDROP_PRINCIPAL
? "" : "aggregation ",
336 howmany
> 1 ? "s" : "", cpu
);
338 if (dtp
->dt_drophdlr
== NULL
)
339 return (dt_set_errno(dtp
, EDT_DROPABORT
));
341 if ((*dtp
->dt_drophdlr
)(&drop
, dtp
->dt_droparg
) == DTRACE_HANDLE_ABORT
)
342 return (dt_set_errno(dtp
, EDT_DROPABORT
));
347 static const struct {
348 dtrace_dropkind_t dtdrt_kind
;
349 uintptr_t dtdrt_offset
;
350 const char *dtdrt_str
;
351 const char *dtdrt_msg
;
353 { DTRACEDROP_DYNAMIC
,
354 offsetof(dtrace_status_t
, dtst_dyndrops
),
355 "dynamic variable drop" },
357 { DTRACEDROP_DYNRINSE
,
358 offsetof(dtrace_status_t
, dtst_dyndrops_rinsing
),
359 "dynamic variable drop", " with non-empty rinsing list" },
361 { DTRACEDROP_DYNDIRTY
,
362 offsetof(dtrace_status_t
, dtst_dyndrops_dirty
),
363 "dynamic variable drop", " with non-empty dirty list" },
366 offsetof(dtrace_status_t
, dtst_specdrops
),
367 "speculative drop" },
369 { DTRACEDROP_SPECBUSY
,
370 offsetof(dtrace_status_t
, dtst_specdrops_busy
),
371 "failed speculation", " (available buffer(s) still busy)" },
373 { DTRACEDROP_SPECUNAVAIL
,
374 offsetof(dtrace_status_t
, dtst_specdrops_unavail
),
375 "failed speculation", " (no speculative buffer available)" },
377 { DTRACEDROP_STKSTROVERFLOW
,
378 offsetof(dtrace_status_t
, dtst_stkstroverflows
),
379 "jstack()/ustack() string table overflow" },
381 { DTRACEDROP_DBLERROR
,
382 offsetof(dtrace_status_t
, dtst_dblerrors
),
383 "error", " in ERROR probe enabling" },
389 dt_handle_status(dtrace_hdl_t
*dtp
, dtrace_status_t
*old
, dtrace_status_t
*new)
391 dtrace_dropdata_t drop
;
393 uintptr_t base
= (uintptr_t)new, obase
= (uintptr_t)old
;
396 bzero(&drop
, sizeof (drop
));
397 drop
.dtdda_handle
= dtp
;
398 drop
.dtdda_cpu
= DTRACE_CPUALL
;
399 drop
.dtdda_msg
= str
;
402 * First, check to see if we've been killed -- in which case we abort.
404 if (new->dtst_killed
&& !old
->dtst_killed
)
405 return (dt_set_errno(dtp
, EDT_BRICKED
));
407 for (i
= 0; _dt_droptab
[i
].dtdrt_str
!= NULL
; i
++) {
408 uintptr_t naddr
= base
+ _dt_droptab
[i
].dtdrt_offset
;
409 uintptr_t oaddr
= obase
+ _dt_droptab
[i
].dtdrt_offset
;
411 uint64_t nval
= *((uint64_t *)naddr
);
412 uint64_t oval
= *((uint64_t *)oaddr
);
417 if (dtp
->dt_droptags
) {
418 (void) snprintf(str
, sizeof (str
), "[%s] ",
419 dt_droptag(_dt_droptab
[i
].dtdrt_kind
));
420 s
= &str
[strlen(str
)];
421 size
= sizeof (str
) - (s
- str
);
427 (void) snprintf(s
, size
, "%llu %s%s%s\n", nval
- oval
,
428 _dt_droptab
[i
].dtdrt_str
, (nval
- oval
> 1) ? "s" : "",
429 _dt_droptab
[i
].dtdrt_msg
!= NULL
?
430 _dt_droptab
[i
].dtdrt_msg
: "");
432 drop
.dtdda_kind
= _dt_droptab
[i
].dtdrt_kind
;
433 drop
.dtdda_total
= nval
;
434 drop
.dtdda_drops
= nval
- oval
;
436 if (dtp
->dt_drophdlr
== NULL
)
437 return (dt_set_errno(dtp
, EDT_DROPABORT
));
439 if ((*dtp
->dt_drophdlr
)(&drop
,
440 dtp
->dt_droparg
) == DTRACE_HANDLE_ABORT
)
441 return (dt_set_errno(dtp
, EDT_DROPABORT
));
448 dt_handle_setopt(dtrace_hdl_t
*dtp
, dtrace_setoptdata_t
*data
)
450 void *arg
= dtp
->dt_setoptarg
;
452 if (dtp
->dt_setopthdlr
== NULL
)
455 if ((*dtp
->dt_setopthdlr
)(data
, arg
) == DTRACE_HANDLE_ABORT
)
456 return (dt_set_errno(dtp
, EDT_DIRABORT
));
462 dt_handle(dtrace_hdl_t
*dtp
, dtrace_probedata_t
*data
)
464 dtrace_eprobedesc_t
*epd
= data
->dtpda_edesc
;
467 switch (epd
->dtepd_uarg
) {
469 rval
= dt_handle_err(dtp
, data
);
473 return (DTRACE_CONSUME_THIS
);
477 return (DTRACE_CONSUME_NEXT
);
479 return (DTRACE_CONSUME_ERROR
);