1 /*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2005 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 package org.objectweb.asm.util; 31 32 import java.util.HashMap; 33 34 import org.objectweb.asm.AnnotationVisitor; 35 import org.objectweb.asm.Attribute; 36 import org.objectweb.asm.Handle; 37 import org.objectweb.asm.TypeAnnotationVisitor; 38 import org.objectweb.asm.Label; 39 import org.objectweb.asm.MethodVisitor; 40 import org.objectweb.asm.Opcodes; 41 import org.objectweb.asm.Type; 42 import org.objectweb.asm.TypePath; 43 import org.objectweb.asm.signature.SignatureReader; 44 import org.objectweb.asm.util.attrs.Traceable; 45 46 /** 47 * A {@link MethodVisitor} that prints a disassembled view of the methods it 48 * visits. 49 * 50 * @author Eric Bruneton 51 */ 52 public class TraceMethodVisitor extends TraceAbstractVisitor implements 53 MethodVisitor 54 { 55 /** 56 * The {@link MethodVisitor} to which this visitor delegates calls. May be 57 * <tt>null</tt>. 58 */ 59 protected MethodVisitor mv; 60 61 /** 62 * Tab for bytecode instructions. 63 */ 64 protected String tab2 = " "; 65 66 /** 67 * Tab for table and lookup switch instructions. 68 */ 69 protected String tab3 = " "; 70 71 /** 72 * Tab for labels. 73 */ 74 protected String ltab = " "; 75 76 /** 77 * The label names. This map associate String values to Label keys. 78 */ 79 protected final HashMap labelNames; 80 81 /** 82 * Constructs a new {@link TraceMethodVisitor}. 83 */ 84 public TraceMethodVisitor() { 85 this(null); 86 } 87 88 /** 89 * Constructs a new {@link TraceMethodVisitor}. 90 * 91 * @param mv the {@link MethodVisitor} to which this visitor delegates 92 * calls. May be <tt>null</tt>. 93 */ 94 public TraceMethodVisitor(final MethodVisitor mv) { 95 this.labelNames = new HashMap(); 96 this.mv = mv; 97 } 98 99 // ------------------------------------------------------------------------ 100 // Implementation of the MethodVisitor interface 101 // ------------------------------------------------------------------------ 102 103 public AnnotationVisitor visitAnnotation( 104 final String desc, 105 final boolean visible) 106 { 107 AnnotationVisitor av = super.visitAnnotation(desc, visible); 108 if (mv != null) { 109 ((TraceAnnotationVisitor) av).av = mv.visitAnnotation(desc, visible); 110 } 111 return av; 112 } 113 114 // jaime 115 public TypeAnnotationVisitor visitTypeAnnotation( 116 final String desc, 117 final boolean visible, 118 final boolean inCode) 119 { 120 TypeAnnotationVisitor xav = super.visitTypeAnnotation(desc, visible); 121 if (mv != null) { 122 ((TraceTypeAnnotationVisitor) xav).xav = 123 mv.visitTypeAnnotation(desc, visible, inCode); 124 } 125 return xav; 126 } 127 //end jaime 128 129 public void visitAttribute(final Attribute attr) { 130 buf.setLength(0); 131 buf.append(tab).append("ATTRIBUTE "); 132 appendDescriptor(-1, attr.type); 133 134 if (attr instanceof Traceable) { 135 ((Traceable) attr).trace(buf, labelNames); 136 } else { 137 buf.append(" : ").append(attr.toString()).append("\n"); 138 } 139 140 text.add(buf.toString()); 141 if (mv != null) { 142 mv.visitAttribute(attr); 143 } 144 } 145 146 public AnnotationVisitor visitAnnotationDefault() { 147 text.add(tab2 + "default="); 148 TraceAnnotationVisitor tav = new TraceAnnotationVisitor(); 149 text.add(tav.getText()); 150 text.add("\n"); 151 if (mv != null) { 152 tav.av = mv.visitAnnotationDefault(); 153 } 154 return tav; 155 } 156 157 public AnnotationVisitor visitParameterAnnotation( 158 final int parameter, 159 final String desc, 160 final boolean visible) 161 { 162 buf.setLength(0); 163 buf.append(tab2).append('@'); 164 appendDescriptor(FIELD_DESCRIPTOR, desc); 165 buf.append('('); 166 text.add(buf.toString()); 167 TraceAnnotationVisitor tav = new TraceAnnotationVisitor(); 168 text.add(tav.getText()); 169 text.add(visible ? ") // parameter " : ") // invisible, parameter "); 170 text.add(new Integer(parameter)); 171 text.add("\n"); 172 if (mv != null) { 173 tav.av = mv.visitParameterAnnotation(parameter, desc, visible); 174 } 175 return tav; 176 } 177 178 public void visitCode() { 179 if (mv != null) { 180 mv.visitCode(); 181 } 182 } 183 184 public void visitInsn(final int opcode) { 185 buf.setLength(0); 186 buf.append(tab2).append(OPCODES[opcode]).append('\n'); 187 text.add(buf.toString()); 188 189 if (mv != null) { 190 mv.visitInsn(opcode); 191 } 192 } 193 194 public void visitIntInsn(final int opcode, final int operand) { 195 buf.setLength(0); 196 buf.append(tab2) 197 .append(OPCODES[opcode]) 198 .append(' ') 199 .append(opcode == Opcodes.NEWARRAY 200 ? TYPES[operand] 201 : Integer.toString(operand)) 202 .append('\n'); 203 text.add(buf.toString()); 204 205 if (mv != null) { 206 mv.visitIntInsn(opcode, operand); 207 } 208 } 209 210 public void visitVarInsn(final int opcode, final int var) { 211 buf.setLength(0); 212 buf.append(tab2) 213 .append(OPCODES[opcode]) 214 .append(' ') 215 .append(var) 216 .append('\n'); 217 text.add(buf.toString()); 218 219 if (mv != null) { 220 mv.visitVarInsn(opcode, var); 221 } 222 } 223 224 public void visitTypeInsn(final int opcode, final String desc) { 225 buf.setLength(0); 226 buf.append(tab2).append(OPCODES[opcode]).append(' '); 227 if (desc.startsWith("[")) { 228 appendDescriptor(FIELD_DESCRIPTOR, desc); 229 } else { 230 appendDescriptor(INTERNAL_NAME, desc); 231 } 232 buf.append('\n'); 233 text.add(buf.toString()); 234 235 if (mv != null) { 236 mv.visitTypeInsn(opcode, desc); 237 } 238 } 239 240 public void visitFieldInsn( 241 final int opcode, 242 final String owner, 243 final String name, 244 final String desc) 245 { 246 buf.setLength(0); 247 buf.append(tab2).append(OPCODES[opcode]).append(' '); 248 appendDescriptor(INTERNAL_NAME, owner); 249 buf.append('.').append(name).append(" : "); 250 appendDescriptor(FIELD_DESCRIPTOR, desc); 251 buf.append('\n'); 252 text.add(buf.toString()); 253 254 if (mv != null) { 255 mv.visitFieldInsn(opcode, owner, name, desc); 256 } 257 } 258 259 public void visitMethodInsn( 260 final int opcode, 261 final String owner, 262 final String name, 263 final String desc) 264 { 265 buf.setLength(0); 266 buf.append(tab2).append(OPCODES[opcode]).append(' '); 267 appendDescriptor(INTERNAL_NAME, owner); 268 buf.append('.').append(name).append(' '); 269 appendDescriptor(METHOD_DESCRIPTOR, desc); 270 buf.append('\n'); 271 text.add(buf.toString()); 272 273 if (mv != null) { 274 mv.visitMethodInsn(opcode, owner, name, desc); 275 } 276 } 277 278 @Override 279 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, 280 Object... bsmArgs) { 281 // TODO Auto-generated method stub 282 283 } 284 285 @Override 286 public AnnotationVisitor visitInsnAnnotation(int typeRef, 287 TypePath typePath, String desc, boolean visible) { 288 // TODO Auto-generated method stub 289 return null; 290 } 291 292 public void visitJumpInsn(final int opcode, final Label label) { 293 buf.setLength(0); 294 buf.append(tab2).append(OPCODES[opcode]).append(' '); 295 appendLabel(label); 296 buf.append('\n'); 297 text.add(buf.toString()); 298 299 if (mv != null) { 300 mv.visitJumpInsn(opcode, label); 301 } 302 } 303 304 public void visitLabel(final Label label) { 305 buf.setLength(0); 306 buf.append(ltab); 307 appendLabel(label); 308 buf.append('\n'); 309 text.add(buf.toString()); 310 311 if (mv != null) { 312 mv.visitLabel(label); 313 } 314 } 315 316 public void visitLdcInsn(final Object cst) { 317 buf.setLength(0); 318 buf.append(tab2).append("LDC "); 319 if (cst instanceof String) { 320 AbstractVisitor.appendString(buf, (String) cst); 321 } else if (cst instanceof Type) { 322 buf.append(((Type) cst).getDescriptor() + ".class"); 323 } else { 324 buf.append(cst); 325 } 326 buf.append('\n'); 327 text.add(buf.toString()); 328 329 if (mv != null) { 330 mv.visitLdcInsn(cst); 331 } 332 } 333 334 public void visitIincInsn(final int var, final int increment) { 335 buf.setLength(0); 336 buf.append(tab2) 337 .append("IINC ") 338 .append(var) 339 .append(' ') 340 .append(increment) 341 .append('\n'); 342 text.add(buf.toString()); 343 344 if (mv != null) { 345 mv.visitIincInsn(var, increment); 346 } 347 } 348 349 public void visitTableSwitchInsn( 350 final int min, 351 final int max, 352 final Label dflt, 353 final Label labels[]) 354 { 355 buf.setLength(0); 356 buf.append(tab2).append("TABLESWITCH\n"); 357 for (int i = 0; i < labels.length; ++i) { 358 buf.append(tab3).append(min + i).append(": "); 359 appendLabel(labels[i]); 360 buf.append('\n'); 361 } 362 buf.append(tab3).append("default: "); 363 appendLabel(dflt); 364 buf.append('\n'); 365 text.add(buf.toString()); 366 367 if (mv != null) { 368 mv.visitTableSwitchInsn(min, max, dflt, labels); 369 } 370 } 371 372 public void visitLookupSwitchInsn( 373 final Label dflt, 374 final int keys[], 375 final Label labels[]) 376 { 377 buf.setLength(0); 378 buf.append(tab2).append("LOOKUPSWITCH\n"); 379 for (int i = 0; i < labels.length; ++i) { 380 buf.append(tab3).append(keys[i]).append(": "); 381 appendLabel(labels[i]); 382 buf.append('\n'); 383 } 384 buf.append(tab3).append("default: "); 385 appendLabel(dflt); 386 buf.append('\n'); 387 text.add(buf.toString()); 388 389 if (mv != null) { 390 mv.visitLookupSwitchInsn(dflt, keys, labels); 391 } 392 } 393 394 public void visitMultiANewArrayInsn(final String desc, final int dims) { 395 buf.setLength(0); 396 buf.append(tab2).append("MULTIANEWARRAY "); 397 appendDescriptor(FIELD_DESCRIPTOR, desc); 398 buf.append(' ').append(dims).append('\n'); 399 text.add(buf.toString()); 400 401 if (mv != null) { 402 mv.visitMultiANewArrayInsn(desc, dims); 403 } 404 } 405 406 public void visitTryCatchBlock( 407 final Label start, 408 final Label end, 409 final Label handler, 410 final String type) 411 { 412 buf.setLength(0); 413 buf.append(tab2).append("TRYCATCHBLOCK "); 414 appendLabel(start); 415 buf.append(' '); 416 appendLabel(end); 417 buf.append(' '); 418 appendLabel(handler); 419 buf.append(' '); 420 appendDescriptor(INTERNAL_NAME, type); 421 buf.append('\n'); 422 text.add(buf.toString()); 423 424 if (mv != null) { 425 mv.visitTryCatchBlock(start, end, handler, type); 426 } 427 } 428 429 public void visitLocalVariable( 430 final String name, 431 final String desc, 432 final String signature, 433 final Label start, 434 final Label end, 435 final int index) 436 { 437 buf.setLength(0); 438 buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' '); 439 appendDescriptor(FIELD_DESCRIPTOR, desc); 440 buf.append(' '); 441 appendLabel(start); 442 buf.append(' '); 443 appendLabel(end); 444 buf.append(' ').append(index).append('\n'); 445 446 if (signature != null) { 447 buf.append(tab2); 448 appendDescriptor(FIELD_SIGNATURE, signature); 449 450 TraceSignatureVisitor sv = new TraceSignatureVisitor(0); 451 SignatureReader r = new SignatureReader(signature); 452 r.acceptType(sv); 453 buf.append(tab2) 454 .append("// declaration: ") 455 .append(sv.getDeclaration()) 456 .append('\n'); 457 } 458 text.add(buf.toString()); 459 460 if (mv != null) { 461 mv.visitLocalVariable(name, desc, signature, start, end, index); 462 } 463 } 464 465 public void visitLineNumber(final int line, final Label start) { 466 buf.setLength(0); 467 buf.append(tab2).append("LINENUMBER ").append(line).append(' '); 468 appendLabel(start); 469 buf.append('\n'); 470 text.add(buf.toString()); 471 472 if (mv != null) { 473 mv.visitLineNumber(line, start); 474 } 475 } 476 477 public void visitMaxs(final int maxStack, final int maxLocals) { 478 buf.setLength(0); 479 buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n'); 480 text.add(buf.toString()); 481 482 buf.setLength(0); 483 buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n'); 484 text.add(buf.toString()); 485 486 if (mv != null) { 487 mv.visitMaxs(maxStack, maxLocals); 488 } 489 } 490 491 public void visitEnd() { 492 super.visitEnd(); 493 494 if (mv != null) { 495 mv.visitEnd(); 496 } 497 } 498 499 // ------------------------------------------------------------------------ 500 // Utility methods 501 // ------------------------------------------------------------------------ 502 503 /** 504 * Appends the name of the given label to {@link #buf buf}. Creates a new 505 * label name if the given label does not yet have one. 506 * 507 * @param l a label. 508 */ 509 public void appendLabel(final Label l) { 510 String name = (String) labelNames.get(l); 511 if (name == null) { 512 name = "L" + labelNames.size(); 513 labelNames.put(l, name); 514 } 515 buf.append(name); 516 } 517 } 518