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
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
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
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
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
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
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
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
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
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
273     getDefaultMessage()
274     {
275 	return defaultMessage;
276     }
277 
278     private void
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 	    throw new InvalidObjectException(e.getMessage());
288 	}
289     }
290 
291     /**
292      * Gets a string representation of this error useful for logging and
293      * not intended for display.  The exact details of the
294      * representation are unspecified and subject to change, but the
295      * following format may be regarded as typical:
296      * <pre><code>
297      * class-name[property1 = value1, property2 = value2]
298      * </code></pre>
299      */
300     public String
301     toString()
302     {
303 	StringBuffer buf = new StringBuffer();
304 	buf.append(Error.class.getName());
305 	buf.append("[probeDescription = ");
306 	buf.append(probeDescription);
307 	buf.append(", epid = ");
308 	buf.append(epid);
309 	buf.append(", cpu = ");
310 	buf.append(cpu);
311 	buf.append(", action = ");
312 	buf.append(action);
313 	buf.append(", offset = ");
314 	buf.append(offset);
315 	buf.append(", fault = ");
316 	buf.append(fault);
317 	buf.append(", address = ");
318 	buf.append(address);
319 	buf.append(", defaultMessage = ");
320 	buf.append(defaultMessage);
321 	buf.append(']');
322 	return buf.toString();
323     }
324 }
325