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 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * ident	"%Z%%M%	%I%	%E% SMI"
27  */
28 package org.opensolaris.os.dtrace;
29 
30 import java.util.*;
31 import java.io.*;
32 import java.beans.*;
33 
34 /**
35  * An error encountered in the native DTrace library while tracing probe
36  * data.  Each of the fault name constants beginning with {@code
37  * DTRACEFLT_} identifies a specific fault with a name that is
38  * guaranteed not to change across API versions.
39  * <p>
40  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
41  *
42  * @see ConsumerListener#errorEncountered(ErrorEvent e)
43  *
44  * @author Tom Erickson
45  */
46 public final class Error implements Serializable {
47     static final long serialVersionUID = 5069931629562700614L;
48 
49     /**
50      * Invalid address.
51      */
52     public static final String DTRACEFLT_BADADDR = "DTRACEFLT_BADADDR";
53     /**
54      * Invalid alignment.
55      */
56     public static final String DTRACEFLT_BADALIGN = "DTRACEFLT_BADALIGN";
57     /**
58      * Illegal operation.
59      */
60     public static final String DTRACEFLT_ILLOP = "DTRACEFLT_ILLOP";
61     /**
62      * Divide-by-zero.
63      */
64     public static final String DTRACEFLT_DIVZERO = "DTRACEFLT_DIVZERO";
65     /**
66      * Out of scratch space.
67      */
68     public static final String DTRACEFLT_NOSCRATCH = "DTRACEFLT_NOSCRATCH";
69     /**
70      * Invalid kernel access.
71      */
72     public static final String DTRACEFLT_KPRIV = "DTRACEFLT_KPRIV";
73     /**
74      * Invalid user access.
75      */
76     public static final String DTRACEFLT_UPRIV = "DTRACEFLT_UPRIV";
77     /**
78      * Tuple stack overflow.
79      */
80     public static final String DTRACEFLT_TUPOFLOW = "DTRACEFLT_TUPOFLOW";
81     /**
82      * Library-level fault.
83      */
84     public static final String DTRACEFLT_LIBRARY = "DTRACEFLT_LIBRARY";
85 
86     static {
87 	try {
88 	    BeanInfo info = Introspector.getBeanInfo(Error.class);
89 	    PersistenceDelegate persistenceDelegate =
90 		    new DefaultPersistenceDelegate(
91 		    new String[] {"probeDescription",
92 		    "enabledProbeID", "CPU", "action", "offset",
93 		    "fault", "address", "defaultMessage"});
94 	    BeanDescriptor d = info.getBeanDescriptor();
95 	    d.setValue("persistenceDelegate", persistenceDelegate);
96 	} catch (IntrospectionException e) {
97 	    e.printStackTrace();
98 	}
99     }
100 
101     /** @serial */
102     private final ProbeDescription probeDescription;
103     /** @serial */
104     private final int epid;
105     /** @serial */
106     private final int cpu;
107     /** @serial */
108     private final int action;
109     /** @serial */
110     private final int offset;
111     /** @serial */
112     private final String fault;
113     /** @serial */
114     private final long address;
115     /** @serial */
116     private final String defaultMessage;
117 
118     /**
119      * Creates a DTrace error with the given properties.  Supports XML
120      * persistence.
121      *
122      * @param pdesc probe description that identifies the error-inducing
123      * probe among all the probes on the system
124      * @param enabledProbeID identifies the error-inducing probe among
125      * all probes enabled by the same {@link Consumer}
126      * @param errorCPU non-negative ID of the CPU where the error was
127      * encountered, or a negative number if the CPU is unknown
128      * @param errorAction integer that identifies the error-inducing
129      * action as the nth action (starting at one) in the error-inducing
130      * probe, or zero if the error is in the predicate rather than in an
131      * action
132      * @param errorOffset error offset in compiled DTrace Intermediate
133      * Format (DIF), or a negative number if the offset is not available
134      * @param faultName name of the specific fault, or {@code null}
135      * if the fault is unknown to the Java DTrace API
136      * @param faultAddress address of fault, or -1 if address is not
137      * applicable to the specific fault
138      * @param errorMessage default message from the native DTrace
139      * library preconstructed from the properties of this error
140      * @throws NullPointerException if the given probe description or
141      * default message is {@code null}
142      */
143     public
Error(ProbeDescription pdesc, int enabledProbeID, int errorCPU, int errorAction, int errorOffset, String faultName, long faultAddress, String errorMessage)144     Error(ProbeDescription pdesc, int enabledProbeID, int errorCPU,
145 	    int errorAction, int errorOffset, String faultName,
146 	    long faultAddress, String errorMessage)
147     {
148 	probeDescription = pdesc;
149 	epid = enabledProbeID;
150 	cpu = errorCPU;
151 	action = errorAction;
152 	offset = errorOffset;
153 	fault = faultName;
154 	address = faultAddress;
155 	defaultMessage = errorMessage;
156 	validate();
157     }
158 
159     private final void
validate()160     validate()
161     {
162 	if (probeDescription == null) {
163 	    throw new NullPointerException(
164 		    "enabled probe description is null");
165 	}
166 	if (defaultMessage == null) {
167 	    throw new NullPointerException("default message is null");
168 	}
169     }
170 
171     /**
172      * Gets the probe description that identifies the error-inducing
173      * probe among all the probes on the system.
174      *
175      * @return non-null probe description
176      */
177     public ProbeDescription
getProbeDescription()178     getProbeDescription()
179     {
180 	return probeDescription;
181     }
182 
183     /**
184      * Gets the enabled probe ID.  The "epid" is different from {@link
185      * ProbeDescription#getID()} because it identifies a probe among all
186      * the probes enabled by a {@link Consumer}, rather than among all
187      * the probes on the system.
188      *
189      * @return the enabled probe ID
190      */
191     public int
getEnabledProbeID()192     getEnabledProbeID()
193     {
194 	return epid;
195     }
196 
197     /**
198      * Gets the CPU that encountered the error.
199      *
200      * @return non-negative CPU ID, or a negative number if the CPU is
201      * unknown
202      */
203     public int
getCPU()204     getCPU()
205     {
206 	return cpu;
207     }
208 
209     /**
210      * Gets the error-inducing action as the <i>nth</i> action (starting
211      * at one) in the error-inducing probe, or zero if the error is in
212      * the predicate rather than in an action.  Note that some actions
213      * in a D program consist of multiple actions internally within the
214      * DTrace library.
215      *
216      * @return zero if the error is in the probe predicate, otherwise
217      * the <i>nth</i> action (<i>n</i> starting at one) from the start
218      * of the probe that induced the error
219      */
220     public int
getAction()221     getAction()
222     {
223 	return action;
224     }
225 
226     /**
227      * Gets the error offset in compiled DTrace Intermediate Format
228      * (DIF), or a negative number if the offset is not available.
229      *
230      * @return the error offset in compiled DTrace Intermediate Format
231      * (DIF), or a negative number if the offset is not available
232      */
233     public int
getOffset()234     getOffset()
235     {
236 	return offset;
237     }
238 
239     /**
240      * Gets the name identifying the specific fault.  The names are
241      * guaranteed not to change across API versions as long as the fault
242      * cases they identify still exist.
243      *
244      * @return name of the specific fault or {@code null} if the
245      * fault is unknown to the Java DTrace API
246      */
247     public String
getFault()248     getFault()
249     {
250 	return fault;
251     }
252 
253     /**
254      * Gets the address of the fault, if any.
255      *
256      * @return address of fault, or -1 if address is not applicable to
257      * the specific fault (the fault is not one of {@link
258      * #DTRACEFLT_BADADDR} or {@link #DTRACEFLT_BADALIGN})
259      */
260     public long
getAddress()261     getAddress()
262     {
263 	return address;
264     }
265 
266     /**
267      * Gets the default message from the native DTrace library
268      * preconstructed from the properties of this error.
269      *
270      * @return non-null preconstructed message
271      */
272     public String
getDefaultMessage()273     getDefaultMessage()
274     {
275 	return defaultMessage;
276     }
277 
278     private void
readObject(ObjectInputStream s)279     readObject(ObjectInputStream s)
280             throws IOException, ClassNotFoundException
281     {
282 	s.defaultReadObject();
283 	// check class invariants
284 	try {
285 	    validate();
286 	} catch (Exception e) {
287 	    InvalidObjectException x = new InvalidObjectException(
288 		    e.getMessage());
289 	    x.initCause(e);
290 	    throw x;
291 	}
292     }
293 
294     /**
295      * Gets a string representation of this error useful for logging and
296      * not intended for display.  The exact details of the
297      * representation are unspecified and subject to change, but the
298      * following format may be regarded as typical:
299      * <pre><code>
300      * class-name[property1 = value1, property2 = value2]
301      * </code></pre>
302      */
303     public String
toString()304     toString()
305     {
306 	StringBuilder buf = new StringBuilder();
307 	buf.append(Error.class.getName());
308 	buf.append("[probeDescription = ");
309 	buf.append(probeDescription);
310 	buf.append(", epid = ");
311 	buf.append(epid);
312 	buf.append(", cpu = ");
313 	buf.append(cpu);
314 	buf.append(", action = ");
315 	buf.append(action);
316 	buf.append(", offset = ");
317 	buf.append(offset);
318 	buf.append(", fault = ");
319 	buf.append(fault);
320 	buf.append(", address = ");
321 	buf.append(address);
322 	buf.append(", defaultMessage = ");
323 	buf.append(defaultMessage);
324 	buf.append(']');
325 	return buf.toString();
326     }
327 }
328