├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── include ├── annotation_default_attribute.hh ├── attribute_info.hh ├── bootstrap_methods_attribute.hh ├── bytecode.hh ├── code_attribute.hh ├── constant_pool.hh ├── constant_pool_entry_parser.hh ├── constant_value_attribute.hh ├── deprecated_attribute.hh ├── enclosing_method_attribute.hh ├── exceptions_attribute.hh ├── field_info.hh ├── find_api_calls.hh ├── inner_classes_attribute.hh ├── invalid_class_format_exception.hh ├── java_class.hh ├── line_number_table_attribute.hh ├── local_variable_table_attribute.hh ├── local_variable_type_table_attribute.hh ├── method_info.hh ├── runtime_invisible_annotations_attribute.hh ├── runtime_invisible_parameter_annotations_attribute.hh ├── runtime_visible_annotations_attribute.hh ├── runtime_visible_parameter_annotations_attribute.hh ├── signature_attribute.hh ├── source_file_attribute.hh ├── stack_map_table_attribute.hh ├── synthetic_attribute.hh └── util.hh ├── lib └── cxxopts.hh └── src ├── attribute ├── annotation_default_attribute.cc ├── bootstrap_methods_attribute.cc ├── code_attribute.cc ├── constant_value_attribute.cc ├── deprecated_attribute.cc ├── enclosing_method_attribute.cc ├── exceptions_attribute.cc ├── inner_classes_attribute.cc ├── line_number_table_attribute.cc ├── local_variable_table_attribute.cc ├── local_variable_type_table_attribute.cc ├── runtime_invisible_annotations_attribute.cc ├── runtime_invisible_parameter_annotations_attribute.cc ├── runtime_visible_annotations_attribute.cc ├── runtime_visible_parameter_annotations_attribute.cc ├── signature_attribute.cc ├── source_file_attribute.cc ├── stack_map_table_attribute.cc └── synthetic_attribute.cc ├── attribute_info.cc ├── constant_pool.cc ├── constant_pool_entry_parser.cc ├── field_info.cc ├── find_api_calls.cc ├── java_class.cc ├── main.cc └── method_info.cc /.gitignore: -------------------------------------------------------------------------------- 1 | .depend 2 | *.o 3 | bytecode-scanner 4 | *.class 5 | *.java 6 | .tags* 7 | bytecode-scanner.ilk 8 | bytecode-scanner.pdb 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Anthony Calandra 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=clang 2 | CXX=clang++ 3 | RM=rm -f 4 | CPPFLAGS=-g -std=c++17 -Wall -Iinclude -Ilib 5 | LDFLAGS=-g -Iinclude 6 | LDLIBS= 7 | NAME=bytecode-scanner 8 | 9 | SRCS=src/main.cc src/java_class.cc src/constant_pool.cc src/constant_pool_entry_parser.cc \ 10 | src/field_info.cc src/attribute_info.cc src/method_info.cc src/attribute/code_attribute.cc \ 11 | src/attribute/bootstrap_methods_attribute.cc \ 12 | src/attribute/annotation_default_attribute.cc src/attribute/constant_value_attribute.cc \ 13 | src/attribute/deprecated_attribute.cc src/attribute/enclosing_method_attribute.cc \ 14 | src/attribute/exceptions_attribute.cc src/attribute/inner_classes_attribute.cc \ 15 | src/attribute/line_number_table_attribute.cc src/attribute/local_variable_table_attribute.cc \ 16 | src/attribute/local_variable_type_table_attribute.cc \ 17 | src/attribute/runtime_invisible_annotations_attribute.cc \ 18 | src/attribute/runtime_invisible_parameter_annotations_attribute.cc \ 19 | src/attribute/runtime_visible_annotations_attribute.cc \ 20 | src/attribute/runtime_visible_parameter_annotations_attribute.cc \ 21 | src/attribute/signature_attribute.cc src/attribute/source_file_attribute.cc \ 22 | src/attribute/stack_map_table_attribute.cc src/attribute/synthetic_attribute.cc \ 23 | src/find_api_calls.cc 24 | OBJS=$(subst .cc,.o,$(SRCS)) 25 | 26 | all: build 27 | 28 | build: $(OBJS) 29 | $(CXX) $(LDFLAGS) -o $(NAME) $(OBJS) $(LDLIBS) 30 | 31 | depend: .depend 32 | 33 | .depend: $(SRCS) 34 | $(RM) ./.depend 35 | $(CXX) $(CPPFLAGS) -MM $^>>./.depend; 36 | 37 | clean: 38 | $(RM) $(OBJS) 39 | 40 | distclean: clean 41 | $(RM) *~ .depend $(NAME) 42 | 43 | include .depend 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bytecode-scanner 2 | This program scans Java bytecode for instances of APIs. For example, specifying `java/io/PrintStream`, will scan the given classfile for calls to constructors and methods of that class, also providing the line number in the sourcefile of where this call takes place. An example application of this is to scan Java programs for malicious intent such as issuing file operations or opening network connections. 3 | 4 | ## Example 5 | Given the sourcefile as Test.java and the compiled classfile Test.class: 6 | ```java 7 | import java.util.*; 8 | 9 | public class Test { 10 | public static void main(String[] args) { 11 | ArrayList list = new ArrayList<>(Arrays.asList(1, 2, 3)); 12 | System.out.println("Hello world!"); 13 | } 14 | } 15 | ``` 16 | 17 | Find instances of APIs using the `-s` (scan) flag, which is a comma-separated list of packages: 18 | ``` 19 | > ./bytecode-scanner -s "java.io.PrintStream,java.util.ArrayList" Test.class 20 | Found the following API calls in Test.class: 21 | java/io/PrintStream.println in method main on line 4 22 | java/util/ArrayList. in method main on line 3 23 | ``` 24 | 25 | Get a full dump of the constant pool using `-c` (constant-pool): 26 | ``` 27 | > ./bytecode-scanner -c Test.class 28 | #1 = MethodRef #11:#20 -> java/lang/Object."":()V 29 | #2 = Class #21 -> java/util/ArrayList 30 | #3 = Class #22 -> java/lang/Integer 31 | #4 = MethodRef #3:#23 -> java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 32 | #5 = MethodRef #24:#25 -> java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; 33 | #6 = MethodRef #2:#26 -> java/util/ArrayList."":(Ljava/util/Collection;)V 34 | #7 = FieldRef #27:#28 -> java/lang/System.out:Ljava/io/PrintStream; 35 | #8 = String #29 -> 哈 哈! 36 | #9 = MethodRef #30:#31 -> java/io/PrintStream.println:(Ljava/lang/String;)V 37 | #10 = Class #32 -> ReadmeTest 38 | #11 = Class #33 -> java/lang/Object 39 | #12 = Utf8 40 | #13 = Utf8 ()V 41 | #14 = Utf8 Code 42 | #15 = Utf8 LineNumberTable 43 | #16 = Utf8 main 44 | #17 = Utf8 ([Ljava/lang/String;)V 45 | #18 = Utf8 SourceFile 46 | #19 = Utf8 ReadmeTest.java 47 | #20 = NameAndType #12:#13 -> "":()V 48 | #21 = Utf8 java/util/ArrayList 49 | #22 = Utf8 java/lang/Integer 50 | #23 = NameAndType #34:#35 -> valueOf:(I)Ljava/lang/Integer; 51 | #24 = Class #36 -> java/util/Arrays 52 | #25 = NameAndType #37:#38 -> asList:([Ljava/lang/Object;)Ljava/util/List; 53 | #26 = NameAndType #12:#39 -> "":(Ljava/util/Collection;)V 54 | #27 = Class #40 -> java/lang/System 55 | #28 = NameAndType #41:#42 -> out:Ljava/io/PrintStream; 56 | #29 = Utf8 哈 哈! 57 | #30 = Class #43 -> java/io/PrintStream 58 | #31 = NameAndType #44:#45 -> println:(Ljava/lang/String;)V 59 | #32 = Utf8 ReadmeTest 60 | #33 = Utf8 java/lang/Object 61 | #34 = Utf8 valueOf 62 | #35 = Utf8 (I)Ljava/lang/Integer; 63 | #36 = Utf8 java/util/Arrays 64 | #37 = Utf8 asList 65 | #38 = Utf8 ([Ljava/lang/Object;)Ljava/util/List; 66 | #39 = Utf8 (Ljava/util/Collection;)V 67 | #40 = Utf8 java/lang/System 68 | #41 = Utf8 out 69 | #42 = Utf8 Ljava/io/PrintStream; 70 | #43 = Utf8 java/io/PrintStream 71 | #44 = Utf8 println 72 | #45 = Utf8 (Ljava/lang/String;)V 73 | ``` 74 | 75 | ## Limitations 76 | A few current limitations with this program are: 77 | * Skips annotation information. 78 | * Not very complete API-wise. 79 | * It may be possible to get around this using Reflection. 80 | 81 | ## License 82 | MIT 83 | 84 | ## Author 85 | Anthony Calandra 86 | -------------------------------------------------------------------------------- /include/annotation_default_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class annotation_default_attribute: public attribute_info 29 | { 30 | public: 31 | annotation_default_attribute() = default; 32 | virtual attribute_info_type get_type() const 33 | { 34 | return attribute_info_type::annotation_default; 35 | } 36 | }; 37 | 38 | std::unique_ptr parse_annotation_default_attribute(std::ifstream& file, 39 | const constant_pool& cp); 40 | -------------------------------------------------------------------------------- /include/attribute_info.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "constant_pool.hh" 27 | 28 | enum class attribute_info_type : uint8_t 29 | { 30 | constant_value, code, stack_map_table, exceptions, inner_classes, enclosing_method, synthetic, 31 | signature, source_file, source_debug_extension, line_number_table, local_variable_table, 32 | local_variable_type_table, deprecated, runtime_visible_annotations, runtime_invisible_annotations, 33 | runtime_visible_parameter_annotations, runtime_invisible_parameter_annotations, annotation_default, 34 | bootstrap_methods 35 | }; 36 | 37 | class attribute_info 38 | { 39 | public: 40 | virtual attribute_info_type get_type() const = 0; 41 | virtual ~attribute_info() = default; 42 | }; 43 | 44 | using entry_attributes = std::vector>; 45 | 46 | entry_attributes parse_attributes(std::ifstream& file, const constant_pool& cp); 47 | void skip_element_value_field(std::ifstream& file); 48 | void skip_annotations(std::ifstream& file); 49 | -------------------------------------------------------------------------------- /include/bootstrap_methods_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | #include "attribute_info.hh" 26 | #include "constant_pool.hh" 27 | #include "util.hh" 28 | 29 | struct bootstrap_method_entry 30 | { 31 | uint16_t bootstrap_method_ref; 32 | std::vector bootstrap_arguments; 33 | 34 | explicit bootstrap_method_entry(uint16_t bootstrap_method_ref, 35 | std::vector bootstrap_arguments) : 36 | bootstrap_method_ref{bootstrap_method_ref}, 37 | bootstrap_arguments{bootstrap_arguments} 38 | {} 39 | }; 40 | 41 | class bootstrap_methods_attribute: public attribute_info 42 | { 43 | std::vector bootstrap_methods; 44 | 45 | public: 46 | explicit bootstrap_methods_attribute(std::vector bootstrap_methods) : 47 | bootstrap_methods{std::move(bootstrap_methods)} 48 | {} 49 | 50 | virtual attribute_info_type get_type() const 51 | { 52 | return attribute_info_type::bootstrap_methods; 53 | } 54 | }; 55 | 56 | std::unique_ptr parse_bootstrap_methods_attribute(std::ifstream& file, 57 | const constant_pool& cp); 58 | -------------------------------------------------------------------------------- /include/bytecode.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | constexpr size_t TOTAL_BYTECODE_INSTRUCTIONS = 205; 25 | 26 | enum class bytecode_tag : uint8_t 27 | { 28 | NOP = 0, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, 29 | LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, BIPUSH, SIPUSH, LDC, 30 | LDC_W, LDC2_W, ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ILOAD_0, ILOAD_1, ILOAD_2, ILOAD_3, LLOAD_0, 31 | LLOAD_1, LLOAD_2, LLOAD_3, FLOAD_0, FLOAD_1, FLOAD_2, FLOAD_3, DLOAD_0, DLOAD_1, DLOAD_2, 32 | DLOAD_3, ALOAD_0, ALOAD_1, ALOAD_2, ALOAD_3, IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, 33 | CALOAD, SALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE, ISTORE_0, ISTORE_1, ISTORE_2, ISTORE_3, 34 | LSTORE_0, LSTORE_1, LSTORE_2, LSTORE_3, FSTORE_0, FSTORE_1, FSTORE_2, FSTORE_3, DSTORE_0, 35 | DSTORE_1, DSTORE_2, DSTORE_3, ASTORE_0, ASTORE_1, ASTORE_2, ASTORE_3, IASTORE, LASTORE, 36 | FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, 37 | DUP2_X1, DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, 38 | IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, 39 | IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, 40 | F2D, D2I, D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IFEQ, IFNE, IFLT, IFGE, 41 | IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, 42 | IF_ACMPNE, GOTO, JSR, RET, TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, 43 | ARETURN, RETURN, GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD, INVOKEVIRTUAL, INVOKESPECIAL, 44 | INVOKESTATIC, INVOKEINTERFACE, INVOKEDYNAMIC, NEW, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, 45 | CHECKCAST, INSTANCEOF, MONITORENTER, MONITOREXIT, WIDE, MULTIANEWARRAY, IFNULL, IFNONNULL, 46 | GOTO_W, JSR_W, BREAKPOINT, IMPDEP1, IMPDEP2 47 | }; 48 | 49 | // These are all required to be the same size because in other parts of the code we assume indices 50 | // for every table are commutative. e.g. See `find_instructions_cb`. 51 | static_assert(static_cast(bytecode_tag::IMPDEP2) + 1 == TOTAL_BYTECODE_INSTRUCTIONS, 52 | "Bytecode tables differ!"); 53 | 54 | constexpr std::array instruction_names = 55 | { 56 | "nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", 57 | "iconst_2", "iconst_3", "iconst_4", "iconst_5", "lconst_0", "lconst_1", "fconst_0", "fconst_1", 58 | "fconst_2", "dconst_0", "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", 59 | "iload", "lload", "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", "iload_3", 60 | "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", "fload_1", "fload_2", "fload_3", 61 | "dload_0", "dload_1", "dload_2", "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", 62 | "iaload", "laload", "faload", "daload", "aaload", "baload", "caload", "saload", "istore", 63 | "lstore", "fstore", "dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3", 64 | "lstore_0", "lstore_1", "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", "fstore_3", 65 | "dstore_0", "dstore_1", "dstore_2", "dstore_3", "astore_0", "astore_1", "astore_2", "astore_3", 66 | "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", 67 | "pop2", "dup", "dup_x1", "dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd", 68 | "fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", "ldiv", 69 | "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", 70 | "ishr", "lshr", "iushr", "lushr", "iand", "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", 71 | "i2f", "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", 72 | "i2s", "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", 73 | "ifle", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", "if_icmpgt", "if_icmple", 74 | "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn", 75 | "lreturn", "freturn", "dreturn", "areturn", "return", "getstatic", "putstatic", "getfield", 76 | "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface", 77 | "invokedynamic", "new", "newarray", "anewarray", "arraylength", "athrow", "checkcast", 78 | "instanceof", "monitorenter", "monitorexit", "wide", "multianewarray", "ifnull", "ifnonnull", 79 | "goto_w", "jsr_w", "breakpoint", "impdep1", "impdep2" 80 | }; 81 | 82 | constexpr std::array instruction_sizes = 83 | { 84 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 85 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 86 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 88 | 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 89 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, 90 | 3, 3, 1, 1, 1, 4, 3, 3, 5, 5, 1, 1, 1 91 | }; 92 | 93 | constexpr size_t get_instruction_size(bytecode_tag instr) 94 | { 95 | return instruction_sizes[static_cast(instr)]; 96 | } 97 | 98 | constexpr const char* const get_instruction_name(bytecode_tag instr) 99 | { 100 | return instruction_names[static_cast(instr)]; 101 | } 102 | -------------------------------------------------------------------------------- /include/code_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "attribute_info.hh" 29 | #include "bytecode.hh" 30 | #include "constant_pool.hh" 31 | #include "util.hh" 32 | 33 | struct exception_table_entry 34 | { 35 | uint16_t start_pc; 36 | uint16_t end_pc; 37 | uint16_t handler_pc; 38 | uint16_t catch_pc; 39 | 40 | explicit exception_table_entry(uint16_t start_pc, uint16_t end_pc, uint16_t handler_pc, 41 | uint16_t catch_pc) : 42 | start_pc{start_pc}, 43 | end_pc{end_pc}, 44 | handler_pc{handler_pc}, 45 | catch_pc{catch_pc} 46 | {} 47 | }; 48 | 49 | class code_attribute: public attribute_info 50 | { 51 | const constant_pool& cp; 52 | [[maybe_unused]] uint16_t max_stack; 53 | [[maybe_unused]] uint16_t max_locals; 54 | // Despite the program counter being a 2-byte short, the code length is a 4-byte int because of 55 | // the case where an instruction at address 0xFFFF is bigger than a byte (e.g. `lookupswitch` is a 56 | // variable-sized instruction thus exceeding the max size of the pc). 57 | uint32_t code_length; 58 | std::unique_ptr bytecode; 59 | std::vector exception_table; 60 | entry_attributes code_attributes; 61 | 62 | public: 63 | explicit code_attribute(const constant_pool& cp, uint16_t max_stack, uint16_t max_locals, 64 | uint32_t code_length, std::unique_ptr bytecode, 65 | std::vector exception_table, entry_attributes code_attributes) : 66 | cp{cp}, 67 | max_stack{max_stack}, 68 | max_locals{max_locals}, 69 | code_length{code_length}, 70 | bytecode{std::move(bytecode)}, 71 | exception_table{std::move(exception_table)}, 72 | code_attributes{std::move(code_attributes)} 73 | {} 74 | 75 | void print_code(std::ostream& out) const; 76 | 77 | template 78 | using find_instructions_cb = 79 | // Since each instruction tag is one byte, the instruction size minus one is the number of 80 | // instruction operands. 81 | typename find_instructions_cb_fn_type::type; 82 | 83 | template 84 | void find_instruction(find_instructions_cb cb) const 85 | { 86 | constexpr size_t target_instr_operands_size = get_instruction_size(instr) - 1; 87 | for (uint32_t pc = 0; pc < code_length;) 88 | { 89 | const bytecode_tag curr_instr = static_cast(bytecode[pc]); 90 | const size_t curr_instr_size = get_instruction_size(curr_instr); 91 | // These are variable-sized instructions and require special parsing. 92 | if (curr_instr == bytecode_tag::LOOKUPSWITCH || 93 | curr_instr == bytecode_tag::TABLESWITCH) 94 | { 95 | // Skip past padding bytes until we get to the first address that is a multiple of 4. 96 | if (pc % 4 != 0) 97 | { 98 | for (; pc % 4 != 0; pc++); 99 | } 100 | 101 | // Skip `default` bytes. 102 | pc += 4; 103 | if (curr_instr == bytecode_tag::LOOKUPSWITCH) 104 | { 105 | // `npairs` is a signed 4-byte, big-endian integer. This should probably never 106 | // be negative. 107 | uint32_t* npairs_bytes = reinterpret_cast(&bytecode[pc]); 108 | uint32_t npairs = to_little_endian_int(*npairs_bytes); 109 | // Each pair consists of two 4-byte ints. 110 | pc += 8 * npairs; 111 | } 112 | else if (curr_instr == bytecode_tag::TABLESWITCH) 113 | { 114 | // Read both `low` and `high` signed ints. These should probably never be 115 | // negative. 116 | uint32_t* low_bytes = reinterpret_cast(&bytecode[pc]); 117 | uint32_t low = to_little_endian_int(*low_bytes); 118 | pc += 4; 119 | 120 | uint32_t* high_bytes = reinterpret_cast(&bytecode[pc]); 121 | uint32_t high = to_little_endian_int(*high_bytes); 122 | // There are `high - low + 1` signed integer offsets that must be skipped. 123 | pc += 4 * (high - low + 1 + 1); 124 | } 125 | 126 | continue; 127 | } 128 | 129 | if (curr_instr == instr) 130 | { 131 | // The type of `operands` is a `std::tuple` with a variable number of types 132 | // (depends on the cb function given). 133 | typename function_args_tuple::type operands; 134 | std::get<0>(operands) = pc & 0xFFFF; 135 | // A `constexpr-for` construct would be perfect here... 136 | if constexpr (target_instr_operands_size >= 1) 137 | std::get<1>(operands) = bytecode[pc + 1]; 138 | if constexpr (target_instr_operands_size >= 2) 139 | std::get<2>(operands) = bytecode[pc + 2]; 140 | if constexpr (target_instr_operands_size >= 3) 141 | std::get<3>(operands) = bytecode[pc + 3]; 142 | if constexpr (target_instr_operands_size >= 4) 143 | std::get<4>(operands) = bytecode[pc + 4]; 144 | 145 | std::apply(cb, operands); 146 | } 147 | 148 | pc += curr_instr_size; 149 | } 150 | } 151 | 152 | const entry_attributes& get_code_attributes() const 153 | { 154 | return code_attributes; 155 | } 156 | 157 | virtual attribute_info_type get_type() const 158 | { 159 | return attribute_info_type::code; 160 | } 161 | }; 162 | 163 | std::unique_ptr parse_code_attribute(std::ifstream& file, const constant_pool& cp); 164 | -------------------------------------------------------------------------------- /include/constant_pool.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | using constant_pool_entry_id = uint16_t; 30 | 31 | #include "constant_pool_entry_parser.hh" 32 | 33 | enum class constant_pool_type : uint8_t 34 | { 35 | Utf8 = 1, Integer = 3, Float, Long, Double, Class, String, FieldRef, MethodRef, 36 | InterfaceMethodRef, NameAndType, MethodHandle = 15, MethodType = 16, InvokeDynamic = 18 37 | }; 38 | 39 | using constant_pool_entry = std::variant; 42 | 43 | struct constant_pool_entry_info 44 | { 45 | constant_pool_type type; 46 | constant_pool_entry entry; 47 | }; 48 | 49 | using constant_pool_entries = std::map; 50 | 51 | class constant_pool 52 | { 53 | constant_pool_entries entries; 54 | 55 | public: 56 | explicit constant_pool(constant_pool_entries entries); 57 | constant_pool() = default; 58 | 59 | size_t size() const 60 | { 61 | return entries.size(); 62 | } 63 | 64 | auto begin() const 65 | { 66 | return entries.begin(); 67 | } 68 | 69 | auto end() const 70 | { 71 | return entries.end(); 72 | } 73 | 74 | auto cbegin() const 75 | { 76 | return entries.cbegin(); 77 | } 78 | 79 | auto cend() const 80 | { 81 | return entries.cend(); 82 | } 83 | 84 | template 85 | std::optional get_entry_as(constant_pool_entry_id index) const 86 | { 87 | auto entries_it = entries.find(index); 88 | if (entries_it == entries.cend()) 89 | { 90 | return std::nullopt; 91 | } 92 | else 93 | { 94 | return std::get(entries_it->second.entry); 95 | } 96 | } 97 | 98 | std::optional get_entry_info(constant_pool_entry_id index) const; 99 | static constant_pool parse_constant_pool(std::ifstream& file); 100 | }; 101 | -------------------------------------------------------------------------------- /include/constant_pool_entry_parser.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "constant_pool.hh" 25 | 26 | template 27 | struct cp_value_entry 28 | { 29 | T value; 30 | }; 31 | using cp_utf8_entry = cp_value_entry; 32 | using cp_integer_entry = cp_value_entry; 33 | using cp_float_entry = cp_value_entry; 34 | using cp_long_entry = cp_value_entry; 35 | using cp_double_entry = cp_value_entry; 36 | 37 | struct cp_index_entry 38 | { 39 | constant_pool_entry_id cp_index; 40 | }; 41 | using cp_class_info_entry = cp_index_entry; 42 | using cp_string_info_entry = cp_index_entry; 43 | using cp_methodtype_info_entry = cp_index_entry; 44 | 45 | struct cp_double_index_entry 46 | { 47 | constant_pool_entry_id cp_index; 48 | constant_pool_entry_id cp_index2; 49 | }; 50 | using cp_fieldref_info_entry = cp_double_index_entry; 51 | using cp_methodref_info_entry = cp_double_index_entry; 52 | using cp_interfacemethodref_info_entry = cp_double_index_entry; 53 | using cp_name_and_type_index_entry = cp_double_index_entry; 54 | using cp_invokedynamic_info_entry = cp_double_index_entry; 55 | 56 | struct cp_methodhandle_info_entry 57 | { 58 | uint8_t reference_kind; 59 | constant_pool_entry_id reference_index; 60 | }; 61 | 62 | cp_utf8_entry parse_cp_utf8_entry(std::ifstream& file); 63 | cp_integer_entry parse_cp_integer_entry(std::ifstream& file); 64 | cp_float_entry parse_cp_float_entry(std::ifstream& file); 65 | cp_long_entry parse_cp_long_entry(std::ifstream& file); 66 | cp_double_entry parse_cp_double_entry(std::ifstream& file); 67 | cp_index_entry parse_cp_index_entry(std::ifstream& file); 68 | cp_double_index_entry parse_cp_double_index_entry(std::ifstream& file); 69 | cp_methodhandle_info_entry parse_cp_methodhandle_info_entry(std::ifstream& file); 70 | -------------------------------------------------------------------------------- /include/constant_value_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class constant_value_attribute: public attribute_info 29 | { 30 | constant_pool_entry_id constantvalue_index; 31 | 32 | public: 33 | explicit constant_value_attribute(constant_pool_entry_id constantvalue_index) : 34 | constantvalue_index{constantvalue_index} 35 | {} 36 | 37 | constant_pool_entry_id get_constant_value_index() const 38 | { 39 | return constantvalue_index; 40 | } 41 | 42 | virtual attribute_info_type get_type() const 43 | { 44 | return attribute_info_type::constant_value; 45 | } 46 | }; 47 | 48 | std::unique_ptr parse_constant_value_attribute(std::ifstream& file, 49 | const constant_pool& cp); 50 | -------------------------------------------------------------------------------- /include/deprecated_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class deprecated_attribute: public attribute_info 29 | { 30 | public: 31 | deprecated_attribute() = default; 32 | virtual attribute_info_type get_type() const 33 | { 34 | return attribute_info_type::deprecated; 35 | } 36 | }; 37 | 38 | std::unique_ptr parse_deprecated_attribute(std::ifstream& file, 39 | const constant_pool& cp); 40 | -------------------------------------------------------------------------------- /include/enclosing_method_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | #include "attribute_info.hh" 26 | #include "constant_pool.hh" 27 | #include "util.hh" 28 | 29 | class enclosing_method_attribute: public attribute_info 30 | { 31 | [[maybe_unused]] constant_pool_entry_id class_index; 32 | [[maybe_unused]] constant_pool_entry_id method_index; 33 | 34 | public: 35 | explicit enclosing_method_attribute(constant_pool_entry_id class_index, 36 | constant_pool_entry_id method_index) : 37 | class_index{class_index}, 38 | method_index{method_index} 39 | {} 40 | 41 | virtual attribute_info_type get_type() const 42 | { 43 | return attribute_info_type::enclosing_method; 44 | } 45 | }; 46 | 47 | std::unique_ptr parse_enclosing_method_attribute(std::ifstream& file, 48 | const constant_pool& cp); 49 | -------------------------------------------------------------------------------- /include/exceptions_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | #include "attribute_info.hh" 26 | #include "constant_pool.hh" 27 | #include "util.hh" 28 | 29 | class exceptions_attribute: public attribute_info 30 | { 31 | std::vector exception_index_table; 32 | 33 | public: 34 | explicit exceptions_attribute(std::vector exception_index_table) : 35 | exception_index_table{std::move(exception_index_table)} 36 | {} 37 | 38 | virtual attribute_info_type get_type() const 39 | { 40 | return attribute_info_type::exceptions; 41 | } 42 | }; 43 | 44 | std::unique_ptr parse_exceptions_attribute(std::ifstream& file, 45 | const constant_pool& cp); 46 | -------------------------------------------------------------------------------- /include/field_info.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "attribute_info.hh" 27 | #include "constant_pool.hh" 28 | 29 | enum class field_access_flags : uint16_t 30 | { 31 | Public = 0x1, Private = 0x2, Protected = 0x4, Static = 0x8, Final = 0x10, 32 | Volatile = 0x40, Transient = 0x80, Synthetic = 0x1000, Enum = 0x4000 33 | }; 34 | 35 | class field_info 36 | { 37 | [[maybe_unused]] const constant_pool& cp; 38 | [[maybe_unused]] field_access_flags access_flags; 39 | [[maybe_unused]] constant_pool_entry_id name_index; 40 | [[maybe_unused]] constant_pool_entry_id descriptor_index; 41 | entry_attributes field_attributes; 42 | 43 | explicit field_info(const constant_pool& cp, field_access_flags access_flags, 44 | constant_pool_entry_id name_index, constant_pool_entry_id descriptor_index, 45 | entry_attributes field_attributes); 46 | 47 | public: 48 | static field_info parse_field(std::ifstream& file, const constant_pool& cp); 49 | }; 50 | 51 | std::vector parse_fields(std::ifstream& file, const constant_pool& cp); 52 | -------------------------------------------------------------------------------- /include/find_api_calls.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | #include "java_class.hh" 26 | 27 | struct api_call_info 28 | { 29 | uint16_t line_number; 30 | std::string api_str; 31 | std::string method; 32 | }; 33 | 34 | std::vector find_api_calls(const java_class& clazz, 35 | const std::vector& apis); 36 | -------------------------------------------------------------------------------- /include/inner_classes_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | #include "attribute_info.hh" 26 | #include "constant_pool.hh" 27 | #include "util.hh" 28 | 29 | struct inner_class_entry 30 | { 31 | constant_pool_entry_id inner_class_info_index; 32 | constant_pool_entry_id outer_class_info_index; 33 | constant_pool_entry_id inner_name_index; 34 | uint16_t inner_class_access_flags; 35 | 36 | explicit inner_class_entry(constant_pool_entry_id inner_class_info_index, 37 | constant_pool_entry_id outer_class_info_index, constant_pool_entry_id inner_name_index, 38 | uint16_t inner_class_access_flags) : 39 | inner_class_info_index{inner_class_info_index}, 40 | outer_class_info_index{outer_class_info_index}, 41 | inner_name_index{inner_name_index}, 42 | inner_class_access_flags{inner_class_access_flags} 43 | {} 44 | }; 45 | 46 | class inner_classes_attribute: public attribute_info 47 | { 48 | std::vector inner_classes; 49 | 50 | public: 51 | explicit inner_classes_attribute(std::vector inner_classes) : 52 | inner_classes{std::move(inner_classes)} 53 | {} 54 | 55 | virtual attribute_info_type get_type() const 56 | { 57 | return attribute_info_type::inner_classes; 58 | } 59 | }; 60 | 61 | std::unique_ptr parse_inner_classes_attribute(std::ifstream& file, 62 | const constant_pool& cp); 63 | -------------------------------------------------------------------------------- /include/invalid_class_format_exception.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | class invalid_class_format: public std::runtime_error 25 | { 26 | public: 27 | explicit invalid_class_format(const char* message) : 28 | std::runtime_error{message} 29 | {} 30 | 31 | const char* what() const noexcept override 32 | { 33 | return std::runtime_error::what(); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /include/java_class.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "attribute_info.hh" 27 | #include "constant_pool.hh" 28 | #include "field_info.hh" 29 | #include "method_info.hh" 30 | 31 | enum class classfile_access_flag : uint16_t 32 | { 33 | Public = 0x1, Final = 0x10, Super = 0x20, Interface = 0x200, Abstract = 0x400, 34 | Synthetic = 0x1000, Annotation = 0x2000, Enum = 0x4000 35 | }; 36 | 37 | class java_class 38 | { 39 | constant_pool cp; 40 | classfile_access_flag access_flags; 41 | constant_pool_entry_id this_index; 42 | constant_pool_entry_id super_index; 43 | std::vector interfaces_ids; 44 | std::vector fields; 45 | std::vector methods; 46 | entry_attributes attributes; 47 | 48 | public: 49 | explicit java_class(constant_pool cp, classfile_access_flag access_flags, 50 | constant_pool_entry_id this_index, constant_pool_entry_id super_index, 51 | std::vector interfaces_ids, std::vector fields, 52 | std::vector methods, entry_attributes attributes); 53 | 54 | explicit java_class(constant_pool cp, classfile_access_flag access_flags, 55 | constant_pool_entry_id this_index, constant_pool_entry_id super_index, 56 | std::vector interfaces_ids); 57 | 58 | const constant_pool& get_class_constant_pool() const 59 | { 60 | return cp; 61 | } 62 | 63 | classfile_access_flag get_class_access_flags() const 64 | { 65 | return access_flags; 66 | } 67 | 68 | constant_pool_entry_id get_class_this_index() const 69 | { 70 | return this_index; 71 | } 72 | 73 | constant_pool_entry_id get_class_super_index() const 74 | { 75 | return super_index; 76 | } 77 | 78 | const std::vector& get_class_interfaces_ids() const 79 | { 80 | return interfaces_ids; 81 | } 82 | 83 | const std::vector& get_class_fields() const 84 | { 85 | return fields; 86 | } 87 | 88 | const std::vector& get_class_methods() const 89 | { 90 | return methods; 91 | } 92 | 93 | const entry_attributes& get_class_attributes() const 94 | { 95 | return attributes; 96 | } 97 | 98 | static java_class parse_class_file(const std::string& path); 99 | }; 100 | -------------------------------------------------------------------------------- /include/line_number_table_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "attribute_info.hh" 28 | #include "constant_pool.hh" 29 | #include "util.hh" 30 | 31 | struct line_number_table_entry 32 | { 33 | uint16_t start_pc; 34 | uint16_t line_number; 35 | 36 | explicit line_number_table_entry(uint16_t start_pc, uint16_t line_number) : 37 | start_pc{start_pc}, 38 | line_number{line_number} 39 | {} 40 | }; 41 | 42 | class line_number_table_attribute: public attribute_info { 43 | std::vector line_number_table; 44 | 45 | public: 46 | explicit line_number_table_attribute(std::vector line_number_table) : 47 | line_number_table{std::move(line_number_table)} 48 | {} 49 | 50 | std::optional find_line_number_from_pc(uint16_t pc) const 51 | { 52 | if (line_number_table.empty()) 53 | { 54 | return std::nullopt; 55 | } 56 | 57 | auto it = std::adjacent_find(line_number_table.cbegin(), line_number_table.cend(), 58 | [pc](const auto& curr_entry, const auto& next_entry) 59 | { 60 | return next_entry.start_pc > pc; 61 | }); 62 | // Past the end, so use the last element. 63 | if (it == line_number_table.cend()) 64 | { 65 | return line_number_table.back().line_number; 66 | } 67 | 68 | return it->line_number; 69 | } 70 | 71 | virtual attribute_info_type get_type() const 72 | { 73 | return attribute_info_type::line_number_table; 74 | } 75 | }; 76 | 77 | std::unique_ptr parse_line_number_table_attribute(std::ifstream& file, 78 | const constant_pool& cp); 79 | -------------------------------------------------------------------------------- /include/local_variable_table_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | #include "attribute_info.hh" 26 | #include "constant_pool.hh" 27 | #include "util.hh" 28 | 29 | struct local_variable_table_entry 30 | { 31 | uint16_t start_pc; 32 | uint16_t length; 33 | constant_pool_entry_id name_index; 34 | constant_pool_entry_id descriptor_index; 35 | uint16_t index; 36 | 37 | explicit local_variable_table_entry(uint16_t start_pc, uint16_t length, 38 | constant_pool_entry_id name_index, constant_pool_entry_id descriptor_index, uint16_t index) : 39 | start_pc{start_pc}, 40 | length{length}, 41 | name_index{name_index}, 42 | descriptor_index{descriptor_index}, 43 | index{index} 44 | {} 45 | }; 46 | 47 | class local_variable_table_attribute: public attribute_info { 48 | std::vector local_variable_table; 49 | 50 | public: 51 | explicit local_variable_table_attribute( 52 | std::vector local_variable_table) : 53 | local_variable_table{std::move(local_variable_table)} 54 | {} 55 | 56 | virtual attribute_info_type get_type() const 57 | { 58 | return attribute_info_type::local_variable_table; 59 | } 60 | }; 61 | 62 | std::unique_ptr parse_local_variable_table_attribute(std::ifstream& file, 63 | const constant_pool& cp); 64 | -------------------------------------------------------------------------------- /include/local_variable_type_table_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | #include "attribute_info.hh" 26 | #include "constant_pool.hh" 27 | #include "util.hh" 28 | 29 | struct local_variable_type_table_entry 30 | { 31 | uint16_t start_pc; 32 | uint16_t length; 33 | constant_pool_entry_id name_index; 34 | constant_pool_entry_id signature_index; 35 | uint16_t index; 36 | 37 | explicit local_variable_type_table_entry(uint16_t start_pc, uint16_t length, 38 | constant_pool_entry_id name_index, constant_pool_entry_id signature_index, uint16_t index) : 39 | start_pc{start_pc}, 40 | length{length}, 41 | name_index{name_index}, 42 | signature_index{signature_index}, 43 | index{index} 44 | {} 45 | }; 46 | 47 | class local_variable_type_table_attribute: public attribute_info { 48 | std::vector local_variable_type_table; 49 | 50 | public: 51 | explicit local_variable_type_table_attribute(std::vector 52 | local_variable_type_table) : 53 | local_variable_type_table{std::move(local_variable_type_table)} 54 | {} 55 | 56 | virtual attribute_info_type get_type() const 57 | { 58 | return attribute_info_type::local_variable_type_table; 59 | } 60 | }; 61 | 62 | std::unique_ptr parse_local_variable_type_table_attribute(std::ifstream& file, 63 | const constant_pool& cp); 64 | -------------------------------------------------------------------------------- /include/method_info.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "attribute_info.hh" 27 | #include "constant_pool.hh" 28 | 29 | enum class method_access_flags : uint16_t 30 | { 31 | Public = 0x1, Private = 0x2, Protected = 0x4, Static = 0x8, Final = 0x10, 32 | Synchronized = 0x20, Bridge = 0x40, Varargs = 0x80, Native = 0x100, 33 | Abstract = 0x400, Strict = 0x800, Synthetic = 0x1000 34 | }; 35 | 36 | class method_info 37 | { 38 | const constant_pool& cp; 39 | [[maybe_unused]] method_access_flags access_flags; 40 | constant_pool_entry_id name_index; 41 | [[maybe_unused]] constant_pool_entry_id descriptor_index; 42 | entry_attributes method_attributes; 43 | 44 | explicit method_info(const constant_pool& cp, method_access_flags access_flags, 45 | constant_pool_entry_id name_index, constant_pool_entry_id descriptor_index, 46 | entry_attributes method_attributes); 47 | 48 | public: 49 | constant_pool_entry_id get_name_index() const 50 | { 51 | return name_index; 52 | } 53 | 54 | std::string get_name() const 55 | { 56 | auto method_name_utf8_ref = cp.get_entry_as(name_index).value(); 57 | return method_name_utf8_ref.value; 58 | } 59 | 60 | const entry_attributes& get_method_attributes() const 61 | { 62 | return method_attributes; 63 | } 64 | 65 | static method_info parse_method_info(std::ifstream& file, const constant_pool& cp); 66 | }; 67 | 68 | std::vector parse_methods(std::ifstream& file, const constant_pool& cp); 69 | -------------------------------------------------------------------------------- /include/runtime_invisible_annotations_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class runtime_invisible_annotations_attribute: public attribute_info 29 | { 30 | public: 31 | runtime_invisible_annotations_attribute() = default; 32 | 33 | virtual attribute_info_type get_type() const 34 | { 35 | return attribute_info_type::runtime_invisible_annotations; 36 | } 37 | }; 38 | 39 | std::unique_ptr parse_runtime_invisible_annotations_attribute(std::ifstream& file, 40 | const constant_pool& cp); 41 | -------------------------------------------------------------------------------- /include/runtime_invisible_parameter_annotations_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class runtime_invisible_parameter_annotations_attribute: public attribute_info 29 | { 30 | public: 31 | runtime_invisible_parameter_annotations_attribute() = default; 32 | 33 | virtual attribute_info_type get_type() const 34 | { 35 | return attribute_info_type::runtime_invisible_parameter_annotations; 36 | } 37 | }; 38 | 39 | std::unique_ptr parse_runtime_invisible_parameter_annotations_attribute( 40 | std::ifstream& file, const constant_pool& cp); 41 | -------------------------------------------------------------------------------- /include/runtime_visible_annotations_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class runtime_visible_annotations_attribute: public attribute_info 29 | { 30 | public: 31 | runtime_visible_annotations_attribute() = default; 32 | 33 | virtual attribute_info_type get_type() const 34 | { 35 | return attribute_info_type::runtime_visible_annotations; 36 | } 37 | }; 38 | 39 | std::unique_ptr parse_runtime_visible_annotations_attribute(std::ifstream& file, 40 | const constant_pool& cp); 41 | -------------------------------------------------------------------------------- /include/runtime_visible_parameter_annotations_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class runtime_visible_parameter_annotations_attribute: public attribute_info 29 | { 30 | public: 31 | runtime_visible_parameter_annotations_attribute() = default; 32 | 33 | virtual attribute_info_type get_type() const 34 | { 35 | return attribute_info_type::runtime_visible_parameter_annotations; 36 | } 37 | }; 38 | 39 | std::unique_ptr parse_runtime_visible_parameter_annotations_attribute( 40 | std::ifstream& file, const constant_pool& cp); 41 | -------------------------------------------------------------------------------- /include/signature_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class signature_attribute: public attribute_info 29 | { 30 | constant_pool_entry_id signature_index; 31 | 32 | public: 33 | explicit signature_attribute(constant_pool_entry_id signature_index) : 34 | signature_index{signature_index} 35 | {} 36 | 37 | constant_pool_entry_id get_signature_index() const 38 | { 39 | return signature_index; 40 | } 41 | 42 | virtual attribute_info_type get_type() const 43 | { 44 | return attribute_info_type::signature; 45 | } 46 | }; 47 | 48 | std::unique_ptr parse_signature_attribute(std::ifstream& file, 49 | const constant_pool& cp); 50 | -------------------------------------------------------------------------------- /include/source_file_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class source_file_attribute: public attribute_info 29 | { 30 | [[maybe_unused]] constant_pool_entry_id sourcefile_index; 31 | 32 | public: 33 | explicit source_file_attribute(constant_pool_entry_id sourcefile_index) : 34 | sourcefile_index{sourcefile_index} 35 | {} 36 | 37 | virtual attribute_info_type get_type() const 38 | { 39 | return attribute_info_type::source_file; 40 | } 41 | }; 42 | 43 | std::unique_ptr parse_source_file_attribute(std::ifstream& file, 44 | const constant_pool& cp); 45 | -------------------------------------------------------------------------------- /include/stack_map_table_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class stack_map_table_attribute: public attribute_info 29 | { 30 | public: 31 | stack_map_table_attribute() = default; 32 | 33 | virtual attribute_info_type get_type() const 34 | { 35 | return attribute_info_type::stack_map_table; 36 | } 37 | }; 38 | 39 | std::unique_ptr parse_stack_map_table_attribute(std::ifstream& file, 40 | const constant_pool& cp); 41 | -------------------------------------------------------------------------------- /include/synthetic_attribute.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "attribute_info.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | class synthetic_attribute: public attribute_info 29 | { 30 | public: 31 | synthetic_attribute() = default; 32 | 33 | virtual attribute_info_type get_type() const 34 | { 35 | return attribute_info_type::synthetic; 36 | } 37 | }; 38 | 39 | std::unique_ptr parse_synthetic_attribute(std::ifstream& file, 40 | const constant_pool& cp); 41 | -------------------------------------------------------------------------------- /include/util.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "invalid_class_format_exception.hh" 27 | 28 | inline uint32_t to_little_endian_int(uint32_t n) 29 | { 30 | return (n & 0xFF) << 24 | ((n >> 8) & 0xFF) << 16 | ((n >> 16) & 0xFF) << 8 | 31 | ((n >> 24) & 0xFF); 32 | } 33 | 34 | inline uint16_t to_little_endian_short(uint16_t n) 35 | { 36 | return (n & 0xFF) << 8 | ((n >> 8) & 0xFF); 37 | } 38 | 39 | inline uint64_t to_little_endian_long(uint64_t n) 40 | { 41 | return (n & 0xFF) << 56 | ((n >> 8) & 0xFF) << 48 | ((n >> 16) & 0xFF) << 40 | 42 | ((n >> 24) & 0xFF) << 32 | ((n >> 32) & 0xFF) << 24 | ((n >> 40) & 0xFF) << 16 | 43 | ((n >> 48) & 0xFF) << 8 | ((n >> 56) & 0xFF); 44 | } 45 | 46 | #define READ_U1_FIELD(var, err_msg) \ 47 | uint8_t var; \ 48 | do \ 49 | { \ 50 | constexpr size_t var##_LENGTH = 1; \ 51 | if (!file.read(reinterpret_cast(&var), var##_LENGTH)) \ 52 | { \ 53 | throw invalid_class_format{err_msg}; \ 54 | } \ 55 | } \ 56 | while (0) 57 | 58 | #define READ_U2_FIELD(var, err_msg) \ 59 | uint16_t var; \ 60 | do \ 61 | { \ 62 | constexpr size_t var##_LENGTH = 2; \ 63 | if (!file.read(reinterpret_cast(&var), var##_LENGTH)) \ 64 | { \ 65 | throw invalid_class_format{err_msg}; \ 66 | } \ 67 | var = to_little_endian_short(var); \ 68 | } \ 69 | while (0) 70 | 71 | #define READ_U4_FIELD(var, err_msg) \ 72 | uint32_t var; \ 73 | do \ 74 | { \ 75 | constexpr size_t var##_LENGTH = 4; \ 76 | if (!file.read(reinterpret_cast(&var), var##_LENGTH)) \ 77 | { \ 78 | throw invalid_class_format{err_msg}; \ 79 | } \ 80 | var = to_little_endian_int(var); \ 81 | } \ 82 | while (0) 83 | 84 | template 85 | struct overloaded : Ts... 86 | { 87 | using Ts::operator()...; 88 | }; 89 | 90 | template 91 | overloaded(Ts...) -> overloaded; 92 | 93 | template 94 | struct function_args_tuple; 95 | 96 | template 97 | struct function_args_tuple> 98 | { 99 | using type = std::tuple; 100 | }; 101 | 102 | template 103 | struct find_instructions_cb_fn_type 104 | { 105 | using type = std::function; 106 | }; 107 | 108 | template <> 109 | struct find_instructions_cb_fn_type<1> 110 | { 111 | using type = std::function; 112 | }; 113 | 114 | template <> 115 | struct find_instructions_cb_fn_type<2> 116 | { 117 | using type = std::function; 118 | }; 119 | 120 | template <> 121 | struct find_instructions_cb_fn_type<3> 122 | { 123 | using type = std::function; 124 | }; 125 | 126 | template <> 127 | struct find_instructions_cb_fn_type<4> 128 | { 129 | using type = std::function; 130 | }; 131 | -------------------------------------------------------------------------------- /lib/cxxopts.hh: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | #ifndef CXXOPTS_HPP_INCLUDED 26 | #define CXXOPTS_HPP_INCLUDED 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #ifdef __cpp_lib_optional 43 | #include 44 | #define CXXOPTS_HAS_OPTIONAL 45 | #endif 46 | 47 | #ifndef CXXOPTS_VECTOR_DELIMITER 48 | #define CXXOPTS_VECTOR_DELIMITER ',' 49 | #endif 50 | 51 | #define CXXOPTS__VERSION_MAJOR 2 52 | #define CXXOPTS__VERSION_MINOR 2 53 | #define CXXOPTS__VERSION_PATCH 0 54 | 55 | namespace cxxopts 56 | { 57 | static constexpr struct { 58 | uint8_t major, minor, patch; 59 | } version = { 60 | CXXOPTS__VERSION_MAJOR, 61 | CXXOPTS__VERSION_MINOR, 62 | CXXOPTS__VERSION_PATCH 63 | }; 64 | } 65 | 66 | //when we ask cxxopts to use Unicode, help strings are processed using ICU, 67 | //which results in the correct lengths being computed for strings when they 68 | //are formatted for the help output 69 | //it is necessary to make sure that can be found by the 70 | //compiler, and that icu-uc is linked in to the binary. 71 | 72 | #ifdef CXXOPTS_USE_UNICODE 73 | #include 74 | 75 | namespace cxxopts 76 | { 77 | typedef icu::UnicodeString String; 78 | 79 | inline 80 | String 81 | toLocalString(std::string s) 82 | { 83 | return icu::UnicodeString::fromUTF8(std::move(s)); 84 | } 85 | 86 | class UnicodeStringIterator : public 87 | std::iterator 88 | { 89 | public: 90 | 91 | UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) 92 | : s(string) 93 | , i(pos) 94 | { 95 | } 96 | 97 | value_type 98 | operator*() const 99 | { 100 | return s->char32At(i); 101 | } 102 | 103 | bool 104 | operator==(const UnicodeStringIterator& rhs) const 105 | { 106 | return s == rhs.s && i == rhs.i; 107 | } 108 | 109 | bool 110 | operator!=(const UnicodeStringIterator& rhs) const 111 | { 112 | return !(*this == rhs); 113 | } 114 | 115 | UnicodeStringIterator& 116 | operator++() 117 | { 118 | ++i; 119 | return *this; 120 | } 121 | 122 | UnicodeStringIterator 123 | operator+(int32_t v) 124 | { 125 | return UnicodeStringIterator(s, i + v); 126 | } 127 | 128 | private: 129 | const icu::UnicodeString* s; 130 | int32_t i; 131 | }; 132 | 133 | inline 134 | String& 135 | stringAppend(String&s, String a) 136 | { 137 | return s.append(std::move(a)); 138 | } 139 | 140 | inline 141 | String& 142 | stringAppend(String& s, int n, UChar32 c) 143 | { 144 | for (int i = 0; i != n; ++i) 145 | { 146 | s.append(c); 147 | } 148 | 149 | return s; 150 | } 151 | 152 | template 153 | String& 154 | stringAppend(String& s, Iterator begin, Iterator end) 155 | { 156 | while (begin != end) 157 | { 158 | s.append(*begin); 159 | ++begin; 160 | } 161 | 162 | return s; 163 | } 164 | 165 | inline 166 | size_t 167 | stringLength(const String& s) 168 | { 169 | return s.length(); 170 | } 171 | 172 | inline 173 | std::string 174 | toUTF8String(const String& s) 175 | { 176 | std::string result; 177 | s.toUTF8String(result); 178 | 179 | return result; 180 | } 181 | 182 | inline 183 | bool 184 | empty(const String& s) 185 | { 186 | return s.isEmpty(); 187 | } 188 | } 189 | 190 | namespace std 191 | { 192 | inline 193 | cxxopts::UnicodeStringIterator 194 | begin(const icu::UnicodeString& s) 195 | { 196 | return cxxopts::UnicodeStringIterator(&s, 0); 197 | } 198 | 199 | inline 200 | cxxopts::UnicodeStringIterator 201 | end(const icu::UnicodeString& s) 202 | { 203 | return cxxopts::UnicodeStringIterator(&s, s.length()); 204 | } 205 | } 206 | 207 | //ifdef CXXOPTS_USE_UNICODE 208 | #else 209 | 210 | namespace cxxopts 211 | { 212 | typedef std::string String; 213 | 214 | template 215 | T 216 | toLocalString(T&& t) 217 | { 218 | return std::forward(t); 219 | } 220 | 221 | inline 222 | size_t 223 | stringLength(const String& s) 224 | { 225 | return s.length(); 226 | } 227 | 228 | inline 229 | String& 230 | stringAppend(String&s, String a) 231 | { 232 | return s.append(std::move(a)); 233 | } 234 | 235 | inline 236 | String& 237 | stringAppend(String& s, size_t n, char c) 238 | { 239 | return s.append(n, c); 240 | } 241 | 242 | template 243 | String& 244 | stringAppend(String& s, Iterator begin, Iterator end) 245 | { 246 | return s.append(begin, end); 247 | } 248 | 249 | template 250 | std::string 251 | toUTF8String(T&& t) 252 | { 253 | return std::forward(t); 254 | } 255 | 256 | inline 257 | bool 258 | empty(const std::string& s) 259 | { 260 | return s.empty(); 261 | } 262 | } 263 | 264 | //ifdef CXXOPTS_USE_UNICODE 265 | #endif 266 | 267 | namespace cxxopts 268 | { 269 | namespace 270 | { 271 | #ifdef _WIN32 272 | const std::string LQUOTE("\'"); 273 | const std::string RQUOTE("\'"); 274 | #else 275 | const std::string LQUOTE("‘"); 276 | const std::string RQUOTE("’"); 277 | #endif 278 | } 279 | 280 | class Value : public std::enable_shared_from_this 281 | { 282 | public: 283 | 284 | virtual ~Value() = default; 285 | 286 | virtual 287 | std::shared_ptr 288 | clone() const = 0; 289 | 290 | virtual void 291 | parse(const std::string& text) const = 0; 292 | 293 | virtual void 294 | parse() const = 0; 295 | 296 | virtual bool 297 | has_default() const = 0; 298 | 299 | virtual bool 300 | is_container() const = 0; 301 | 302 | virtual bool 303 | has_implicit() const = 0; 304 | 305 | virtual std::string 306 | get_default_value() const = 0; 307 | 308 | virtual std::string 309 | get_implicit_value() const = 0; 310 | 311 | virtual std::shared_ptr 312 | default_value(const std::string& value) = 0; 313 | 314 | virtual std::shared_ptr 315 | implicit_value(const std::string& value) = 0; 316 | 317 | virtual std::shared_ptr 318 | no_implicit_value() = 0; 319 | 320 | virtual bool 321 | is_boolean() const = 0; 322 | }; 323 | 324 | class OptionException : public std::exception 325 | { 326 | public: 327 | OptionException(const std::string& message) 328 | : m_message(message) 329 | { 330 | } 331 | 332 | virtual const char* 333 | what() const noexcept 334 | { 335 | return m_message.c_str(); 336 | } 337 | 338 | private: 339 | std::string m_message; 340 | }; 341 | 342 | class OptionSpecException : public OptionException 343 | { 344 | public: 345 | 346 | OptionSpecException(const std::string& message) 347 | : OptionException(message) 348 | { 349 | } 350 | }; 351 | 352 | class OptionParseException : public OptionException 353 | { 354 | public: 355 | OptionParseException(const std::string& message) 356 | : OptionException(message) 357 | { 358 | } 359 | }; 360 | 361 | class option_exists_error : public OptionSpecException 362 | { 363 | public: 364 | option_exists_error(const std::string& option) 365 | : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") 366 | { 367 | } 368 | }; 369 | 370 | class invalid_option_format_error : public OptionSpecException 371 | { 372 | public: 373 | invalid_option_format_error(const std::string& format) 374 | : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) 375 | { 376 | } 377 | }; 378 | 379 | class option_syntax_exception : public OptionParseException { 380 | public: 381 | option_syntax_exception(const std::string& text) 382 | : OptionParseException("Argument " + LQUOTE + text + RQUOTE + 383 | " starts with a - but has incorrect syntax") 384 | { 385 | } 386 | }; 387 | 388 | class option_not_exists_exception : public OptionParseException 389 | { 390 | public: 391 | option_not_exists_exception(const std::string& option) 392 | : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") 393 | { 394 | } 395 | }; 396 | 397 | class missing_argument_exception : public OptionParseException 398 | { 399 | public: 400 | missing_argument_exception(const std::string& option) 401 | : OptionParseException( 402 | "Option " + LQUOTE + option + RQUOTE + " is missing an argument" 403 | ) 404 | { 405 | } 406 | }; 407 | 408 | class option_requires_argument_exception : public OptionParseException 409 | { 410 | public: 411 | option_requires_argument_exception(const std::string& option) 412 | : OptionParseException( 413 | "Option " + LQUOTE + option + RQUOTE + " requires an argument" 414 | ) 415 | { 416 | } 417 | }; 418 | 419 | class option_not_has_argument_exception : public OptionParseException 420 | { 421 | public: 422 | option_not_has_argument_exception 423 | ( 424 | const std::string& option, 425 | const std::string& arg 426 | ) 427 | : OptionParseException( 428 | "Option " + LQUOTE + option + RQUOTE + 429 | " does not take an argument, but argument " + 430 | LQUOTE + arg + RQUOTE + " given" 431 | ) 432 | { 433 | } 434 | }; 435 | 436 | class option_not_present_exception : public OptionParseException 437 | { 438 | public: 439 | option_not_present_exception(const std::string& option) 440 | : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") 441 | { 442 | } 443 | }; 444 | 445 | class argument_incorrect_type : public OptionParseException 446 | { 447 | public: 448 | argument_incorrect_type 449 | ( 450 | const std::string& arg 451 | ) 452 | : OptionParseException( 453 | "Argument " + LQUOTE + arg + RQUOTE + " failed to parse" 454 | ) 455 | { 456 | } 457 | }; 458 | 459 | class option_required_exception : public OptionParseException 460 | { 461 | public: 462 | option_required_exception(const std::string& option) 463 | : OptionParseException( 464 | "Option " + LQUOTE + option + RQUOTE + " is required but not present" 465 | ) 466 | { 467 | } 468 | }; 469 | 470 | namespace values 471 | { 472 | namespace 473 | { 474 | std::basic_regex integer_pattern 475 | ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); 476 | std::basic_regex truthy_pattern 477 | ("(t|T)(rue)?|1"); 478 | std::basic_regex falsy_pattern 479 | ("(f|F)(alse)?|0"); 480 | } 481 | 482 | namespace detail 483 | { 484 | template 485 | struct SignedCheck; 486 | 487 | template 488 | struct SignedCheck 489 | { 490 | template 491 | void 492 | operator()(bool negative, U u, const std::string& text) 493 | { 494 | if (negative) 495 | { 496 | if (u > static_cast((std::numeric_limits::min)())) 497 | { 498 | throw argument_incorrect_type(text); 499 | } 500 | } 501 | else 502 | { 503 | if (u > static_cast((std::numeric_limits::max)())) 504 | { 505 | throw argument_incorrect_type(text); 506 | } 507 | } 508 | } 509 | }; 510 | 511 | template 512 | struct SignedCheck 513 | { 514 | template 515 | void 516 | operator()(bool, U, const std::string&) {} 517 | }; 518 | 519 | template 520 | void 521 | check_signed_range(bool negative, U value, const std::string& text) 522 | { 523 | SignedCheck::is_signed>()(negative, value, text); 524 | } 525 | } 526 | 527 | template 528 | R 529 | checked_negate(T&& t, const std::string&, std::true_type) 530 | { 531 | // if we got to here, then `t` is a positive number that fits into 532 | // `R`. So to avoid MSVC C4146, we first cast it to `R`. 533 | // See https://github.com/jarro2783/cxxopts/issues/62 for more details. 534 | return -static_cast(t-1)-1; 535 | } 536 | 537 | template 538 | T 539 | checked_negate(T&&, const std::string& text, std::false_type) 540 | { 541 | throw argument_incorrect_type(text); 542 | } 543 | 544 | template 545 | void 546 | integer_parser(const std::string& text, T& value) 547 | { 548 | std::smatch match; 549 | std::regex_match(text, match, integer_pattern); 550 | 551 | if (match.length() == 0) 552 | { 553 | throw argument_incorrect_type(text); 554 | } 555 | 556 | if (match.length(4) > 0) 557 | { 558 | value = 0; 559 | return; 560 | } 561 | 562 | using US = typename std::make_unsigned::type; 563 | 564 | constexpr bool is_signed = std::numeric_limits::is_signed; 565 | const bool negative = match.length(1) > 0; 566 | const uint8_t base = match.length(2) > 0 ? 16 : 10; 567 | 568 | auto value_match = match[3]; 569 | 570 | US result = 0; 571 | 572 | for (auto iter = value_match.first; iter != value_match.second; ++iter) 573 | { 574 | US digit = 0; 575 | 576 | if (*iter >= '0' && *iter <= '9') 577 | { 578 | digit = static_cast(*iter - '0'); 579 | } 580 | else if (base == 16 && *iter >= 'a' && *iter <= 'f') 581 | { 582 | digit = static_cast(*iter - 'a' + 10); 583 | } 584 | else if (base == 16 && *iter >= 'A' && *iter <= 'F') 585 | { 586 | digit = static_cast(*iter - 'A' + 10); 587 | } 588 | else 589 | { 590 | throw argument_incorrect_type(text); 591 | } 592 | 593 | US next = result * base + digit; 594 | if (result > next) 595 | { 596 | throw argument_incorrect_type(text); 597 | } 598 | 599 | result = next; 600 | } 601 | 602 | detail::check_signed_range(negative, result, text); 603 | 604 | if (negative) 605 | { 606 | value = checked_negate(result, 607 | text, 608 | std::integral_constant()); 609 | } 610 | else 611 | { 612 | value = static_cast(result); 613 | } 614 | } 615 | 616 | template 617 | void stringstream_parser(const std::string& text, T& value) 618 | { 619 | std::stringstream in(text); 620 | in >> value; 621 | if (!in) { 622 | throw argument_incorrect_type(text); 623 | } 624 | } 625 | 626 | inline 627 | void 628 | parse_value(const std::string& text, uint8_t& value) 629 | { 630 | integer_parser(text, value); 631 | } 632 | 633 | inline 634 | void 635 | parse_value(const std::string& text, int8_t& value) 636 | { 637 | integer_parser(text, value); 638 | } 639 | 640 | inline 641 | void 642 | parse_value(const std::string& text, uint16_t& value) 643 | { 644 | integer_parser(text, value); 645 | } 646 | 647 | inline 648 | void 649 | parse_value(const std::string& text, int16_t& value) 650 | { 651 | integer_parser(text, value); 652 | } 653 | 654 | inline 655 | void 656 | parse_value(const std::string& text, uint32_t& value) 657 | { 658 | integer_parser(text, value); 659 | } 660 | 661 | inline 662 | void 663 | parse_value(const std::string& text, int32_t& value) 664 | { 665 | integer_parser(text, value); 666 | } 667 | 668 | inline 669 | void 670 | parse_value(const std::string& text, uint64_t& value) 671 | { 672 | integer_parser(text, value); 673 | } 674 | 675 | inline 676 | void 677 | parse_value(const std::string& text, int64_t& value) 678 | { 679 | integer_parser(text, value); 680 | } 681 | 682 | inline 683 | void 684 | parse_value(const std::string& text, bool& value) 685 | { 686 | std::smatch result; 687 | std::regex_match(text, result, truthy_pattern); 688 | 689 | if (!result.empty()) 690 | { 691 | value = true; 692 | return; 693 | } 694 | 695 | std::regex_match(text, result, falsy_pattern); 696 | if (!result.empty()) 697 | { 698 | value = false; 699 | return; 700 | } 701 | 702 | throw argument_incorrect_type(text); 703 | } 704 | 705 | inline 706 | void 707 | parse_value(const std::string& text, std::string& value) 708 | { 709 | value = text; 710 | } 711 | 712 | // The fallback parser. It uses the stringstream parser to parse all types 713 | // that have not been overloaded explicitly. It has to be placed in the 714 | // source code before all other more specialized templates. 715 | template 716 | void 717 | parse_value(const std::string& text, T& value) { 718 | stringstream_parser(text, value); 719 | } 720 | 721 | template 722 | void 723 | parse_value(const std::string& text, std::vector& value) 724 | { 725 | std::stringstream in(text); 726 | std::string token; 727 | while(in.eof() == false && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) { 728 | T v; 729 | parse_value(token, v); 730 | value.emplace_back(std::move(v)); 731 | } 732 | } 733 | 734 | #ifdef CXXOPTS_HAS_OPTIONAL 735 | template 736 | void 737 | parse_value(const std::string& text, std::optional& value) 738 | { 739 | T result; 740 | parse_value(text, result); 741 | value = std::move(result); 742 | } 743 | #endif 744 | 745 | template 746 | struct type_is_container 747 | { 748 | static constexpr bool value = false; 749 | }; 750 | 751 | template 752 | struct type_is_container> 753 | { 754 | static constexpr bool value = true; 755 | }; 756 | 757 | template 758 | class abstract_value : public Value 759 | { 760 | using Self = abstract_value; 761 | 762 | public: 763 | abstract_value() 764 | : m_result(std::make_shared()) 765 | , m_store(m_result.get()) 766 | { 767 | } 768 | 769 | abstract_value(T* t) 770 | : m_store(t) 771 | { 772 | } 773 | 774 | virtual ~abstract_value() = default; 775 | 776 | abstract_value(const abstract_value& rhs) 777 | { 778 | if (rhs.m_result) 779 | { 780 | m_result = std::make_shared(); 781 | m_store = m_result.get(); 782 | } 783 | else 784 | { 785 | m_store = rhs.m_store; 786 | } 787 | 788 | m_default = rhs.m_default; 789 | m_implicit = rhs.m_implicit; 790 | m_default_value = rhs.m_default_value; 791 | m_implicit_value = rhs.m_implicit_value; 792 | } 793 | 794 | void 795 | parse(const std::string& text) const 796 | { 797 | parse_value(text, *m_store); 798 | } 799 | 800 | bool 801 | is_container() const 802 | { 803 | return type_is_container::value; 804 | } 805 | 806 | void 807 | parse() const 808 | { 809 | parse_value(m_default_value, *m_store); 810 | } 811 | 812 | bool 813 | has_default() const 814 | { 815 | return m_default; 816 | } 817 | 818 | bool 819 | has_implicit() const 820 | { 821 | return m_implicit; 822 | } 823 | 824 | std::shared_ptr 825 | default_value(const std::string& value) 826 | { 827 | m_default = true; 828 | m_default_value = value; 829 | return shared_from_this(); 830 | } 831 | 832 | std::shared_ptr 833 | implicit_value(const std::string& value) 834 | { 835 | m_implicit = true; 836 | m_implicit_value = value; 837 | return shared_from_this(); 838 | } 839 | 840 | std::shared_ptr 841 | no_implicit_value() 842 | { 843 | m_implicit = false; 844 | return shared_from_this(); 845 | } 846 | 847 | std::string 848 | get_default_value() const 849 | { 850 | return m_default_value; 851 | } 852 | 853 | std::string 854 | get_implicit_value() const 855 | { 856 | return m_implicit_value; 857 | } 858 | 859 | bool 860 | is_boolean() const 861 | { 862 | return std::is_same::value; 863 | } 864 | 865 | const T& 866 | get() const 867 | { 868 | if (m_store == nullptr) 869 | { 870 | return *m_result; 871 | } 872 | else 873 | { 874 | return *m_store; 875 | } 876 | } 877 | 878 | protected: 879 | std::shared_ptr m_result; 880 | T* m_store; 881 | 882 | bool m_default = false; 883 | bool m_implicit = false; 884 | 885 | std::string m_default_value; 886 | std::string m_implicit_value; 887 | }; 888 | 889 | template 890 | class standard_value : public abstract_value 891 | { 892 | public: 893 | using abstract_value::abstract_value; 894 | 895 | std::shared_ptr 896 | clone() const 897 | { 898 | return std::make_shared>(*this); 899 | } 900 | }; 901 | 902 | template <> 903 | class standard_value : public abstract_value 904 | { 905 | public: 906 | ~standard_value() = default; 907 | 908 | standard_value() 909 | { 910 | set_default_and_implicit(); 911 | } 912 | 913 | standard_value(bool* b) 914 | : abstract_value(b) 915 | { 916 | set_default_and_implicit(); 917 | } 918 | 919 | std::shared_ptr 920 | clone() const 921 | { 922 | return std::make_shared>(*this); 923 | } 924 | 925 | private: 926 | 927 | void 928 | set_default_and_implicit() 929 | { 930 | m_default = true; 931 | m_default_value = "false"; 932 | m_implicit = true; 933 | m_implicit_value = "true"; 934 | } 935 | }; 936 | } 937 | 938 | template 939 | std::shared_ptr 940 | value() 941 | { 942 | return std::make_shared>(); 943 | } 944 | 945 | template 946 | std::shared_ptr 947 | value(T& t) 948 | { 949 | return std::make_shared>(&t); 950 | } 951 | 952 | class OptionAdder; 953 | 954 | class OptionDetails 955 | { 956 | public: 957 | OptionDetails 958 | ( 959 | const std::string& short_, 960 | const std::string& long_, 961 | const String& desc, 962 | std::shared_ptr val 963 | ) 964 | : m_short(short_) 965 | , m_long(long_) 966 | , m_desc(desc) 967 | , m_value(val) 968 | , m_count(0) 969 | { 970 | } 971 | 972 | OptionDetails(const OptionDetails& rhs) 973 | : m_desc(rhs.m_desc) 974 | , m_count(rhs.m_count) 975 | { 976 | m_value = rhs.m_value->clone(); 977 | } 978 | 979 | OptionDetails(OptionDetails&& rhs) = default; 980 | 981 | const String& 982 | description() const 983 | { 984 | return m_desc; 985 | } 986 | 987 | const Value& value() const { 988 | return *m_value; 989 | } 990 | 991 | std::shared_ptr 992 | make_storage() const 993 | { 994 | return m_value->clone(); 995 | } 996 | 997 | const std::string& 998 | short_name() const 999 | { 1000 | return m_short; 1001 | } 1002 | 1003 | const std::string& 1004 | long_name() const 1005 | { 1006 | return m_long; 1007 | } 1008 | 1009 | private: 1010 | std::string m_short; 1011 | std::string m_long; 1012 | String m_desc; 1013 | std::shared_ptr m_value; 1014 | int m_count; 1015 | }; 1016 | 1017 | struct HelpOptionDetails 1018 | { 1019 | std::string s; 1020 | std::string l; 1021 | String desc; 1022 | bool has_default; 1023 | std::string default_value; 1024 | bool has_implicit; 1025 | std::string implicit_value; 1026 | std::string arg_help; 1027 | bool is_container; 1028 | bool is_boolean; 1029 | }; 1030 | 1031 | struct HelpGroupDetails 1032 | { 1033 | std::string name; 1034 | std::string description; 1035 | std::vector options; 1036 | }; 1037 | 1038 | class OptionValue 1039 | { 1040 | public: 1041 | void 1042 | parse 1043 | ( 1044 | std::shared_ptr details, 1045 | const std::string& text 1046 | ) 1047 | { 1048 | ensure_value(details); 1049 | ++m_count; 1050 | m_value->parse(text); 1051 | } 1052 | 1053 | void 1054 | parse_default(std::shared_ptr details) 1055 | { 1056 | ensure_value(details); 1057 | m_value->parse(); 1058 | } 1059 | 1060 | size_t 1061 | count() const 1062 | { 1063 | return m_count; 1064 | } 1065 | 1066 | template 1067 | const T& 1068 | as() const 1069 | { 1070 | if (m_value == nullptr) { 1071 | throw std::domain_error("No value"); 1072 | } 1073 | 1074 | #ifdef CXXOPTS_NO_RTTI 1075 | return static_cast&>(*m_value).get(); 1076 | #else 1077 | return dynamic_cast&>(*m_value).get(); 1078 | #endif 1079 | } 1080 | 1081 | private: 1082 | void 1083 | ensure_value(std::shared_ptr details) 1084 | { 1085 | if (m_value == nullptr) 1086 | { 1087 | m_value = details->make_storage(); 1088 | } 1089 | } 1090 | 1091 | std::shared_ptr m_value; 1092 | size_t m_count = 0; 1093 | }; 1094 | 1095 | class KeyValue 1096 | { 1097 | public: 1098 | KeyValue(std::string key_, std::string value_) 1099 | : m_key(std::move(key_)) 1100 | , m_value(std::move(value_)) 1101 | { 1102 | } 1103 | 1104 | const 1105 | std::string& 1106 | key() const 1107 | { 1108 | return m_key; 1109 | } 1110 | 1111 | const 1112 | std::string& 1113 | value() const 1114 | { 1115 | return m_value; 1116 | } 1117 | 1118 | template 1119 | T 1120 | as() const 1121 | { 1122 | T result; 1123 | values::parse_value(m_value, result); 1124 | return result; 1125 | } 1126 | 1127 | private: 1128 | std::string m_key; 1129 | std::string m_value; 1130 | }; 1131 | 1132 | class ParseResult 1133 | { 1134 | public: 1135 | 1136 | ParseResult( 1137 | const std::shared_ptr< 1138 | std::unordered_map> 1139 | >, 1140 | std::vector, 1141 | bool allow_unrecognised, 1142 | int&, char**&); 1143 | 1144 | size_t 1145 | count(const std::string& o) const 1146 | { 1147 | auto iter = m_options->find(o); 1148 | if (iter == m_options->end()) 1149 | { 1150 | return 0; 1151 | } 1152 | 1153 | auto riter = m_results.find(iter->second); 1154 | 1155 | return riter->second.count(); 1156 | } 1157 | 1158 | const OptionValue& 1159 | operator[](const std::string& option) const 1160 | { 1161 | auto iter = m_options->find(option); 1162 | 1163 | if (iter == m_options->end()) 1164 | { 1165 | throw option_not_present_exception(option); 1166 | } 1167 | 1168 | auto riter = m_results.find(iter->second); 1169 | 1170 | return riter->second; 1171 | } 1172 | 1173 | const std::vector& 1174 | arguments() const 1175 | { 1176 | return m_sequential; 1177 | } 1178 | 1179 | private: 1180 | 1181 | void 1182 | parse(int& argc, char**& argv); 1183 | 1184 | void 1185 | add_to_option(const std::string& option, const std::string& arg); 1186 | 1187 | bool 1188 | consume_positional(std::string a); 1189 | 1190 | void 1191 | parse_option 1192 | ( 1193 | std::shared_ptr value, 1194 | const std::string& name, 1195 | const std::string& arg = "" 1196 | ); 1197 | 1198 | void 1199 | parse_default(std::shared_ptr details); 1200 | 1201 | void 1202 | checked_parse_arg 1203 | ( 1204 | int argc, 1205 | char* argv[], 1206 | int& current, 1207 | std::shared_ptr value, 1208 | const std::string& name 1209 | ); 1210 | 1211 | const std::shared_ptr< 1212 | std::unordered_map> 1213 | > m_options; 1214 | std::vector m_positional; 1215 | std::vector::iterator m_next_positional; 1216 | std::unordered_set m_positional_set; 1217 | std::unordered_map, OptionValue> m_results; 1218 | 1219 | bool m_allow_unrecognised; 1220 | 1221 | std::vector m_sequential; 1222 | }; 1223 | 1224 | class Options 1225 | { 1226 | typedef std::unordered_map> 1227 | OptionMap; 1228 | public: 1229 | 1230 | Options(std::string program, std::string help_string = "") 1231 | : m_program(std::move(program)) 1232 | , m_help_string(toLocalString(std::move(help_string))) 1233 | , m_custom_help("[OPTION...]") 1234 | , m_positional_help("positional parameters") 1235 | , m_show_positional(false) 1236 | , m_allow_unrecognised(false) 1237 | , m_options(std::make_shared()) 1238 | , m_next_positional(m_positional.end()) 1239 | { 1240 | } 1241 | 1242 | Options& 1243 | positional_help(std::string help_text) 1244 | { 1245 | m_positional_help = std::move(help_text); 1246 | return *this; 1247 | } 1248 | 1249 | Options& 1250 | custom_help(std::string help_text) 1251 | { 1252 | m_custom_help = std::move(help_text); 1253 | return *this; 1254 | } 1255 | 1256 | Options& 1257 | show_positional_help() 1258 | { 1259 | m_show_positional = true; 1260 | return *this; 1261 | } 1262 | 1263 | Options& 1264 | allow_unrecognised_options() 1265 | { 1266 | m_allow_unrecognised = true; 1267 | return *this; 1268 | } 1269 | 1270 | ParseResult 1271 | parse(int& argc, char**& argv); 1272 | 1273 | OptionAdder 1274 | add_options(std::string group = ""); 1275 | 1276 | void 1277 | add_option 1278 | ( 1279 | const std::string& group, 1280 | const std::string& s, 1281 | const std::string& l, 1282 | std::string desc, 1283 | std::shared_ptr value, 1284 | std::string arg_help 1285 | ); 1286 | 1287 | //parse positional arguments into the given option 1288 | void 1289 | parse_positional(std::string option); 1290 | 1291 | void 1292 | parse_positional(std::vector options); 1293 | 1294 | void 1295 | parse_positional(std::initializer_list options); 1296 | 1297 | template 1298 | void 1299 | parse_positional(Iterator begin, Iterator end) { 1300 | parse_positional(std::vector{begin, end}); 1301 | } 1302 | 1303 | std::string 1304 | help(const std::vector& groups = {}) const; 1305 | 1306 | const std::vector 1307 | groups() const; 1308 | 1309 | const HelpGroupDetails& 1310 | group_help(const std::string& group) const; 1311 | 1312 | private: 1313 | 1314 | void 1315 | add_one_option 1316 | ( 1317 | const std::string& option, 1318 | std::shared_ptr details 1319 | ); 1320 | 1321 | String 1322 | help_one_group(const std::string& group) const; 1323 | 1324 | void 1325 | generate_group_help 1326 | ( 1327 | String& result, 1328 | const std::vector& groups 1329 | ) const; 1330 | 1331 | void 1332 | generate_all_groups_help(String& result) const; 1333 | 1334 | std::string m_program; 1335 | String m_help_string; 1336 | std::string m_custom_help; 1337 | std::string m_positional_help; 1338 | bool m_show_positional; 1339 | bool m_allow_unrecognised; 1340 | 1341 | std::shared_ptr m_options; 1342 | std::vector m_positional; 1343 | std::vector::iterator m_next_positional; 1344 | std::unordered_set m_positional_set; 1345 | 1346 | //mapping from groups to help options 1347 | std::map m_help; 1348 | }; 1349 | 1350 | class OptionAdder 1351 | { 1352 | public: 1353 | 1354 | OptionAdder(Options& options, std::string group) 1355 | : m_options(options), m_group(std::move(group)) 1356 | { 1357 | } 1358 | 1359 | OptionAdder& 1360 | operator() 1361 | ( 1362 | const std::string& opts, 1363 | const std::string& desc, 1364 | std::shared_ptr value 1365 | = ::cxxopts::value(), 1366 | std::string arg_help = "" 1367 | ); 1368 | 1369 | private: 1370 | Options& m_options; 1371 | std::string m_group; 1372 | }; 1373 | 1374 | namespace 1375 | { 1376 | constexpr int OPTION_LONGEST = 30; 1377 | constexpr int OPTION_DESC_GAP = 2; 1378 | 1379 | std::basic_regex option_matcher 1380 | ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); 1381 | 1382 | std::basic_regex option_specifier 1383 | ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); 1384 | 1385 | String 1386 | format_option 1387 | ( 1388 | const HelpOptionDetails& o 1389 | ) 1390 | { 1391 | auto& s = o.s; 1392 | auto& l = o.l; 1393 | 1394 | String result = " "; 1395 | 1396 | if (s.size() > 0) 1397 | { 1398 | result += "-" + toLocalString(s) + ","; 1399 | } 1400 | else 1401 | { 1402 | result += " "; 1403 | } 1404 | 1405 | if (l.size() > 0) 1406 | { 1407 | result += " --" + toLocalString(l); 1408 | } 1409 | 1410 | auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg"; 1411 | 1412 | if (!o.is_boolean) 1413 | { 1414 | if (o.has_implicit) 1415 | { 1416 | result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]"; 1417 | } 1418 | else 1419 | { 1420 | result += " " + arg; 1421 | } 1422 | } 1423 | 1424 | return result; 1425 | } 1426 | 1427 | String 1428 | format_description 1429 | ( 1430 | const HelpOptionDetails& o, 1431 | size_t start, 1432 | size_t width 1433 | ) 1434 | { 1435 | auto desc = o.desc; 1436 | 1437 | if (o.has_default && (!o.is_boolean || o.default_value != "false")) 1438 | { 1439 | desc += toLocalString(" (default: " + o.default_value + ")"); 1440 | } 1441 | 1442 | String result; 1443 | 1444 | auto current = std::begin(desc); 1445 | auto startLine = current; 1446 | auto lastSpace = current; 1447 | 1448 | auto size = size_t{}; 1449 | 1450 | while (current != std::end(desc)) 1451 | { 1452 | if (*current == ' ') 1453 | { 1454 | lastSpace = current; 1455 | } 1456 | 1457 | if (*current == '\n') 1458 | { 1459 | startLine = current + 1; 1460 | lastSpace = startLine; 1461 | } 1462 | else if (size > width) 1463 | { 1464 | if (lastSpace == startLine) 1465 | { 1466 | stringAppend(result, startLine, current + 1); 1467 | stringAppend(result, "\n"); 1468 | stringAppend(result, start, ' '); 1469 | startLine = current + 1; 1470 | lastSpace = startLine; 1471 | } 1472 | else 1473 | { 1474 | stringAppend(result, startLine, lastSpace); 1475 | stringAppend(result, "\n"); 1476 | stringAppend(result, start, ' '); 1477 | startLine = lastSpace + 1; 1478 | } 1479 | size = 0; 1480 | } 1481 | else 1482 | { 1483 | ++size; 1484 | } 1485 | 1486 | ++current; 1487 | } 1488 | 1489 | //append whatever is left 1490 | stringAppend(result, startLine, current); 1491 | 1492 | return result; 1493 | } 1494 | } 1495 | 1496 | inline 1497 | ParseResult::ParseResult 1498 | ( 1499 | const std::shared_ptr< 1500 | std::unordered_map> 1501 | > options, 1502 | std::vector positional, 1503 | bool allow_unrecognised, 1504 | int& argc, char**& argv 1505 | ) 1506 | : m_options(options) 1507 | , m_positional(std::move(positional)) 1508 | , m_next_positional(m_positional.begin()) 1509 | , m_allow_unrecognised(allow_unrecognised) 1510 | { 1511 | parse(argc, argv); 1512 | } 1513 | 1514 | inline 1515 | OptionAdder 1516 | Options::add_options(std::string group) 1517 | { 1518 | return OptionAdder(*this, std::move(group)); 1519 | } 1520 | 1521 | inline 1522 | OptionAdder& 1523 | OptionAdder::operator() 1524 | ( 1525 | const std::string& opts, 1526 | const std::string& desc, 1527 | std::shared_ptr value, 1528 | std::string arg_help 1529 | ) 1530 | { 1531 | std::match_results result; 1532 | std::regex_match(opts.c_str(), result, option_specifier); 1533 | 1534 | if (result.empty()) 1535 | { 1536 | throw invalid_option_format_error(opts); 1537 | } 1538 | 1539 | const auto& short_match = result[2]; 1540 | const auto& long_match = result[3]; 1541 | 1542 | if (!short_match.length() && !long_match.length()) 1543 | { 1544 | throw invalid_option_format_error(opts); 1545 | } else if (long_match.length() == 1 && short_match.length()) 1546 | { 1547 | throw invalid_option_format_error(opts); 1548 | } 1549 | 1550 | auto option_names = [] 1551 | ( 1552 | const std::sub_match& short_, 1553 | const std::sub_match& long_ 1554 | ) 1555 | { 1556 | if (long_.length() == 1) 1557 | { 1558 | return std::make_tuple(long_.str(), short_.str()); 1559 | } 1560 | else 1561 | { 1562 | return std::make_tuple(short_.str(), long_.str()); 1563 | } 1564 | }(short_match, long_match); 1565 | 1566 | m_options.add_option 1567 | ( 1568 | m_group, 1569 | std::get<0>(option_names), 1570 | std::get<1>(option_names), 1571 | desc, 1572 | value, 1573 | std::move(arg_help) 1574 | ); 1575 | 1576 | return *this; 1577 | } 1578 | 1579 | inline 1580 | void 1581 | ParseResult::parse_default(std::shared_ptr details) 1582 | { 1583 | m_results[details].parse_default(details); 1584 | } 1585 | 1586 | inline 1587 | void 1588 | ParseResult::parse_option 1589 | ( 1590 | std::shared_ptr value, 1591 | const std::string& /*name*/, 1592 | const std::string& arg 1593 | ) 1594 | { 1595 | auto& result = m_results[value]; 1596 | result.parse(value, arg); 1597 | 1598 | m_sequential.emplace_back(value->long_name(), arg); 1599 | } 1600 | 1601 | inline 1602 | void 1603 | ParseResult::checked_parse_arg 1604 | ( 1605 | int argc, 1606 | char* argv[], 1607 | int& current, 1608 | std::shared_ptr value, 1609 | const std::string& name 1610 | ) 1611 | { 1612 | if (current + 1 >= argc) 1613 | { 1614 | if (value->value().has_implicit()) 1615 | { 1616 | parse_option(value, name, value->value().get_implicit_value()); 1617 | } 1618 | else 1619 | { 1620 | throw missing_argument_exception(name); 1621 | } 1622 | } 1623 | else 1624 | { 1625 | if (value->value().has_implicit()) 1626 | { 1627 | parse_option(value, name, value->value().get_implicit_value()); 1628 | } 1629 | else 1630 | { 1631 | parse_option(value, name, argv[current + 1]); 1632 | ++current; 1633 | } 1634 | } 1635 | } 1636 | 1637 | inline 1638 | void 1639 | ParseResult::add_to_option(const std::string& option, const std::string& arg) 1640 | { 1641 | auto iter = m_options->find(option); 1642 | 1643 | if (iter == m_options->end()) 1644 | { 1645 | throw option_not_exists_exception(option); 1646 | } 1647 | 1648 | parse_option(iter->second, option, arg); 1649 | } 1650 | 1651 | inline 1652 | bool 1653 | ParseResult::consume_positional(std::string a) 1654 | { 1655 | while (m_next_positional != m_positional.end()) 1656 | { 1657 | auto iter = m_options->find(*m_next_positional); 1658 | if (iter != m_options->end()) 1659 | { 1660 | auto& result = m_results[iter->second]; 1661 | if (!iter->second->value().is_container()) 1662 | { 1663 | if (result.count() == 0) 1664 | { 1665 | add_to_option(*m_next_positional, a); 1666 | ++m_next_positional; 1667 | return true; 1668 | } 1669 | else 1670 | { 1671 | ++m_next_positional; 1672 | continue; 1673 | } 1674 | } 1675 | else 1676 | { 1677 | add_to_option(*m_next_positional, a); 1678 | return true; 1679 | } 1680 | } 1681 | else 1682 | { 1683 | throw option_not_exists_exception(*m_next_positional); 1684 | } 1685 | } 1686 | 1687 | return false; 1688 | } 1689 | 1690 | inline 1691 | void 1692 | Options::parse_positional(std::string option) 1693 | { 1694 | parse_positional(std::vector{std::move(option)}); 1695 | } 1696 | 1697 | inline 1698 | void 1699 | Options::parse_positional(std::vector options) 1700 | { 1701 | m_positional = std::move(options); 1702 | m_next_positional = m_positional.begin(); 1703 | 1704 | m_positional_set.insert(m_positional.begin(), m_positional.end()); 1705 | } 1706 | 1707 | inline 1708 | void 1709 | Options::parse_positional(std::initializer_list options) 1710 | { 1711 | parse_positional(std::vector(std::move(options))); 1712 | } 1713 | 1714 | inline 1715 | ParseResult 1716 | Options::parse(int& argc, char**& argv) 1717 | { 1718 | ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv); 1719 | return result; 1720 | } 1721 | 1722 | inline 1723 | void 1724 | ParseResult::parse(int& argc, char**& argv) 1725 | { 1726 | int current = 1; 1727 | 1728 | int nextKeep = 1; 1729 | 1730 | bool consume_remaining = false; 1731 | 1732 | while (current != argc) 1733 | { 1734 | if (strcmp(argv[current], "--") == 0) 1735 | { 1736 | consume_remaining = true; 1737 | ++current; 1738 | break; 1739 | } 1740 | 1741 | std::match_results result; 1742 | std::regex_match(argv[current], result, option_matcher); 1743 | 1744 | if (result.empty()) 1745 | { 1746 | //not a flag 1747 | 1748 | // but if it starts with a `-`, then it's an error 1749 | if (argv[current][0] == '-' && argv[current][1] != '\0') { 1750 | if (!m_allow_unrecognised) { 1751 | throw option_syntax_exception(argv[current]); 1752 | } 1753 | } 1754 | 1755 | //if true is returned here then it was consumed, otherwise it is 1756 | //ignored 1757 | if (consume_positional(argv[current])) 1758 | { 1759 | } 1760 | else 1761 | { 1762 | argv[nextKeep] = argv[current]; 1763 | ++nextKeep; 1764 | } 1765 | //if we return from here then it was parsed successfully, so continue 1766 | } 1767 | else 1768 | { 1769 | //short or long option? 1770 | if (result[4].length() != 0) 1771 | { 1772 | const std::string& s = result[4]; 1773 | 1774 | for (std::size_t i = 0; i != s.size(); ++i) 1775 | { 1776 | std::string name(1, s[i]); 1777 | auto iter = m_options->find(name); 1778 | 1779 | if (iter == m_options->end()) 1780 | { 1781 | if (m_allow_unrecognised) 1782 | { 1783 | continue; 1784 | } 1785 | else 1786 | { 1787 | //error 1788 | throw option_not_exists_exception(name); 1789 | } 1790 | } 1791 | 1792 | auto value = iter->second; 1793 | 1794 | if (i + 1 == s.size()) 1795 | { 1796 | //it must be the last argument 1797 | checked_parse_arg(argc, argv, current, value, name); 1798 | } 1799 | else if (value->value().has_implicit()) 1800 | { 1801 | parse_option(value, name, value->value().get_implicit_value()); 1802 | } 1803 | else 1804 | { 1805 | //error 1806 | throw option_requires_argument_exception(name); 1807 | } 1808 | } 1809 | } 1810 | else if (result[1].length() != 0) 1811 | { 1812 | const std::string& name = result[1]; 1813 | 1814 | auto iter = m_options->find(name); 1815 | 1816 | if (iter == m_options->end()) 1817 | { 1818 | if (m_allow_unrecognised) 1819 | { 1820 | // keep unrecognised options in argument list, skip to next argument 1821 | argv[nextKeep] = argv[current]; 1822 | ++nextKeep; 1823 | ++current; 1824 | continue; 1825 | } 1826 | else 1827 | { 1828 | //error 1829 | throw option_not_exists_exception(name); 1830 | } 1831 | } 1832 | 1833 | auto opt = iter->second; 1834 | 1835 | //equals provided for long option? 1836 | if (result[2].length() != 0) 1837 | { 1838 | //parse the option given 1839 | 1840 | parse_option(opt, name, result[3]); 1841 | } 1842 | else 1843 | { 1844 | //parse the next argument 1845 | checked_parse_arg(argc, argv, current, opt, name); 1846 | } 1847 | } 1848 | 1849 | } 1850 | 1851 | ++current; 1852 | } 1853 | 1854 | for (auto& opt : *m_options) 1855 | { 1856 | auto& detail = opt.second; 1857 | auto& value = detail->value(); 1858 | 1859 | auto& store = m_results[detail]; 1860 | 1861 | if(!store.count() && value.has_default()){ 1862 | parse_default(detail); 1863 | } 1864 | } 1865 | 1866 | if (consume_remaining) 1867 | { 1868 | while (current < argc) 1869 | { 1870 | if (!consume_positional(argv[current])) { 1871 | break; 1872 | } 1873 | ++current; 1874 | } 1875 | 1876 | //adjust argv for any that couldn't be swallowed 1877 | while (current != argc) { 1878 | argv[nextKeep] = argv[current]; 1879 | ++nextKeep; 1880 | ++current; 1881 | } 1882 | } 1883 | 1884 | argc = nextKeep; 1885 | 1886 | } 1887 | 1888 | inline 1889 | void 1890 | Options::add_option 1891 | ( 1892 | const std::string& group, 1893 | const std::string& s, 1894 | const std::string& l, 1895 | std::string desc, 1896 | std::shared_ptr value, 1897 | std::string arg_help 1898 | ) 1899 | { 1900 | auto stringDesc = toLocalString(std::move(desc)); 1901 | auto option = std::make_shared(s, l, stringDesc, value); 1902 | 1903 | if (s.size() > 0) 1904 | { 1905 | add_one_option(s, option); 1906 | } 1907 | 1908 | if (l.size() > 0) 1909 | { 1910 | add_one_option(l, option); 1911 | } 1912 | 1913 | //add the help details 1914 | auto& options = m_help[group]; 1915 | 1916 | options.options.emplace_back(HelpOptionDetails{s, l, stringDesc, 1917 | value->has_default(), value->get_default_value(), 1918 | value->has_implicit(), value->get_implicit_value(), 1919 | std::move(arg_help), 1920 | value->is_container(), 1921 | value->is_boolean()}); 1922 | } 1923 | 1924 | inline 1925 | void 1926 | Options::add_one_option 1927 | ( 1928 | const std::string& option, 1929 | std::shared_ptr details 1930 | ) 1931 | { 1932 | auto in = m_options->emplace(option, details); 1933 | 1934 | if (!in.second) 1935 | { 1936 | throw option_exists_error(option); 1937 | } 1938 | } 1939 | 1940 | inline 1941 | String 1942 | Options::help_one_group(const std::string& g) const 1943 | { 1944 | typedef std::vector> OptionHelp; 1945 | 1946 | auto group = m_help.find(g); 1947 | if (group == m_help.end()) 1948 | { 1949 | return ""; 1950 | } 1951 | 1952 | OptionHelp format; 1953 | 1954 | size_t longest = 0; 1955 | 1956 | String result; 1957 | 1958 | if (!g.empty()) 1959 | { 1960 | result += toLocalString(" " + g + " options:\n"); 1961 | } 1962 | 1963 | for (const auto& o : group->second.options) 1964 | { 1965 | if (m_positional_set.find(o.l) != m_positional_set.end() && 1966 | !m_show_positional) 1967 | { 1968 | continue; 1969 | } 1970 | 1971 | auto s = format_option(o); 1972 | longest = (std::max)(longest, stringLength(s)); 1973 | format.push_back(std::make_pair(s, String())); 1974 | } 1975 | 1976 | longest = (std::min)(longest, static_cast(OPTION_LONGEST)); 1977 | 1978 | //widest allowed description 1979 | auto allowed = size_t{76} - longest - OPTION_DESC_GAP; 1980 | 1981 | auto fiter = format.begin(); 1982 | for (const auto& o : group->second.options) 1983 | { 1984 | if (m_positional_set.find(o.l) != m_positional_set.end() && 1985 | !m_show_positional) 1986 | { 1987 | continue; 1988 | } 1989 | 1990 | auto d = format_description(o, longest + OPTION_DESC_GAP, allowed); 1991 | 1992 | result += fiter->first; 1993 | if (stringLength(fiter->first) > longest) 1994 | { 1995 | result += '\n'; 1996 | result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' ')); 1997 | } 1998 | else 1999 | { 2000 | result += toLocalString(std::string(longest + OPTION_DESC_GAP - 2001 | stringLength(fiter->first), 2002 | ' ')); 2003 | } 2004 | result += d; 2005 | result += '\n'; 2006 | 2007 | ++fiter; 2008 | } 2009 | 2010 | return result; 2011 | } 2012 | 2013 | inline 2014 | void 2015 | Options::generate_group_help 2016 | ( 2017 | String& result, 2018 | const std::vector& print_groups 2019 | ) const 2020 | { 2021 | for (size_t i = 0; i != print_groups.size(); ++i) 2022 | { 2023 | const String& group_help_text = help_one_group(print_groups[i]); 2024 | if (empty(group_help_text)) 2025 | { 2026 | continue; 2027 | } 2028 | result += group_help_text; 2029 | if (i < print_groups.size() - 1) 2030 | { 2031 | result += '\n'; 2032 | } 2033 | } 2034 | } 2035 | 2036 | inline 2037 | void 2038 | Options::generate_all_groups_help(String& result) const 2039 | { 2040 | std::vector all_groups; 2041 | all_groups.reserve(m_help.size()); 2042 | 2043 | for (auto& group : m_help) 2044 | { 2045 | all_groups.push_back(group.first); 2046 | } 2047 | 2048 | generate_group_help(result, all_groups); 2049 | } 2050 | 2051 | inline 2052 | std::string 2053 | Options::help(const std::vector& help_groups) const 2054 | { 2055 | String result = m_help_string + "\nUsage:\n " + 2056 | toLocalString(m_program) + " " + toLocalString(m_custom_help); 2057 | 2058 | if (m_positional.size() > 0 && m_positional_help.size() > 0) { 2059 | result += " " + toLocalString(m_positional_help); 2060 | } 2061 | 2062 | result += "\n\n"; 2063 | 2064 | if (help_groups.size() == 0) 2065 | { 2066 | generate_all_groups_help(result); 2067 | } 2068 | else 2069 | { 2070 | generate_group_help(result, help_groups); 2071 | } 2072 | 2073 | return toUTF8String(result); 2074 | } 2075 | 2076 | inline 2077 | const std::vector 2078 | Options::groups() const 2079 | { 2080 | std::vector g; 2081 | 2082 | std::transform( 2083 | m_help.begin(), 2084 | m_help.end(), 2085 | std::back_inserter(g), 2086 | [] (const std::map::value_type& pair) 2087 | { 2088 | return pair.first; 2089 | } 2090 | ); 2091 | 2092 | return g; 2093 | } 2094 | 2095 | inline 2096 | const HelpGroupDetails& 2097 | Options::group_help(const std::string& group) const 2098 | { 2099 | return m_help.at(group); 2100 | } 2101 | 2102 | } 2103 | 2104 | #endif //CXXOPTS_HPP_INCLUDED 2105 | -------------------------------------------------------------------------------- /src/attribute/annotation_default_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "annotation_default_attribute.hh" 23 | #include "attribute_info.hh" 24 | #include "constant_pool.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_annotation_default_attribute(std::ifstream& file, 28 | const constant_pool& cp) 29 | { 30 | skip_element_value_field(file); 31 | return std::make_unique(); 32 | } 33 | -------------------------------------------------------------------------------- /src/attribute/bootstrap_methods_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "attribute_info.hh" 24 | #include "bootstrap_methods_attribute.hh" 25 | #include "constant_pool.hh" 26 | #include "util.hh" 27 | 28 | std::unique_ptr parse_bootstrap_methods_attribute(std::ifstream& file, 29 | const constant_pool& cp) 30 | { 31 | READ_U2_FIELD(num_bootstrap_methods, "Failed to parse number of bootstrap methods of " 32 | "BootstrapMethods attribute."); 33 | std::vector bootstrap_methods; 34 | for (uint16_t curr_bm_idx = 0; curr_bm_idx < num_bootstrap_methods; curr_bm_idx++) 35 | { 36 | READ_U2_FIELD(bootstrap_method_ref, "Failed to parse bootstrap method ref of " 37 | "BootstrapMethods attribute."); 38 | READ_U2_FIELD(num_bootstrap_arguments, "Failed to parse number of bootstrap arguments of " 39 | "BootstrapMethods attribute."); 40 | std::vector bootstrap_arguments; 41 | for (uint16_t curr_ba_idx = 0; curr_ba_idx < num_bootstrap_arguments; curr_ba_idx++) 42 | { 43 | READ_U2_FIELD(bootstrap_argument, "Failed to parse bootstrap argument of " 44 | "BootstrapMethods attribute."); 45 | bootstrap_arguments.push_back(bootstrap_argument); 46 | } 47 | 48 | bootstrap_methods.emplace_back(bootstrap_method_ref, std::move(bootstrap_arguments)); 49 | } 50 | 51 | return std::make_unique(std::move(bootstrap_methods)); 52 | } 53 | -------------------------------------------------------------------------------- /src/attribute/code_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "code_attribute.hh" 26 | 27 | void code_attribute::print_code(std::ostream& out) const 28 | { 29 | for (uint32_t pc = 0; pc < code_length;) 30 | { 31 | const bytecode_tag curr_instr = static_cast(bytecode[pc]); 32 | const size_t curr_instr_size = get_instruction_size(curr_instr); 33 | 34 | out << std::right << pc << ": " << std::left << get_instruction_name(curr_instr); 35 | // These are variable-sized instructions and require special parsing. 36 | if (curr_instr == bytecode_tag::LOOKUPSWITCH || 37 | curr_instr == bytecode_tag::TABLESWITCH) 38 | { 39 | // Skip past padding bytes until we get to the first address that is a multiple of 4. 40 | if (pc % 4 != 0) 41 | { 42 | for (; pc % 4 != 0; pc++); 43 | } 44 | 45 | // Skip `default` bytes. 46 | pc += 4; 47 | if (curr_instr == bytecode_tag::LOOKUPSWITCH) 48 | { 49 | // `npairs` is a signed 4-byte, big-endian integer. This should probably never 50 | // be negative. 51 | uint32_t* npairs_bytes = reinterpret_cast(&bytecode[pc]); 52 | uint32_t npairs = to_little_endian_int(*npairs_bytes); 53 | // Each pair consists of two 4-byte ints. 54 | pc += 8 * npairs; 55 | } 56 | else if (curr_instr == bytecode_tag::TABLESWITCH) 57 | { 58 | // Read both `low` and `high` signed ints. These should probably never be 59 | // negative. 60 | uint32_t* low_bytes = reinterpret_cast(&bytecode[pc]); 61 | uint32_t low = to_little_endian_int(*low_bytes); 62 | pc += 4; 63 | 64 | uint32_t* high_bytes = reinterpret_cast(&bytecode[pc]); 65 | uint32_t high = to_little_endian_int(*high_bytes); 66 | // There are `high - low + 1` signed integer offsets that must be skipped. 67 | pc += 4 * (high - low + 1 + 1); 68 | } 69 | 70 | out << std::endl; 71 | continue; 72 | } 73 | 74 | // Instructions with an operand that references the constant pool. 75 | if (curr_instr == bytecode_tag::GETSTATIC || 76 | curr_instr == bytecode_tag::PUTSTATIC || 77 | curr_instr == bytecode_tag::GETFIELD || 78 | curr_instr == bytecode_tag::PUTFIELD || 79 | curr_instr == bytecode_tag::LDC_W || 80 | curr_instr == bytecode_tag::LDC2_W || 81 | curr_instr == bytecode_tag::INVOKEVIRTUAL || 82 | curr_instr == bytecode_tag::INVOKESPECIAL || 83 | curr_instr == bytecode_tag::INVOKESTATIC || 84 | curr_instr == bytecode_tag::INVOKEINTERFACE || 85 | curr_instr == bytecode_tag::NEW || 86 | curr_instr == bytecode_tag::CHECKCAST || 87 | curr_instr == bytecode_tag::INSTANCEOF || 88 | curr_instr == bytecode_tag::ANEWARRAY || 89 | curr_instr == bytecode_tag::MULTIANEWARRAY) 90 | { 91 | uint8_t* index1 = reinterpret_cast(&bytecode[pc + 1]); 92 | uint8_t* index2 = reinterpret_cast(&bytecode[pc + 2]); 93 | constant_pool_entry_id cp_index = (*index1 << 8) | *index2; 94 | out << '\t' << "#" << cp_index << "// "; 95 | } 96 | 97 | pc += curr_instr_size; 98 | out << std::endl; 99 | } 100 | } 101 | 102 | std::unique_ptr parse_code_attribute(std::ifstream& file, 103 | const constant_pool& cp) 104 | { 105 | READ_U2_FIELD(max_stack, "Failed to parse max stack count of Code attribute."); 106 | READ_U2_FIELD(max_locals, "Failed to parse max local count of Code attribute."); 107 | READ_U4_FIELD(code_length, "Failed to parse code length of Code attribute."); 108 | auto bytecode = std::make_unique(code_length); 109 | if (!file.read(reinterpret_cast(bytecode.get()), code_length)) 110 | { 111 | throw invalid_class_format{"Failed to parse bytecode of Code attribute."}; 112 | } 113 | 114 | READ_U2_FIELD(exception_table_length, "Failed to parse exception table length of Code " 115 | "attribute."); 116 | std::vector exception_table; 117 | for (uint16_t curr_et_idx = 0; curr_et_idx < exception_table_length; curr_et_idx++) 118 | { 119 | READ_U2_FIELD(start_pc, "Failed to parse start pc of Code attribute."); 120 | READ_U2_FIELD(end_pc, "Failed to parse end pc of Code attribute."); 121 | READ_U2_FIELD(handler_pc, "Failed to parse handler pc of Code attribute."); 122 | READ_U2_FIELD(catch_pc, "Failed to parse catch pc of Code attribute."); 123 | exception_table.emplace_back(start_pc, end_pc, handler_pc, catch_pc); 124 | } 125 | 126 | return std::make_unique(cp, max_stack, max_locals, code_length, 127 | std::move(bytecode), std::move(exception_table), parse_attributes(file, cp)); 128 | } 129 | -------------------------------------------------------------------------------- /src/attribute/constant_value_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "constant_value_attribute.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_constant_value_attribute(std::ifstream& file, 28 | const constant_pool& cp) 29 | { 30 | READ_U2_FIELD(constantvalue_index, "Failed to parse constant value of ConstantValue " 31 | "attribute."); 32 | return std::make_unique(constantvalue_index); 33 | } 34 | -------------------------------------------------------------------------------- /src/attribute/deprecated_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "deprecated_attribute.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_deprecated_attribute(std::ifstream& file, 28 | const constant_pool& cp) 29 | { 30 | return std::make_unique(); 31 | } 32 | -------------------------------------------------------------------------------- /src/attribute/enclosing_method_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "attribute_info.hh" 24 | #include "constant_pool.hh" 25 | #include "enclosing_method_attribute.hh" 26 | #include "util.hh" 27 | 28 | std::unique_ptr parse_enclosing_method_attribute(std::ifstream& file, 29 | const constant_pool& cp) 30 | { 31 | READ_U2_FIELD(class_index, "Failed to parse class index of EnclosingMethod attribute."); 32 | READ_U2_FIELD(method_index, "Failed to parse method index of EnclosingMethod attribute."); 33 | return std::make_unique(class_index, method_index); 34 | } 35 | -------------------------------------------------------------------------------- /src/attribute/exceptions_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "attribute_info.hh" 24 | #include "constant_pool.hh" 25 | #include "exceptions_attribute.hh" 26 | #include "util.hh" 27 | 28 | std::unique_ptr parse_exceptions_attribute(std::ifstream& file, 29 | const constant_pool& cp) 30 | { 31 | READ_U2_FIELD(number_of_exceptions, "Failed to parse line number of exceptions of method."); 32 | std::vector exception_index_table; 33 | for (uint16_t curr_et_idx = 0; curr_et_idx < number_of_exceptions; curr_et_idx++) 34 | { 35 | READ_U2_FIELD(exception_table_entry, "Failed to parse exception table entry of method."); 36 | exception_index_table.emplace_back(exception_table_entry); 37 | } 38 | 39 | return std::make_unique(std::move(exception_index_table)); 40 | } 41 | -------------------------------------------------------------------------------- /src/attribute/inner_classes_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "attribute_info.hh" 24 | #include "constant_pool.hh" 25 | #include "inner_classes_attribute.hh" 26 | #include "util.hh" 27 | 28 | std::unique_ptr parse_inner_classes_attribute(std::ifstream& file, 29 | const constant_pool& cp) 30 | { 31 | READ_U2_FIELD(number_of_classes, "Failed to parse number of classes of InnerClasses " 32 | "attribute."); 33 | std::vector inner_classes; 34 | for (uint16_t curr_class_idx = 0; curr_class_idx < number_of_classes; curr_class_idx++) 35 | { 36 | READ_U2_FIELD(inner_class_info_index, "Failed to parse inner class info index of " 37 | "InnerClasses attribute."); 38 | READ_U2_FIELD(outer_class_info_index, "Failed to parse outer class info index of " 39 | "InnerClasses attribute."); 40 | READ_U2_FIELD(inner_name_index, "Failed to parse inner name index of InnerClasses " 41 | "attribute."); 42 | READ_U2_FIELD(inner_class_access_flags, "Failed to parse inner class access flags of " 43 | "InnerClasses attribute."); 44 | inner_classes.emplace_back(inner_class_info_index, outer_class_info_index, inner_name_index, 45 | inner_class_access_flags); 46 | } 47 | 48 | return std::make_unique(std::move(inner_classes)); 49 | } 50 | -------------------------------------------------------------------------------- /src/attribute/line_number_table_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "attribute_info.hh" 24 | #include "constant_pool.hh" 25 | #include "line_number_table_attribute.hh" 26 | #include "util.hh" 27 | 28 | std::unique_ptr parse_line_number_table_attribute(std::ifstream& file, 29 | const constant_pool& cp) 30 | { 31 | READ_U2_FIELD(line_number_table_length, "Failed to parse line number table length of " 32 | "LineNumberTable attribute."); 33 | std::vector line_number_table; 34 | for (uint16_t curr_lnt_idx = 0; curr_lnt_idx < line_number_table_length; curr_lnt_idx++) 35 | { 36 | READ_U2_FIELD(start_pc, "Failed to parse start pc of LineNumberTable attribute."); 37 | READ_U2_FIELD(line_number, "Failed to parse line number of LineNumberTable attribute."); 38 | line_number_table.emplace_back(start_pc, line_number); 39 | } 40 | 41 | return std::make_unique(std::move(line_number_table)); 42 | } 43 | -------------------------------------------------------------------------------- /src/attribute/local_variable_table_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "attribute_info.hh" 24 | #include "constant_pool.hh" 25 | #include "local_variable_table_attribute.hh" 26 | #include "util.hh" 27 | 28 | std::unique_ptr parse_local_variable_table_attribute(std::ifstream& file, 29 | const constant_pool& cp) 30 | { 31 | READ_U2_FIELD(local_variable_table_length, "Failed to parse local variable table length of " 32 | "LocalVariableTable attribute."); 33 | std::vector local_variable_table; 34 | for (uint16_t curr_lvt_idx = 0; curr_lvt_idx < local_variable_table_length; curr_lvt_idx++) 35 | { 36 | READ_U2_FIELD(start_pc, "Failed to parse start pc of LocalVariableTable attribute."); 37 | READ_U2_FIELD(length, "Failed to parse length of LocalVariableTable attribute."); 38 | READ_U2_FIELD(name_index, "Failed to parse name index of LocalVariableTable attribute."); 39 | READ_U2_FIELD(descriptor_index, "Failed to parse descriptor index of LocalVariableTable " 40 | "attribute."); 41 | READ_U2_FIELD(index, "Failed to parse index of LocalVariableTable attribute."); 42 | local_variable_table.emplace_back(start_pc, length, name_index, descriptor_index, index); 43 | } 44 | 45 | return std::make_unique(std::move(local_variable_table)); 46 | } 47 | -------------------------------------------------------------------------------- /src/attribute/local_variable_type_table_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "attribute_info.hh" 24 | #include "constant_pool.hh" 25 | #include "local_variable_type_table_attribute.hh" 26 | #include "util.hh" 27 | 28 | std::unique_ptr parse_local_variable_type_table_attribute(std::ifstream& file, 29 | const constant_pool& cp) 30 | { 31 | READ_U2_FIELD(local_variable_type_table_length, "Failed to parse local variable type table " 32 | "length of LocalVariableTypeTable attribute."); 33 | std::vector local_variable_type_table; 34 | for (uint16_t curr_lvtt_idx = 0; curr_lvtt_idx < local_variable_type_table_length; 35 | curr_lvtt_idx++) 36 | { 37 | READ_U2_FIELD(start_pc, "Failed to parse start pc of LocalVariableTypeTable attribute."); 38 | READ_U2_FIELD(length, "Failed to parse length of LocalVariableTypeTable attribute."); 39 | READ_U2_FIELD(name_index, "Failed to parse name index of LocalVariableTypeTable " 40 | "attribute."); 41 | READ_U2_FIELD(signature_index, "Failed to parse signature index of LocalVariableTypeTable " 42 | "attribute."); 43 | READ_U2_FIELD(index, "Failed to parse index of LocalVariableTypeTable attribute."); 44 | local_variable_type_table.emplace_back(start_pc, length, name_index, signature_index, 45 | index); 46 | } 47 | 48 | return std::make_unique( 49 | std::move(local_variable_type_table)); 50 | } 51 | -------------------------------------------------------------------------------- /src/attribute/runtime_invisible_annotations_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "runtime_invisible_annotations_attribute.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_runtime_invisible_annotations_attribute(std::ifstream& file, 28 | const constant_pool& cp) 29 | { 30 | skip_annotations(file); 31 | return std::make_unique(); 32 | } 33 | -------------------------------------------------------------------------------- /src/attribute/runtime_invisible_parameter_annotations_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "runtime_invisible_parameter_annotations_attribute.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_runtime_invisible_parameter_annotations_attribute( 28 | std::ifstream& file, const constant_pool& cp) 29 | { 30 | READ_U1_FIELD(num_parameters, "Failed to parse number of parameter annotations of " 31 | "RuntimeInvisibleParameterAnnotations attribute."); 32 | for (uint8_t curr_param_idx = 0; curr_param_idx < num_parameters; curr_param_idx++) 33 | { 34 | skip_annotations(file); 35 | } 36 | 37 | return std::make_unique(); 38 | } 39 | -------------------------------------------------------------------------------- /src/attribute/runtime_visible_annotations_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "runtime_visible_annotations_attribute.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_runtime_visible_annotations_attribute(std::ifstream& file, 28 | const constant_pool& cp) 29 | { 30 | skip_annotations(file); 31 | return std::make_unique(); 32 | } 33 | -------------------------------------------------------------------------------- /src/attribute/runtime_visible_parameter_annotations_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "runtime_visible_parameter_annotations_attribute.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_runtime_visible_parameter_annotations_attribute( 28 | std::ifstream& file, const constant_pool& cp) 29 | { 30 | READ_U1_FIELD(num_parameters, "Failed to parse number of parameter annotations of " 31 | "RuntimeVisibleParameterAnnotations attribute."); 32 | for (uint8_t curr_param_idx = 0; curr_param_idx < num_parameters; curr_param_idx++) 33 | { 34 | skip_annotations(file); 35 | } 36 | 37 | return std::make_unique(); 38 | } 39 | -------------------------------------------------------------------------------- /src/attribute/signature_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "signature_attribute.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_signature_attribute(std::ifstream& file, 28 | const constant_pool& cp) 29 | { 30 | READ_U2_FIELD(signature_index, "Failed to parse signature index of Signature attribute."); 31 | return std::make_unique(signature_index); 32 | } 33 | -------------------------------------------------------------------------------- /src/attribute/source_file_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "source_file_attribute.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_source_file_attribute(std::ifstream& file, 28 | const constant_pool& cp) 29 | { 30 | READ_U2_FIELD(sourcefile_index, "Failed to parse source file index of SourceFile attribute."); 31 | return std::make_unique(sourcefile_index); 32 | } 33 | -------------------------------------------------------------------------------- /src/attribute/stack_map_table_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "stack_map_table_attribute.hh" 25 | #include "util.hh" 26 | 27 | static void skip_verification_type_info(std::ifstream& file, uint16_t length) 28 | { 29 | for (uint16_t current = 0; current < length; current++) 30 | { 31 | READ_U1_FIELD(tag, "Failed to parse tag for current verification type info entry of " 32 | "StackMapTable attribute."); 33 | if (tag == 7 || tag == 8) 34 | { 35 | READ_U2_FIELD(tmp, "Failed to parse cp info/offset for current verification type info " 36 | "entry of StackMapTable attribute."); 37 | } 38 | } 39 | } 40 | 41 | std::unique_ptr parse_stack_map_table_attribute(std::ifstream& file, 42 | const constant_pool& cp) 43 | { 44 | READ_U2_FIELD(number_of_entries, "Failed to parse number of stack map table entries of " 45 | "StackMapTable attribute."); 46 | for (uint16_t curr_entry_idx = 0; curr_entry_idx < number_of_entries; curr_entry_idx++) 47 | { 48 | READ_U1_FIELD(frame_type, "Failed to parse frame type for current entry of StackMapTable " 49 | "attribute."); 50 | if (frame_type >= 64 && frame_type <= 127) 51 | { 52 | skip_verification_type_info(file, 1); 53 | } 54 | else if (frame_type == 247) 55 | { 56 | READ_U2_FIELD(offset_delta, "Failed to parse offset delta for current entry of " 57 | "StackMapTable attribute."); 58 | skip_verification_type_info(file, 1); 59 | } 60 | else if (frame_type >= 248 && frame_type <= 251) 61 | { 62 | READ_U2_FIELD(offset_delta, "Failed to parse offset delta for current entry of " 63 | "StackMapTable attribute."); 64 | } 65 | else if (frame_type >= 252 && frame_type <= 254) 66 | { 67 | READ_U2_FIELD(offset_delta, "Failed to parse offset delta for current entry of " 68 | "StackMapTable attribute."); 69 | skip_verification_type_info(file, frame_type - 251); 70 | } 71 | else if (frame_type == 255) 72 | { 73 | READ_U2_FIELD(offset_delta, "Failed to parse offset delta for current entry of " 74 | "StackMapTable attribute."); 75 | READ_U2_FIELD(number_of_locals, "Failed to parse number of locals for current entry of " 76 | "StackMapTable attribute."); 77 | skip_verification_type_info(file, number_of_locals); 78 | READ_U2_FIELD(number_of_stack_items, "Failed to parse number of stack items for " 79 | "current entry of StackMapTable attribute."); 80 | skip_verification_type_info(file, number_of_stack_items); 81 | } 82 | } 83 | 84 | return std::make_unique(); 85 | } 86 | -------------------------------------------------------------------------------- /src/attribute/synthetic_attribute.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | 22 | #include "attribute_info.hh" 23 | #include "constant_pool.hh" 24 | #include "synthetic_attribute.hh" 25 | #include "util.hh" 26 | 27 | std::unique_ptr parse_synthetic_attribute(std::ifstream& file, 28 | const constant_pool& cp) 29 | { 30 | return std::make_unique(); 31 | } 32 | -------------------------------------------------------------------------------- /src/attribute_info.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "attribute_info.hh" 29 | #include "constant_pool.hh" 30 | #include "invalid_class_format_exception.hh" 31 | #include "util.hh" 32 | 33 | #include "annotation_default_attribute.hh" 34 | #include "bootstrap_methods_attribute.hh" 35 | #include "code_attribute.hh" 36 | #include "constant_value_attribute.hh" 37 | #include "deprecated_attribute.hh" 38 | #include "enclosing_method_attribute.hh" 39 | #include "exceptions_attribute.hh" 40 | #include "inner_classes_attribute.hh" 41 | #include "line_number_table_attribute.hh" 42 | #include "local_variable_table_attribute.hh" 43 | #include "local_variable_type_table_attribute.hh" 44 | #include "runtime_invisible_annotations_attribute.hh" 45 | #include "runtime_invisible_parameter_annotations_attribute.hh" 46 | #include "runtime_visible_annotations_attribute.hh" 47 | #include "runtime_visible_parameter_annotations_attribute.hh" 48 | #include "signature_attribute.hh" 49 | #include "source_file_attribute.hh" 50 | #include "stack_map_table_attribute.hh" 51 | #include "synthetic_attribute.hh" 52 | 53 | void skip_element_value_field(std::ifstream& file) 54 | { 55 | READ_U1_FIELD(tag, "Failed to read tag for annotation."); 56 | unsigned char tag_char = reinterpret_cast(tag); 57 | if (tag_char == 'B' || tag_char == 'C' || tag_char == 'D' || tag_char == 'F' || 58 | tag_char == 'I' || tag_char == 'J' || tag_char == 'S' || tag_char == 'Z' || 59 | tag_char == 's') 60 | { 61 | READ_U2_FIELD(const_value_index, "Failed to read const value index for annotation."); 62 | } 63 | else if (tag_char == 'e') 64 | { 65 | READ_U2_FIELD(type_name_index, "Failed to read type name index for annotation."); 66 | READ_U2_FIELD(const_name_index, "Failed to read const name index for annotation."); 67 | } 68 | else if (tag_char == 'c') 69 | { 70 | READ_U2_FIELD(class_info_index, "Failed to read const info index for annotation."); 71 | } 72 | else if (tag_char == '@') 73 | { 74 | skip_annotations(file); 75 | } 76 | else if (tag_char == '[') 77 | { 78 | READ_U2_FIELD(num_values, "Failed to read values length for annotation."); 79 | skip_element_value_field(file); 80 | } 81 | else 82 | { 83 | throw invalid_class_format{"Unknown annotation tag type."}; 84 | } 85 | } 86 | 87 | void skip_annotations(std::ifstream& file) 88 | { 89 | READ_U2_FIELD(num_annotations, "Failed to read annotations length for field."); 90 | for (uint16_t curr_annotation_idx = 0; curr_annotation_idx < num_annotations; 91 | curr_annotation_idx++) 92 | { 93 | READ_U2_FIELD(type_index, "Failed to read type index for annotation."); 94 | READ_U2_FIELD(num_ev_pairs, "Failed to read ev pairs length for annotation."); 95 | for (uint16_t curr_ev_pair_idx = 0; curr_ev_pair_idx < num_ev_pairs; curr_ev_pair_idx++) 96 | { 97 | READ_U2_FIELD(element_name_index, "Failed to read element name index for annotation."); 98 | skip_element_value_field(file); 99 | } 100 | } 101 | } 102 | 103 | using attribute_parser_fn = std::function(std::ifstream&, const 104 | constant_pool&)>; 105 | using utf8_entry_value_type = decltype(std::declval().value); 106 | using attribute_parser_table = std::unordered_map; 107 | 108 | attribute_parser_table build_attribute_parser_table() 109 | { 110 | attribute_parser_table table; 111 | table["AnnotationDefault"] = parse_annotation_default_attribute; 112 | table["BootstrapMethods"] = parse_bootstrap_methods_attribute; 113 | table["Code"] = parse_code_attribute; 114 | table["ConstantValue"] = parse_constant_value_attribute; 115 | table["Deprecated"] = parse_deprecated_attribute; 116 | table["EnclosingMethod"] = parse_enclosing_method_attribute; 117 | table["Exceptions"] = parse_exceptions_attribute; 118 | table["InnerClasses"] = parse_inner_classes_attribute; 119 | table["LineNumberTable"] = parse_line_number_table_attribute; 120 | table["LocalVariableTable"] = parse_local_variable_table_attribute; 121 | table["LocalVariableTypeTable"] = parse_local_variable_type_table_attribute; 122 | table["RuntimeInvisibleAnnotations"] = parse_runtime_invisible_annotations_attribute; 123 | table["RuntimeInvisibleParameterAnnotations"] = 124 | parse_runtime_invisible_parameter_annotations_attribute; 125 | table["RuntimeVisibleAnnotations"] = parse_runtime_visible_annotations_attribute; 126 | table["RuntimeVisibleParameterAnnotations"] = 127 | parse_runtime_visible_parameter_annotations_attribute; 128 | table["Signature"] = parse_signature_attribute; 129 | table["SourceFile"] = parse_source_file_attribute; 130 | table["StackMapTable"] = parse_stack_map_table_attribute; 131 | table["Synthetic"] = parse_synthetic_attribute; 132 | return table; 133 | } 134 | 135 | static const attribute_parser_table attribute_parsers = build_attribute_parser_table(); 136 | 137 | entry_attributes parse_attributes(std::ifstream& file, const constant_pool& cp) 138 | { 139 | entry_attributes field_attributes; 140 | READ_U2_FIELD(attributes_count, "Failed to parse attributes count of field."); 141 | for (uint16_t curr_attribute_idx = 0; curr_attribute_idx < attributes_count; 142 | curr_attribute_idx++) 143 | { 144 | READ_U2_FIELD(attribute_name_index, "Failed to parse attribute name index of field."); 145 | READ_U4_FIELD(attribute_length, "Failed to parse attribute length of field."); 146 | auto cp_entry_handle = cp.get_entry_info(attribute_name_index); 147 | // Unexpected attribute entries must be ignored according to the JVM spec. 148 | if (!cp_entry_handle) 149 | { 150 | // Skip the rest of this attribute. 151 | file.seekg(attribute_length, std::ios::ios_base::cur); 152 | continue; 153 | } 154 | 155 | constant_pool_entry_info cp_entry = cp_entry_handle.value(); 156 | // At this point, a valid cp entry has been found but is not a UTF8 symbol. Since 157 | // attributes must be identified by the UTF8 entry value, the class is probably malformed. 158 | if (cp_entry.type != constant_pool_type::Utf8) 159 | { 160 | throw invalid_class_format{"Attribute name unidentifiable -- cp entry not utf8."}; 161 | } 162 | 163 | auto utf8_entry = std::get(cp_entry.entry); 164 | auto attribute_parser_it = attribute_parsers.find(utf8_entry.value); 165 | if (attribute_parser_it == attribute_parsers.cend()) 166 | { 167 | throw invalid_class_format{"Attribute parser not found."}; 168 | } 169 | 170 | // Skip over debugger information. 171 | if (utf8_entry.value == "SourceDebugExtension") 172 | { 173 | file.seekg(attribute_length, std::ios::ios_base::cur); 174 | continue; 175 | } 176 | 177 | const auto& parser_fn = attribute_parser_it->second; 178 | field_attributes.emplace_back(parser_fn(file, cp)); 179 | } 180 | 181 | return field_attributes; 182 | } 183 | -------------------------------------------------------------------------------- /src/constant_pool.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "constant_pool.hh" 28 | #include "constant_pool_entry_parser.hh" 29 | #include "invalid_class_format_exception.hh" 30 | #include "util.hh" 31 | 32 | using cp_parser_fn = std::function; 33 | using cp_parser_table = std::unordered_map; 34 | 35 | cp_parser_table build_cp_entry_parser_table() 36 | { 37 | cp_parser_table table; 38 | table[constant_pool_type::Utf8] = parse_cp_utf8_entry; 39 | table[constant_pool_type::Integer] = parse_cp_integer_entry; 40 | table[constant_pool_type::Float] = parse_cp_float_entry; 41 | table[constant_pool_type::Long] = parse_cp_long_entry; 42 | table[constant_pool_type::Double] = parse_cp_double_entry; 43 | table[constant_pool_type::Class] = parse_cp_index_entry; 44 | table[constant_pool_type::String] = parse_cp_index_entry; 45 | table[constant_pool_type::FieldRef] = parse_cp_double_index_entry; 46 | table[constant_pool_type::MethodRef] = parse_cp_double_index_entry; 47 | table[constant_pool_type::InterfaceMethodRef] = parse_cp_double_index_entry; 48 | table[constant_pool_type::NameAndType] = parse_cp_double_index_entry; 49 | table[constant_pool_type::MethodType] = parse_cp_index_entry; 50 | table[constant_pool_type::MethodHandle] = parse_cp_methodhandle_info_entry; 51 | table[constant_pool_type::InvokeDynamic] = parse_cp_double_index_entry; 52 | return table; 53 | } 54 | 55 | static const cp_parser_table cp_entry_parser_table = build_cp_entry_parser_table(); 56 | 57 | constant_pool constant_pool::parse_constant_pool(std::ifstream& file) 58 | { 59 | READ_U2_FIELD(constant_pool_count, "Failed to parse constant pool count."); 60 | if (constant_pool_count > 0) 61 | { 62 | constant_pool_count--; 63 | } 64 | 65 | constant_pool_entries entries; 66 | // Read in each constant pool entry. Since we don't know what entry we are looking at until 67 | // we see the tag, we visit (by tag) and construct an entry. 68 | for (constant_pool_entry_id curr_idx = 0; curr_idx < constant_pool_count;) 69 | { 70 | // Read the tag. 71 | READ_U1_FIELD(current_entry_tag_bytes, "Failed to parse entry tag length."); 72 | auto current_entry_tag = constant_pool_type{current_entry_tag_bytes}; 73 | 74 | // Now that we know what this next chunk is, construct it. 75 | auto parser_it = cp_entry_parser_table.find(current_entry_tag); 76 | if (parser_it == cp_entry_parser_table.cend()) 77 | { 78 | throw invalid_class_format{"Unknown constant pool tag."}; 79 | } 80 | 81 | // Lookup the parser function for the given tag and emplace the object it parses into our 82 | // constant pool. 83 | const auto& parse_entry_fn = parser_it->second; 84 | constant_pool_entry parse_entry = parse_entry_fn(file); 85 | entries.emplace(curr_idx + 1, 86 | constant_pool_entry_info{current_entry_tag, std::move(parse_entry)}); 87 | // Doubles and Longs increment the constant pool index by 2. 88 | curr_idx += (current_entry_tag == constant_pool_type::Double || current_entry_tag == constant_pool_type::Long) ? 2 : 1; 89 | } 90 | 91 | return constant_pool{std::move(entries)}; 92 | } 93 | 94 | constant_pool::constant_pool(constant_pool_entries entries) : 95 | entries{std::move(entries)} 96 | {} 97 | 98 | std::optional constant_pool::get_entry_info(constant_pool_entry_id index) 99 | const 100 | { 101 | auto entries_it = entries.find(index); 102 | if (entries_it == entries.cend()) 103 | { 104 | return std::nullopt; 105 | } 106 | else 107 | { 108 | return entries_it->second; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/constant_pool_entry_parser.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "constant_pool.hh" 25 | #include "constant_pool_entry_parser.hh" 26 | #include "invalid_class_format_exception.hh" 27 | #include "util.hh" 28 | 29 | cp_utf8_entry parse_cp_utf8_entry(std::ifstream& file) 30 | { 31 | READ_U2_FIELD(utf8_length, "Failed to parse constant pool utf8 string entry."); 32 | std::string utf8_string(utf8_length, '\0'); 33 | if (!file.read(utf8_string.data(), utf8_length)) 34 | { 35 | throw invalid_class_format{"Failed to parse constant pool utf8 string entry."}; 36 | } 37 | 38 | return cp_utf8_entry{std::move(utf8_string)}; 39 | } 40 | 41 | cp_integer_entry parse_cp_integer_entry(std::ifstream& file) 42 | { 43 | READ_U4_FIELD(number, "Failed to parse constant pool integer entry."); 44 | return cp_integer_entry{static_cast(number)}; 45 | } 46 | 47 | cp_float_entry parse_cp_float_entry(std::ifstream& file) 48 | { 49 | READ_U4_FIELD(bits, "Failed to parse constant pool float entry."); 50 | float number = 0; 51 | if (bits == 0x7F800000) 52 | { 53 | number = std::numeric_limits::infinity(); 54 | } 55 | else if (bits == 0xFF800000) 56 | { 57 | number = -std::numeric_limits::infinity(); 58 | } 59 | else if ((bits >= 0x7F800001 && bits <= 0x7FFFFFFF) || 60 | (bits >= 0xFF800001 && bits <= 0xFFFFFFFF)) 61 | { 62 | number = std::numeric_limits::quiet_NaN(); 63 | } 64 | else 65 | { 66 | int32_t s = ((bits >> 31) == 0) ? 1 : -1; 67 | int32_t e = ((bits >> 23) & 0xFF); 68 | int32_t m = (e == 0) ? (bits & 0x7FFFFF) << 1 : (bits & 0x7FFFFF) | 0x800000; 69 | number = s * m * std::powf(2.f, e - 150); 70 | } 71 | 72 | return cp_float_entry{number}; 73 | } 74 | 75 | cp_long_entry parse_cp_long_entry(std::ifstream& file) 76 | { 77 | constexpr size_t LONG_ENTRY_LENGTH = 8; 78 | uint64_t number = 0; 79 | if (!file.read(reinterpret_cast(&number), LONG_ENTRY_LENGTH)) 80 | { 81 | throw invalid_class_format{"Failed to parse constant pool long entry."}; 82 | } 83 | 84 | uint32_t high_bytes = (number >> 32) & 0xFFFFFFFF; 85 | uint32_t low_bytes = number & 0xFFFFFFFF; 86 | number = to_little_endian_long((static_cast(high_bytes) << 32) + low_bytes); 87 | return cp_long_entry{static_cast(number)}; 88 | } 89 | 90 | cp_double_entry parse_cp_double_entry(std::ifstream& file) 91 | { 92 | constexpr size_t DOUBLE_ENTRY_LENGTH = 8; 93 | uint64_t bits = 0; 94 | if (!file.read(reinterpret_cast(&bits), DOUBLE_ENTRY_LENGTH)) 95 | { 96 | throw invalid_class_format{"Failed to parse constant pool double entry."}; 97 | } 98 | 99 | uint32_t high_bytes = (bits >> 32) & 0xFFFFFFFF; 100 | uint32_t low_bytes = bits & 0xFFFFFFFF; 101 | bits = to_little_endian_long((static_cast(high_bytes) << 32) + low_bytes); 102 | double number = 0; 103 | if (bits == 0x7FF0000000000000L) 104 | { 105 | number = std::numeric_limits::infinity(); 106 | } 107 | else if (bits == 0xFFF0000000000000L) 108 | { 109 | number = -std::numeric_limits::infinity(); 110 | } 111 | else if ((bits >= 0x7FF0000000000001L && bits <= 0x7FFFFFFFFFFFFFFFL) || 112 | (bits >= 0xFFF0000000000001L && bits <= 0xFFFFFFFFFFFFFFFFL)) 113 | { 114 | number = std::numeric_limits::quiet_NaN(); 115 | } 116 | else 117 | { 118 | int32_t s = ((bits >> 63) == 0) ? 1 : -1; 119 | int32_t e = static_cast((bits >> 52) & 0x7FFL); 120 | int64_t m = (e == 0) 121 | ? (bits & 0xFFFFFFFFFFFFFL) << 1 122 | : (bits & 0xFFFFFFFFFFFFFL) | 0x10000000000000L; 123 | number = s * m * std::pow(2., e - 1075); 124 | } 125 | 126 | return cp_double_entry{number}; 127 | } 128 | 129 | cp_index_entry parse_cp_index_entry(std::ifstream& file) 130 | { 131 | READ_U2_FIELD(cp_index, "Failed to parse constant pool index entry."); 132 | return cp_index_entry{cp_index}; 133 | } 134 | 135 | cp_double_index_entry parse_cp_double_index_entry(std::ifstream& file) 136 | { 137 | READ_U2_FIELD(cp_index, "Failed to parse constant pool double index entry."); 138 | READ_U2_FIELD(cp_index2, "Failed to parse constant pool double index entry."); 139 | return cp_double_index_entry{cp_index, cp_index2}; 140 | } 141 | 142 | cp_methodhandle_info_entry parse_cp_methodhandle_info_entry(std::ifstream& file) 143 | { 144 | READ_U1_FIELD(reference_kind, "Failed to parse constant pool method handle entry."); 145 | READ_U2_FIELD(reference_info, "Failed to parse constant pool method handle entry."); 146 | return cp_methodhandle_info_entry{reference_kind, reference_info}; 147 | } 148 | -------------------------------------------------------------------------------- /src/field_info.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "attribute_info.hh" 24 | #include "field_info.hh" 25 | #include "util.hh" 26 | 27 | std::vector parse_fields(std::ifstream& file, const constant_pool& cp) 28 | { 29 | std::vector fields; 30 | READ_U2_FIELD(fields_count, "Failed to parse fields count of class file."); 31 | for (uint16_t curr_field_idx = 0; curr_field_idx < fields_count; curr_field_idx++) 32 | { 33 | fields.emplace_back(field_info::parse_field(file, cp)); 34 | } 35 | 36 | return fields; 37 | } 38 | 39 | field_info field_info::parse_field(std::ifstream& file, const constant_pool& cp) 40 | { 41 | READ_U2_FIELD(access_flag_bytes, "Failed to parse access flags of field."); 42 | 43 | auto access_flags = field_access_flags{access_flag_bytes}; 44 | READ_U2_FIELD(name_index, "Failed to parse name index of field."); 45 | READ_U2_FIELD(descriptor_index, "Failed to parse descriptor index of field."); 46 | return field_info{cp, access_flags, name_index, descriptor_index, parse_attributes(file, cp)}; 47 | } 48 | 49 | field_info::field_info(const constant_pool& cp, field_access_flags access_flags, 50 | constant_pool_entry_id name_index, constant_pool_entry_id descriptor_index, 51 | entry_attributes field_attributes) : 52 | cp{cp}, 53 | access_flags{access_flags}, 54 | name_index{name_index}, 55 | descriptor_index{descriptor_index}, 56 | field_attributes{std::move(field_attributes)} 57 | {} 58 | -------------------------------------------------------------------------------- /src/find_api_calls.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "attribute_info.hh" 26 | #include "code_attribute.hh" 27 | #include "find_api_calls.hh" 28 | #include "invalid_class_format_exception.hh" 29 | #include "java_class.hh" 30 | #include "line_number_table_attribute.hh" 31 | 32 | std::optional get_api_call_info(const constant_pool& cp, uint16_t pc, uint8_t high, uint8_t low, 33 | const std::vector& apis) 34 | { 35 | constant_pool_entry_id cp_method_ref = (high << 8) + low; 36 | auto method_ref = cp.get_entry_as(cp_method_ref).value(); 37 | // Extract the class name from the method reference. 38 | auto class_ref = cp.get_entry_as(method_ref.cp_index).value(); 39 | auto class_name_utf8_ref = cp.get_entry_as(class_ref.cp_index).value(); 40 | // If the class name matches ones we're looking for, get the method name too, and 41 | // return the API handle. 42 | auto apis_iter = std::find(apis.cbegin(), apis.cend(), class_name_utf8_ref.value); 43 | if (apis_iter != apis.cend()) 44 | { 45 | // Extract the method name from the constant pool. 46 | auto name_and_type_ref = cp.get_entry_as(method_ref.cp_index2).value(); 47 | auto method_name_utf8_ref = cp.get_entry_as(name_and_type_ref.cp_index).value(); 48 | return std::make_optional({ 49 | // Store the pc instead of line number for now. 50 | pc, class_name_utf8_ref.value + "." + method_name_utf8_ref.value, "" 51 | }); 52 | } 53 | 54 | return std::nullopt; 55 | } 56 | 57 | uint16_t get_line_number(const code_attribute& code, uint16_t pc) 58 | { 59 | for (const auto& code_attr: code.get_code_attributes()) 60 | { 61 | if (code_attr->get_type() == attribute_info_type::line_number_table) 62 | { 63 | const auto& lnt_attr = dynamic_cast(*code_attr); 64 | return *lnt_attr.find_line_number_from_pc(pc); 65 | } 66 | } 67 | 68 | // Should never reach here. 69 | throw invalid_class_format{"Missing `LineNumberTable` attribute in `Code`."}; 70 | return 0; 71 | } 72 | 73 | std::vector find_api_calls(const java_class& clazz, const std::vector& apis) 74 | { 75 | std::vector calls; 76 | const auto& cp = clazz.get_class_constant_pool(); 77 | for (const method_info& method: clazz.get_class_methods()) 78 | { 79 | for (const auto& attr: method.get_method_attributes()) 80 | { 81 | // The `Code` attribute contains raw bytecode and line number information. 82 | if (attr->get_type() == attribute_info_type::code) 83 | { 84 | const auto& code_attr = dynamic_cast(*attr); 85 | const auto instruction_cb = [&](uint16_t pc, uint8_t high, uint8_t low) 86 | { 87 | if (auto call = get_api_call_info(cp, pc, high, low, apis); call) 88 | { 89 | call->line_number = get_line_number(code_attr, call->line_number); 90 | call->method = method.get_name(); 91 | calls.emplace_back(*call); 92 | } 93 | }; 94 | 95 | // Call the callback when an `invokevirtual` instruction is found in bytecode. 96 | code_attr.find_instruction(instruction_cb); 97 | // Call the callback when an `invokespecial` instruction is found in bytecode. 98 | code_attr.find_instruction(instruction_cb); 99 | } 100 | } 101 | } 102 | 103 | return calls; 104 | } 105 | -------------------------------------------------------------------------------- /src/java_class.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "constant_pool.hh" 24 | #include "field_info.hh" 25 | #include "invalid_class_format_exception.hh" 26 | #include "java_class.hh" 27 | #include "method_info.hh" 28 | #include "util.hh" 29 | 30 | constexpr const uint32_t CLASS_MAGIC_NUMBER = 0xCAFEBABE; 31 | 32 | struct version_info 33 | { 34 | uint16_t minor_version; 35 | uint16_t major_version; 36 | }; 37 | 38 | java_class java_class::parse_class_file(const std::string& path) 39 | { 40 | std::ifstream file {path, std::ios::binary}; 41 | if (!file.is_open()) 42 | { 43 | throw std::ios_base::failure{"Classfile not found at " + path}; 44 | } 45 | 46 | READ_U4_FIELD(magic_number, "Failed to parse magic number."); 47 | // Either a malformed Java classfile or not one at all. 48 | if (magic_number != CLASS_MAGIC_NUMBER) 49 | { 50 | throw invalid_class_format{"Parsed magic number does not match Java classfile."}; 51 | } 52 | 53 | // TODO needs to convert values to LE. 54 | version_info version_info; 55 | constexpr size_t VERSION_INFO_LENGTH = 4; 56 | if (!file.read(reinterpret_cast(&version_info), VERSION_INFO_LENGTH)) 57 | { 58 | throw invalid_class_format{"Failed to parse version info of class file."}; 59 | } 60 | 61 | constant_pool constant_pool = constant_pool::parse_constant_pool(file); 62 | 63 | READ_U2_FIELD(access_flag_bytes, "Failed to parse access flags of class file."); 64 | auto access_flags = classfile_access_flag{access_flag_bytes}; 65 | 66 | READ_U2_FIELD(this_index, "Failed to parse `this` index of class file."); 67 | READ_U2_FIELD(super_index, "Failed to parse `super` index of class file."); 68 | READ_U2_FIELD(interface_count, "Failed to parse interface count of class file."); 69 | 70 | std::vector interfaces_ids; 71 | for (uint16_t curr_interface_idx = 0; curr_interface_idx < interface_count; 72 | curr_interface_idx++) 73 | { 74 | READ_U2_FIELD(entry_id, "Failed to parse interface id of class file."); 75 | interfaces_ids.push_back(entry_id); 76 | } 77 | 78 | auto class_instance = java_class{ 79 | std::move(constant_pool), access_flags, this_index, super_index, std::move(interfaces_ids) 80 | }; 81 | class_instance.fields = parse_fields(file, class_instance.cp); 82 | class_instance.methods = parse_methods(file, class_instance.cp); 83 | class_instance.attributes = parse_attributes(file, class_instance.cp); 84 | return class_instance; 85 | } 86 | 87 | java_class::java_class(constant_pool cp, classfile_access_flag access_flags, 88 | constant_pool_entry_id this_index, constant_pool_entry_id super_index, 89 | std::vector interfaces_ids, std::vector fields, 90 | std::vector methods, entry_attributes attributes) : 91 | cp{std::move(cp)}, 92 | access_flags{access_flags}, 93 | this_index{this_index}, 94 | super_index{super_index}, 95 | interfaces_ids{std::move(interfaces_ids)}, 96 | fields{std::move(fields)}, 97 | methods{std::move(methods)}, 98 | attributes{std::move(attributes)} 99 | {} 100 | 101 | java_class::java_class(constant_pool cp, classfile_access_flag access_flags, 102 | constant_pool_entry_id this_index, constant_pool_entry_id super_index, 103 | std::vector interfaces_ids) : 104 | java_class{std::move(cp), access_flags, this_index, super_index, 105 | std::move(interfaces_ids), {}, {}, {}} 106 | {} 107 | -------------------------------------------------------------------------------- /src/main.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "cxxopts.hh" 30 | 31 | #include "find_api_calls.hh" 32 | #include "invalid_class_format_exception.hh" 33 | #include "java_class.hh" 34 | 35 | void denormalize_api_names(std::vector& apis) 36 | { 37 | std::for_each(apis.begin(), apis.end(), [](std::string& api) 38 | { 39 | std::replace(api.begin(), api.end(), '.', '/'); 40 | api.erase(std::remove(api.begin(), api.end(), ' '), api.end()); 41 | }); 42 | } 43 | 44 | void do_dump_cp(const java_class& clazz) 45 | { 46 | std::vector id_col, entry_col, pointed_col; 47 | const auto& constant_pool = clazz.get_class_constant_pool(); 48 | for (const auto& [entry_id, entry_data] : constant_pool) 49 | { 50 | std::stringstream id_str, entry_str, pointed_str; 51 | id_str << "#" << entry_id << " = "; 52 | 53 | const constant_pool_type entry_type = entry_data.type; 54 | // Convert each constant pool entry to a printable string. 55 | std::visit([&](const auto& arg) 56 | { 57 | using cp_entry_type = std::decay_t; 58 | if constexpr (std::is_same_v) 59 | { 60 | id_str << "Utf8"; 61 | entry_str << arg.value; 62 | } 63 | else if constexpr (std::is_same_v) 64 | { 65 | id_str << "Integer"; 66 | entry_str << arg.value; 67 | } 68 | else if constexpr (std::is_same_v) 69 | { 70 | id_str << "Float"; 71 | entry_str << arg.value; 72 | } 73 | else if constexpr (std::is_same_v) 74 | { 75 | id_str << "Long"; 76 | entry_str << arg.value; 77 | } 78 | else if constexpr (std::is_same_v) 79 | { 80 | id_str << "Double"; 81 | entry_str << arg.value; 82 | } 83 | else if constexpr (std::is_same_v) 84 | id_str << "MethodHandle"; 85 | else if constexpr (std::is_same_v) 86 | { 87 | if (entry_type == constant_pool_type::Class) 88 | id_str << "Class"; 89 | else if (entry_type == constant_pool_type::String) 90 | id_str << "String"; 91 | else if (entry_type == constant_pool_type::MethodType) 92 | id_str << "MethodType"; 93 | 94 | entry_str << "#" << arg.cp_index; 95 | 96 | // Class, String, and MethodType all point to a Utf8 index. 97 | auto utf8_entry = constant_pool.get_entry_as(arg.cp_index).value(); 98 | pointed_str << "-> " << utf8_entry.value; 99 | } 100 | else if constexpr (std::is_same_v) 101 | { 102 | if (entry_type == constant_pool_type::FieldRef) 103 | id_str << "FieldRef"; 104 | else if (entry_type == constant_pool_type::MethodRef) 105 | id_str << "MethodRef"; 106 | else if (entry_type == constant_pool_type::InterfaceMethodRef) 107 | id_str << "InterfaceMethodRef"; 108 | else if (entry_type == constant_pool_type::NameAndType) 109 | id_str << "NameAndType"; 110 | else if (entry_type == constant_pool_type::InvokeDynamic) 111 | id_str << "InvokeDynamic"; 112 | 113 | entry_str << "#" << arg.cp_index << ":#" << arg.cp_index2; 114 | pointed_str << "-> "; 115 | 116 | // These are used to allow the NameAndType entry logic to be reused for 117 | // entries that have it as their second constant pool operand. 118 | constant_pool_type current_entry_type = entry_type; 119 | cp_double_index_entry current_entry = arg; 120 | 121 | // FieldRef, MethodRef, and InterfaceMethodRef point to a Class entry and 122 | // NameAndType entry. 123 | if (current_entry_type == constant_pool_type::FieldRef || 124 | current_entry_type == constant_pool_type::MethodRef || 125 | current_entry_type == constant_pool_type::InterfaceMethodRef) 126 | { 127 | // Get Class entry. 128 | auto class_entry = 129 | constant_pool.get_entry_as(current_entry.cp_index).value(); 130 | // From the Class entry, get the Utf8 entry. 131 | auto utf8_entry = 132 | constant_pool.get_entry_as(class_entry.cp_index).value(); 133 | pointed_str << utf8_entry.value << "."; 134 | 135 | // To avoid repeating code, set the current entry to the NameAndType 136 | // entry. 137 | current_entry_type = constant_pool_type::NameAndType; 138 | current_entry = 139 | constant_pool.get_entry_as(current_entry.cp_index2).value(); 140 | } 141 | 142 | // NameAndType points to two Utf8 entries. 143 | if (current_entry_type == constant_pool_type::NameAndType) 144 | { 145 | // Pull out the the Utf8 entries from NameAndType (respectively). 146 | auto name_utf8_entry = 147 | constant_pool.get_entry_as(current_entry.cp_index).value(); 148 | auto type_utf8_entry = 149 | constant_pool.get_entry_as(current_entry.cp_index2).value(); 150 | 151 | // `` has quotes around it according to Java's tool; follow 152 | // their format. 153 | std::string normalize_init = name_utf8_entry.value == "" 154 | ? "\"\"" 155 | : name_utf8_entry.value; 156 | pointed_str << normalize_init << ":" << type_utf8_entry.value; 157 | } 158 | } 159 | }, entry_data.entry); 160 | 161 | id_col.push_back(id_str.str()); 162 | entry_col.push_back(entry_str.str()); 163 | pointed_col.push_back(pointed_str.str()); 164 | } 165 | 166 | // If any of the column entries are different sizes, it's likely the class parsing failed silently. 167 | if (id_col.size() != entry_col.size() || entry_col.size() != pointed_col.size()) 168 | { 169 | throw invalid_class_format{"Failed to dump constant pool."}; 170 | } 171 | 172 | // If there is nothing to output, just return. 173 | if (!id_col.size() || !entry_col.size() || !pointed_col.size()) 174 | { 175 | return; 176 | } 177 | 178 | const auto str_compare = [](const std::string& lhs, const std::string& rhs) { 179 | return lhs.size() < rhs.size(); 180 | }; 181 | auto id_col_longest = std::max_element(id_col.cbegin(), id_col.cend(), str_compare)->size(); 182 | auto entry_col_longest = std::max_element(entry_col.cbegin(), entry_col.cend(), str_compare)->size(); 183 | auto pointed_col_longest = std::max_element(pointed_col.cbegin(), pointed_col.cend(), str_compare)->size(); 184 | 185 | for (size_t i = 0; i < id_col.size(); i++) 186 | { 187 | std::cout 188 | << std::left 189 | << std::setw(id_col_longest + 1) << id_col[i] 190 | << std::setw(entry_col_longest + 1) << entry_col[i] 191 | << std::setw(pointed_col_longest) << pointed_col[i] 192 | << std::endl; 193 | } 194 | } 195 | 196 | void do_dump_class(const java_class& clazz) 197 | { 198 | const std::vector& methods = clazz.get_class_methods(); 199 | for (const auto& method : methods) 200 | { 201 | std::string method_name = method.get_name(); 202 | std::cout << method_name << ":" << std::endl; 203 | 204 | const entry_attributes& attributes = method.get_method_attributes(); 205 | for (const auto& attribute : attributes) 206 | { 207 | std::cout << static_cast(attribute->get_type()) << std::endl; 208 | } 209 | 210 | std::cout << std::endl; 211 | } 212 | } 213 | 214 | void do_scan(const java_class& clazz, const std::string& class_name, const std::vector& api_names) 215 | { 216 | std::cout << "Found the following API calls in " << class_name << ":" << std::endl; 217 | const auto calls = find_api_calls(clazz, api_names); 218 | for (const auto& call : calls) 219 | { 220 | std::cout << '\t' << call.api_str << " in method " << call.method << " on line " << 221 | call.line_number << std::endl; 222 | } 223 | } 224 | 225 | void do_command(cxxopts::ParseResult args, bool& error) { 226 | const auto class_name = args["input"].as(); 227 | try 228 | { 229 | const auto clazz = java_class::parse_class_file(class_name); 230 | if (args.count("dump-cp")) 231 | { 232 | do_dump_cp(clazz); 233 | } 234 | else if (args.count("dump-class")) 235 | { 236 | do_dump_class(clazz); 237 | } 238 | else if (args.count("scan")) 239 | { 240 | // The constant pool stores APIs as, for example, "java/io/PrintStream" instead of the 241 | // common convention of "java.io.PrintStream". 242 | auto api_names = args["scan"].as>(); 243 | denormalize_api_names(api_names); 244 | do_scan(clazz, class_name, api_names); 245 | } 246 | else 247 | { 248 | error = true; 249 | } 250 | } 251 | catch (const std::ios::failure& io_failure) 252 | { 253 | std::cerr << io_failure.what() << std::endl; 254 | } 255 | catch (const invalid_class_format& icf) 256 | { 257 | std::cerr << icf.what() << std::endl; 258 | } 259 | } 260 | 261 | int main(int argc, char** argv) 262 | { 263 | cxxopts::Options options("bytecode-scanner", "Java bytecode utility"); 264 | options 265 | .allow_unrecognised_options() 266 | .add_options() 267 | ("input", "Input class file", cxxopts::value()) 268 | ("c,dump-cp", "Dump constant pool") 269 | ("d,dump-class", "Dump given class") 270 | ("s,scan", "Scan for a CSV list of APIs", cxxopts::value>()); 271 | options.parse_positional({ "input" }); 272 | 273 | bool error = false; 274 | try 275 | { 276 | cxxopts::ParseResult args = options.parse(argc, argv); 277 | if (!args.count("input")) 278 | { 279 | error = true; 280 | } 281 | 282 | if (!error) 283 | { 284 | do_command(std::move(args), error); 285 | } 286 | } 287 | catch (const cxxopts::OptionException& e) 288 | { 289 | error = true; 290 | } 291 | 292 | if (error) 293 | { 294 | std::cerr << options.help() << std::endl; 295 | return 1; 296 | } 297 | 298 | return 0; 299 | } 300 | -------------------------------------------------------------------------------- /src/method_info.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Anthony Calandra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "attribute_info.hh" 24 | #include "constant_pool.hh" 25 | #include "method_info.hh" 26 | #include "util.hh" 27 | 28 | std::vector parse_methods(std::ifstream& file, const constant_pool& cp) 29 | { 30 | std::vector methods; 31 | READ_U2_FIELD(methods_count, "Failed to parse methods count of class file."); 32 | for (uint16_t curr_method_idx = 0; curr_method_idx < methods_count; curr_method_idx++) 33 | { 34 | methods.emplace_back(method_info::parse_method_info(file, cp)); 35 | } 36 | 37 | return methods; 38 | } 39 | 40 | method_info method_info::parse_method_info(std::ifstream& file, const constant_pool& cp) 41 | { 42 | READ_U2_FIELD(access_flag_bytes, "Failed to parse access flags of method."); 43 | auto access_flags = method_access_flags{access_flag_bytes}; 44 | READ_U2_FIELD(name_index, "Failed to parse name index of method."); 45 | READ_U2_FIELD(descriptor_index, "Failed to parse descriptor index of method."); 46 | return method_info{cp, access_flags, name_index, descriptor_index, parse_attributes(file, cp)}; 47 | } 48 | 49 | method_info::method_info(const constant_pool& cp, method_access_flags access_flags, 50 | constant_pool_entry_id name_index, constant_pool_entry_id descriptor_index, 51 | entry_attributes method_attributes) : 52 | cp{cp}, 53 | access_flags{access_flags}, 54 | name_index{name_index}, 55 | descriptor_index{descriptor_index}, 56 | method_attributes{std::move(method_attributes)} 57 | {} 58 | --------------------------------------------------------------------------------