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.io.*;
31 import java.beans.*;
32 
33 /**
34  * A value generated by the DTrace {@code mod()}, {@code func()}, or
35  * {@code sym()} action used to lookup the symbol associated with a
36  * kernel address.
37  * <p>
38  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
39  *
40  * @author Tom Erickson
41  */
42 public final class KernelSymbolRecord implements SymbolValueRecord,
43        Serializable, Comparable <KernelSymbolRecord>
44 {
45     static final long serialVersionUID = -7156627773519296848L;
46 
47     static {
48 	try {
49 	    BeanInfo info = Introspector.getBeanInfo(KernelSymbolRecord.class);
50 	    PersistenceDelegate persistenceDelegate =
51 		    new DefaultPersistenceDelegate(
52 		    new String[] {"symbol", "address"})
53 	    {
54 		/*
55 		 * Need to prevent DefaultPersistenceDelegate from using
56 		 * overridden equals() method, resulting in a
57 		 * StackOverFlowError.  Revert to PersistenceDelegate
58 		 * implementation.  See
59 		 * http://forum.java.sun.com/thread.jspa?threadID=
60 		 * 477019&tstart=135
61 		 */
62 		protected boolean
63 		mutatesTo(Object oldInstance, Object newInstance)
64 		{
65 		    return (newInstance != null && oldInstance != null &&
66 			    oldInstance.getClass() == newInstance.getClass());
67 		}
68 	    };
69 	    BeanDescriptor d = info.getBeanDescriptor();
70 	    d.setValue("persistenceDelegate", persistenceDelegate);
71 	} catch (IntrospectionException e) {
72 	    e.printStackTrace();
73 	}
74     }
75 
76     /** @serial */
77     private String symbol; // set natively after creation; treat as final
78     /** @serial */
79     private final long address;
80 
81     /**
82      * Called by native code.
83      */
84     private
KernelSymbolRecord(long addressValue)85     KernelSymbolRecord(long addressValue)
86     {
87 	address = addressValue;
88     }
89 
90     /**
91      * Creates a {@code KernelSymbolRecord} with the given symbol lookup
92      * and kernel address converted in probe context as a result of the
93      * DTrace {@code mod()}, {@code func()}, or {@code sym()} action.
94      * <p>
95      * Supports XML persistence.
96      *
97      * @param addressValue symbol address
98      * @param lookupValue the result in the native DTrace library of
99      * looking up the symbol associated with the given kernel address
100      * @throws NullPointerException if the given lookup value is {@code null}
101      */
102     public
KernelSymbolRecord(String lookupValue, long addressValue)103     KernelSymbolRecord(String lookupValue, long addressValue)
104     {
105 	symbol = lookupValue;
106 	address = addressValue;
107 	validate();
108     }
109 
110     private final void
validate()111     validate()
112     {
113 	if (symbol == null) {
114 	    throw new NullPointerException("symbol is null");
115 	}
116     }
117 
118     /**
119      * Gets the result of the address lookup in the same form returned
120      * by {@link Consumer#lookupKernelFunction(long address)}.
121      *
122      * @return non-null address lookup in the format defined by the
123      * native DTrace library
124      */
125     public String
getSymbol()126     getSymbol()
127     {
128 	return symbol;
129     }
130 
131     /**
132      * Called by native code and ProbeData addSymbolRecord()
133      */
134     void
setSymbol(String lookupValue)135     setSymbol(String lookupValue)
136     {
137 	symbol = lookupValue;
138 	validate();
139     }
140 
141     /**
142      * Gets the symbol's kernel address.
143      *
144      * @return the symbol's kernel address
145      */
146     public long
getAddress()147     getAddress()
148     {
149 	return address;
150     }
151 
152     /**
153      * Gets the symbol's kernel address.  The value is used in {@link
154      * #equals(Object o) equals()} and {@link
155      * #compareTo(KernelSymbolRecord r) compareTo()} to test equality
156      * and to determine the natural ordering of {@code
157      * KernelSymbolRecord} instances.
158      *
159      * @return non-null value of the symbol's kernel address
160      */
161     public Long
getValue()162     getValue()
163     {
164 	return address;
165     }
166 
167     /**
168      * Compares the specified object with this {@code KernelSymbolRecord}
169      * for equality.  Returns {@code true} if and only if the specified
170      * object is also a {@code KernelSymbolRecord} and both records have
171      * the same address.
172      *
173      * @return {@code true} if and only if the specified object is also
174      * a {@code KernelSymbolRecord} and both records have the same
175      * address
176      */
177     @Override
178     public boolean
equals(Object o)179     equals(Object o)
180     {
181 	if (o instanceof KernelSymbolRecord) {
182 	    KernelSymbolRecord r = (KernelSymbolRecord)o;
183 	    return (address == r.address);
184 	}
185 	return false;
186     }
187 
188     /**
189      * Overridden to ensure that equal instances have equal hash codes.
190      */
191     @Override
192     public int
hashCode()193     hashCode()
194     {
195 	return (int)(address ^ (address >>> 32));
196     }
197 
198     /**
199      * Compares this record with the given kernel symbol lookup and
200      * orders by address.  The comparison treats addresses as unsigned
201      * values so the ordering is consistent with that defined in the
202      * native DTrace library. The {@code compareTo()} method is
203      * compatible with {@link #equals(Object o) equals()}.
204      *
205      * @return -1, 0, or 1 as this record's address is less than, equal
206      * to, or greater than the given record's address
207      */
208     public int
compareTo(KernelSymbolRecord r)209     compareTo(KernelSymbolRecord r)
210     {
211 	return ProbeData.compareUnsigned(address, r.address);
212     }
213 
214     private void
readObject(ObjectInputStream s)215     readObject(ObjectInputStream s)
216             throws IOException, ClassNotFoundException
217     {
218 	s.defaultReadObject();
219 	// check class invariants
220 	try {
221 	    validate();
222 	} catch (Exception e) {
223 	    InvalidObjectException x = new InvalidObjectException(
224 		    e.getMessage());
225 	    x.initCause(e);
226 	    throw x;
227 	}
228     }
229 
230     /**
231      * Gets the result of this symbol lookup.  The format is defined in
232      * the native DTrace library and is as stable as that library
233      * definition.
234      *
235      * @return {@link #getSymbol()}
236      */
237     @Override
238     public String
toString()239     toString()
240     {
241 	return symbol;
242     }
243 }
244