1/* 2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.instrument; 27 28import java.lang.instrument.Instrumentation; 29import java.lang.instrument.ClassFileTransformer; 30import java.security.ProtectionDomain; 31 32/* 33 * Copyright 2003 Wily Technology, Inc. 34 */ 35 36/** 37 * Support class for the InstrumentationImpl. Manages the list of registered transformers. 38 * Keeps everything in the right order, deals with sync of the list, 39 * and actually does the calling of the transformers. 40 */ 41public class TransformerManager 42{ 43 private class TransformerInfo { 44 final ClassFileTransformer mTransformer; 45 String mPrefix; 46 47 TransformerInfo(ClassFileTransformer transformer) { 48 mTransformer = transformer; 49 mPrefix = null; 50 } 51 52 ClassFileTransformer transformer() { 53 return mTransformer; 54 } 55 56 String getPrefix() { 57 return mPrefix; 58 } 59 60 void setPrefix(String prefix) { 61 mPrefix = prefix; 62 } 63 } 64 65 /** 66 * a given instance of this list is treated as immutable to simplify sync; 67 * we pay copying overhead whenever the list is changed rather than every time 68 * the list is referenced. 69 * The array is kept in the order the transformers are added via addTransformer 70 * (first added is 0, last added is length-1) 71 * Use an array, not a List or other Collection. This keeps the set of classes 72 * used by this code to a minimum. We want as few dependencies as possible in this 73 * code, since it is used inside the class definition system. Any class referenced here 74 * cannot be transformed by Java code. 75 */ 76 private TransformerInfo[] mTransformerList; 77 78 /*** 79 * Is this TransformerManager for transformers capable of retransformation? 80 */ 81 private boolean mIsRetransformable; 82 83 TransformerManager(boolean isRetransformable) { 84 mTransformerList = new TransformerInfo[0]; 85 mIsRetransformable = isRetransformable; 86 } 87 88 boolean isRetransformable() { 89 return mIsRetransformable; 90 } 91 92 public synchronized void 93 addTransformer( ClassFileTransformer transformer) { 94 TransformerInfo[] oldList = mTransformerList; 95 TransformerInfo[] newList = new TransformerInfo[oldList.length + 1]; 96 System.arraycopy( oldList, 97 0, 98 newList, 99 0, 100 oldList.length); 101 newList[oldList.length] = new TransformerInfo(transformer); 102 mTransformerList = newList; 103 } 104 105 public synchronized boolean 106 removeTransformer(ClassFileTransformer transformer) { 107 boolean found = false; 108 TransformerInfo[] oldList = mTransformerList; 109 int oldLength = oldList.length; 110 int newLength = oldLength - 1; 111 112 // look for it in the list, starting at the last added, and remember 113 // where it was if we found it 114 int matchingIndex = 0; 115 for ( int x = oldLength - 1; x >= 0; x-- ) { 116 if ( oldList[x].transformer() == transformer ) { 117 found = true; 118 matchingIndex = x; 119 break; 120 } 121 } 122 123 // make a copy of the array without the matching element 124 if ( found ) { 125 TransformerInfo[] newList = new TransformerInfo[newLength]; 126 127 // copy up to but not including the match 128 if ( matchingIndex > 0 ) { 129 System.arraycopy( oldList, 130 0, 131 newList, 132 0, 133 matchingIndex); 134 } 135 136 // if there is anything after the match, copy it as well 137 if ( matchingIndex < (newLength) ) { 138 System.arraycopy( oldList, 139 matchingIndex + 1, 140 newList, 141 matchingIndex, 142 (newLength) - matchingIndex); 143 } 144 mTransformerList = newList; 145 } 146 return found; 147 } 148 149 synchronized boolean 150 includesTransformer(ClassFileTransformer transformer) { 151 for (TransformerInfo info : mTransformerList) { 152 if ( info.transformer() == transformer ) { 153 return true; 154 } 155 } 156 return false; 157 } 158 159 // This function doesn't actually snapshot anything, but should be 160 // used to set a local variable, which will snapshot the transformer 161 // list because of the copying semantics of mTransformerList (see 162 // the comment for mTransformerList). 163 private TransformerInfo[] 164 getSnapshotTransformerList() { 165 return mTransformerList; 166 } 167 168 public byte[] 169 transform( Module module, 170 ClassLoader loader, 171 String classname, 172 Class<?> classBeingRedefined, 173 ProtectionDomain protectionDomain, 174 byte[] classfileBuffer) { 175 boolean someoneTouchedTheBytecode = false; 176 177 TransformerInfo[] transformerList = getSnapshotTransformerList(); 178 179 byte[] bufferToUse = classfileBuffer; 180 181 // order matters, gotta run 'em in the order they were added 182 for ( int x = 0; x < transformerList.length; x++ ) { 183 TransformerInfo transformerInfo = transformerList[x]; 184 ClassFileTransformer transformer = transformerInfo.transformer(); 185 byte[] transformedBytes = null; 186 187 try { 188 transformedBytes = transformer.transform( module, 189 loader, 190 classname, 191 classBeingRedefined, 192 protectionDomain, 193 bufferToUse); 194 } 195 catch (Throwable t) { 196 // don't let any one transformer mess it up for the others. 197 // This is where we need to put some logging. What should go here? FIXME 198 } 199 200 if ( transformedBytes != null ) { 201 someoneTouchedTheBytecode = true; 202 bufferToUse = transformedBytes; 203 } 204 } 205 206 // if someone modified it, return the modified buffer. 207 // otherwise return null to mean "no transforms occurred" 208 byte [] result; 209 if ( someoneTouchedTheBytecode ) { 210 result = bufferToUse; 211 } 212 else { 213 result = null; 214 } 215 216 return result; 217 } 218 219 220 int 221 getTransformerCount() { 222 TransformerInfo[] transformerList = getSnapshotTransformerList(); 223 return transformerList.length; 224 } 225 226 boolean 227 setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) { 228 TransformerInfo[] transformerList = getSnapshotTransformerList(); 229 230 for ( int x = 0; x < transformerList.length; x++ ) { 231 TransformerInfo transformerInfo = transformerList[x]; 232 ClassFileTransformer aTransformer = transformerInfo.transformer(); 233 234 if ( aTransformer == transformer ) { 235 transformerInfo.setPrefix(prefix); 236 return true; 237 } 238 } 239 return false; 240 } 241 242 243 String[] 244 getNativeMethodPrefixes() { 245 TransformerInfo[] transformerList = getSnapshotTransformerList(); 246 String[] prefixes = new String[transformerList.length]; 247 248 for ( int x = 0; x < transformerList.length; x++ ) { 249 TransformerInfo transformerInfo = transformerList[x]; 250 prefixes[x] = transformerInfo.getPrefix(); 251 } 252 return prefixes; 253 } 254} 255