1127bbe13Stomee /* 2127bbe13Stomee * CDDL HEADER START 3127bbe13Stomee * 4127bbe13Stomee * The contents of this file are subject to the terms of the 5127bbe13Stomee * Common Development and Distribution License (the "License"). 6127bbe13Stomee * You may not use this file except in compliance with the License. 7127bbe13Stomee * 8127bbe13Stomee * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9127bbe13Stomee * or http://www.opensolaris.org/os/licensing. 10127bbe13Stomee * See the License for the specific language governing permissions 11127bbe13Stomee * and limitations under the License. 12127bbe13Stomee * 13127bbe13Stomee * When distributing Covered Code, include this CDDL HEADER in each 14127bbe13Stomee * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15127bbe13Stomee * If applicable, add the following below this CDDL HEADER, with the 16127bbe13Stomee * fields enclosed by brackets "[]" replaced with your own identifying 17127bbe13Stomee * information: Portions Copyright [yyyy] [name of copyright owner] 18127bbe13Stomee * 19127bbe13Stomee * CDDL HEADER END 20127bbe13Stomee */ 21127bbe13Stomee 22127bbe13Stomee /* 2391cfa10aStomee * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24127bbe13Stomee * Use is subject to license terms. 25127bbe13Stomee * 26127bbe13Stomee * ident "%Z%%M% %I% %E% SMI" 27127bbe13Stomee */ 28127bbe13Stomee package org.opensolaris.os.dtrace; 29127bbe13Stomee 30127bbe13Stomee import java.io.*; 31127bbe13Stomee import java.beans.*; 32127bbe13Stomee 33127bbe13Stomee /** 34127bbe13Stomee * A value generated by the DTrace {@code umod()}, {@code ufunc()}, or 35127bbe13Stomee * {@code usym()} action used to lookup the symbol associated with a 36127bbe13Stomee * user address. 37127bbe13Stomee * <p> 38127bbe13Stomee * Immutable. Supports persistence using {@link java.beans.XMLEncoder}. 39127bbe13Stomee * 40127bbe13Stomee * @author Tom Erickson 41127bbe13Stomee */ 42127bbe13Stomee public final class UserSymbolRecord implements SymbolValueRecord, 43127bbe13Stomee Serializable, Comparable <UserSymbolRecord> 44127bbe13Stomee { 45127bbe13Stomee static final long serialVersionUID = -591954442654439794L; 46127bbe13Stomee 47127bbe13Stomee static { 48127bbe13Stomee try { 49127bbe13Stomee BeanInfo info = Introspector.getBeanInfo(UserSymbolRecord.class); 50127bbe13Stomee PersistenceDelegate persistenceDelegate = 51127bbe13Stomee new DefaultPersistenceDelegate( 52127bbe13Stomee new String[] {"processID", "symbol", "address"}) 53127bbe13Stomee { 54127bbe13Stomee /* 55127bbe13Stomee * Need to prevent DefaultPersistenceDelegate from using 56127bbe13Stomee * overridden equals() method, resulting in a 57127bbe13Stomee * StackOverFlowError. Revert to PersistenceDelegate 58127bbe13Stomee * implementation. See 59127bbe13Stomee * http://forum.java.sun.com/thread.jspa?threadID= 60127bbe13Stomee * 477019&tstart=135 61127bbe13Stomee */ 62127bbe13Stomee protected boolean 63127bbe13Stomee mutatesTo(Object oldInstance, Object newInstance) 64127bbe13Stomee { 65127bbe13Stomee return (newInstance != null && oldInstance != null && 66127bbe13Stomee oldInstance.getClass() == newInstance.getClass()); 67127bbe13Stomee } 68127bbe13Stomee }; 69127bbe13Stomee BeanDescriptor d = info.getBeanDescriptor(); 70127bbe13Stomee d.setValue("persistenceDelegate", persistenceDelegate); 71127bbe13Stomee } catch (IntrospectionException e) { 72127bbe13Stomee e.printStackTrace(); 73127bbe13Stomee } 74127bbe13Stomee } 75127bbe13Stomee 76127bbe13Stomee // serialized explicitly to hide implementation; treat as final 77127bbe13Stomee private transient Value value; 78127bbe13Stomee // set natively after creation; treat as final 79127bbe13Stomee private transient String symbol; 80127bbe13Stomee 81127bbe13Stomee /** 82127bbe13Stomee * Called by native code. 83127bbe13Stomee */ 84127bbe13Stomee private UserSymbolRecord(int pid, long addressValue)85127bbe13Stomee UserSymbolRecord(int pid, long addressValue) 86127bbe13Stomee { 87127bbe13Stomee value = new Value(pid, addressValue); 88127bbe13Stomee } 89127bbe13Stomee 90127bbe13Stomee /** 91127bbe13Stomee * Creates a {@code UserSymbolRecord} with the given process ID, 92127bbe13Stomee * symbol lookup, and user address converted in probe context as a 93127bbe13Stomee * result of the DTrace {@code umod()}, {@code ufunc()}, or {@code 94127bbe13Stomee * usym()} action. 95127bbe13Stomee * <p> 96127bbe13Stomee * Supports XML persistence. 97127bbe13Stomee * 98127bbe13Stomee * @param pid non-negative user process ID 99127bbe13Stomee * @param lookupValue the result in the native DTrace library of 100127bbe13Stomee * looking up the symbol associated with the given user address 101127bbe13Stomee * @param addressValue symbol address 102127bbe13Stomee * @throws NullPointerException if the given lookup value is {@code null} 103127bbe13Stomee * @throws IllegalArgumentException if the given process ID is 104127bbe13Stomee * negative 105127bbe13Stomee */ 106127bbe13Stomee public UserSymbolRecord(int pid, String lookupValue, long addressValue)107127bbe13Stomee UserSymbolRecord(int pid, String lookupValue, long addressValue) 108127bbe13Stomee { 109127bbe13Stomee value = new Value(pid, addressValue); 110127bbe13Stomee symbol = lookupValue; 111127bbe13Stomee validate(); 112127bbe13Stomee } 113127bbe13Stomee 11491cfa10aStomee private final void validate()115127bbe13Stomee validate() 116127bbe13Stomee { 117127bbe13Stomee if (symbol == null) { 118127bbe13Stomee throw new NullPointerException("symbol is null"); 119127bbe13Stomee } 120127bbe13Stomee } 121127bbe13Stomee 122127bbe13Stomee /** 123127bbe13Stomee * Gets the process ID associated with this record's symbol. 124127bbe13Stomee * 125127bbe13Stomee * @return non-negative pid 126127bbe13Stomee */ 127127bbe13Stomee public int getProcessID()128127bbe13Stomee getProcessID() 129127bbe13Stomee { 130127bbe13Stomee return value.getProcessID(); 131127bbe13Stomee } 132127bbe13Stomee 133127bbe13Stomee /** 134127bbe13Stomee * Gets the result of the address lookup in the same form returned 135127bbe13Stomee * by {@link Consumer#lookupUserFunction(int pid, long address)}. 136127bbe13Stomee * 137127bbe13Stomee * @return non-null address lookup in the format defined by the 138127bbe13Stomee * native DTrace library 139127bbe13Stomee */ 140127bbe13Stomee public String getSymbol()141127bbe13Stomee getSymbol() 142127bbe13Stomee { 143127bbe13Stomee return symbol; 144127bbe13Stomee } 145127bbe13Stomee 146127bbe13Stomee /** 147127bbe13Stomee * Called by native code and ProbeData addSymbolRecord() 148127bbe13Stomee */ 149127bbe13Stomee void setSymbol(String lookupValue)150127bbe13Stomee setSymbol(String lookupValue) 151127bbe13Stomee { 152127bbe13Stomee symbol = lookupValue; 153127bbe13Stomee validate(); 154127bbe13Stomee } 155127bbe13Stomee 156127bbe13Stomee /** 157127bbe13Stomee * Gets the symbol's user address. 158127bbe13Stomee * 159127bbe13Stomee * @return the symbol's user address 160127bbe13Stomee */ 161127bbe13Stomee public long getAddress()162127bbe13Stomee getAddress() 163127bbe13Stomee { 164127bbe13Stomee return value.getAddress(); 165127bbe13Stomee } 166127bbe13Stomee 167127bbe13Stomee /** 168127bbe13Stomee * Gets the composite value of the symbol's process ID and address. 169127bbe13Stomee * The value is used in {@link #equals(Object o) equals()} and 170127bbe13Stomee * {@link #compareTo(UserSymbolRecord r) compareTo()} to test 171127bbe13Stomee * equality and to determine the natural ordering of {@code 172127bbe13Stomee * UserSymbolRecord} instances. 173127bbe13Stomee * 174127bbe13Stomee * @return non-null composite value of the symbols's process ID and 175127bbe13Stomee * address 176127bbe13Stomee */ 177127bbe13Stomee public Value getValue()178127bbe13Stomee getValue() 179127bbe13Stomee { 180127bbe13Stomee return value; 181127bbe13Stomee } 182127bbe13Stomee 183127bbe13Stomee /** 184127bbe13Stomee * Compares the specified object with this {@code UserSymbolRecord} 185127bbe13Stomee * for equality. Returns {@code true} if and only if the specified 186127bbe13Stomee * object is also a {@code UserSymbolRecord} and both records have 187127bbe13Stomee * the same process ID and the same address. 188127bbe13Stomee * 189127bbe13Stomee * @return {@code true} if and only if the specified object is also 190127bbe13Stomee * a {@code UserSymbolRecord} and both records have the same 191127bbe13Stomee * process ID and the same address 192127bbe13Stomee */ 193127bbe13Stomee @Override 194127bbe13Stomee public boolean equals(Object o)195127bbe13Stomee equals(Object o) 196127bbe13Stomee { 197127bbe13Stomee if (o instanceof UserSymbolRecord) { 198127bbe13Stomee UserSymbolRecord r = (UserSymbolRecord)o; 199127bbe13Stomee return value.equals(r.value); 200127bbe13Stomee } 201127bbe13Stomee return false; 202127bbe13Stomee } 203127bbe13Stomee 204127bbe13Stomee /** 205127bbe13Stomee * Overridden to ensure that equal instances have equal hash codes. 206127bbe13Stomee */ 207127bbe13Stomee @Override 208127bbe13Stomee public int hashCode()209127bbe13Stomee hashCode() 210127bbe13Stomee { 211127bbe13Stomee return value.hashCode(); 212127bbe13Stomee } 213127bbe13Stomee 214127bbe13Stomee /** 215127bbe13Stomee * Compares this record with the given user symbol lookup and orders 216127bbe13Stomee * by the combined value of process ID first and address second. 217127bbe13Stomee * The comparison treats addresses as unsigned values so the 218127bbe13Stomee * ordering is consistent with that defined in the native DTrace 219127bbe13Stomee * library. The {@code compareTo()} method is compatible with {@link 220127bbe13Stomee * #equals(Object o) equals()}. 221127bbe13Stomee * 222127bbe13Stomee * @return -1, 0, or 1 as this record's combined process ID and 223127bbe13Stomee * address is less than, equal to, or greater than the given 224127bbe13Stomee * record's combined process ID and address 225127bbe13Stomee */ 226127bbe13Stomee public int compareTo(UserSymbolRecord r)227127bbe13Stomee compareTo(UserSymbolRecord r) 228127bbe13Stomee { 229127bbe13Stomee return value.compareTo(r.value); 230127bbe13Stomee } 231127bbe13Stomee 232127bbe13Stomee /** 233127bbe13Stomee * Serialize this {@code UserSymbolRecord} instance. 234127bbe13Stomee * 235127bbe13Stomee * @serialData processID ({@code int}), followed by symbol ({@code 236127bbe13Stomee * java.lang.String}), followed by address ({@code long}) 237127bbe13Stomee */ 238127bbe13Stomee private void writeObject(ObjectOutputStream s)239127bbe13Stomee writeObject(ObjectOutputStream s) throws IOException 240127bbe13Stomee { 241127bbe13Stomee s.defaultWriteObject(); 242127bbe13Stomee s.writeInt(getProcessID()); 243127bbe13Stomee s.writeObject(getSymbol()); 244127bbe13Stomee s.writeLong(getAddress()); 245127bbe13Stomee } 246127bbe13Stomee 247127bbe13Stomee private void readObject(ObjectInputStream s)248127bbe13Stomee readObject(ObjectInputStream s) 249127bbe13Stomee throws IOException, ClassNotFoundException 250127bbe13Stomee { 251127bbe13Stomee s.defaultReadObject(); 252127bbe13Stomee int pid = s.readInt(); 253127bbe13Stomee symbol = (String)s.readObject(); 254127bbe13Stomee long addressValue = s.readLong(); 255127bbe13Stomee try { 256127bbe13Stomee value = new Value(pid, addressValue); 257127bbe13Stomee validate(); 258127bbe13Stomee } catch (Exception e) { 259*4ae67516Stomee InvalidObjectException x = new InvalidObjectException( 260*4ae67516Stomee e.getMessage()); 261*4ae67516Stomee x.initCause(e); 262*4ae67516Stomee throw x; 263127bbe13Stomee } 264127bbe13Stomee } 265127bbe13Stomee 266127bbe13Stomee /** 267127bbe13Stomee * Gets the result of this symbol lookup. The format is defined in 268127bbe13Stomee * the native DTrace library and is as stable as that library 269127bbe13Stomee * definition. 270127bbe13Stomee * 271127bbe13Stomee * @return {@link #getSymbol()} 272127bbe13Stomee */ 273127bbe13Stomee @Override 274127bbe13Stomee public String toString()275127bbe13Stomee toString() 276127bbe13Stomee { 277127bbe13Stomee return symbol; 278127bbe13Stomee } 279127bbe13Stomee 280127bbe13Stomee /** 281127bbe13Stomee * The composite value of a symbol's process ID and user address. 282127bbe13Stomee * <p> 283127bbe13Stomee * Immutable. Supports persistence using {@link 284127bbe13Stomee * java.beans.XMLEncoder}. 285127bbe13Stomee */ 286127bbe13Stomee public static final class Value implements Serializable, 287127bbe13Stomee Comparable <Value> { 288127bbe13Stomee static final long serialVersionUID = -91449037747641135L; 289127bbe13Stomee 290127bbe13Stomee static { 291127bbe13Stomee try { 292127bbe13Stomee BeanInfo info = Introspector.getBeanInfo( 293127bbe13Stomee UserSymbolRecord.Value.class); 294127bbe13Stomee PersistenceDelegate persistenceDelegate = 295127bbe13Stomee new DefaultPersistenceDelegate( 296127bbe13Stomee new String[] {"processID", "address"}) 297127bbe13Stomee { 298127bbe13Stomee /* 299127bbe13Stomee * Need to prevent DefaultPersistenceDelegate from using 300127bbe13Stomee * overridden equals() method, resulting in a 301127bbe13Stomee * StackOverFlowError. Revert to PersistenceDelegate 302127bbe13Stomee * implementation. See 303127bbe13Stomee * http://forum.java.sun.com/thread.jspa?threadID= 304127bbe13Stomee * 477019&tstart=135 305127bbe13Stomee */ 306127bbe13Stomee protected boolean 307127bbe13Stomee mutatesTo(Object oldInstance, Object newInstance) 308127bbe13Stomee { 309127bbe13Stomee return (newInstance != null && oldInstance != null && 310127bbe13Stomee oldInstance.getClass() == 311127bbe13Stomee newInstance.getClass()); 312127bbe13Stomee } 313127bbe13Stomee }; 314127bbe13Stomee BeanDescriptor d = info.getBeanDescriptor(); 315127bbe13Stomee d.setValue("persistenceDelegate", persistenceDelegate); 316127bbe13Stomee } catch (IntrospectionException e) { 317127bbe13Stomee e.printStackTrace(); 318127bbe13Stomee } 319127bbe13Stomee } 320127bbe13Stomee 321127bbe13Stomee /** @serial */ 322127bbe13Stomee private final int processID; 323127bbe13Stomee /** @serial */ 324127bbe13Stomee private final long address; 325127bbe13Stomee 326127bbe13Stomee /** 327127bbe13Stomee * Creates a composite value with the given user process ID and 328127bbe13Stomee * symbol address. 329127bbe13Stomee * <p> 330127bbe13Stomee * Supports XML persistence. 331127bbe13Stomee * 332127bbe13Stomee * @param pid non-negative process ID 333127bbe13Stomee * @param addressValue symbol address 334127bbe13Stomee * @throws IllegalArgumentException if the given process ID is 335127bbe13Stomee * negative 336127bbe13Stomee */ 337127bbe13Stomee public Value(int pid, long addressValue)338127bbe13Stomee Value(int pid, long addressValue) 339127bbe13Stomee { 340127bbe13Stomee processID = pid; 341127bbe13Stomee address = addressValue; 342127bbe13Stomee validate(); 343127bbe13Stomee } 344127bbe13Stomee 34591cfa10aStomee private final void validate()346127bbe13Stomee validate() 347127bbe13Stomee { 348127bbe13Stomee if (processID < 0) { 349127bbe13Stomee throw new IllegalArgumentException("process ID is negative"); 350127bbe13Stomee } 351127bbe13Stomee } 352127bbe13Stomee 353127bbe13Stomee /** 354127bbe13Stomee * Gets the process ID associated with this value's user 355127bbe13Stomee * address. 356127bbe13Stomee * 357127bbe13Stomee * @return non-negative pid 358127bbe13Stomee */ 359127bbe13Stomee public int getProcessID()360127bbe13Stomee getProcessID() 361127bbe13Stomee { 362127bbe13Stomee return processID; 363127bbe13Stomee } 364127bbe13Stomee 365127bbe13Stomee /** 366127bbe13Stomee * Gets the symbol's user address. 367127bbe13Stomee * 368127bbe13Stomee * @return the symbol's user address 369127bbe13Stomee */ 370127bbe13Stomee public long getAddress()371127bbe13Stomee getAddress() 372127bbe13Stomee { 373127bbe13Stomee return address; 374127bbe13Stomee } 375127bbe13Stomee 376127bbe13Stomee /** 377127bbe13Stomee * Compares the specified object with this {@code 378127bbe13Stomee * UserSymbolRecord.Value} for equality. Returns {@code true} 379127bbe13Stomee * if and only if the specified object is also a {@code 380127bbe13Stomee * UserSymbolRecord.Value} and both values have the same process 381127bbe13Stomee * ID and the same address. 382127bbe13Stomee * 383127bbe13Stomee * @return {@code true} if and only if the specified object is 384127bbe13Stomee * also a {@code UserSymbolRecord.Value} and both values have 385127bbe13Stomee * the same process ID and the same address 386127bbe13Stomee */ 387127bbe13Stomee @Override 388127bbe13Stomee public boolean equals(Object o)389127bbe13Stomee equals(Object o) 390127bbe13Stomee { 391127bbe13Stomee if (o instanceof Value) { 392127bbe13Stomee Value v = (Value)o; 393127bbe13Stomee return ((processID == v.processID) && (address == v.address)); 394127bbe13Stomee } 395127bbe13Stomee return false; 396127bbe13Stomee } 397127bbe13Stomee 398127bbe13Stomee /** 399127bbe13Stomee * Overridden to ensure that equal instances have equal hash 400127bbe13Stomee * codes. 401127bbe13Stomee */ 402127bbe13Stomee @Override 403127bbe13Stomee public int hashCode()404127bbe13Stomee hashCode() 405127bbe13Stomee { 406127bbe13Stomee int hash = 17; 407127bbe13Stomee hash = 37 * hash + processID; 408127bbe13Stomee hash = 37 * hash + (int)(address ^ (address >>> 32)); 409127bbe13Stomee return hash; 410127bbe13Stomee } 411127bbe13Stomee 412127bbe13Stomee /** 413127bbe13Stomee * Compares this value with the given {@code 414127bbe13Stomee * UserSymbolRecord.Value} and orders by process ID first and 415127bbe13Stomee * address second. The comparison treats addresses as unsigned 416127bbe13Stomee * values so the ordering is consistent with that defined in the 417127bbe13Stomee * native DTrace library. The {@code compareTo()} method is 418127bbe13Stomee * compatible with {@link #equals(Object o) equals()}. 419127bbe13Stomee * 420127bbe13Stomee * @return -1, 0, or 1 as this value's combined process ID and 421127bbe13Stomee * address is less than, equal to, or greater than the given 422127bbe13Stomee * value's combined process ID and address 423127bbe13Stomee */ 424127bbe13Stomee public int compareTo(Value v)425127bbe13Stomee compareTo(Value v) 426127bbe13Stomee { 427127bbe13Stomee int cmp; 428127bbe13Stomee cmp = (processID < v.processID ? -1 : 429127bbe13Stomee (processID > v.processID ? 1 : 0)); 430127bbe13Stomee if (cmp == 0) { 431127bbe13Stomee cmp = ProbeData.compareUnsigned(address, v.address); 432127bbe13Stomee } 433127bbe13Stomee return cmp; 434127bbe13Stomee } 435127bbe13Stomee 436127bbe13Stomee private void readObject(ObjectInputStream s)437127bbe13Stomee readObject(ObjectInputStream s) 438127bbe13Stomee throws IOException, ClassNotFoundException 439127bbe13Stomee { 440127bbe13Stomee s.defaultReadObject(); 441127bbe13Stomee // check class invariants 442127bbe13Stomee try { 443127bbe13Stomee validate(); 444127bbe13Stomee } catch (Exception e) { 445*4ae67516Stomee InvalidObjectException x = new InvalidObjectException( 446*4ae67516Stomee e.getMessage()); 447*4ae67516Stomee x.initCause(e); 448*4ae67516Stomee throw x; 449127bbe13Stomee } 450127bbe13Stomee } 451127bbe13Stomee 452127bbe13Stomee /** 453127bbe13Stomee * Gets a string representation of this {@code 454127bbe13Stomee * UserSymbolRecord.Value} instance useful for logging and not 455127bbe13Stomee * intended for display. The exact details of the 456127bbe13Stomee * representation are unspecified and subject to change, but the 457127bbe13Stomee * following format may be regarded as typical: 458127bbe13Stomee * <pre><code> 459127bbe13Stomee * class-name[property1 = value1, property2 = value2] 460127bbe13Stomee * </code></pre> 461127bbe13Stomee */ 462127bbe13Stomee public String toString()463127bbe13Stomee toString() 464127bbe13Stomee { 465127bbe13Stomee StringBuilder buf = new StringBuilder(); 466127bbe13Stomee buf.append(Value.class.getName()); 467127bbe13Stomee buf.append("[processID = "); 468127bbe13Stomee buf.append(processID); 469127bbe13Stomee buf.append(", address = "); 470127bbe13Stomee buf.append(address); 471127bbe13Stomee buf.append(']'); 472127bbe13Stomee return buf.toString(); 473127bbe13Stomee } 474127bbe13Stomee } 475127bbe13Stomee } 476