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