/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* ident "%Z%%M% %I% %E% SMI"
*/
package org.opensolaris.os.dtrace;
import java.io.*;
import java.beans.*;
/**
* A value generated by the DTrace {@code mod()}, {@code func()}, or
* {@code sym()} action used to lookup the symbol associated with a
* kernel address.
* <p>
* Immutable. Supports persistence using {@link java.beans.XMLEncoder}.
*
* @author Tom Erickson
*/
public final class KernelSymbolRecord implements SymbolValueRecord,
Serializable, Comparable <KernelSymbolRecord>
{
static final long serialVersionUID = -7156627773519296848L;
static {
try {
BeanInfo info = Introspector.getBeanInfo(KernelSymbolRecord.class);
PersistenceDelegate persistenceDelegate =
new DefaultPersistenceDelegate(
new String[] {"symbol", "address"})
{
/*
* Need to prevent DefaultPersistenceDelegate from using
* overridden equals() method, resulting in a
* StackOverFlowError. Revert to PersistenceDelegate
* implementation. See
* http://forum.java.sun.com/thread.jspa?threadID=
* 477019&tstart=135
*/
protected boolean
mutatesTo(Object oldInstance, Object newInstance)
{
return (newInstance != null && oldInstance != null &&
oldInstance.getClass() == newInstance.getClass());
}
};
BeanDescriptor d = info.getBeanDescriptor();
d.setValue("persistenceDelegate", persistenceDelegate);
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
/** @serial */
private String symbol; // set natively after creation; treat as final
/** @serial */
private final long address;
/**
* Called by native code.
*/
private
KernelSymbolRecord(long addressValue)
{
address = addressValue;
}
/**
* Creates a {@code KernelSymbolRecord} with the given symbol lookup
* and kernel address converted in probe context as a result of the
* DTrace {@code mod()}, {@code func()}, or {@code sym()} action.
* <p>
* Supports XML persistence.
*
* @param addressValue symbol address
* @param lookupValue the result in the native DTrace library of
* looking up the symbol associated with the given kernel address
* @throws NullPointerException if the given lookup value is {@code null}
*/
public
KernelSymbolRecord(String lookupValue, long addressValue)
{
symbol = lookupValue;
address = addressValue;
validate();
}
private final void
validate()
{
if (symbol == null) {
throw new NullPointerException("symbol is null");
}
}
/**
* Gets the result of the address lookup in the same form returned
* by {@link Consumer#lookupKernelFunction(long address)}.
*
* @return non-null address lookup in the format defined by the
* native DTrace library
*/
public String
getSymbol()
{
return symbol;
}
/**
* Called by native code and ProbeData addSymbolRecord()
*/
void
setSymbol(String lookupValue)
{
symbol = lookupValue;
validate();
}
/**
* Gets the symbol's kernel address.
*
* @return the symbol's kernel address
*/
public long
getAddress()
{
return address;
}
/**
* Gets the symbol's kernel address. The value is used in {@link
* #equals(Object o) equals()} and {@link
* #compareTo(KernelSymbolRecord r) compareTo()} to test equality
* and to determine the natural ordering of {@code
* KernelSymbolRecord} instances.
*
* @return non-null value of the symbol's kernel address
*/
public Long
getValue()
{
return address;
}
/**
* Compares the specified object with this {@code KernelSymbolRecord}
* for equality. Returns {@code true} if and only if the specified
* object is also a {@code KernelSymbolRecord} and both records have
* the same address.
*
* @return {@code true} if and only if the specified object is also
* a {@code KernelSymbolRecord} and both records have the same
* address
*/
@Override
public boolean
equals(Object o)
{
if (o instanceof KernelSymbolRecord) {
KernelSymbolRecord r = (KernelSymbolRecord)o;
return (address == r.address);
}
return false;
}
/**
* Overridden to ensure that equal instances have equal hash codes.
*/
@Override
public int
hashCode()
{
return (int)(address ^ (address >>> 32));
}
/**
* Compares this record with the given kernel symbol lookup and
* orders by address. The comparison treats addresses as unsigned
* values so the ordering is consistent with that defined in the
* native DTrace library. The {@code compareTo()} method is
* compatible with {@link #equals(Object o) equals()}.
*
* @return -1, 0, or 1 as this record's address is less than, equal
* to, or greater than the given record's address
*/
public int
compareTo(KernelSymbolRecord r)
{
return ProbeData.compareUnsigned(address, r.address);
}
private void
readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject();
// check class invariants
try {
validate();
} catch (Exception e) {
InvalidObjectException x = new InvalidObjectException(
e.getMessage());
x.initCause(e);
throw x;
}
}
/**
* Gets the result of this symbol lookup. The format is defined in
* the native DTrace library and is as stable as that library
* definition.
*
* @return {@link #getSymbol()}
*/
@Override
public String
toString()
{
return symbol;
}
}