blob: 86740ca942ee2fc28b646de34153aa2bbd388a3d [file] [log] [blame]
Stuart McCullochbb014372012-06-07 21:57:32 +00001package aQute.libg.classdump;
2
3import java.io.*;
4import java.lang.reflect.*;
5
6public class ClassDumper {
Stuart McCulloch2286f232012-06-15 13:27:53 +00007 /**
8 * <pre>
9 * ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its
10 * package.
11 * ACC_FINAL 0x0010 Declared final; no subclasses allowed.
12 * ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the
13 * invokespecial instruction.
14 * ACC_INTERFACE 0x0200 Is an interface, not a
15 * class.
16 * ACC_ABSTRACT 0x0400 Declared abstract; may not be instantiated.
17 * </pre>
18 *
19 * @param mod
20 */
21 final static int ACC_PUBLIC = 0x0001; // Declared public; may be
22 // accessed
23 // from outside its package.
24 final static int ACC_FINAL = 0x0010; // Declared final; no
25 // subclasses
26 // allowed.
27 final static int ACC_SUPER = 0x0020; // Treat superclass methods
28 // specially when invoked by the
29 // invokespecial instruction.
30 final static int ACC_INTERFACE = 0x0200; // Is an interface, not a
31 // classs
32 final static int ACC_ABSTRACT = 0x0400; // Declared abstract; may
33 // not be
34 // instantiated.
Stuart McCullochbb014372012-06-07 21:57:32 +000035
Stuart McCulloch2286f232012-06-15 13:27:53 +000036 final static class Assoc {
37 Assoc(byte tag, int a, int b) {
38 this.tag = tag;
39 this.a = a;
40 this.b = b;
41 }
Stuart McCullochbb014372012-06-07 21:57:32 +000042
Stuart McCulloch2286f232012-06-15 13:27:53 +000043 byte tag;
44 int a;
45 int b;
Stuart McCullochbb014372012-06-07 21:57:32 +000046
Stuart McCulloch2286f232012-06-15 13:27:53 +000047 }
Stuart McCullochbb014372012-06-07 21:57:32 +000048
Stuart McCulloch2286f232012-06-15 13:27:53 +000049 final String path;
Stuart McCulloch7adbc952012-07-12 22:12:58 +000050 final static String NUM_COLUMN = "%-30s %d%n";
51 final static String HEX_COLUMN = "%-30s %x%n";
52 final static String STR_COLUMN = "%-30s %s%n";
Stuart McCullochbb014372012-06-07 21:57:32 +000053
Stuart McCulloch2286f232012-06-15 13:27:53 +000054 PrintStream ps = System.err;
55 Object[] pool;
56 InputStream in;
Stuart McCullochbb014372012-06-07 21:57:32 +000057
Stuart McCulloch2286f232012-06-15 13:27:53 +000058 public ClassDumper(String path) throws Exception {
59 this(path, new FileInputStream(new File(path)));
60 }
Stuart McCullochbb014372012-06-07 21:57:32 +000061
Stuart McCulloch2286f232012-06-15 13:27:53 +000062 public ClassDumper(String path, InputStream in) throws IOException {
63 this.path = path;
64 this.in = in;
65 }
Stuart McCullochbb014372012-06-07 21:57:32 +000066
Stuart McCulloch2286f232012-06-15 13:27:53 +000067 public void dump(PrintStream ps) throws Exception {
68 if (ps != null)
69 this.ps = ps;
70 DataInputStream din = new DataInputStream(in);
71 parseClassFile(din);
72 din.close();
73 }
Stuart McCullochbb014372012-06-07 21:57:32 +000074
Stuart McCulloch2286f232012-06-15 13:27:53 +000075 void parseClassFile(DataInputStream in) throws IOException {
76 int magic = in.readInt();
77 if (magic != 0xCAFEBABE)
78 throw new IOException("Not a valid class file (no CAFEBABE header)");
Stuart McCullochbb014372012-06-07 21:57:32 +000079
Stuart McCulloch2286f232012-06-15 13:27:53 +000080 ps.printf(HEX_COLUMN, "magic", magic);
81 int minor = in.readUnsignedShort(); // minor version
82 int major = in.readUnsignedShort(); // major version
83 ps.printf(STR_COLUMN, "version", "" + major + "." + minor);
84 int pool_size = in.readUnsignedShort();
85 ps.printf(NUM_COLUMN, "pool size", pool_size);
86 pool = new Object[pool_size];
Stuart McCullochbb014372012-06-07 21:57:32 +000087
Stuart McCulloch2286f232012-06-15 13:27:53 +000088 process: for (int poolIndex = 1; poolIndex < pool_size; poolIndex++) {
89 byte tag = in.readByte();
Stuart McCullochbb014372012-06-07 21:57:32 +000090
Stuart McCulloch2286f232012-06-15 13:27:53 +000091 switch (tag) {
92 case 0 :
Stuart McCulloch7adbc952012-07-12 22:12:58 +000093 ps.printf("%30d tag (0)%n", poolIndex);
Stuart McCulloch2286f232012-06-15 13:27:53 +000094 break process;
Stuart McCullochbb014372012-06-07 21:57:32 +000095
Stuart McCulloch2286f232012-06-15 13:27:53 +000096 case 1 :
97 String name = in.readUTF();
98 pool[poolIndex] = name;
Stuart McCulloch7adbc952012-07-12 22:12:58 +000099 ps.printf("%30d tag(1) utf8 '%s'%n", poolIndex, name);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000100 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000101
Stuart McCulloch2286f232012-06-15 13:27:53 +0000102 case 2 :
103 throw new IOException("Invalid tag " + tag);
Stuart McCullochbb014372012-06-07 21:57:32 +0000104
Stuart McCulloch2286f232012-06-15 13:27:53 +0000105 case 3 :
106 int i = in.readInt();
107 pool[poolIndex] = Integer.valueOf(i);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000108 ps.printf("%30d tag(3) int %s%n", poolIndex, i);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000109 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000110
Stuart McCulloch2286f232012-06-15 13:27:53 +0000111 case 4 :
112 float f = in.readFloat();
113 pool[poolIndex] = new Float(f);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000114 ps.printf("%30d tag(4) float %s%n", poolIndex, f);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000115 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000116
Stuart McCulloch2286f232012-06-15 13:27:53 +0000117 // For some insane optimization reason are
118 // the long and the double two entries in the
119 // constant pool. See 4.4.5
120 case 5 :
121 long l = in.readLong();
122 pool[poolIndex] = Long.valueOf(l);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000123 ps.printf("%30d tag(5) long %s%n", poolIndex, l);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000124 poolIndex++;
125 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000126
Stuart McCulloch2286f232012-06-15 13:27:53 +0000127 case 6 :
128 double d = in.readDouble();
129 pool[poolIndex] = new Double(d);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000130 ps.printf("%30d tag(6) double %s%n", poolIndex, d);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000131 poolIndex++;
132 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000133
Stuart McCulloch2286f232012-06-15 13:27:53 +0000134 case 7 :
135 int class_index = in.readUnsignedShort();
136 pool[poolIndex] = Integer.valueOf(class_index);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000137 ps.printf("%30d tag(7) constant classs %d%n", poolIndex, class_index);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000138 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000139
Stuart McCulloch2286f232012-06-15 13:27:53 +0000140 case 8 :
141 int string_index = in.readUnsignedShort();
142 pool[poolIndex] = Integer.valueOf(string_index);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000143 ps.printf("%30d tag(8) constant string %d%n", poolIndex, string_index);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000144 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000145
Stuart McCulloch2286f232012-06-15 13:27:53 +0000146 case 9 : // Field ref
147 class_index = in.readUnsignedShort();
148 int name_and_type_index = in.readUnsignedShort();
149 pool[poolIndex] = new Assoc((byte) 9, class_index, name_and_type_index);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000150 ps.printf("%30d tag(9) field ref %d/%d%n", poolIndex, class_index, name_and_type_index);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000151 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000152
Stuart McCulloch2286f232012-06-15 13:27:53 +0000153 case 10 : // Method ref
154 class_index = in.readUnsignedShort();
155 name_and_type_index = in.readUnsignedShort();
156 pool[poolIndex] = new Assoc((byte) 10, class_index, name_and_type_index);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000157 ps.printf("%30d tag(10) method ref %d/%d%n", poolIndex, class_index, name_and_type_index);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000158 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000159
Stuart McCulloch2286f232012-06-15 13:27:53 +0000160 case 11 : // Interface and Method ref
161 class_index = in.readUnsignedShort();
162 name_and_type_index = in.readUnsignedShort();
163 pool[poolIndex] = new Assoc((byte) 11, class_index, name_and_type_index);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000164 ps.printf("%30d tag(11) interface and method ref %d/%d%n", poolIndex, class_index,
Stuart McCulloch2286f232012-06-15 13:27:53 +0000165 name_and_type_index);
166 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000167
Stuart McCulloch2286f232012-06-15 13:27:53 +0000168 // Name and Type
169 case 12 :
170 int name_index = in.readUnsignedShort();
171 int descriptor_index = in.readUnsignedShort();
172 pool[poolIndex] = new Assoc(tag, name_index, descriptor_index);
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000173 ps.printf("%30d tag(12) name and type %d/%d%n", poolIndex, name_index, descriptor_index);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000174 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000175
Stuart McCulloch2286f232012-06-15 13:27:53 +0000176 default :
177 throw new IllegalArgumentException("Unknown tag: " + tag);
178 }
179 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000180
Stuart McCulloch2286f232012-06-15 13:27:53 +0000181 int access = in.readUnsignedShort(); // access
182 printAccess(access);
183 int this_class = in.readUnsignedShort();
184 int super_class = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000185 ps.printf("%-30s %x %s(#%d)%n", "this_class", access, pool[this_class], this_class);
186 ps.printf("%-30s %s(#%d)%n", "super_class", pool[super_class], super_class);
Stuart McCullochbb014372012-06-07 21:57:32 +0000187
Stuart McCulloch2286f232012-06-15 13:27:53 +0000188 int interfaces_count = in.readUnsignedShort();
189 ps.printf(NUM_COLUMN, "interface count", interfaces_count);
190 for (int i = 0; i < interfaces_count; i++) {
191 int interface_index = in.readUnsignedShort();
192 ps.printf("%-30s interface %s(#%d)", "interface count", pool[interface_index], interfaces_count);
193 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000194
Stuart McCulloch2286f232012-06-15 13:27:53 +0000195 int field_count = in.readUnsignedShort();
196 ps.printf(NUM_COLUMN, "field count", field_count);
197 for (int i = 0; i < field_count; i++) {
198 access = in.readUnsignedShort(); // access
199 printAccess(access);
200 int name_index = in.readUnsignedShort();
201 int descriptor_index = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000202 ps.printf("%-30s %x %s(#%d) %s(#%d)%n", "field def", access, pool[name_index], name_index,
Stuart McCulloch2286f232012-06-15 13:27:53 +0000203 pool[descriptor_index], descriptor_index);
204 doAttributes(in, " ");
205 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000206
Stuart McCulloch2286f232012-06-15 13:27:53 +0000207 int method_count = in.readUnsignedShort();
208 ps.printf(NUM_COLUMN, "method count", method_count);
209 for (int i = 0; i < method_count; i++) {
210 int access_flags = in.readUnsignedShort();
211 printAccess(access_flags);
212 int name_index = in.readUnsignedShort();
213 int descriptor_index = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000214 ps.printf("%-30s %x %s(#%d) %s(#%d)%n", "method def", access_flags, pool[name_index], name_index,
Stuart McCulloch2286f232012-06-15 13:27:53 +0000215 pool[descriptor_index], descriptor_index);
216 doAttributes(in, " ");
217 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000218
Stuart McCulloch2286f232012-06-15 13:27:53 +0000219 doAttributes(in, "");
220 if (in.read() >= 0)
221 ps.printf("Extra bytes follow ...");
222 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000223
Stuart McCulloch2286f232012-06-15 13:27:53 +0000224 /**
225 * Called for each attribute in the class, field, or method.
226 *
227 * @param in
228 * The stream
229 * @throws IOException
230 */
231 private void doAttributes(DataInputStream in, String indent) throws IOException {
232 int attribute_count = in.readUnsignedShort();
233 ps.printf(NUM_COLUMN, indent + "attribute count", attribute_count);
234 for (int j = 0; j < attribute_count; j++) {
235 doAttribute(in, indent + j + ": ");
236 }
237 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000238
Stuart McCulloch2286f232012-06-15 13:27:53 +0000239 /**
240 * Process a single attribute, if not recognized, skip it.
241 *
242 * @param in
243 * the data stream
244 * @throws IOException
245 */
246 private void doAttribute(DataInputStream in, String indent) throws IOException {
247 int attribute_name_index = in.readUnsignedShort();
248 long attribute_length = in.readInt();
249 attribute_length &= 0xFFFF;
250 String attributeName = (String) pool[attribute_name_index];
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000251 ps.printf("%-30s %s(#%d)%n", indent + "attribute", attributeName, attribute_name_index);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000252 if ("RuntimeVisibleAnnotations".equals(attributeName))
253 doAnnotations(in, indent);
254 else if ("SourceFile".equals(attributeName))
255 doSourceFile(in, indent);
256 else if ("Code".equals(attributeName))
257 doCode(in, indent);
258 else if ("LineNumberTable".equals(attributeName))
259 doLineNumberTable(in, indent);
260 else if ("LocalVariableTable".equals(attributeName))
261 doLocalVariableTable(in, indent);
262 else if ("InnerClasses".equals(attributeName))
263 doInnerClasses(in, indent);
264 else if ("Exceptions".equals(attributeName))
265 doExceptions(in, indent);
266 else if ("EnclosingMethod".equals(attributeName))
267 doEnclosingMethod(in, indent);
268 else if ("Signature".equals(attributeName))
269 doSignature(in, indent);
270 else if ("Synthetic".equals(attributeName))
271 ; // Is empty!
272 else if ("Deprecated".equals(attributeName))
273 ; // Is Empty
274 else {
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000275 ps.printf("%-30s %d%n", indent + "Unknown attribute, skipping", attribute_length);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000276 if (attribute_length > 0x7FFFFFFF) {
277 throw new IllegalArgumentException("Attribute > 2Gb");
278 }
279 byte buffer[] = new byte[(int) attribute_length];
280 in.readFully(buffer);
281 printHex(buffer);
282 }
283 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000284
Stuart McCulloch2286f232012-06-15 13:27:53 +0000285 /**
286 * <pre>
287 * Signature_attribute {
288 * u2 attribute_name_index;
289 * u4 attribute_length;
290 * u2 signature_index;
291 * }
292 * </pre>
293 *
294 * @param in
295 * @param indent
296 */
297 void doSignature(DataInputStream in, String indent) throws IOException {
298 int signature_index = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000299 ps.printf("%-30s %s(#%d)%n", indent + "signature", pool[signature_index], signature_index);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000300 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000301
Stuart McCulloch2286f232012-06-15 13:27:53 +0000302 /**
303 * <pre>
304 * EnclosingMethod_attribute {
305 * u2 attribute_name_index;
306 * u4 attribute_length;
307 * u2 class_index
308 * u2 method_index;
309 * }
310 *
311 * </pre>
312 */
313 void doEnclosingMethod(DataInputStream in, String indent) throws IOException {
314 int class_index = in.readUnsignedShort();
315 int method_index = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000316 ps.printf("%-30s %s(#%d/c) %s%n", //
Stuart McCulloch2286f232012-06-15 13:27:53 +0000317 indent + "enclosing method", //
318 pool[((Integer) pool[class_index]).intValue()], //
319 class_index, //
320 (method_index == 0 ? "<>" : pool[method_index]));
321 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000322
Stuart McCulloch2286f232012-06-15 13:27:53 +0000323 /**
324 * <pre>
325 * Exceptions_attribute {
326 * u2 attribute_name_index;
327 * u4 attribute_length;
328 * u2 number_of_exceptions;
329 * u2 exception_index_table[number_of_exceptions];
330 * }
331 * </pre>
332 *
333 * @param in
334 * @param indent
335 */
336 private void doExceptions(DataInputStream in, String indent) throws IOException {
337 int number_of_exceptions = in.readUnsignedShort();
338 ps.printf(NUM_COLUMN, indent + "number of exceptions", number_of_exceptions);
339 StringBuilder sb = new StringBuilder();
340 String del = "";
341 for (int i = 0; i < number_of_exceptions; i++) {
342 int exception_index_table = in.readUnsignedShort();
343 sb.append(del);
344 sb.append(pool[((Integer) pool[exception_index_table])]);
345 sb.append("(#");
346 sb.append(exception_index_table);
347 sb.append("/c)");
348 del = ", ";
349 }
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000350 ps.printf("%-30s %d: %s%n", indent + "exceptions", number_of_exceptions, sb);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000351 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000352
Stuart McCulloch2286f232012-06-15 13:27:53 +0000353 /**
354 * <pre>
355 * Code_attribute {
356 * u2 attribute_name_index;
357 * u4 attribute_length;
358 * u2 max_stack;
359 * u2 max_locals;
360 * u4 code_length;
361 * u1 code[code_length];
362 * u2 exception_table_length;
363 * { u2 start_pc;
364 * u2 end_pc;
365 * u2 handler_pc;
366 * u2 catch_type;
367 * } exception_table[exception_table_length];
368 * u2 attributes_count;
369 * attribute_info attributes[attributes_count];
370 * }
371 * </pre>
372 *
373 * @param in
374 * @param pool
375 * @throws IOException
376 */
377 private void doCode(DataInputStream in, String indent) throws IOException {
378 int max_stack = in.readUnsignedShort();
379 int max_locals = in.readUnsignedShort();
380 int code_length = in.readInt();
381 ps.printf(NUM_COLUMN, indent + "max_stack", max_stack);
382 ps.printf(NUM_COLUMN, indent + "max_locals", max_locals);
383 ps.printf(NUM_COLUMN, indent + "code_length", code_length);
384 byte code[] = new byte[code_length];
385 in.readFully(code);
386 printHex(code);
387 int exception_table_length = in.readUnsignedShort();
388 ps.printf(NUM_COLUMN, indent + "exception_table_length", exception_table_length);
Stuart McCullochbb014372012-06-07 21:57:32 +0000389
Stuart McCulloch2286f232012-06-15 13:27:53 +0000390 for (int i = 0; i < exception_table_length; i++) {
391 int start_pc = in.readUnsignedShort();
392 int end_pc = in.readUnsignedShort();
393 int handler_pc = in.readUnsignedShort();
394 int catch_type = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000395 ps.printf("%-30s %d/%d/%d/%d%n", indent + "exception_table", start_pc, end_pc, handler_pc, catch_type);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000396 }
397 doAttributes(in, indent + " ");
398 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000399
Stuart McCulloch2286f232012-06-15 13:27:53 +0000400 /**
401 * We must find Class.forName references ...
402 *
403 * @param code
404 */
405 protected void printHex(byte[] code) {
406 int index = 0;
407 while (index < code.length) {
408 StringBuilder sb = new StringBuilder();
409 for (int i = 0; i < 16 && index < code.length; i++) {
410 String s = Integer.toHexString((0xFF & code[index++])).toUpperCase();
411 if (s.length() == 1)
412 sb.append("0");
413 sb.append(s);
414 sb.append(" ");
415 }
416 ps.printf(STR_COLUMN, "", sb.toString());
417 }
418 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000419
Stuart McCulloch2286f232012-06-15 13:27:53 +0000420 private void doSourceFile(DataInputStream in, String indent) throws IOException {
421 int sourcefile_index = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000422 ps.printf("%-30s %s(#%d)%n", indent + "Source file", pool[sourcefile_index], sourcefile_index);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000423 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000424
Stuart McCulloch2286f232012-06-15 13:27:53 +0000425 private void doAnnotations(DataInputStream in, String indent) throws IOException {
426 int num_annotations = in.readUnsignedShort(); // # of annotations
427 ps.printf(NUM_COLUMN, indent + "Number of annotations", num_annotations);
428 for (int a = 0; a < num_annotations; a++) {
429 doAnnotation(in, indent);
430 }
431 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000432
Stuart McCulloch2286f232012-06-15 13:27:53 +0000433 private void doAnnotation(DataInputStream in, String indent) throws IOException {
434 int type_index = in.readUnsignedShort();
435 ps.printf("%-30s %s(#%d)", indent + "type", pool[type_index], type_index);
436 int num_element_value_pairs = in.readUnsignedShort();
437 ps.printf(NUM_COLUMN, indent + "num_element_value_pairs", num_element_value_pairs);
438 for (int v = 0; v < num_element_value_pairs; v++) {
439 int element_name_index = in.readUnsignedShort();
440 ps.printf(NUM_COLUMN, indent + "element_name_index", element_name_index);
441 doElementValue(in, indent);
442 }
443 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000444
Stuart McCulloch2286f232012-06-15 13:27:53 +0000445 private void doElementValue(DataInputStream in, String indent) throws IOException {
446 int tag = in.readUnsignedByte();
447 switch (tag) {
448 case 'B' :
449 case 'C' :
450 case 'D' :
451 case 'F' :
452 case 'I' :
453 case 'J' :
454 case 'S' :
455 case 'Z' :
456 case 's' :
457 int const_value_index = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000458 ps.printf("%-30s %c %s(#%d)%n", indent + "element value", tag, pool[const_value_index],
Stuart McCulloch2286f232012-06-15 13:27:53 +0000459 const_value_index);
460 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000461
Stuart McCulloch2286f232012-06-15 13:27:53 +0000462 case 'e' :
463 int type_name_index = in.readUnsignedShort();
464 int const_name_index = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000465 ps.printf("%-30s %c %s(#%d) %s(#%d)%n", indent + "type+const", tag, pool[type_name_index],
Stuart McCulloch2286f232012-06-15 13:27:53 +0000466 type_name_index, pool[const_name_index], const_name_index);
467 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000468
Stuart McCulloch2286f232012-06-15 13:27:53 +0000469 case 'c' :
470 int class_info_index = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000471 ps.printf("%-30s %c %s(#%d)%n", indent + "element value", tag, pool[class_info_index], class_info_index);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000472 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000473
Stuart McCulloch2286f232012-06-15 13:27:53 +0000474 case '@' :
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000475 ps.printf("%-30s %c%n", indent + "sub annotation", tag);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000476 doAnnotation(in, indent);
477 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000478
Stuart McCulloch2286f232012-06-15 13:27:53 +0000479 case '[' :
480 int num_values = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000481 ps.printf("%-30s %c num_values=%d%n", indent + "sub element value", tag, num_values);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000482 for (int i = 0; i < num_values; i++) {
483 doElementValue(in, indent);
484 }
485 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000486
Stuart McCulloch2286f232012-06-15 13:27:53 +0000487 default :
488 throw new IllegalArgumentException("Invalid value for Annotation ElementValue tag " + tag);
489 }
490 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000491
Stuart McCulloch2286f232012-06-15 13:27:53 +0000492 /**
493 * <pre>
494 * LineNumberTable_attribute {
495 * u2 attribute_name_index;
496 * u4 attribute_length;
497 * u2 line_number_table_length;
498 * { u2 start_pc;
499 * u2 line_number;
500 * } line_number_table[line_number_table_length];
501 * }
502 *
503 * </pre>
504 */
505 void doLineNumberTable(DataInputStream in, String indent) throws IOException {
506 int line_number_table_length = in.readUnsignedShort();
507 ps.printf(NUM_COLUMN, indent + "line number table length", line_number_table_length);
508 StringBuilder sb = new StringBuilder();
509 for (int i = 0; i < line_number_table_length; i++) {
510 int start_pc = in.readUnsignedShort();
511 int line_number = in.readUnsignedShort();
512 sb.append(start_pc);
513 sb.append("/");
514 sb.append(line_number);
515 sb.append(" ");
516 }
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000517 ps.printf("%-30s %d: %s%n", indent + "line number table", line_number_table_length, sb);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000518 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000519
Stuart McCulloch2286f232012-06-15 13:27:53 +0000520 /**
521 * <pre>
522 * LocalVariableTable_attribute {
523 * u2 attribute_name_index;
524 * u4 attribute_length;
525 * u2 local_variable_table_length;
526 * { u2 start_pc;
527 * u2 length;
528 * u2 name_index;
529 * u2 descriptor_index;
530 * u2 index;
531 * } local_variable_table[local_variable_table_length];
532 * }
533 * </pre>
534 */
Stuart McCullochbb014372012-06-07 21:57:32 +0000535
Stuart McCulloch2286f232012-06-15 13:27:53 +0000536 void doLocalVariableTable(DataInputStream in, String indent) throws IOException {
537 int local_variable_table_length = in.readUnsignedShort();
538 ps.printf(NUM_COLUMN, indent + "local variable table length", local_variable_table_length);
539 for (int i = 0; i < local_variable_table_length; i++) {
540 int start_pc = in.readUnsignedShort();
541 int length = in.readUnsignedShort();
542 int name_index = in.readUnsignedShort();
543 int descriptor_index = in.readUnsignedShort();
544 int index = in.readUnsignedShort();
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000545 ps.printf("%-30s %d: %d/%d %s(#%d) %s(#%d)%n", indent, index, start_pc, length, pool[name_index],
Stuart McCulloch2286f232012-06-15 13:27:53 +0000546 name_index, pool[descriptor_index], descriptor_index);
547 }
548 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000549
Stuart McCulloch2286f232012-06-15 13:27:53 +0000550 /**
551 * <pre>
552 * InnerClasses_attribute {
553 * u2 attribute_name_index;
554 * u4 attribute_length;
555 * u2 number_of_classes;
556 * { u2 inner_class_info_index;
557 * u2 outer_class_info_index;
558 * u2 inner_name_index;
559 * u2 inner_class_access_flags;
560 * } classes[number_of_classes];
561 * }
562 * </pre>
563 */
564 void doInnerClasses(DataInputStream in, String indent) throws IOException {
565 int number_of_classes = in.readUnsignedShort();
566 ps.printf(NUM_COLUMN, indent + "number of classes", number_of_classes);
567 for (int i = 0; i < number_of_classes; i++) {
568 int inner_class_info_index = in.readUnsignedShort();
569 int outer_class_info_index = in.readUnsignedShort();
570 int inner_name_index = in.readUnsignedShort();
571 int inner_class_access_flags = in.readUnsignedShort();
572 printAccess(inner_class_access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000573
Stuart McCulloch2286f232012-06-15 13:27:53 +0000574 String iname = "<>";
575 String oname = iname;
Stuart McCullochbb014372012-06-07 21:57:32 +0000576
Stuart McCulloch2286f232012-06-15 13:27:53 +0000577 if (inner_class_info_index != 0)
578 iname = (String) pool[((Integer) pool[inner_class_info_index]).intValue()];
579 if (outer_class_info_index != 0)
580 oname = (String) pool[((Integer) pool[outer_class_info_index]).intValue()];
Stuart McCullochbb014372012-06-07 21:57:32 +0000581
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000582 ps.printf("%-30s %d: %x %s(#%d/c) %s(#%d/c) %s(#%d) %n", indent, i, inner_class_access_flags, iname,
Stuart McCulloch2286f232012-06-15 13:27:53 +0000583 inner_class_info_index, oname, outer_class_info_index, pool[inner_name_index], inner_name_index);
584 }
585 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000586
Stuart McCulloch2286f232012-06-15 13:27:53 +0000587 void printClassAccess(int mod) {
588 ps.printf("%-30s", "Class Access");
589 if ((ACC_PUBLIC & mod) != 0)
590 ps.print(" public");
591 if ((ACC_FINAL & mod) != 0)
592 ps.print(" final");
593 if ((ACC_SUPER & mod) != 0)
594 ps.print(" super");
595 if ((ACC_INTERFACE & mod) != 0)
596 ps.print(" interface");
597 if ((ACC_ABSTRACT & mod) != 0)
598 ps.print(" abstract");
Stuart McCullochbb014372012-06-07 21:57:32 +0000599
Stuart McCulloch2286f232012-06-15 13:27:53 +0000600 ps.println();
601 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000602
Stuart McCulloch2286f232012-06-15 13:27:53 +0000603 void printAccess(int mod) {
604 ps.printf("%-30s", "Access");
605 if (Modifier.isStatic(mod))
606 ps.print(" static");
607 if (Modifier.isAbstract(mod))
608 ps.print(" abstract");
609 if (Modifier.isPublic(mod))
610 ps.print(" public");
611 if (Modifier.isFinal(mod))
612 ps.print(" final");
613 if (Modifier.isInterface(mod))
614 ps.print(" interface");
615 if (Modifier.isNative(mod))
616 ps.print(" native");
617 if (Modifier.isPrivate(mod))
618 ps.print(" private");
619 if (Modifier.isProtected(mod))
620 ps.print(" protected");
621 if (Modifier.isStrict(mod))
622 ps.print(" strict");
623 if (Modifier.isSynchronized(mod))
624 ps.print(" synchronized");
625 if (Modifier.isTransient(mod))
626 ps.print(" transient");
627 if (Modifier.isVolatile(mod))
628 ps.print(" volatile");
Stuart McCullochbb014372012-06-07 21:57:32 +0000629
Stuart McCulloch2286f232012-06-15 13:27:53 +0000630 ps.println();
631 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000632
Stuart McCulloch2286f232012-06-15 13:27:53 +0000633 public static void main(String args[]) throws Exception {
634 if (args.length == 0) {
635 System.err.println("clsd <class file>+");
636 }
637 for (int i = 0; i < args.length; i++) {
638 File f = new File(args[i]);
639 if (!f.isFile())
640 System.err.println("File does not exist or is directory " + f);
641 else {
642 ClassDumper cd = new ClassDumper(args[i]);
643 cd.dump(null);
644 }
645 }
646 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000647
648}