blob: adf98240427f29e9dc394f96f92c3c0cd8df7bfa [file] [log] [blame]
Stuart McCullochbb014372012-06-07 21:57:32 +00001/* Copyright 2006 aQute SARL
2 * Licensed under the Apache License, Version 2.0, see http://www.apache.org/licenses/LICENSE-2.0 */
3package aQute.libg.classdump;
4
5import java.io.*;
6import java.lang.reflect.*;
7
8public class ClassDumper {
Stuart McCulloch2286f232012-06-15 13:27:53 +00009 /**
10 * <pre>
11 * ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its
12 * package.
13 * ACC_FINAL 0x0010 Declared final; no subclasses allowed.
14 * ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the
15 * invokespecial instruction.
16 * ACC_INTERFACE 0x0200 Is an interface, not a
17 * class.
18 * ACC_ABSTRACT 0x0400 Declared abstract; may not be instantiated.
19 * </pre>
20 *
21 * @param mod
22 */
23 final static int ACC_PUBLIC = 0x0001; // Declared public; may be
24 // accessed
25 // from outside its package.
26 final static int ACC_FINAL = 0x0010; // Declared final; no
27 // subclasses
28 // allowed.
29 final static int ACC_SUPER = 0x0020; // Treat superclass methods
30 // specially when invoked by the
31 // invokespecial instruction.
32 final static int ACC_INTERFACE = 0x0200; // Is an interface, not a
33 // classs
34 final static int ACC_ABSTRACT = 0x0400; // Declared abstract; may
35 // not be
36 // instantiated.
Stuart McCullochbb014372012-06-07 21:57:32 +000037
Stuart McCulloch2286f232012-06-15 13:27:53 +000038 final static class Assoc {
39 Assoc(byte tag, int a, int b) {
40 this.tag = tag;
41 this.a = a;
42 this.b = b;
43 }
Stuart McCullochbb014372012-06-07 21:57:32 +000044
Stuart McCulloch2286f232012-06-15 13:27:53 +000045 byte tag;
46 int a;
47 int b;
Stuart McCullochbb014372012-06-07 21:57:32 +000048
Stuart McCulloch2286f232012-06-15 13:27:53 +000049 }
Stuart McCullochbb014372012-06-07 21:57:32 +000050
Stuart McCulloch2286f232012-06-15 13:27:53 +000051 final String path;
52 final static String NUM_COLUMN = "%-30s %d\n";
53 final static String HEX_COLUMN = "%-30s %x\n";
54 final static String STR_COLUMN = "%-30s %s\n";
Stuart McCullochbb014372012-06-07 21:57:32 +000055
Stuart McCulloch2286f232012-06-15 13:27:53 +000056 PrintStream ps = System.err;
57 Object[] pool;
58 InputStream in;
Stuart McCullochbb014372012-06-07 21:57:32 +000059
Stuart McCulloch2286f232012-06-15 13:27:53 +000060 public ClassDumper(String path) throws Exception {
61 this(path, new FileInputStream(new File(path)));
62 }
Stuart McCullochbb014372012-06-07 21:57:32 +000063
Stuart McCulloch2286f232012-06-15 13:27:53 +000064 public ClassDumper(String path, InputStream in) throws IOException {
65 this.path = path;
66 this.in = in;
67 }
Stuart McCullochbb014372012-06-07 21:57:32 +000068
Stuart McCulloch2286f232012-06-15 13:27:53 +000069 public void dump(PrintStream ps) throws Exception {
70 if (ps != null)
71 this.ps = ps;
72 DataInputStream din = new DataInputStream(in);
73 parseClassFile(din);
74 din.close();
75 }
Stuart McCullochbb014372012-06-07 21:57:32 +000076
Stuart McCulloch2286f232012-06-15 13:27:53 +000077 void parseClassFile(DataInputStream in) throws IOException {
78 int magic = in.readInt();
79 if (magic != 0xCAFEBABE)
80 throw new IOException("Not a valid class file (no CAFEBABE header)");
Stuart McCullochbb014372012-06-07 21:57:32 +000081
Stuart McCulloch2286f232012-06-15 13:27:53 +000082 ps.printf(HEX_COLUMN, "magic", magic);
83 int minor = in.readUnsignedShort(); // minor version
84 int major = in.readUnsignedShort(); // major version
85 ps.printf(STR_COLUMN, "version", "" + major + "." + minor);
86 int pool_size = in.readUnsignedShort();
87 ps.printf(NUM_COLUMN, "pool size", pool_size);
88 pool = new Object[pool_size];
Stuart McCullochbb014372012-06-07 21:57:32 +000089
Stuart McCulloch2286f232012-06-15 13:27:53 +000090 process: for (int poolIndex = 1; poolIndex < pool_size; poolIndex++) {
91 byte tag = in.readByte();
Stuart McCullochbb014372012-06-07 21:57:32 +000092
Stuart McCulloch2286f232012-06-15 13:27:53 +000093 switch (tag) {
94 case 0 :
95 ps.printf("%30d tag (0)\n", poolIndex);
96 break process;
Stuart McCullochbb014372012-06-07 21:57:32 +000097
Stuart McCulloch2286f232012-06-15 13:27:53 +000098 case 1 :
99 String name = in.readUTF();
100 pool[poolIndex] = name;
101 ps.printf("%30d tag(1) utf8 '%s'\n", poolIndex, name);
102 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000103
Stuart McCulloch2286f232012-06-15 13:27:53 +0000104 case 2 :
105 throw new IOException("Invalid tag " + tag);
Stuart McCullochbb014372012-06-07 21:57:32 +0000106
Stuart McCulloch2286f232012-06-15 13:27:53 +0000107 case 3 :
108 int i = in.readInt();
109 pool[poolIndex] = Integer.valueOf(i);
110 ps.printf("%30d tag(3) int %s\n", poolIndex, i);
111 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000112
Stuart McCulloch2286f232012-06-15 13:27:53 +0000113 case 4 :
114 float f = in.readFloat();
115 pool[poolIndex] = new Float(f);
116 ps.printf("%30d tag(4) float %s\n", poolIndex, f);
117 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000118
Stuart McCulloch2286f232012-06-15 13:27:53 +0000119 // For some insane optimization reason are
120 // the long and the double two entries in the
121 // constant pool. See 4.4.5
122 case 5 :
123 long l = in.readLong();
124 pool[poolIndex] = Long.valueOf(l);
125 ps.printf("%30d tag(5) long %s\n", poolIndex, l);
126 poolIndex++;
127 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000128
Stuart McCulloch2286f232012-06-15 13:27:53 +0000129 case 6 :
130 double d = in.readDouble();
131 pool[poolIndex] = new Double(d);
132 ps.printf("%30d tag(6) double %s\n", poolIndex, d);
133 poolIndex++;
134 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000135
Stuart McCulloch2286f232012-06-15 13:27:53 +0000136 case 7 :
137 int class_index = in.readUnsignedShort();
138 pool[poolIndex] = Integer.valueOf(class_index);
139 ps.printf("%30d tag(7) constant classs %d\n", poolIndex, class_index);
140 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000141
Stuart McCulloch2286f232012-06-15 13:27:53 +0000142 case 8 :
143 int string_index = in.readUnsignedShort();
144 pool[poolIndex] = Integer.valueOf(string_index);
145 ps.printf("%30d tag(8) constant string %d\n", poolIndex, string_index);
146 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000147
Stuart McCulloch2286f232012-06-15 13:27:53 +0000148 case 9 : // Field ref
149 class_index = in.readUnsignedShort();
150 int name_and_type_index = in.readUnsignedShort();
151 pool[poolIndex] = new Assoc((byte) 9, class_index, name_and_type_index);
152 ps.printf("%30d tag(9) field ref %d/%d\n", poolIndex, class_index, name_and_type_index);
153 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000154
Stuart McCulloch2286f232012-06-15 13:27:53 +0000155 case 10 : // Method ref
156 class_index = in.readUnsignedShort();
157 name_and_type_index = in.readUnsignedShort();
158 pool[poolIndex] = new Assoc((byte) 10, class_index, name_and_type_index);
159 ps.printf("%30d tag(10) method ref %d/%d\n", poolIndex, class_index, name_and_type_index);
160 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000161
Stuart McCulloch2286f232012-06-15 13:27:53 +0000162 case 11 : // Interface and Method ref
163 class_index = in.readUnsignedShort();
164 name_and_type_index = in.readUnsignedShort();
165 pool[poolIndex] = new Assoc((byte) 11, class_index, name_and_type_index);
166 ps.printf("%30d tag(11) interface and method ref %d/%d\n", poolIndex, class_index,
167 name_and_type_index);
168 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000169
Stuart McCulloch2286f232012-06-15 13:27:53 +0000170 // Name and Type
171 case 12 :
172 int name_index = in.readUnsignedShort();
173 int descriptor_index = in.readUnsignedShort();
174 pool[poolIndex] = new Assoc(tag, name_index, descriptor_index);
175 ps.printf("%30d tag(12) name and type %d/%d\n", poolIndex, name_index, descriptor_index);
176 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000177
Stuart McCulloch2286f232012-06-15 13:27:53 +0000178 default :
179 throw new IllegalArgumentException("Unknown tag: " + tag);
180 }
181 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000182
Stuart McCulloch2286f232012-06-15 13:27:53 +0000183 int access = in.readUnsignedShort(); // access
184 printAccess(access);
185 int this_class = in.readUnsignedShort();
186 int super_class = in.readUnsignedShort();
187 ps.printf("%-30s %x %s(#%d)\n", "this_class", access, pool[this_class], this_class);
188 ps.printf("%-30s %s(#%d)\n", "super_class", pool[super_class], super_class);
Stuart McCullochbb014372012-06-07 21:57:32 +0000189
Stuart McCulloch2286f232012-06-15 13:27:53 +0000190 int interfaces_count = in.readUnsignedShort();
191 ps.printf(NUM_COLUMN, "interface count", interfaces_count);
192 for (int i = 0; i < interfaces_count; i++) {
193 int interface_index = in.readUnsignedShort();
194 ps.printf("%-30s interface %s(#%d)", "interface count", pool[interface_index], interfaces_count);
195 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000196
Stuart McCulloch2286f232012-06-15 13:27:53 +0000197 int field_count = in.readUnsignedShort();
198 ps.printf(NUM_COLUMN, "field count", field_count);
199 for (int i = 0; i < field_count; i++) {
200 access = in.readUnsignedShort(); // access
201 printAccess(access);
202 int name_index = in.readUnsignedShort();
203 int descriptor_index = in.readUnsignedShort();
204 ps.printf("%-30s %x %s(#%d) %s(#%d)\n", "field def", access, pool[name_index], name_index,
205 pool[descriptor_index], descriptor_index);
206 doAttributes(in, " ");
207 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000208
Stuart McCulloch2286f232012-06-15 13:27:53 +0000209 int method_count = in.readUnsignedShort();
210 ps.printf(NUM_COLUMN, "method count", method_count);
211 for (int i = 0; i < method_count; i++) {
212 int access_flags = in.readUnsignedShort();
213 printAccess(access_flags);
214 int name_index = in.readUnsignedShort();
215 int descriptor_index = in.readUnsignedShort();
216 ps.printf("%-30s %x %s(#%d) %s(#%d)\n", "method def", access_flags, pool[name_index], name_index,
217 pool[descriptor_index], descriptor_index);
218 doAttributes(in, " ");
219 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000220
Stuart McCulloch2286f232012-06-15 13:27:53 +0000221 doAttributes(in, "");
222 if (in.read() >= 0)
223 ps.printf("Extra bytes follow ...");
224 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000225
Stuart McCulloch2286f232012-06-15 13:27:53 +0000226 /**
227 * Called for each attribute in the class, field, or method.
228 *
229 * @param in
230 * The stream
231 * @throws IOException
232 */
233 private void doAttributes(DataInputStream in, String indent) throws IOException {
234 int attribute_count = in.readUnsignedShort();
235 ps.printf(NUM_COLUMN, indent + "attribute count", attribute_count);
236 for (int j = 0; j < attribute_count; j++) {
237 doAttribute(in, indent + j + ": ");
238 }
239 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000240
Stuart McCulloch2286f232012-06-15 13:27:53 +0000241 /**
242 * Process a single attribute, if not recognized, skip it.
243 *
244 * @param in
245 * the data stream
246 * @throws IOException
247 */
248 private void doAttribute(DataInputStream in, String indent) throws IOException {
249 int attribute_name_index = in.readUnsignedShort();
250 long attribute_length = in.readInt();
251 attribute_length &= 0xFFFF;
252 String attributeName = (String) pool[attribute_name_index];
253 ps.printf("%-30s %s(#%d)\n", indent + "attribute", attributeName, attribute_name_index);
254 if ("RuntimeVisibleAnnotations".equals(attributeName))
255 doAnnotations(in, indent);
256 else if ("SourceFile".equals(attributeName))
257 doSourceFile(in, indent);
258 else if ("Code".equals(attributeName))
259 doCode(in, indent);
260 else if ("LineNumberTable".equals(attributeName))
261 doLineNumberTable(in, indent);
262 else if ("LocalVariableTable".equals(attributeName))
263 doLocalVariableTable(in, indent);
264 else if ("InnerClasses".equals(attributeName))
265 doInnerClasses(in, indent);
266 else if ("Exceptions".equals(attributeName))
267 doExceptions(in, indent);
268 else if ("EnclosingMethod".equals(attributeName))
269 doEnclosingMethod(in, indent);
270 else if ("Signature".equals(attributeName))
271 doSignature(in, indent);
272 else if ("Synthetic".equals(attributeName))
273 ; // Is empty!
274 else if ("Deprecated".equals(attributeName))
275 ; // Is Empty
276 else {
277 ps.printf("%-30s %d\n", indent + "Unknown attribute, skipping", attribute_length);
278 if (attribute_length > 0x7FFFFFFF) {
279 throw new IllegalArgumentException("Attribute > 2Gb");
280 }
281 byte buffer[] = new byte[(int) attribute_length];
282 in.readFully(buffer);
283 printHex(buffer);
284 }
285 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000286
Stuart McCulloch2286f232012-06-15 13:27:53 +0000287 /**
288 * <pre>
289 * Signature_attribute {
290 * u2 attribute_name_index;
291 * u4 attribute_length;
292 * u2 signature_index;
293 * }
294 * </pre>
295 *
296 * @param in
297 * @param indent
298 */
299 void doSignature(DataInputStream in, String indent) throws IOException {
300 int signature_index = in.readUnsignedShort();
301 ps.printf("%-30s %s(#%d)\n", indent + "signature", pool[signature_index], signature_index);
302 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000303
Stuart McCulloch2286f232012-06-15 13:27:53 +0000304 /**
305 * <pre>
306 * EnclosingMethod_attribute {
307 * u2 attribute_name_index;
308 * u4 attribute_length;
309 * u2 class_index
310 * u2 method_index;
311 * }
312 *
313 * </pre>
314 */
315 void doEnclosingMethod(DataInputStream in, String indent) throws IOException {
316 int class_index = in.readUnsignedShort();
317 int method_index = in.readUnsignedShort();
318 ps.printf("%-30s %s(#%d/c) %s\n", //
319 indent + "enclosing method", //
320 pool[((Integer) pool[class_index]).intValue()], //
321 class_index, //
322 (method_index == 0 ? "<>" : pool[method_index]));
323 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000324
Stuart McCulloch2286f232012-06-15 13:27:53 +0000325 /**
326 * <pre>
327 * Exceptions_attribute {
328 * u2 attribute_name_index;
329 * u4 attribute_length;
330 * u2 number_of_exceptions;
331 * u2 exception_index_table[number_of_exceptions];
332 * }
333 * </pre>
334 *
335 * @param in
336 * @param indent
337 */
338 private void doExceptions(DataInputStream in, String indent) throws IOException {
339 int number_of_exceptions = in.readUnsignedShort();
340 ps.printf(NUM_COLUMN, indent + "number of exceptions", number_of_exceptions);
341 StringBuilder sb = new StringBuilder();
342 String del = "";
343 for (int i = 0; i < number_of_exceptions; i++) {
344 int exception_index_table = in.readUnsignedShort();
345 sb.append(del);
346 sb.append(pool[((Integer) pool[exception_index_table])]);
347 sb.append("(#");
348 sb.append(exception_index_table);
349 sb.append("/c)");
350 del = ", ";
351 }
352 ps.printf("%-30s %d: %s\n", indent + "exceptions", number_of_exceptions, sb);
353 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000354
Stuart McCulloch2286f232012-06-15 13:27:53 +0000355 /**
356 * <pre>
357 * Code_attribute {
358 * u2 attribute_name_index;
359 * u4 attribute_length;
360 * u2 max_stack;
361 * u2 max_locals;
362 * u4 code_length;
363 * u1 code[code_length];
364 * u2 exception_table_length;
365 * { u2 start_pc;
366 * u2 end_pc;
367 * u2 handler_pc;
368 * u2 catch_type;
369 * } exception_table[exception_table_length];
370 * u2 attributes_count;
371 * attribute_info attributes[attributes_count];
372 * }
373 * </pre>
374 *
375 * @param in
376 * @param pool
377 * @throws IOException
378 */
379 private void doCode(DataInputStream in, String indent) throws IOException {
380 int max_stack = in.readUnsignedShort();
381 int max_locals = in.readUnsignedShort();
382 int code_length = in.readInt();
383 ps.printf(NUM_COLUMN, indent + "max_stack", max_stack);
384 ps.printf(NUM_COLUMN, indent + "max_locals", max_locals);
385 ps.printf(NUM_COLUMN, indent + "code_length", code_length);
386 byte code[] = new byte[code_length];
387 in.readFully(code);
388 printHex(code);
389 int exception_table_length = in.readUnsignedShort();
390 ps.printf(NUM_COLUMN, indent + "exception_table_length", exception_table_length);
Stuart McCullochbb014372012-06-07 21:57:32 +0000391
Stuart McCulloch2286f232012-06-15 13:27:53 +0000392 for (int i = 0; i < exception_table_length; i++) {
393 int start_pc = in.readUnsignedShort();
394 int end_pc = in.readUnsignedShort();
395 int handler_pc = in.readUnsignedShort();
396 int catch_type = in.readUnsignedShort();
397 ps.printf("%-30s %d/%d/%d/%d\n", indent + "exception_table", start_pc, end_pc, handler_pc, catch_type);
398 }
399 doAttributes(in, indent + " ");
400 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000401
Stuart McCulloch2286f232012-06-15 13:27:53 +0000402 /**
403 * We must find Class.forName references ...
404 *
405 * @param code
406 */
407 protected void printHex(byte[] code) {
408 int index = 0;
409 while (index < code.length) {
410 StringBuilder sb = new StringBuilder();
411 for (int i = 0; i < 16 && index < code.length; i++) {
412 String s = Integer.toHexString((0xFF & code[index++])).toUpperCase();
413 if (s.length() == 1)
414 sb.append("0");
415 sb.append(s);
416 sb.append(" ");
417 }
418 ps.printf(STR_COLUMN, "", sb.toString());
419 }
420 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000421
Stuart McCulloch2286f232012-06-15 13:27:53 +0000422 private void doSourceFile(DataInputStream in, String indent) throws IOException {
423 int sourcefile_index = in.readUnsignedShort();
424 ps.printf("%-30s %s(#%d)\n", indent + "Source file", pool[sourcefile_index], sourcefile_index);
425 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000426
Stuart McCulloch2286f232012-06-15 13:27:53 +0000427 private void doAnnotations(DataInputStream in, String indent) throws IOException {
428 int num_annotations = in.readUnsignedShort(); // # of annotations
429 ps.printf(NUM_COLUMN, indent + "Number of annotations", num_annotations);
430 for (int a = 0; a < num_annotations; a++) {
431 doAnnotation(in, indent);
432 }
433 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000434
Stuart McCulloch2286f232012-06-15 13:27:53 +0000435 private void doAnnotation(DataInputStream in, String indent) throws IOException {
436 int type_index = in.readUnsignedShort();
437 ps.printf("%-30s %s(#%d)", indent + "type", pool[type_index], type_index);
438 int num_element_value_pairs = in.readUnsignedShort();
439 ps.printf(NUM_COLUMN, indent + "num_element_value_pairs", num_element_value_pairs);
440 for (int v = 0; v < num_element_value_pairs; v++) {
441 int element_name_index = in.readUnsignedShort();
442 ps.printf(NUM_COLUMN, indent + "element_name_index", element_name_index);
443 doElementValue(in, indent);
444 }
445 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000446
Stuart McCulloch2286f232012-06-15 13:27:53 +0000447 private void doElementValue(DataInputStream in, String indent) throws IOException {
448 int tag = in.readUnsignedByte();
449 switch (tag) {
450 case 'B' :
451 case 'C' :
452 case 'D' :
453 case 'F' :
454 case 'I' :
455 case 'J' :
456 case 'S' :
457 case 'Z' :
458 case 's' :
459 int const_value_index = in.readUnsignedShort();
460 ps.printf("%-30s %c %s(#%d)\n", indent + "element value", tag, pool[const_value_index],
461 const_value_index);
462 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000463
Stuart McCulloch2286f232012-06-15 13:27:53 +0000464 case 'e' :
465 int type_name_index = in.readUnsignedShort();
466 int const_name_index = in.readUnsignedShort();
467 ps.printf("%-30s %c %s(#%d) %s(#%d)\n", indent + "type+const", tag, pool[type_name_index],
468 type_name_index, pool[const_name_index], const_name_index);
469 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000470
Stuart McCulloch2286f232012-06-15 13:27:53 +0000471 case 'c' :
472 int class_info_index = in.readUnsignedShort();
473 ps.printf("%-30s %c %s(#%d)\n", indent + "element value", tag, pool[class_info_index], class_info_index);
474 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000475
Stuart McCulloch2286f232012-06-15 13:27:53 +0000476 case '@' :
477 ps.printf("%-30s %c\n", indent + "sub annotation", tag);
478 doAnnotation(in, indent);
479 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000480
Stuart McCulloch2286f232012-06-15 13:27:53 +0000481 case '[' :
482 int num_values = in.readUnsignedShort();
483 ps.printf("%-30s %c num_values=%d\n", indent + "sub element value", tag, num_values);
484 for (int i = 0; i < num_values; i++) {
485 doElementValue(in, indent);
486 }
487 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000488
Stuart McCulloch2286f232012-06-15 13:27:53 +0000489 default :
490 throw new IllegalArgumentException("Invalid value for Annotation ElementValue tag " + tag);
491 }
492 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000493
Stuart McCulloch2286f232012-06-15 13:27:53 +0000494 /**
495 * <pre>
496 * LineNumberTable_attribute {
497 * u2 attribute_name_index;
498 * u4 attribute_length;
499 * u2 line_number_table_length;
500 * { u2 start_pc;
501 * u2 line_number;
502 * } line_number_table[line_number_table_length];
503 * }
504 *
505 * </pre>
506 */
507 void doLineNumberTable(DataInputStream in, String indent) throws IOException {
508 int line_number_table_length = in.readUnsignedShort();
509 ps.printf(NUM_COLUMN, indent + "line number table length", line_number_table_length);
510 StringBuilder sb = new StringBuilder();
511 for (int i = 0; i < line_number_table_length; i++) {
512 int start_pc = in.readUnsignedShort();
513 int line_number = in.readUnsignedShort();
514 sb.append(start_pc);
515 sb.append("/");
516 sb.append(line_number);
517 sb.append(" ");
518 }
519 ps.printf("%-30s %d: %s\n", indent + "line number table", line_number_table_length, sb);
520 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000521
Stuart McCulloch2286f232012-06-15 13:27:53 +0000522 /**
523 * <pre>
524 * LocalVariableTable_attribute {
525 * u2 attribute_name_index;
526 * u4 attribute_length;
527 * u2 local_variable_table_length;
528 * { u2 start_pc;
529 * u2 length;
530 * u2 name_index;
531 * u2 descriptor_index;
532 * u2 index;
533 * } local_variable_table[local_variable_table_length];
534 * }
535 * </pre>
536 */
Stuart McCullochbb014372012-06-07 21:57:32 +0000537
Stuart McCulloch2286f232012-06-15 13:27:53 +0000538 void doLocalVariableTable(DataInputStream in, String indent) throws IOException {
539 int local_variable_table_length = in.readUnsignedShort();
540 ps.printf(NUM_COLUMN, indent + "local variable table length", local_variable_table_length);
541 for (int i = 0; i < local_variable_table_length; i++) {
542 int start_pc = in.readUnsignedShort();
543 int length = in.readUnsignedShort();
544 int name_index = in.readUnsignedShort();
545 int descriptor_index = in.readUnsignedShort();
546 int index = in.readUnsignedShort();
547 ps.printf("%-30s %d: %d/%d %s(#%d) %s(#%d)\n", indent, index, start_pc, length, pool[name_index],
548 name_index, pool[descriptor_index], descriptor_index);
549 }
550 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000551
Stuart McCulloch2286f232012-06-15 13:27:53 +0000552 /**
553 * <pre>
554 * InnerClasses_attribute {
555 * u2 attribute_name_index;
556 * u4 attribute_length;
557 * u2 number_of_classes;
558 * { u2 inner_class_info_index;
559 * u2 outer_class_info_index;
560 * u2 inner_name_index;
561 * u2 inner_class_access_flags;
562 * } classes[number_of_classes];
563 * }
564 * </pre>
565 */
566 void doInnerClasses(DataInputStream in, String indent) throws IOException {
567 int number_of_classes = in.readUnsignedShort();
568 ps.printf(NUM_COLUMN, indent + "number of classes", number_of_classes);
569 for (int i = 0; i < number_of_classes; i++) {
570 int inner_class_info_index = in.readUnsignedShort();
571 int outer_class_info_index = in.readUnsignedShort();
572 int inner_name_index = in.readUnsignedShort();
573 int inner_class_access_flags = in.readUnsignedShort();
574 printAccess(inner_class_access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000575
Stuart McCulloch2286f232012-06-15 13:27:53 +0000576 String iname = "<>";
577 String oname = iname;
Stuart McCullochbb014372012-06-07 21:57:32 +0000578
Stuart McCulloch2286f232012-06-15 13:27:53 +0000579 if (inner_class_info_index != 0)
580 iname = (String) pool[((Integer) pool[inner_class_info_index]).intValue()];
581 if (outer_class_info_index != 0)
582 oname = (String) pool[((Integer) pool[outer_class_info_index]).intValue()];
Stuart McCullochbb014372012-06-07 21:57:32 +0000583
Stuart McCulloch2286f232012-06-15 13:27:53 +0000584 ps.printf("%-30s %d: %x %s(#%d/c) %s(#%d/c) %s(#%d) \n", indent, i, inner_class_access_flags, iname,
585 inner_class_info_index, oname, outer_class_info_index, pool[inner_name_index], inner_name_index);
586 }
587 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000588
Stuart McCulloch2286f232012-06-15 13:27:53 +0000589 void printClassAccess(int mod) {
590 ps.printf("%-30s", "Class Access");
591 if ((ACC_PUBLIC & mod) != 0)
592 ps.print(" public");
593 if ((ACC_FINAL & mod) != 0)
594 ps.print(" final");
595 if ((ACC_SUPER & mod) != 0)
596 ps.print(" super");
597 if ((ACC_INTERFACE & mod) != 0)
598 ps.print(" interface");
599 if ((ACC_ABSTRACT & mod) != 0)
600 ps.print(" abstract");
Stuart McCullochbb014372012-06-07 21:57:32 +0000601
Stuart McCulloch2286f232012-06-15 13:27:53 +0000602 ps.println();
603 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000604
Stuart McCulloch2286f232012-06-15 13:27:53 +0000605 void printAccess(int mod) {
606 ps.printf("%-30s", "Access");
607 if (Modifier.isStatic(mod))
608 ps.print(" static");
609 if (Modifier.isAbstract(mod))
610 ps.print(" abstract");
611 if (Modifier.isPublic(mod))
612 ps.print(" public");
613 if (Modifier.isFinal(mod))
614 ps.print(" final");
615 if (Modifier.isInterface(mod))
616 ps.print(" interface");
617 if (Modifier.isNative(mod))
618 ps.print(" native");
619 if (Modifier.isPrivate(mod))
620 ps.print(" private");
621 if (Modifier.isProtected(mod))
622 ps.print(" protected");
623 if (Modifier.isStrict(mod))
624 ps.print(" strict");
625 if (Modifier.isSynchronized(mod))
626 ps.print(" synchronized");
627 if (Modifier.isTransient(mod))
628 ps.print(" transient");
629 if (Modifier.isVolatile(mod))
630 ps.print(" volatile");
Stuart McCullochbb014372012-06-07 21:57:32 +0000631
Stuart McCulloch2286f232012-06-15 13:27:53 +0000632 ps.println();
633 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000634
Stuart McCulloch2286f232012-06-15 13:27:53 +0000635 public static void main(String args[]) throws Exception {
636 if (args.length == 0) {
637 System.err.println("clsd <class file>+");
638 }
639 for (int i = 0; i < args.length; i++) {
640 File f = new File(args[i]);
641 if (!f.isFile())
642 System.err.println("File does not exist or is directory " + f);
643 else {
644 ClassDumper cd = new ClassDumper(args[i]);
645 cd.dump(null);
646 }
647 }
648 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000649
650}