1 /* 2 * Copyright (c) 2007, 2018, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package nsk.share.jdi.sde; 24 25 import java.io.File; 26 import java.io.FileInputStream; 27 import java.io.FileOutputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.UnsupportedEncodingException; 31 32 import nsk.share.Consts; 33 34 /* 35 * Inserts in class file 'SourceDebugExtension' attribute based on input .SMAP file. 36 */ 37 public class InstallSDE { 38 static final String nameSDE = "SourceDebugExtension"; 39 40 private byte[] orig; 41 42 private byte[] sdeAttr; 43 44 private byte[] gen; 45 46 private int origPos = 0; 47 48 private int genPos = 0; 49 50 private int sdeIndex; 51 install(File inClassFile, File smapFile, File outClassFile, boolean verbose)52 public static void install(File inClassFile, File smapFile, File outClassFile, boolean verbose) throws IOException { 53 new InstallSDE(inClassFile, smapFile, outClassFile, verbose); 54 } 55 install(byte[] aOrig, byte[] aSdeAttr, File outClassFile, boolean verbose)56 public static void install(byte[] aOrig, byte[] aSdeAttr, File outClassFile, boolean verbose) throws IOException { 57 new InstallSDE(aOrig, aSdeAttr, outClassFile, verbose); 58 } 59 install(File inOutClassFile, File attrFile, boolean verbose)60 public static void install(File inOutClassFile, File attrFile, boolean verbose) throws IOException { 61 File tmpFile = new File(inOutClassFile.getPath() + "tmp"); 62 63 new InstallSDE(inOutClassFile, attrFile, tmpFile, verbose); 64 65 if (!inOutClassFile.delete()) { 66 throw new IOException("inOutClassFile.delete() failed"); 67 } 68 if (!tmpFile.renameTo(inOutClassFile)) { 69 throw new IOException("tmpFile.renameTo(inOutClassFile) failed"); 70 } 71 } 72 abort(String msg)73 private static void abort(String msg) { 74 System.err.println(msg); 75 System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); 76 } 77 InstallSDE(File inClassFile, File attrFile, File outClassFile, boolean verbose)78 private InstallSDE(File inClassFile, File attrFile, File outClassFile, boolean verbose) throws IOException { 79 if (!inClassFile.exists()) { 80 abort("no such file: " + inClassFile); 81 } 82 if (!attrFile.exists()) { 83 abort("no such file: " + attrFile); 84 } 85 86 // get the bytes 87 orig = readWhole(inClassFile); 88 sdeAttr = readWhole(attrFile); 89 gen = new byte[orig.length + sdeAttr.length + 100]; 90 91 // do it 92 addSDE(verbose); 93 94 // write result 95 FileOutputStream outStream = new FileOutputStream(outClassFile); 96 outStream.write(gen, 0, genPos); 97 outStream.close(); 98 } 99 InstallSDE(byte[] aOrig, byte[] aSdeAttr, File outClassFile, boolean verbose)100 private InstallSDE(byte[] aOrig, byte[] aSdeAttr, File outClassFile, boolean verbose) throws IOException { 101 orig = aOrig; 102 sdeAttr = aSdeAttr; 103 gen = new byte[orig.length + sdeAttr.length + 100]; 104 105 // do it 106 addSDE(verbose); 107 108 // write result 109 FileOutputStream outStream = new FileOutputStream(outClassFile); 110 outStream.write(gen, 0, genPos); 111 outStream.close(); 112 } 113 readWhole(File input)114 private byte[] readWhole(File input) throws IOException { 115 FileInputStream inStream = new FileInputStream(input); 116 try { 117 return readWhole(inStream, (int) input.length()); 118 } finally { 119 inStream.close(); 120 } 121 } 122 readWhole(InputStream inStream, int len)123 private byte[] readWhole(InputStream inStream, int len) throws IOException { 124 byte[] bytes = new byte[len]; 125 126 if (inStream.read(bytes, 0, len) != len) { 127 abort("expected size: " + len); 128 } 129 130 return bytes; 131 } 132 addSDE(boolean verbose)133 private void addSDE(boolean verbose) throws UnsupportedEncodingException { 134 copy(4 + 2 + 2); // magic min/maj version 135 int constantPoolCountPos = genPos; 136 int constantPoolCount = readU2(); 137 writeU2(constantPoolCount); 138 // copy old constant pool return index of SDE symbol, if found 139 sdeIndex = copyConstantPool(constantPoolCount, verbose); 140 if (sdeIndex < 0) { 141 // if "SourceDebugExtension" symbol not there add it 142 writeUtf8ForSDE(); 143 144 // increment the countantPoolCount 145 sdeIndex = constantPoolCount; 146 ++constantPoolCount; 147 randomAccessWriteU2(constantPoolCountPos, constantPoolCount); 148 149 if (verbose) { 150 System.out.println("SourceDebugExtension not found, installed at: " + sdeIndex); 151 } 152 } else { 153 if (verbose) { 154 System.out.println("SourceDebugExtension found at: " + sdeIndex); 155 } 156 } 157 copy(2 + 2 + 2); // access, this, super 158 int interfaceCount = readU2(); 159 writeU2(interfaceCount); 160 if (verbose) { 161 System.out.println("interfaceCount: " + interfaceCount); 162 } 163 copy(interfaceCount * 2); 164 copyMembers(verbose); // fields 165 copyMembers(verbose); // methods 166 int attrCountPos = genPos; 167 int attrCount = readU2(); 168 writeU2(attrCount); 169 if (verbose) { 170 System.out.println("class attrCount: " + attrCount); 171 } 172 // copy the class attributes, return true if SDE attr found (not copied) 173 if (!copyAttrs(attrCount, verbose)) { 174 // we will be adding SDE and it isn't already counted 175 ++attrCount; 176 randomAccessWriteU2(attrCountPos, attrCount); 177 if (verbose) { 178 System.out.println("class attrCount incremented"); 179 } 180 } 181 writeAttrForSDE(sdeIndex); 182 } 183 copyMembers(boolean verbose)184 private void copyMembers(boolean verbose) { 185 int count = readU2(); 186 writeU2(count); 187 if (verbose) { 188 System.out.println("members count: " + count); 189 } 190 for (int i = 0; i < count; ++i) { 191 copy(6); // access, name, descriptor 192 int attrCount = readU2(); 193 writeU2(attrCount); 194 if (verbose) { 195 System.out.println("member attr count: " + attrCount); 196 } 197 copyAttrs(attrCount, verbose); 198 } 199 } 200 copyAttrs(int attrCount, boolean verbose)201 private boolean copyAttrs(int attrCount, boolean verbose) { 202 boolean sdeFound = false; 203 for (int i = 0; i < attrCount; ++i) { 204 int nameIndex = readU2(); 205 // don't write old SDE 206 if (nameIndex == sdeIndex) { 207 sdeFound = true; 208 if (verbose) { 209 System.out.println("SDE attr found"); 210 } 211 } else { 212 writeU2(nameIndex); // name 213 int len = readU4(); 214 writeU4(len); 215 copy(len); 216 if (verbose) { 217 System.out.println("attr len: " + len); 218 } 219 } 220 } 221 return sdeFound; 222 } 223 writeAttrForSDE(int index)224 private void writeAttrForSDE(int index) { 225 writeU2(index); 226 writeU4(sdeAttr.length); 227 for (int i = 0; i < sdeAttr.length; ++i) { 228 writeU1(sdeAttr[i]); 229 } 230 } 231 randomAccessWriteU2(int pos, int val)232 private void randomAccessWriteU2(int pos, int val) { 233 int savePos = genPos; 234 genPos = pos; 235 writeU2(val); 236 genPos = savePos; 237 } 238 readU1()239 private int readU1() { 240 return ((int) orig[origPos++]) & 0xFF; 241 } 242 readU2()243 private int readU2() { 244 int res = readU1(); 245 return (res << 8) + readU1(); 246 } 247 readU4()248 private int readU4() { 249 int res = readU2(); 250 return (res << 16) + readU2(); 251 } 252 writeU1(int val)253 private void writeU1(int val) { 254 gen[genPos++] = (byte) val; 255 } 256 writeU2(int val)257 private void writeU2(int val) { 258 writeU1(val >> 8); 259 writeU1(val & 0xFF); 260 } 261 writeU4(int val)262 private void writeU4(int val) { 263 writeU2(val >> 16); 264 writeU2(val & 0xFFFF); 265 } 266 copy(int count)267 private void copy(int count) { 268 for (int i = 0; i < count; ++i) { 269 gen[genPos++] = orig[origPos++]; 270 } 271 } 272 readBytes(int count)273 private byte[] readBytes(int count) { 274 byte[] bytes = new byte[count]; 275 for (int i = 0; i < count; ++i) { 276 bytes[i] = orig[origPos++]; 277 } 278 return bytes; 279 } 280 writeBytes(byte[] bytes)281 private void writeBytes(byte[] bytes) { 282 for (int i = 0; i < bytes.length; ++i) { 283 gen[genPos++] = bytes[i]; 284 } 285 } 286 copyConstantPool(int constantPoolCount, boolean verbose)287 private int copyConstantPool(int constantPoolCount, boolean verbose) throws UnsupportedEncodingException { 288 int sdeIndex = -1; 289 // copy const pool index zero not in class file 290 if ( verbose ) 291 System.out.println("cp count=" + constantPoolCount); 292 for (int i = 1; i < constantPoolCount; ++i) { 293 int tag = readU1(); 294 writeU1(tag); 295 if ( verbose ) 296 System.out.println(i + ": tag=" + tag); 297 switch (tag) { 298 case 7: // Class 299 case 8: // String 300 case 16: // MethodType 301 copy(2); 302 break; 303 case 15: // MethodHandle 304 copy(3); 305 break; 306 case 9: // Field 307 case 10: // Method 308 case 11: // InterfaceMethod 309 case 3: // Integer 310 case 4: // Float 311 case 12: // NameAndType 312 case 17: // InvokeDynamic_17 (will go away) 313 case 18: // InokeDynamic 314 copy(4); 315 break; 316 case 5: // Long 317 case 6: // Double 318 copy(8); 319 ++i; 320 break; 321 case 1: // Utf8 322 int len = readU2(); 323 writeU2(len); 324 byte[] utf8 = readBytes(len); 325 String str = new String(utf8, "UTF-8"); 326 if (verbose) { 327 System.out.println(i + " read class attr -- '" + str + "'"); 328 } 329 if (str.equals(nameSDE)) { 330 sdeIndex = i; 331 } 332 writeBytes(utf8); 333 break; 334 default: 335 abort("unexpected tag: " + tag); 336 break; 337 } 338 } 339 return sdeIndex; 340 } 341 writeUtf8ForSDE()342 private void writeUtf8ForSDE() { 343 int len = nameSDE.length(); 344 writeU1(1); // Utf8 tag 345 writeU2(len); 346 for (int i = 0; i < len; ++i) { 347 writeU1(nameSDE.charAt(i)); 348 } 349 } 350 } 351