1/* Program to dump out a Java(TM) .class file. 2 Functionally similar to Sun's javap. 3 4 Copyright (C) 1996-2015 Free Software Foundation, Inc. 5 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 3, or (at your option) 11any later version. 12 13GCC is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with GCC; see the file COPYING3. If not see 20<http://www.gnu.org/licenses/>. 21 22Java and all Java-based marks are trademarks or registered trademarks 23of Sun Microsystems, Inc. in the United States and other countries. 24The Free Software Foundation is independent of Sun Microsystems, Inc. */ 25 26/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */ 27 28/* 29 jcf-dump is a program to print out the contents of class files. 30 Usage: jcf-dump [FLAGS] CLASS 31 Each CLASS is either: 32 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or 33 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class"). 34 + The name of a .zip or .jar file (which prints all the classes in the 35 archive). 36 37 OPTIONS: 38 -c 39 Dis-assemble each method. 40 -classpath PATH 41 Overrides $CLASSPATH. 42 --print-main 43 Print nothing if there is no valid "main" method; 44 otherwise, print only the class name. 45 --javap 46 Print output in the style of Sun's javap program. VERY UNFINISHED. 47 */ 48 49 50#include "config.h" 51#include "system.h" 52#include "coretypes.h" 53#include "intl.h" 54#include "diagnostic.h" 55 56#include "jcf.h" 57#include "hash-set.h" 58#include "machmode.h" 59#include "vec.h" 60#include "double-int.h" 61#include "input.h" 62#include "alias.h" 63#include "symtab.h" 64#include "options.h" 65#include "wide-int.h" 66#include "inchash.h" 67#include "tree.h" 68#include "java-tree.h" 69 70#include "version.h" 71 72#include <getopt.h> 73#include <math.h> 74 75/* Output file. */ 76FILE *out; 77/* Name of output file, if NULL if stdout. */ 78char *output_file = NULL; 79 80int verbose = 0; 81 82int flag_disassemble_methods = 0; 83int flag_print_class_info = 1; 84int flag_print_constant_pool = 0; 85int flag_print_fields = 1; 86int flag_print_methods = 1; 87int flag_print_attributes = 1; 88 89/* Print names of classes that have a "main" method. */ 90int flag_print_main = 0; 91 92/* Index in constant pool of this class. */ 93int this_class_index = 0; 94 95int class_access_flags = 0; 96 97/* Print in format similar to javap. VERY INCOMPLETE. */ 98int flag_javap_compatible = 0; 99 100static void print_access_flags (FILE *, uint16, char); 101static void print_constant_terse (FILE*, JCF*, int, int); 102static void print_constant_terse_with_index (FILE *, JCF *, int, int); 103static void print_constant (FILE *, JCF *, int, int); 104static void print_constant_ref (FILE *, JCF *, int); 105static void disassemble_method (JCF*, const unsigned char *, int); 106static void print_name (FILE*, JCF*, int); 107static void print_signature (FILE*, JCF*, int, int); 108static int utf8_equal_string (struct JCF*, int, const char *); 109static void usage (void) ATTRIBUTE_NORETURN; 110static void help (void) ATTRIBUTE_NORETURN; 111static void version (void) ATTRIBUTE_NORETURN; 112static void process_class (struct JCF *); 113static void print_constant_pool (struct JCF *); 114static void print_exception_table (struct JCF *, const unsigned char *entries, 115 int); 116static void indent (FILE *, int); 117static void print_element_value (FILE *, JCF *, int); 118static void print_annotation (FILE *, JCF *, int); 119static void print_annotations (FILE *, JCF *, int); 120static void print_parameter_annotations (FILE *, JCF *, int); 121 122#define PRINT_SIGNATURE_RESULT_ONLY 1 123#define PRINT_SIGNATURE_ARGS_ONLY 2 124 125static int 126utf8_equal_string (JCF *jcf, int index, const char * value) 127{ 128 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index) 129 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8) 130 { 131 int len = strlen (value); 132 if (JPOOL_UTF_LENGTH (jcf, index) == len 133 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0) 134 return 1; 135 } 136 return 0; 137} 138 139#define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \ 140 this_class_index = 0; \ 141 if (flag_print_class_info) \ 142 fprintf (out, \ 143 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\ 144 (unsigned long) MAGIC, (long) MINOR, (long) MAJOR) 145 146#define HANDLE_START_CONSTANT_POOL(COUNT) \ 147 if (flag_print_constant_pool) \ 148 fprintf (out, "\nConstant pool (count: %d):\n", COUNT) 149 150#define HANDLE_SOURCEFILE(INDEX) \ 151{ fprintf (out, "Attribute "); \ 152 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \ 153 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \ 154 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); } 155 156#define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \ 157 this_class_index = THIS; \ 158 class_access_flags = ACCESS_FLAGS; \ 159 if (flag_print_class_info) \ 160 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \ 161 print_access_flags (out, ACCESS_FLAGS, 'c'); \ 162 fputc ('\n', out); \ 163 fprintf (out, "This class: "); \ 164 print_constant_terse_with_index (out, jcf, THIS, CONSTANT_Class); \ 165 if (flag_print_constant_pool || SUPER != 0) \ 166 fprintf (out, ", super: "); \ 167 if (flag_print_constant_pool) \ 168 { \ 169 fprintf (out, "%d", SUPER); \ 170 if (SUPER != 0) \ 171 fputc ('=', out); \ 172 } \ 173 if (SUPER != 0) \ 174 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \ 175 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \ 176 } 177 178#define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \ 179 (flag_print_attributes <= 0) 180 181#define HANDLE_CLASS_INTERFACE(INDEX) \ 182 if (flag_print_class_info) \ 183 { fprintf (out, "- Implements: "); \ 184 print_constant_terse_with_index (out, jcf, INDEX, CONSTANT_Class); \ 185 fputc ('\n', out); } 186 187#define HANDLE_START_FIELDS(FIELDS_COUNT) \ 188 if (flag_print_fields) \ 189 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT) 190 191#define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ 192 if (flag_print_fields) \ 193 { fprintf (out, "Field name:"); \ 194 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \ 195 print_access_flags (out, ACCESS_FLAGS, 'f'); \ 196 fprintf (out, " Descriptor: "); \ 197 if (flag_print_constant_pool) \ 198 fprintf (out, "%d=", SIGNATURE); \ 199 print_signature (out, jcf, SIGNATURE, 0); \ 200 fputc ('\n', out); } \ 201 else \ 202 flag_print_attributes--; 203 204#define HANDLE_END_FIELD() \ 205 if (! flag_print_fields) \ 206 flag_print_attributes++; 207 208#define HANDLE_START_METHODS(METHODS_COUNT) \ 209 if (flag_print_methods) \ 210 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \ 211 else \ 212 flag_print_attributes--; 213 214 215#define HANDLE_END_METHODS() \ 216 if (! flag_print_methods) \ 217 flag_print_attributes++; 218 219#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ 220{ \ 221 if (flag_print_methods) \ 222 { \ 223 if (flag_javap_compatible) \ 224 { \ 225 fprintf (out, " "); \ 226 print_access_flags (out, ACCESS_FLAGS, 'm'); \ 227 fputc (' ', out); \ 228 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \ 229 fputc (' ', out); \ 230 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \ 231 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \ 232 fputc ('\n', out); \ 233 } \ 234 else \ 235 { \ 236 fprintf (out, "\nMethod name:"); \ 237 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \ 238 print_access_flags (out, ACCESS_FLAGS, 'm'); \ 239 fprintf (out, " Descriptor: "); \ 240 if (flag_print_constant_pool) \ 241 fprintf (out, "%d=", SIGNATURE); \ 242 print_signature (out, jcf, SIGNATURE, 0); \ 243 fputc ('\n', out); \ 244 } \ 245 } \ 246 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \ 247 && utf8_equal_string (jcf, NAME, "main") \ 248 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \ 249 && this_class_index > 0 \ 250 && (class_access_flags & ACC_PUBLIC)) \ 251 { \ 252 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \ 253 fputc ('\n', out); \ 254 } \ 255} 256 257#define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \ 258( fprintf (out, "Attribute "), \ 259 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \ 260 fprintf (out, ", length:%ld", (long) LENGTH) ) 261 262#define HANDLE_CONSTANTVALUE(VALUE_INDEX) \ 263( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \ 264 fprintf (out, ", value: "), \ 265 print_constant_ref (out, jcf, VALUE_INDEX), \ 266 fprintf (out, "\n") ) 267 268#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \ 269{ COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \ 270 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \ 271 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \ 272 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); } 273 274#define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \ 275 print_exception_table (jcf, ENTRIES, COUNT) 276 277#define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \ 278{ int n = (COUNT); int i; \ 279 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \ 280 fprintf (out, ", count: %d\n", n); \ 281 for (i = 0; i < n; i++) {\ 282 int ex_index = JCF_readu2 (jcf); \ 283 fprintf (out, "%3d: ", i); \ 284 print_constant_ref (out, jcf, ex_index); \ 285 fputc ('\n', out); } } 286 287#define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \ 288{ int n = (COUNT); int i; \ 289 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \ 290 fprintf (out, ", count: %d\n", n); \ 291 for (i = 0; i < n; i++) {\ 292 int start_pc = JCF_readu2 (jcf); \ 293 int length = JCF_readu2 (jcf); \ 294 int name_index = JCF_readu2 (jcf); \ 295 int signature_index = JCF_readu2 (jcf); \ 296 int slot = JCF_readu2 (jcf); \ 297 fprintf (out, " slot#%d: name: ", slot); \ 298 if (flag_print_constant_pool) \ 299 fprintf (out, "%d=", name_index); \ 300 print_name (out, jcf, name_index); \ 301 fprintf (out, ", type: "); \ 302 if (flag_print_constant_pool) \ 303 fprintf (out, "%d=", signature_index); \ 304 print_signature (out, jcf, signature_index, 0); \ 305 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }} 306 307#define HANDLE_LOCALVARIABLETYPETABLE_ATTRIBUTE(COUNT) \ 308{ int n = (COUNT); int i; \ 309 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \ 310 fprintf (out, ", count: %d\n", n); \ 311 for (i = 0; i < n; i++) { \ 312 int start_pc = JCF_readu2 (jcf); \ 313 int length = JCF_readu2 (jcf); \ 314 int name_index = JCF_readu2 (jcf); \ 315 int signature_index = JCF_readu2 (jcf); \ 316 int slot = JCF_readu2 (jcf); \ 317 fprintf (out, " slot#%d: name: ", slot); \ 318 if (flag_print_constant_pool) \ 319 fprintf (out, "%d=", name_index); \ 320 print_name (out, jcf, name_index); \ 321 fprintf (out, ", type: "); \ 322 if (flag_print_constant_pool) \ 323 fprintf (out, "%d=", signature_index); \ 324 print_signature (out, jcf, signature_index, 0); \ 325 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }} 326 327#define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \ 328{ int n = (COUNT); int i; \ 329 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 330 fprintf (out, ", count: %d\n", n); \ 331 if (flag_disassemble_methods) \ 332 for (i = 0; i < n; i++) {\ 333 int start_pc = JCF_readu2 (jcf); \ 334 int line_number = JCF_readu2 (jcf); \ 335 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\ 336 else \ 337 JCF_SKIP (jcf, 4 * n); } 338 339#define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \ 340{ int n = (COUNT); \ 341 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 342 while (n--) \ 343 { \ 344 uint16 inner_class_info_index = JCF_readu2 (jcf); \ 345 uint16 outer_class_info_index = JCF_readu2 (jcf); \ 346 uint16 inner_name_index = JCF_readu2 (jcf); \ 347 uint16 inner_class_access_flags = JCF_readu2 (jcf); \ 348 \ 349 if (flag_print_class_info) \ 350 { \ 351 fprintf (out, "\n inner: "); \ 352 if (inner_class_info_index == 0) \ 353 fprintf (out, " (no inner info index)"); \ 354 else \ 355 print_constant_terse_with_index (out, jcf, \ 356 inner_class_info_index, \ 357 CONSTANT_Class); \ 358 if (inner_name_index == 0) \ 359 fprintf (out, " (anonymous)"); \ 360 else if (verbose || flag_print_constant_pool) \ 361 { \ 362 fprintf (out, " ("); \ 363 print_constant_terse_with_index (out, jcf, inner_name_index, \ 364 CONSTANT_Utf8); \ 365 fputc (')', out); \ 366 } \ 367 fprintf (out, ", access flags: 0x%x", inner_class_access_flags); \ 368 print_access_flags (out, inner_class_access_flags, 'c'); \ 369 fprintf (out, ", outer class: "); \ 370 if (outer_class_info_index == 0) \ 371 fprintf (out, "(not a member)"); \ 372 else \ 373 print_constant_terse_with_index (out, jcf, \ 374 outer_class_info_index, \ 375 CONSTANT_Class); \ 376 } \ 377 } \ 378 if (flag_print_class_info) \ 379 fputc ('\n', out); \ 380} 381 382#define HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE(LENGTH) \ 383{ int i, n = (LENGTH), c = 0; \ 384 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 385 fputc ('\n', out); \ 386 for (i = 0; i < n; i++) { c = JCF_readu(jcf); fputc(c, out); } \ 387 if (c != '\r' && c != '\n') fputc('\n', out); } 388 389#define HANDLE_ENCLOSINGMETHOD_ATTRIBUTE() \ 390 { uint16 class_index, method_index; \ 391 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 392 class_index = JCF_readu2 (jcf); \ 393 method_index = JCF_readu2 (jcf); \ 394 fprintf (out, "\n Class: "); \ 395 print_constant_terse_with_index (out, jcf, class_index, CONSTANT_Class); \ 396 fprintf (out, "\n Method: "); \ 397 print_constant_terse_with_index (out, jcf, method_index, \ 398 CONSTANT_NameAndType); \ 399 fputc ('\n', out); \ 400} 401 402#define HANDLE_SIGNATURE_ATTRIBUTE() \ 403{ \ 404 uint16 signature; \ 405 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 406 signature = JCF_readu2 (jcf); \ 407 fprintf (out, "\n Value: "); \ 408 print_constant_terse_with_index (out, jcf, signature, CONSTANT_Utf8); \ 409 fputc ('\n', out); \ 410} 411 412#define HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE() \ 413{ \ 414 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 415 print_annotations (out, jcf, 1); \ 416} 417 418#define HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE() \ 419{ \ 420 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 421 print_annotations (out, jcf, 1); \ 422} 423 424#define HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \ 425{ \ 426 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 427 print_parameter_annotations (out, jcf, 1); \ 428} 429 430#define HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \ 431{ \ 432 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 433 print_parameter_annotations (out, jcf, 1); \ 434} 435 436#define HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE() \ 437{ \ 438 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 439 print_element_value (out, jcf, 1); \ 440} 441 442#define HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE() \ 443{ \ 444 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ 445 fputc ('\n', out); jcf_parse_bootstrap_methods (jcf, attribute_length); \ 446} 447 448#define HANDLE_END_BOOTSTRAP_METHODS(NUM_METHODS) \ 449 { \ 450 int i; \ 451 for (i = 0; i < NUM_METHODS; i++) \ 452 { \ 453 bootstrap_method *m = &jcf->bootstrap_methods.methods[i]; \ 454 fprintf (out, " %d: ", i); \ 455 print_constant (out, jcf, m->method_ref, 1); \ 456 fprintf (out, "\n"); \ 457 } \ 458 } 459 460#define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \ 461{ COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \ 462 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); } 463 464#define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \ 465 if (flag_print_attributes > 0) \ 466 fprintf (out, "\nAttributes (count: %d):\n", attributes_count); 467 468#include "javaop.h" 469 470 471 472static void 473indent (FILE *stream, int level) 474{ 475 int i; 476 for (i = 0; i < level; ++i) 477 fprintf (stream, " "); 478} 479 480static void 481print_element_value (FILE *stream, JCF *jcf, int level) 482{ 483 uint8 tag = JCF_readu (jcf); 484 indent (stream, level); 485 switch (tag) 486 { 487 case 'B': 488 case 'C': 489 case 'S': 490 case 'Z': 491 case 'I': 492 { 493 uint16 cindex = JCF_readu2 (jcf); 494 print_constant_terse_with_index (stream, jcf, cindex, 495 CONSTANT_Integer); 496 } 497 break; 498 case 'D': 499 { 500 uint16 cindex = JCF_readu2 (jcf); 501 print_constant_terse_with_index (stream, jcf, cindex, 502 CONSTANT_Double); 503 } 504 break; 505 case 'F': 506 { 507 uint16 cindex = JCF_readu2 (jcf); 508 print_constant_terse_with_index (stream, jcf, cindex, 509 CONSTANT_Float); 510 } 511 break; 512 case 'J': 513 { 514 uint16 cindex = JCF_readu2 (jcf); 515 print_constant_terse_with_index (stream, jcf, cindex, 516 CONSTANT_Long); 517 } 518 break; 519 case 's': 520 { 521 uint16 cindex = JCF_readu2 (jcf); 522 /* Despite what the JVM spec says, compilers generate a Utf8 523 constant here, not a String. */ 524 print_constant_terse_with_index (stream, jcf, cindex, 525 CONSTANT_Utf8); 526 } 527 break; 528 529 case 'e': 530 { 531 uint16 type_name_index = JCF_readu2 (jcf); 532 uint16 const_name_index = JCF_readu2 (jcf); 533 fprintf (stream, "enum class: "); 534 print_constant_terse_with_index (stream, jcf, type_name_index, 535 CONSTANT_Utf8); 536 fprintf (stream, "\n"); 537 indent (stream, level); 538 fprintf (stream, "Field: "); 539 print_constant_terse_with_index (stream, jcf, const_name_index, 540 CONSTANT_Utf8); 541 } 542 break; 543 case 'c': 544 { 545 uint16 class_info_index = JCF_readu2 (jcf); 546 print_constant_terse_with_index (stream, jcf, class_info_index, 547 CONSTANT_Utf8); 548 } 549 break; 550 case '@': 551 { 552 fprintf (stream, "Annotation:\n"); 553 print_annotation (stream, jcf, level + 1); 554 } 555 break; 556 case '[': 557 { 558 uint16 n_array_elts = JCF_readu2 (jcf); 559 fprintf (stream, "array[%d]: [\n", (int) n_array_elts); 560 while (n_array_elts--) 561 print_element_value (stream, jcf, level + 1); 562 indent (stream, level); 563 fprintf (stream, "]"); 564 } 565 break; 566 default: 567 fprintf (stream, "Unexpected tag value: %d", (int) tag); 568 break; 569 } 570 fputc ('\n', stream); 571} 572 573static void 574print_annotation (FILE *stream, JCF *jcf, int level) 575{ 576 uint16 type_index = JCF_readu2 (jcf); 577 uint16 npairs = JCF_readu2 (jcf); 578 fprintf (stream, "\n"); 579 indent (stream, level); 580 fprintf (stream, "Annotation name: "); 581 print_constant_terse_with_index (stream, jcf, type_index, 582 CONSTANT_Utf8); 583 if (npairs) 584 { 585 fprintf (stream, "\n"); 586 while (npairs--) 587 { 588 uint16 name_index = JCF_readu2 (jcf); 589 indent (stream, level + 1); 590 fprintf (stream, "Name: "); 591 print_constant_terse_with_index (stream, jcf, name_index, 592 CONSTANT_Utf8); 593 fprintf (stream, "\n"); 594 print_element_value (stream, jcf, level + 2); 595 } 596 } 597} 598 599static void 600print_annotations (FILE *stream, JCF *jcf, int level) 601{ 602 uint16 num = JCF_readu2 (jcf); 603 while (num--) 604 print_annotation (stream, jcf, level); 605} 606 607static void 608print_parameter_annotations (FILE *stream, JCF *jcf, int level) 609{ 610 uint8 nparams = JCF_readu (jcf); 611 uint8 i; 612 for (i = 0; i < nparams; ++i) 613 { 614 indent (stream, level); 615 fprintf (stream, "Parameter annotations (%d):\n", (int) i); 616 print_annotations (stream, jcf, level + 1); 617 } 618} 619 620 621 622static void 623print_constant_ref (FILE *stream, JCF *jcf, int index) 624{ 625 if (index <= 0 || index >= JPOOL_SIZE(jcf)) 626 fprintf (stream, "<out of range>"); 627 else 628 { 629 if (flag_print_constant_pool) 630 fprintf (stream, "#%d=", index); 631 fputc ('<', stream); 632 print_constant (stream, jcf, index, 1); 633 fputc ('>', stream); 634 } 635} 636 637/* Print the access flags given by FLAGS. 638 The CONTEXT is one of 'c' (class flags), 'f' (field flags), 639 or 'm' (method flags). */ 640 641static void 642print_access_flags (FILE *stream, uint16 flags, char context) 643{ 644 if (flags & ACC_PUBLIC) fprintf (stream, " public"); 645 if (flags & ACC_PRIVATE) fprintf (stream, " private"); 646 if (flags & ACC_PROTECTED) fprintf (stream, " protected"); 647 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract"); 648 if (flags & ACC_STATIC) fprintf (stream, " static"); 649 if (flags & ACC_FINAL) fprintf (stream, " final"); 650 if (flags & ACC_TRANSIENT) 651 fprintf (stream, context == 'm' ? " varargs" : " transient"); 652 if (flags & ACC_VOLATILE) 653 fprintf (stream, context == 'm' ? " bridge" : " volatile"); 654 if (flags & ACC_NATIVE) fprintf (stream, " native"); 655 if (flags & ACC_SYNCHRONIZED) 656 { 657 if (context == 'c') 658 fprintf (stream, " super"); 659 else 660 fprintf (stream, " synchronized"); 661 } 662 if (flags & ACC_INTERFACE) 663 fprintf (stream, (flags & ACC_ANNOTATION) ? " @interface" : " interface"); 664 if (flags & ACC_ENUM) fprintf (stream, " enum"); 665 if (flags & ACC_STRICT) fprintf (stream, " strictfp"); 666 if (flags & ACC_SYNTHETIC) fprintf (stream, " synthetic"); 667} 668 669 670static void 671print_name (FILE* stream, JCF* jcf, int name_index) 672{ 673 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8) 674 fprintf (stream, "<not a UTF8 constant>"); 675 else 676 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index), 677 JPOOL_UTF_LENGTH (jcf, name_index)); 678} 679 680/* If the type of the constant at INDEX matches EXPECTED, 681 print it tersely, otherwise more verbosely. */ 682 683static void 684print_constant_terse (FILE *out, JCF *jcf, int index, int expected) 685{ 686 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)) 687 fprintf (out, "<constant pool index %d not in range>", index); 688 else if (JPOOL_TAG (jcf, index) != expected) 689 { 690 fprintf (out, "<Unexpected constant type "); 691 print_constant (out, jcf, index, 1); 692 fprintf (out, ">"); 693 } 694 else 695 print_constant (out, jcf, index, 0); 696} 697 698static void 699print_constant_terse_with_index (FILE *out, JCF *jcf, int index, int expected) 700{ 701 if (flag_print_constant_pool) 702 fprintf (out, "%d=", index); 703 print_constant_terse (out, jcf, index, expected); 704} 705 706/* Print the constant at INDEX in JCF's constant pool. 707 If verbosity==0, print very tersely (no extraneous text). 708 If verbosity==1, prefix the type of the constant. 709 If verbosity==2, add more descriptive text. */ 710 711static void 712print_constant (FILE *out, JCF *jcf, int index, int verbosity) 713{ 714 int j, n; 715 jlong num; 716 const char *str; 717 int kind = JPOOL_TAG (jcf, index); 718 switch (kind) 719 { 720 case CONSTANT_Class: 721 n = JPOOL_USHORT1 (jcf, index); 722 if (verbosity > 0) 723 { 724 if (verbosity > 1) 725 fprintf (out, "Class name: %d=", n); 726 else 727 fprintf (out, "Class "); 728 } 729 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n)) 730 fprintf (out, "<out of range>"); 731 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8) 732 { 733 int len = JPOOL_UTF_LENGTH (jcf, n); 734 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.'); 735 } 736 else 737 print_constant_terse (out, jcf, n, CONSTANT_Utf8); 738 break; 739 case CONSTANT_Fieldref: 740 str = "Field"; goto field_or_method; 741 case CONSTANT_Methodref: 742 str = "Method"; goto field_or_method; 743 case CONSTANT_InterfaceMethodref: 744 str = "InterfaceMethod"; goto field_or_method; 745 field_or_method: 746 { 747 uint16 tclass = JPOOL_USHORT1 (jcf, index); 748 uint16 name_and_type = JPOOL_USHORT2 (jcf, index); 749 if (verbosity == 2) 750 fprintf (out, "%sref class: %d=", str, tclass); 751 else if (verbosity > 0) 752 fprintf (out, "%s ", str); 753 print_constant_terse (out, jcf, tclass, CONSTANT_Class); 754 if (verbosity < 2) 755 fprintf (out, "."); 756 else 757 fprintf (out, " name_and_type: %d=<", name_and_type); 758 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType); 759 if (verbosity == 2) 760 fputc ('>', out); 761 } 762 break; 763 case CONSTANT_String: 764 j = JPOOL_USHORT1 (jcf, index); 765 if (verbosity > 0) 766 { 767 if (verbosity > 1) 768 fprintf (out, "String %d=", j); 769 else 770 fprintf (out, "String "); 771 } 772 print_constant_terse (out, jcf, j, CONSTANT_Utf8); 773 break; 774 case CONSTANT_Integer: 775 if (verbosity > 0) 776 fprintf (out, "Integer "); 777 num = JPOOL_INT (jcf, index); 778 goto integer; 779 case CONSTANT_Long: 780 if (verbosity > 0) 781 fprintf (out, "Long "); 782 num = JPOOL_LONG (jcf, index); 783 goto integer; 784 integer: 785 { 786 char buffer[25]; 787 format_int (buffer, num, 10); 788 fprintf (out, "%s", buffer); 789 if (verbosity > 1) 790 { 791 format_uint (buffer, (uint64)num, 16); 792 fprintf (out, "=0x%s", buffer); 793 } 794 } 795 break; 796 case CONSTANT_Float: 797 { 798 jfloat fnum = JPOOL_FLOAT (jcf, index); 799 800 if (verbosity > 0) 801 fputs ("Float ", out); 802 803 if (fnum.negative) 804 putc ('-', out); 805 806 if (JFLOAT_FINITE (fnum)) 807 { 808 int dummy; 809 int exponent = fnum.exponent - JFLOAT_EXP_BIAS; 810 double f; 811 uint32 mantissa = fnum.mantissa; 812 if (fnum.exponent == 0) 813 /* Denormal. */ 814 exponent++; 815 else 816 /* Normal; add the implicit bit. */ 817 mantissa |= ((uint32)1 << 23); 818 819 f = frexp ((float) mantissa, &dummy); 820 f = ldexp (f, exponent + 1); 821 fprintf (out, "%.10g", f); 822 } 823 else 824 { 825 if (fnum.mantissa == 0) 826 fputs ("Inf", out); 827 else if (fnum.mantissa & JFLOAT_QNAN_MASK) 828 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK)); 829 else 830 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK)); 831 } 832 833 if (verbosity > 1) 834 fprintf (out, ", bits = 0x%08lx", (unsigned long) JPOOL_UINT (jcf, index)); 835 836 break; 837 } 838 case CONSTANT_Double: 839 { 840 jdouble dnum = JPOOL_DOUBLE (jcf, index); 841 842 if (verbosity > 0) 843 fputs ("Double ", out); 844 845 if (dnum.negative) 846 putc ('-', out); 847 848 if (JDOUBLE_FINITE (dnum)) 849 { 850 int dummy; 851 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS; 852 double d; 853 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32) 854 + dnum.mantissa1); 855 if (dnum.exponent == 0) 856 /* Denormal. */ 857 exponent++; 858 else 859 /* Normal; add the implicit bit. */ 860 mantissa |= ((uint64)1 << 52); 861 862 d = frexp ((double) mantissa, &dummy); 863 d = ldexp (d, exponent + 1); 864 fprintf (out, "%.20g", d); 865 } 866 else 867 { 868 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK; 869 mantissa = (mantissa << 32) + dnum.mantissa1; 870 871 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0) 872 fputs ("Inf", out); 873 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK) 874 fprintf (out, "QNaN(%" HOST_LONG_LONG_FORMAT "u)", 875 (unsigned long long)mantissa); 876 else 877 fprintf (out, "SNaN(%" HOST_LONG_LONG_FORMAT "u)", 878 (unsigned long long)mantissa); 879 } 880 if (verbosity > 1) 881 { 882 int32 hi, lo; 883 hi = JPOOL_UINT (jcf, index); 884 lo = JPOOL_UINT (jcf, index + 1); 885 fprintf (out, ", bits = 0x%08lx%08lx", (unsigned long) hi, 886 (unsigned long) lo); 887 } 888 break; 889 } 890 case CONSTANT_NameAndType: 891 { 892 uint16 name = JPOOL_USHORT1 (jcf, index); 893 uint16 sig = JPOOL_USHORT2 (jcf, index); 894 if (verbosity > 0) 895 { 896 if (verbosity > 1) 897 fprintf (out, "NameAndType name: %d=", name); 898 else 899 fprintf (out, "NameAndType "); 900 } 901 print_name (out, jcf, name); 902 if (verbosity <= 1) 903 fputc (' ', out); 904 else 905 fprintf (out, ", signature: %d=", sig); 906 print_signature (out, jcf, sig, 0); 907 } 908 break; 909 case CONSTANT_Utf8: 910 { 911 const unsigned char *str = JPOOL_UTF_DATA (jcf, index); 912 int length = JPOOL_UTF_LENGTH (jcf, index); 913 if (verbosity > 0) 914 { /* Print as 8-bit bytes. */ 915 fputs ("Utf8: \"", out); 916 while (--length >= 0) 917 jcf_print_char (out, *str++); 918 } 919 else 920 { /* Print as Unicode. */ 921 fputc ('\"', out); 922 jcf_print_utf8 (out, str, length); 923 } 924 fputc ('\"', out); 925 } 926 break; 927 case CONSTANT_MethodHandle: 928 { 929 int kind = JPOOL_USHORT1 (jcf, index); 930 if (verbosity > 0) 931 fprintf (out, "MethodHandle kind: %d=", kind); 932 switch(kind) { 933 case 1: 934 case 2: 935 case 3: 936 case 4: 937 if (verbosity > 0) 938 fprintf (out, "Fieldref: %ld=", (long) JPOOL_USHORT2 (jcf, index)); 939 print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0); 940 case 5: 941 case 6: 942 case 7: 943 case 8: 944 if (verbosity > 0) 945 fprintf (out, "Methodref: %ld=", (long) JPOOL_USHORT2 (jcf, index)); 946 print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0); 947 break; 948 case 9: 949 if (verbosity > 0) 950 fprintf (out, "InterfaceMethodref: %ld=", 951 (long) JPOOL_USHORT2 (jcf, index)); 952 print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0); 953 break; 954 } 955 break; 956 } 957 case CONSTANT_MethodType: 958 if (verbosity > 0) 959 fprintf (out, "MethodType %ld: ", (long) JPOOL_USHORT1 (jcf, index)); 960 print_signature (out, jcf, JPOOL_USHORT1 (jcf, index), 0); 961 break; 962 case CONSTANT_InvokeDynamic: 963 { 964 uint16 name_and_type = JPOOL_USHORT2 (jcf, index); 965 if (verbosity > 0) 966 fprintf (out, "InvokeDynamic: "); 967 fprintf (out, "bootstrap_method: %ld ", 968 (long) JPOOL_USHORT1 (jcf, index)); 969 if (verbosity == 2) 970 fprintf (out, " name_and_type: %d=<", name_and_type); 971 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType); 972 if (verbosity == 2) 973 fputc ('>', out); 974 break; 975 } 976 default: 977 fprintf (out, "(Unknown constant type %d)", kind); 978 } 979} 980 981static void 982print_constant_pool (JCF *jcf) 983{ 984 int i; 985 for (i = 1; i < JPOOL_SIZE(jcf); i++) 986 { 987 int kind = JPOOL_TAG (jcf, i); 988 fprintf (out, "#%d: ", i); 989 print_constant (out, jcf, i, 2); 990 fprintf (out, "\n"); 991 if (kind == CONSTANT_Double || kind == CONSTANT_Long) 992 i++; /* These take up two slots in the constant table */ 993 } 994} 995 996static void 997print_signature_type (FILE* stream, const unsigned char **ptr, 998 const unsigned char *limit) 999{ 1000 int array_size; 1001 if ((*ptr) >= limit) 1002 return; 1003 switch (*(*ptr)) 1004 { 1005 case '[': 1006 array_size = -1; 1007 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++) 1008 { 1009 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0'; 1010 } 1011 print_signature_type (stream, ptr, limit); 1012 if (array_size == -1) 1013 fprintf (stream, "[]"); 1014 else 1015 fprintf (stream, "[%d]", array_size); 1016 break; 1017 case '(': 1018 { 1019 int nargs = 0; 1020 fputc (*(*ptr)++, stream); 1021 for (; **ptr != ')' && *ptr < limit; nargs++) 1022 { 1023 if (nargs > 0) 1024 fputc (',', stream); 1025 print_signature_type (stream, ptr, limit); 1026 } 1027 if (*ptr < limit) 1028 { 1029 fputc (*(*ptr)++, stream); 1030 print_signature_type (stream, ptr, limit); 1031 } 1032 else 1033 fprintf (stream, "???"); 1034 } 1035 break; 1036 1037 case 'B': fprintf (stream, "byte"); (*ptr)++; break; 1038 case 'C': fprintf (stream, "char"); (*ptr)++; break; 1039 case 'D': fprintf (stream, "double"); (*ptr)++; break; 1040 case 'F': fprintf (stream, "float"); (*ptr)++; break; 1041 case 'S': fprintf (stream, "short"); (*ptr)++; break; 1042 case 'I': fprintf (stream, "int"); (*ptr)++; break; 1043 case 'J': fprintf (stream, "long"); (*ptr)++; break; 1044 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break; 1045 case 'V': fprintf (stream, "void"); (*ptr)++; break; 1046 1047 case 'L': 1048 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++) 1049 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr)); 1050 if (*(*ptr) == ';') 1051 (*ptr)++; 1052 break; 1053 default: 1054 jcf_print_char (stream, *(*ptr)++); 1055 } 1056} 1057 1058static void 1059print_signature (FILE* stream, JCF *jcf, int signature_index, int options) 1060{ 1061 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8) 1062 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8); 1063 else 1064 { 1065 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index); 1066 int length = JPOOL_UTF_LENGTH (jcf, signature_index); 1067 const unsigned char *limit; 1068 limit = str + length; 1069 if (str >= limit) 1070 fprintf (stream, "<empty signature string>"); 1071 else 1072 { 1073 if (options & PRINT_SIGNATURE_RESULT_ONLY) 1074 { 1075 while (str < limit && *str++ != ')') ; 1076 } 1077 if (options & PRINT_SIGNATURE_ARGS_ONLY) 1078 { 1079 str++; 1080 fputc ('(', stream); 1081 while (str < limit && *str != ')') 1082 { 1083 print_signature_type (stream, &str, limit); 1084 if (*str != ')') 1085 fputs (", ", stream); 1086 } 1087 fputc (')', stream); 1088 } 1089 else 1090 { 1091 print_signature_type (stream, &str, limit); 1092 if (str < limit) 1093 { 1094 fprintf (stream, "<junk:"); 1095 jcf_print_utf8 (stream, str, limit - str); 1096 fputc ('>', stream); 1097 } 1098 } 1099 } 1100 } 1101} 1102 1103 1104static void 1105print_exception_table (JCF *jcf, const unsigned char *entries, int count) 1106{ 1107 /* Print exception table. */ 1108 int i = count; 1109 if (i > 0) 1110 { 1111 const unsigned char *ptr = entries; 1112 fprintf (out, "Exceptions (count: %d):\n", i); 1113 for (; --i >= 0; ptr+= 8) 1114 { 1115 int start_pc = GET_u2 (ptr); 1116 int end_pc = GET_u2 (ptr+2); 1117 int handler_pc = GET_u2 (ptr+4); 1118 int catch_type = GET_u2 (ptr+6); 1119 fprintf (out, " start: %d, end: %d, handler: %d, type: ", 1120 start_pc, end_pc, handler_pc); 1121 if (catch_type == 0) 1122 fputs ("0 /* finally */", out); 1123 else 1124 print_constant_terse_with_index (out, jcf, 1125 catch_type, CONSTANT_Class); 1126 fputc ('\n', out); 1127 } 1128 } 1129} 1130 1131#include "jcf-reader.c" 1132 1133static void 1134process_class (JCF *jcf) 1135{ 1136 int code; 1137 if (jcf_parse_preamble (jcf) != 0) 1138 fprintf (stderr, _("Not a valid Java .class file.\n")); 1139 1140 /* Parse and possibly print constant pool */ 1141 code = jcf_parse_constant_pool (jcf); 1142 if (code != 0) 1143 { 1144 fprintf (stderr, _("error while parsing constant pool\n")); 1145 exit (FATAL_EXIT_CODE); 1146 } 1147 code = verify_constant_pool (jcf); 1148 if (code > 0) 1149 { 1150 fprintf (stderr, _("error in constant pool entry #%d\n"), code); 1151 exit (FATAL_EXIT_CODE); 1152 } 1153 if (flag_print_constant_pool) 1154 print_constant_pool (jcf); 1155 1156 jcf_parse_class (jcf); 1157 code = jcf_parse_fields (jcf); 1158 if (code != 0) 1159 { 1160 fprintf (stderr, _("error while parsing fields\n")); 1161 exit (FATAL_EXIT_CODE); 1162 } 1163 code = jcf_parse_methods (jcf); 1164 if (code != 0) 1165 { 1166 fprintf (stderr, _("error while parsing methods\n")); 1167 exit (FATAL_EXIT_CODE); 1168 } 1169 code = jcf_parse_final_attributes (jcf); 1170 if (code != 0) 1171 { 1172 fprintf (stderr, _("error while parsing final attributes\n")); 1173 exit (FATAL_EXIT_CODE); 1174 } 1175 jcf->filename = NULL; 1176} 1177 1178 1179 1180/* This is used to mark options with no short value. */ 1181#define LONG_OPT(Num) ((Num) + 128) 1182 1183#define OPT_classpath LONG_OPT (0) 1184#define OPT_CLASSPATH OPT_classpath 1185#define OPT_bootclasspath LONG_OPT (1) 1186#define OPT_extdirs LONG_OPT (2) 1187#define OPT_HELP LONG_OPT (3) 1188#define OPT_VERSION LONG_OPT (4) 1189#define OPT_JAVAP LONG_OPT (5) 1190 1191static const struct option options[] = 1192{ 1193 { "classpath", required_argument, NULL, OPT_classpath }, 1194 { "bootclasspath", required_argument, NULL, OPT_bootclasspath }, 1195 { "extdirs", required_argument, NULL, OPT_extdirs }, 1196 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH }, 1197 { "help", no_argument, NULL, OPT_HELP }, 1198 { "verbose", no_argument, NULL, 'v' }, 1199 { "version", no_argument, NULL, OPT_VERSION }, 1200 { "javap", no_argument, NULL, OPT_JAVAP }, 1201 { "print-main", no_argument, &flag_print_main, 1 }, 1202 { "print-constants", no_argument, &flag_print_constant_pool, 1 }, 1203 { NULL, no_argument, NULL, 0 } 1204}; 1205 1206static void 1207usage (void) 1208{ 1209 fprintf (stderr, _("Try 'jcf-dump --help' for more information.\n")); 1210 exit (1); 1211} 1212 1213static void 1214help (void) 1215{ 1216 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n")); 1217 printf (_("Display contents of a class file in readable form.\n\n")); 1218 printf (_(" -c Disassemble method bodies\n")); 1219 printf (_(" --javap Generate output in 'javap' format\n")); 1220 printf ("\n"); 1221 printf (_(" --classpath PATH Set path to find .class files\n")); 1222 printf (_(" -IDIR Append directory to class path\n")); 1223 printf (_(" --bootclasspath PATH Override built-in class path\n")); 1224 printf (_(" --extdirs PATH Set extensions directory path\n")); 1225 printf (_(" -o FILE Set output file name\n")); 1226 printf ("\n"); 1227 printf (_(" --help Print this help, then exit\n")); 1228 printf (_(" --version Print version number, then exit\n")); 1229 printf (_(" -v, --verbose Print extra information while running\n")); 1230 printf ("\n"); 1231 printf (_("For bug reporting instructions, please see:\n" 1232 "%s.\n"), bug_report_url); 1233 exit (0); 1234} 1235 1236static void 1237version (void) 1238{ 1239 printf ("jcf-dump %s%s\n\n", pkgversion_string, version_string); 1240 printf ("Copyright %s 2015 Free Software Foundation, Inc.\n", _("(C)")); 1241 printf (_("This is free software; see the source for copying conditions. There is NO\n" 1242 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n")); 1243 exit (0); 1244} 1245 1246int 1247main (int argc, char** argv) 1248{ 1249 JCF jcf[1]; 1250 int argi, opt; 1251 const char *p; 1252 1253 p = argv[0] + strlen (argv[0]); 1254 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1])) 1255 --p; 1256 progname = p; 1257 1258 xmalloc_set_program_name (progname); 1259 1260 /* Unlock the stdio streams. */ 1261 unlock_std_streams (); 1262 1263 gcc_init_libintl (); 1264 1265 diagnostic_initialize (global_dc, 0); 1266 1267 if (argc <= 1) 1268 { 1269 fprintf (stderr, _("jcf-dump: no classes specified\n")); 1270 usage (); 1271 } 1272 1273 jcf_path_init (); 1274 1275 /* We use getopt_long_only to allow single `-' long options. For 1276 some of our options this is more natural. */ 1277 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1) 1278 { 1279 switch (opt) 1280 { 1281 case 0: 1282 /* Already handled. */ 1283 break; 1284 1285 case 'o': 1286 output_file = optarg; 1287 break; 1288 1289 case 'I': 1290 jcf_path_include_arg (optarg); 1291 break; 1292 1293 case 'v': 1294 verbose++; 1295 break; 1296 1297 case 'c': 1298 flag_disassemble_methods = 1; 1299 break; 1300 1301 case OPT_classpath: 1302 jcf_path_classpath_arg (optarg); 1303 break; 1304 1305 case OPT_bootclasspath: 1306 jcf_path_bootclasspath_arg (optarg); 1307 break; 1308 1309 case OPT_extdirs: 1310 jcf_path_extdirs_arg (optarg); 1311 break; 1312 1313 case OPT_HELP: 1314 help (); 1315 break; 1316 1317 case OPT_VERSION: 1318 version (); 1319 break; 1320 1321 case OPT_JAVAP: 1322 flag_javap_compatible++; 1323 flag_print_constant_pool = 0; 1324 flag_print_attributes = 0; 1325 break; 1326 1327 default: 1328 usage (); 1329 } 1330 } 1331 1332 if (verbose && ! flag_javap_compatible) 1333 flag_print_constant_pool = 1; 1334 1335 if (optind == argc) 1336 { 1337 fprintf (stderr, _("jcf-dump: no classes specified\n")); 1338 usage (); 1339 } 1340 1341 jcf_path_seal (verbose); 1342 1343 if (flag_print_main) 1344 { 1345 flag_print_fields = 0; 1346 flag_print_methods = 0; 1347 flag_print_constant_pool = 0; 1348 flag_print_attributes = 0; 1349 flag_print_class_info = 0; 1350 } 1351 1352 if (output_file) 1353 { 1354 out = fopen (output_file, "w"); 1355 if (! out) 1356 { 1357 fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file); 1358 return FATAL_EXIT_CODE; 1359 } 1360 } 1361 else 1362 out = stdout; 1363 1364 if (optind >= argc) 1365 { 1366 fprintf (out, "Reading .class from <standard input>.\n"); 1367 open_class ("<stdio>", jcf, 0, NULL); 1368 process_class (jcf); 1369 } 1370 else 1371 { 1372 for (argi = optind; argi < argc; argi++) 1373 { 1374 char *arg = argv[argi]; 1375 const char *class_filename = find_class (arg, strlen (arg), jcf); 1376 if (class_filename == NULL) 1377 class_filename = find_classfile (arg, jcf, NULL); 1378 if (class_filename == NULL) 1379 { 1380 perror ("Could not find class"); 1381 return FATAL_EXIT_CODE; 1382 } 1383 JCF_FILL (jcf, 4); 1384 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC) 1385 { 1386 long compressed_size, member_size; 1387 int compression_method, filename_length, extra_length; 1388 const char *filename; 1389 int total_length; 1390 if (flag_print_class_info) 1391 fprintf (out, "Reading classes from archive %s.\n", 1392 class_filename); 1393 for (;;) 1394 { 1395 int skip = 0; 1396 jcf_filbuf_t save_filbuf = jcf->filbuf; 1397 long magic = JCF_readu4_le (jcf); 1398 if (magic == 0x02014b50 || magic == 0x06054b50) 1399 break; /* got to central directory */ 1400 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */ 1401 { 1402 fprintf (stderr, _("bad format of .zip/.jar archive\n")); 1403 return FATAL_EXIT_CODE; 1404 } 1405 JCF_FILL (jcf, 26); 1406 JCF_SKIP (jcf, 2); 1407 (void) /* general_purpose_bits = */ JCF_readu2_le (jcf); 1408 compression_method = JCF_readu2_le (jcf); 1409 JCF_SKIP (jcf, 8); 1410 compressed_size = JCF_readu4_le (jcf); 1411 member_size = JCF_readu4_le (jcf); 1412 filename_length = JCF_readu2_le (jcf); 1413 extra_length = JCF_readu2_le (jcf); 1414 total_length = filename_length + extra_length 1415 + compressed_size; 1416 if (jcf->read_end - jcf->read_ptr < total_length) 1417 jcf_trim_old_input (jcf); 1418 JCF_FILL (jcf, total_length); 1419 filename = (const char *) jcf->read_ptr; 1420 JCF_SKIP (jcf, filename_length); 1421 JCF_SKIP (jcf, extra_length); 1422 if (filename_length > 0 1423 && filename[filename_length-1] == '/') 1424 { 1425 if (flag_print_class_info) 1426 fprintf (out, "[Skipping directory %.*s]\n", 1427 filename_length, filename); 1428 skip = 1; 1429 } 1430 else if (compression_method != 0) 1431 { 1432 if (flag_print_class_info) 1433 fprintf (out, "[Skipping compressed file %.*s]\n", 1434 filename_length, filename); 1435 skip = 1; 1436 } 1437 else if (member_size < 4 1438 || GET_u4 (jcf->read_ptr) != 0xcafebabe) 1439 { 1440 if (flag_print_class_info) 1441 fprintf (out, "[Skipping non-.class member %.*s]\n", 1442 filename_length, filename); 1443 skip = 1; 1444 } 1445 else 1446 { 1447 if (flag_print_class_info) 1448 fprintf (out, "Reading class member: %.*s.\n", 1449 filename_length, filename); 1450 } 1451 if (skip) 1452 { 1453 JCF_SKIP (jcf, compressed_size); 1454 } 1455 else 1456 { 1457 unsigned char *save_end; 1458 jcf->filbuf = jcf_unexpected_eof; 1459 save_end = jcf->read_end; 1460 jcf->read_end = jcf->read_ptr + compressed_size; 1461 process_class (jcf); 1462 jcf->filbuf = save_filbuf; 1463 jcf->read_end = save_end; 1464 } 1465 } 1466 } 1467 else 1468 { 1469 if (flag_print_class_info) 1470 fprintf (out, "Reading .class from %s.\n", class_filename); 1471 process_class (jcf); 1472 } 1473 JCF_FINISH(jcf); 1474 } 1475 } 1476 1477 return SUCCESS_EXIT_CODE; 1478} 1479 1480 1481 1482static void 1483disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len) 1484{ 1485#undef PTR 1486 int PC; 1487 int i; 1488 int saw_wide = 0; 1489 if (flag_disassemble_methods == 0) 1490 return; 1491#define BCODE byte_ops 1492 for (PC = 0; PC < len;) 1493 { 1494 int oldpc = PC; 1495 int saw_index; 1496 jint INT_temp; 1497 switch (byte_ops[PC++]) 1498 { 1499 1500/* This is the actual code emitted for each of opcodes in javaops.def. 1501 The actual opcode-specific stuff is handled by the OPKIND macro. 1502 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called. 1503 Those macros are defined below. The OPKINDs that do not have any 1504 inline parameters (such as BINOP) and therefore do mot need anything 1505 else to me printed out just use an empty body. */ 1506 1507#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \ 1508 case OPCODE: \ 1509 fprintf (out, "%3d: %s", oldpc, #OPNAME); \ 1510 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \ 1511 fputc ('\n', out); \ 1512 break; 1513 1514#define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1) 1515#define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2) 1516#define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1) 1517#define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2) 1518 1519#define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \ 1520 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1) 1521 1522/* Print out operand (if not implied by the opcode) for PUSCH opcodes. 1523 These all push a constant onto the opcode stack. */ 1524#define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \ 1525 saw_index = 0, i = (OPERAND_VALUE); \ 1526 if (oldpc+1 == PC) /* nothing */; \ 1527 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \ 1528 else fprintf (out, " %d", i); 1529 1530/* Print out operand (a local variable index) for LOAD opcodes. 1531 These all push local variable onto the opcode stack. */ 1532#define LOAD(OPERAND_TYPE, OPERAND_VALUE) \ 1533 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store; 1534 1535/* Handle STORE opcodes same as LOAD opcodes. 1536 These all store a value from the opcode stack in a local variable. */ 1537#define STORE LOAD 1538 1539/* Handle more kind of opcodes. */ 1540#define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ 1541#define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ 1542#define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ 1543#define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ 1544#define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ 1545#define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ 1546#define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ 1547 1548/* Handle putfield and getfield opcodes, with static versions. */ 1549#define FIELD(MAYBE_STATIC, PUT_OR_GET) \ 1550 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2) 1551 1552/* Print operand for invoke opcodes. */ 1553#define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \ 1554 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\ 1555 if (OPERAND_VALUE) /* for invokeinterface */ \ 1556 { int nargs = IMMEDIATE_u1; PC++; \ 1557 fprintf (out, " nargs:%d", nargs); } 1558 1559#define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \ 1560 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); 1561 1562#define ARRAY(OPERAND_TYPE, SUBOP) \ 1563 ARRAY_##SUBOP(OPERAND_TYPE) 1564/* Handle sub-categories of ARRAY opcodes. */ 1565#define ARRAY_LOAD(TYPE) /* nothing */ 1566#define ARRAY_STORE(TYPE) /* nothing */ 1567#define ARRAY_LENGTH(TYPE) /* nothing */ 1568#define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE 1569#define ARRAY_NEW_NUM \ 1570 INT_temp = IMMEDIATE_u1; \ 1571 { switch ((int) INT_temp) { \ 1572 case 4: fputs (" boolean", out); break; \ 1573 case 5: fputs (" char", out); break; \ 1574 case 6: fputs (" float", out); break; \ 1575 case 7: fputs (" double", out); break; \ 1576 case 8: fputs (" byte", out); break; \ 1577 case 9: fputs (" short", out); break; \ 1578 case 10: fputs (" int", out); break; \ 1579 case 11: fputs (" long", out); break; \ 1580 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\ 1581 } } 1582 1583#define ARRAY_NEW_PTR \ 1584 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); 1585 1586#define ARRAY_NEW_MULTI \ 1587 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \ 1588 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */ 1589 1590#define TEST(OPERAND_TYPE, OPERAND_VALUE) \ 1591 fprintf (out, " %d", oldpc + IMMEDIATE_s2) 1592 1593#define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \ 1594 saw_index = 0, INT_temp = (OPERAND_VALUE); \ 1595 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp)) 1596 1597#define JSR(OPERAND_TYPE, OPERAND_VALUE) \ 1598 saw_index = 0, INT_temp = (OPERAND_VALUE); \ 1599 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp)) 1600 1601#undef RET /* Defined by config/i386/i386.h */ 1602#define RET(OPERAND_TYPE, OPERAND_VALUE) \ 1603 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \ 1604 saw_wide = 0; \ 1605 fprintf (out, " %ld", (long) INT_temp); 1606 1607#define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \ 1608 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH 1609 1610#define LOOKUP_SWITCH \ 1611 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \ 1612 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \ 1613 while (--npairs >= 0) { \ 1614 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \ 1615 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \ 1616 } 1617 1618#define TABLE_SWITCH \ 1619 { jint default_offset = IMMEDIATE_s4; \ 1620 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \ 1621 fprintf (out, " low=%ld, high=%ld, default=%ld", \ 1622 (long) low, (long) high, (long) default_offset+oldpc); \ 1623 for (; low <= high; low++) { \ 1624 jint offset = IMMEDIATE_s4; \ 1625 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \ 1626 } 1627 1628#define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \ 1629 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE) 1630 1631#define SPECIAL_IINC(OPERAND_TYPE) \ 1632 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \ 1633 fprintf (out, " %d", i); \ 1634 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \ 1635 saw_wide = 0; \ 1636 fprintf (out, " %d", i) 1637 1638#define SPECIAL_WIDE(OPERAND_TYPE) \ 1639 saw_wide = 1; 1640 1641#define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */ 1642#define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */ 1643#define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */ 1644#define SPECIAL_THROW(OPERAND_TYPE) /* nothing */ 1645 1646#define IMPL(OPERAND_TYPE, OPERAND_VALUE) \ 1647 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE) 1648 1649#define COND(OPERAND_TYPE, OPERAND_VALUE) \ 1650 TEST(OPERAND_TYPE, OPERAND_VALUE) 1651 1652#include "javaop.def" 1653 1654 load_store: 1655 if (oldpc+1 == PC) /* nothing - local index implied by opcode */; 1656 else 1657 { 1658 saw_wide = 0; 1659 fprintf (out, " %ld", (long) INT_temp); 1660 } 1661 fputc ('\n', out); 1662 break; 1663 1664 default: 1665 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]); 1666 } 1667 } 1668} 1669