/* * 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 2008 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.util.*; import java.io.*; import java.util.regex.Pattern; import java.beans.*; /** * A value generated by the DTrace {@code stack()} action. *
* Immutable. Supports persistence using {@link java.beans.XMLEncoder}.
*
* @author Tom Erickson
*/
public final class KernelStackRecord implements StackValueRecord,
Serializable, Comparable
* This implementation first checks if the specified object is this
* {@code KernelStackRecord}. If so, it returns {@code true}.
*
* @return {@code true} if and only if the specified object is also
* a {@code KernelStackRecord} and both records have the same raw
* stack data
*/
@Override
public boolean
equals(Object o)
{
if (o == this) {
return true;
}
if (o instanceof KernelStackRecord) {
KernelStackRecord r = (KernelStackRecord)o;
return Arrays.equals(rawStackData, r.rawStackData);
}
return false;
}
/**
* Overridden to ensure that equal instances have equal hash codes.
*/
@Override
public int
hashCode()
{
return Arrays.hashCode(rawStackData);
}
/**
* Compares this record with the given {@code KernelStackRecord}.
* Compares the first unequal pair of bytes at the same index in
* each record's raw stack data, or if all corresponding bytes are
* equal, compares the length of each record's array of raw stack
* data. Corresponding bytes are compared as unsigned values. The
* {@code compareTo()} method is compatible with {@link
* #equals(Object o) equals()}.
*
* This implementation first checks if the specified record is this
* {@code KernelStackRecord}. If so, it returns {@code 0}.
*
* @return -1, 0, or 1 as this record's raw stack data is less than,
* equal to, or greater than the given record's raw stack data.
*/
public int
compareTo(KernelStackRecord r)
{
if (r == this) {
return 0;
}
return ProbeData.compareByteArrays(rawStackData, r.rawStackData);
}
private void
readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject();
// Make a defensive copy of stack frames and raw bytes
if (stackFrames != null) {
stackFrames = stackFrames.clone();
}
if (rawStackData != null) {
rawStackData = rawStackData.clone();
}
// check class invariants
try {
validate();
} catch (Exception e) {
InvalidObjectException x = new InvalidObjectException(
e.getMessage());
x.initCause(e);
throw x;
}
}
/**
* Gets a multi-line string representation of a stack with one frame
* per line. Each line is of the format {@code
* module`function+offset}, where {@code module} and {@code
* function} are symbol names and offset is a hex integer preceded
* by {@code 0x}. For example: {@code genunix`open+0x19}. The
* offset (and the preceding '+' sign) are omitted if offset is
* zero. If function name lookup fails, the raw pointer value is
* used instead. In that case, the module name (and the `
* delimiter) may or may not be present, depending on whether or not
* module lookup also fails, and a raw pointer value appears in
* place of {@code function+offset} as a hex value preceded by
* {@code 0x}. The format just described, not including surrounding
* whitespce, is defined in the native DTrace library and is as
* stable as that library definition. Each line is indented by an
* equal (unspecified) number of spaces.
*
* If human-readable stack frames are not available (see {@link
* #getStackFrames()}), a table represenation of {@link
* #getRawStackData()} is returned instead. The table displays 16
* bytes per row in unsigned hex followed by the ASCII character
* representations of those bytes. Each unprintable character is
* represented by a period (.).
*/
@Override
public String
toString()
{
StackFrame[] frames = getStackFrames();
if (frames.length == 0) {
return ScalarRecord.rawBytesString(rawStackData);
}
StringBuilder buf = new StringBuilder();
buf.append('\n');
for (StackFrame f : frames) {
for (int i = 0; i < STACK_INDENT; ++i) {
buf.append(' ');
}
buf.append(f);
buf.append('\n');
}
return buf.toString();
}
}