1 30 package com.tc.asm.util; 31 32 import java.io.FileInputStream ; 33 import java.io.PrintWriter ; 34 import java.util.List ; 35 36 import com.tc.asm.AnnotationVisitor; 37 import com.tc.asm.FieldVisitor; 38 import com.tc.asm.ClassAdapter; 39 import com.tc.asm.ClassReader; 40 import com.tc.asm.ClassVisitor; 41 import com.tc.asm.MethodVisitor; 42 import com.tc.asm.Opcodes; 43 import com.tc.asm.Attribute; 44 import com.tc.asm.Type; 45 import com.tc.asm.tree.AbstractInsnNode; 46 import com.tc.asm.tree.MethodNode; 47 import com.tc.asm.tree.ClassNode; 48 import com.tc.asm.tree.TryCatchBlockNode; 49 import com.tc.asm.tree.analysis.Analyzer; 50 import com.tc.asm.tree.analysis.SimpleVerifier; 51 import com.tc.asm.tree.analysis.Frame; 52 53 64 public class CheckClassAdapter extends ClassAdapter { 65 66 69 private boolean start; 70 71 74 private boolean source; 75 76 79 private boolean outer; 80 81 84 private boolean end; 85 86 95 public static void main(final String [] args) throws Exception { 96 if (args.length != 1) { 97 System.err.println("Verifies the given class."); 98 System.err.println("Usage: CheckClassAdapter " 99 + "<fully qualified class name or class file name>"); 100 return; 101 } 102 ClassReader cr; 103 if (args[0].endsWith(".class")) { 104 cr = new ClassReader(new FileInputStream (args[0])); 105 } else { 106 cr = new ClassReader(args[0]); 107 } 108 109 verify(cr, false, new PrintWriter (System.err)); 110 } 111 112 119 public static void verify(ClassReader cr, boolean dump, PrintWriter pw) { 120 ClassNode cn = new ClassNode(); 121 cr.accept(new CheckClassAdapter(cn), true); 122 123 List methods = cn.methods; 124 for (int i = 0; i < methods.size(); ++i) { 125 MethodNode method = (MethodNode) methods.get(i); 126 if (method.instructions.size() > 0) { 127 Analyzer a = new Analyzer(new SimpleVerifier(Type.getType("L" 128 + cn.name + ";"), 129 Type.getType("L" + cn.superName + ";"), 130 (cn.access & Opcodes.ACC_INTERFACE) != 0)); 131 try { 132 a.analyze(cn.name, method); 133 if (!dump) { 134 continue; 135 } 136 } catch (Exception e) { 137 e.printStackTrace(); 138 } 139 Frame[] frames = a.getFrames(); 140 141 TraceMethodVisitor mv = new TraceMethodVisitor(); 142 143 pw.println(method.name + method.desc); 144 for (int j = 0; j < method.instructions.size(); ++j) { 145 ((AbstractInsnNode) method.instructions.get(j)).accept(mv); 146 147 StringBuffer s = new StringBuffer (); 148 Frame f = frames[j]; 149 if (f == null) { 150 s.append('?'); 151 } else { 152 for (int k = 0; k < f.getLocals(); ++k) { 153 s.append(getShortName(f.getLocal(k).toString())) 154 .append(' '); 155 } 156 s.append(" : "); 157 for (int k = 0; k < f.getStackSize(); ++k) { 158 s.append(getShortName(f.getStack(k).toString())) 159 .append(' '); 160 } 161 } 162 while (s.length() < method.maxStack + method.maxLocals + 1) 163 { 164 s.append(' '); 165 } 166 pw.print(Integer.toString(j + 100000).substring(1)); 167 pw.print(" " + s + " : " + mv.buf); } 169 for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { 170 ((TryCatchBlockNode) method.tryCatchBlocks.get(j)).accept(mv); 171 pw.print(" " + mv.buf); 172 } 173 pw.println(); 174 } 175 } 176 } 177 178 private static String getShortName(String name) { 179 int n = name.lastIndexOf('/'); 180 int k = name.length(); 181 if(name.charAt(k-1)==';') k--; 182 return n==-1 ? name : name.substring(n+1, k); 183 } 184 185 190 public CheckClassAdapter(final ClassVisitor cv) { 191 super(cv); 192 } 193 194 198 public void visit( 199 final int version, 200 final int access, 201 final String name, 202 final String signature, 203 final String superName, 204 final String [] interfaces) 205 { 206 if (start) { 207 throw new IllegalStateException ("visit must be called only once"); 208 } else { 209 start = true; 210 } 211 checkState(); 212 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL 213 + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE 214 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC 215 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM 216 + Opcodes.ACC_DEPRECATED); 217 CheckMethodAdapter.checkInternalName(name, "class name"); 218 if ("java/lang/Object".equals(name)) { 219 if (superName != null) { 220 throw new IllegalArgumentException ("The super class name of the Object class must be 'null'"); 221 } 222 } else { 223 CheckMethodAdapter.checkInternalName(superName, "super class name"); 224 } 225 if (signature != null) { 226 } 228 if ((access & Opcodes.ACC_INTERFACE) != 0) { 229 if (!"java/lang/Object".equals(superName)) { 230 throw new IllegalArgumentException ("The super class name of interfaces must be 'java/lang/Object'"); 231 } 232 } 233 if (interfaces != null) { 234 for (int i = 0; i < interfaces.length; ++i) { 235 CheckMethodAdapter.checkInternalName(interfaces[i], 236 "interface name at index " + i); 237 } 238 } 239 cv.visit(version, access, name, signature, superName, interfaces); 240 } 241 242 public void visitSource(final String file, final String debug) { 243 checkState(); 244 if (source) { 245 throw new IllegalStateException ("visitSource can be called only once."); 246 } 247 source = true; 248 cv.visitSource(file, debug); 249 } 250 251 public void visitOuterClass( 252 final String owner, 253 final String name, 254 final String desc) 255 { 256 checkState(); 257 if (outer) { 258 throw new IllegalStateException ("visitSource can be called only once."); 259 } 260 outer = true; 261 if (owner == null) { 262 throw new IllegalArgumentException ("Illegal outer class owner"); 263 } 264 if (desc != null) { 265 CheckMethodAdapter.checkMethodDesc(desc); 266 } 267 cv.visitOuterClass(owner, name, desc); 268 } 269 270 public void visitInnerClass( 271 final String name, 272 final String outerName, 273 final String innerName, 274 final int access) 275 { 276 checkState(); 277 CheckMethodAdapter.checkInternalName(name, "class name"); 278 if (outerName != null) { 279 CheckMethodAdapter.checkInternalName(outerName, "outer class name"); 280 } 281 if (innerName != null) { 282 CheckMethodAdapter.checkIdentifier(innerName, "inner class name"); 283 } 284 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE 285 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC 286 + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE 287 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC 288 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM); 289 cv.visitInnerClass(name, outerName, innerName, access); 290 } 291 292 public FieldVisitor visitField( 293 final int access, 294 final String name, 295 final String desc, 296 final String signature, 297 final Object value) 298 { 299 checkState(); 300 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE 301 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC 302 + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE 303 + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC 304 + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED); 305 CheckMethodAdapter.checkIdentifier(name, "field name"); 306 CheckMethodAdapter.checkDesc(desc, false); 307 if (signature != null) { 308 } 310 if (value != null) { 311 CheckMethodAdapter.checkConstant(value); 312 } 313 FieldVisitor av = cv.visitField(access, name, desc, signature, value); 314 return new CheckFieldAdapter(av); 315 } 316 317 public MethodVisitor visitMethod( 318 final int access, 319 final String name, 320 final String desc, 321 final String signature, 322 final String [] exceptions) 323 { 324 checkState(); 325 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE 326 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC 327 + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED 328 + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE 329 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT 330 + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED); 331 CheckMethodAdapter.checkMethodIdentifier(name, "method name"); 332 CheckMethodAdapter.checkMethodDesc(desc); 333 if (signature != null) { 334 } 336 if (exceptions != null) { 337 for (int i = 0; i < exceptions.length; ++i) { 338 CheckMethodAdapter.checkInternalName(exceptions[i], 339 "exception name at index " + i); 340 } 341 } 342 return new CheckMethodAdapter(cv.visitMethod(access, 343 name, 344 desc, 345 signature, 346 exceptions)); 347 } 348 349 public AnnotationVisitor visitAnnotation( 350 final String desc, 351 final boolean visible) 352 { 353 checkState(); 354 CheckMethodAdapter.checkDesc(desc, false); 355 return new CheckAnnotationAdapter(cv.visitAnnotation(desc, visible)); 356 } 357 358 public void visitAttribute(final Attribute attr) { 359 checkState(); 360 if (attr == null) { 361 throw new IllegalArgumentException ("Invalid attribute (must not be null)"); 362 } 363 cv.visitAttribute(attr); 364 } 365 366 public void visitEnd() { 367 checkState(); 368 end = true; 369 cv.visitEnd(); 370 } 371 372 376 380 private void checkState() { 381 if (!start) { 382 throw new IllegalStateException ("Cannot visit member before visit has been called."); 383 } 384 if (end) { 385 throw new IllegalStateException ("Cannot visit member after visitEnd has been called."); 386 } 387 } 388 389 397 static void checkAccess(final int access, final int possibleAccess) { 398 if ((access & ~possibleAccess) != 0) { 399 throw new IllegalArgumentException ("Invalid access flags: " 400 + access); 401 } 402 int pub = ((access & Opcodes.ACC_PUBLIC) != 0 ? 1 : 0); 403 int pri = ((access & Opcodes.ACC_PRIVATE) != 0 ? 1 : 0); 404 int pro = ((access & Opcodes.ACC_PROTECTED) != 0 ? 1 : 0); 405 if (pub + pri + pro > 1) { 406 throw new IllegalArgumentException ("public private and protected are mutually exclusive: " 407 + access); 408 } 409 int fin = ((access & Opcodes.ACC_FINAL) != 0 ? 1 : 0); 410 int abs = ((access & Opcodes.ACC_ABSTRACT) != 0 ? 1 : 0); 411 if (fin + abs > 1) { 412 throw new IllegalArgumentException ("final and abstract are mutually exclusive: " 413 + access); 414 } 415 } 416 } 417 | Popular Tags |