#pragma endian big #pragma pattern_limit 100000000 #include #include #include #include #include using BitfieldOrder = std::core::BitfieldOrder; using u1 = u8; using u2 = u16; using u4 = u32; using f4 = float; using f8 = double; using cp_ref = u16 [[format("fmt::const_ref_top")]]; bool applyPadding = false; struct cp_info { bool isTop = false; if(applyPadding) { isTop = true; applyPadding = false; } else { u1 tag; match(tag) { (1): { /* cp_utf8 */ u2 length; char bytes[length]; } (3): { /* cp_integer */ u4 bytes; } (4): { /* cp_float */ float bytes; } (5): { /* cp_long */ u64 bytes; applyPadding = true; } (6): { /* cp_double */ double bytes; applyPadding = true; } (7): { /* cp_class */ cp_ref name_index; } (8): { /* cp_string */ cp_ref string_index; } (9): { /* cp_fieldref */ cp_ref class_index; cp_ref name_and_type_index; } (10): { /* cp_methodref */ cp_ref class_index; cp_ref name_and_type_index; } (11): { /* cp_interface_methodref */ cp_ref class_index; cp_ref name_and_type_index; } (12): { /* cp_name_and_type */ cp_ref name_index; cp_ref descriptor_index; } (15): { /* cp_method_handle */ u1 reference_kind; cp_ref reference_index; } (16): { /* cp_method_type */ cp_ref descriptor_index; } (18): { /* cp_invoke_dynamic */ u2 bootstrap_method_attr_index; cp_ref name_and_type_index; } (19): { /* cp_module */ cp_ref name_index; } (20): { /* cp_package */ cp_ref name_index; } } } } [[format("fmt::const_name")]]; namespace fmt { fn const_name(auto tag) { if(tag.isTop) return "Top"; match(tag.tag) { (1): return "Utf8"; (3): return "Integer"; (4): return "Float"; (5): return "Long"; (6): return "Double"; (7): return "Class"; (8): return "String"; (9): return "Fieldref"; (10): return "Methodref"; (11): return "InterfaceMethodref"; (12): return "NameAndType"; (15): return "MethodHandle"; (16): return "MethodType"; (18): return "InvokeDynamic"; (_): return "Unknown"; } }; fn const_ref(u2 index) { cp_info info = file.constant_pool[index-1]; match(info.tag) { (1): return info.bytes; (3): return std::format("{:d} [{:d}]", index, info.bytes); (4): return std::format("{:d} [{:f}]", index, info.bytes); (5): return std::format("{:d} [{:d}", index, info.bytes); (6): return std::format("{:d} [{:f}", index, info.bytes); (7): return std::format("{:d} [Class({})]", index, fmt::const_ref(info.name_index)); (8): return std::format("{:d} [String({})]", index, fmt::const_ref(info.string_index)); (9): return std::format("{:d} [Fieldref({}, {})]", index, fmt::const_ref(info.class_index), fmt::const_ref(info.name_and_type_index)); (10): return std::format("{:d} [Methodref({}, {})]", index, fmt::const_ref(info.class_index), fmt::const_ref(info.name_and_type_index)); (11): return std::format("{:d} [InterfaceMethodref({}, {})]", index, fmt::const_ref(info.class_index), fmt::const_ref(info.name_and_type_index)); (12): return std::format("{:d} [NameAndType({}, {})]", index, fmt::const_ref(info.name_index), fmt::const_ref(info.descriptor_index)); (15): return std::format("{:d} [MethodHandle({}, {})]", index, info.reference_kind, fmt::const_ref(info.reference_index)); (16): return std::format("{:d} [MethodType({})]", index, fmt::const_ref(info.descriptor_index)); (18): return std::format("{:d} [InvokeDynamic({}, {})]", index, info.bootstrap_method_attr_index, fmt::const_ref(info.name_and_type_index)); (19): return std::format("{:d} [Module({})]", index, fmt::const_ref(info.name_index)); (20): return std::format("{:d} [Package({})]", index, fmt::const_ref(info.name_index)); (_): return std::format("{:d} [Unknown]", index); } }; fn const_ref_top(u2 index) { cp_info info = file.constant_pool[index-1]; match(info.tag) { (1): return std::format("{:d} [{:s}]", index, info.bytes); (_): return fmt::const_ref(index); } }; fn attribute(auto info) { return file.constant_pool[info.attribute_name_index-1].bytes; }; fn verif_type_info(auto info) { match(info.tag) { (0): return "TOP"; (1): return "INTEGER"; (2): return "FLOAT"; (3): return "DOUBLE"; (4): return "LONG"; (5): return "NULL"; (6): return "UNINITIALIZED_THIS"; (7): return std::format("Object({})", fmt::const_ref(info.cpool_index)); (8): return std::format("Uninitialized({})", info.offset); (_): return "Unknown"; } }; fn stack_map_frame(auto frame) { match(frame.frame_type) { (0 ... 63): return std::format("SAME [{}]", frame.frame_type); (64 ... 127): return std::format("SAME_LOCALS_1_STACK_ITEM [{}]", frame.frame_type); (247): return std::format("SAME_LOCALS_1_STACK_ITEM_EXTENDED [{}]", frame.frame_type); (248 ... 250): return std::format("CHOP [{}]", frame.frame_type); (251): return std::format("SAME_FRAME_EXTENDED [{}]", frame.frame_type); (252 ... 254): return std::format("APPEND [{}]", frame.frame_type); (255): return std::format("FULL_FRAME [{}]", frame.frame_type); } }; fn element_value(auto element) { match(element.tag) { ('B'): return std::format("byte [{:s}]", fmt::const_ref(element.const_value_index)); ('C'): return std::format("char [{:s}]", fmt::const_ref(element.const_value_index)); ('D'): return std::format("double [{:s}]", fmt::const_ref(element.const_value_index)); ('F'): return std::format("float [{:s}]", fmt::const_ref(element.const_value_index)); ('I'): return std::format("int [{:s}]", fmt::const_ref(element.const_value_index)); ('J'): return std::format("long [{:s}]", fmt::const_ref(element.const_value_index)); ('S'): return std::format("short [{:s}]", fmt::const_ref(element.const_value_index)); ('Z'): return std::format("boolean [{:s}]", fmt::const_ref(element.const_value_index)); ('s'): return std::format("String [{:s}]", fmt::const_ref(element.const_value_index)); ('e'): return std::format("Enum [{:s}, {:s}]", fmt::const_ref(element.type_name_index), fmt::const_ref(element.const_name_index)); ('c'): return std::format("Class [{:s}]", fmt::const_ref(element.class_info_index)); ('@'): return std::format("Annotation [{:s}]", fmt::const_ref(element.annotation_value.type_index)); ('['): return std::format("Array [{:s}]", fmt::const_ref(element.num_values)); } }; } enum major_version : u2 { JDK_1_1 = 45, JDK_1_2 = 46, JDK_1_3 = 47, JDK_1_4 = 48, Java_SE_5_0 = 49, Java_SE_6 = 50, Java_SE_7 = 51, Java_SE_8 = 52, Java_SE_9 = 53, Java_SE_10 = 54, Java_SE_11 = 55, Java_SE_12 = 56, Java_SE_13 = 57, Java_SE_14 = 58, Java_SE_15 = 59, Java_SE_16 = 60, Java_SE_17 = 61, }; bitfield access_flags_method { ACC_PUBLIC : 1; // 0x0001 ACC_PRIVATE : 1; // 0x0002 ACC_PROTECTED : 1; // 0x0004 ACC_STATIC : 1; // 0x0008 ACC_FINAL : 1; // 0x0010 ACC_SYNCHRONIZED: 1; // 0x0020 ACC_BRIDGE : 1; // 0x0040 ACC_VARARGS : 1; // 0x0080 ACC_NATIVE : 1; // 0x0100 padding : 1; // 0x0200 ACC_ABSTRACT : 1; // 0x0400 ACC_STRICT : 1; // 0x0800 ACC_SYNTHETIC : 1; // 0x1000 padding : 1; // 0x2000 padding : 1; // 0x4000 padding : 1; // 0x8000 } [[bitfield_order(BitfieldOrder::LeastToMostSignificant, 16)]]; bitfield access_flags_field { ACC_PUBLIC : 1; // 0x0001 ACC_PRIVATE : 1; // 0x0002 ACC_PROTECTED : 1; // 0x0004 ACC_STATIC : 1; // 0x0008 ACC_FINAL : 1; // 0x0010 padding : 1; // 0x0020 ACC_VOLATILE : 1; // 0x0040 ACC_TRANSIENT : 1; // 0x0080 padding : 1; // 0x0100 padding : 1; // 0x0200 padding : 1; // 0x0400 padding : 1; // 0x0800 ACC_SYNTHETIC : 1; // 0x1000 padding : 1; // 0x2000 ACC_ENUM : 1; // 0x4000 padding : 1; // 0x8000 } [[bitfield_order(BitfieldOrder::LeastToMostSignificant, 16)]]; bitfield access_flags_class { ACC_PUBLIC : 1; // 0x0001 padding : 1; // 0x0002 padding : 1; // 0x0004 padding : 1; // 0x0008 ACC_FINAL : 1; // 0x0010 ACC_SUPER : 1; // 0x0020 padding : 1; // 0x0040 padding : 1; // 0x0080 padding : 1; // 0x0100 ACC_INTERFACE : 1; // 0x0200 ACC_ABSTRACT : 1; // 0x0400 padding : 1; // 0x0800 ACC_SYNTHETIC : 1; // 0x1000 ACC_ANNOTATION : 1; // 0x2000 ACC_ENUM : 1; // 0x4000 ACC_MODULE : 1; // 0x8000 } [[bitfield_order(BitfieldOrder::LeastToMostSignificant, 16)]]; bitfield access_flags_module { padding : 1; // 0x0001 padding : 1; // 0x0002 padding : 1; // 0x0004 padding : 1; // 0x0008 padding : 1; // 0x0010 ACC_TRANSITIVE : 1; // 0x0020 ACC_STATIC_PHASE : 1; // 0x0040 padding : 1; // 0x0080 padding : 1; // 0x0100 padding : 1; // 0x0200 padding : 1; // 0x0400 padding : 1; // 0x0800 ACC_SYNTHETIC : 1; // 0x1000 padding : 1; // 0x2000 padding : 1; // 0x4000 ACC_MANDATED : 1; // 0x8000 } [[bitfield_order(BitfieldOrder::LeastToMostSignificant, 16)]]; using attribute_code; struct attribute_constant_value { cp_ref constantvalue_index; } [[static]]; struct verification_type_info { u1 tag; match(tag) { (0): { /* Top_variable_info */ } (1): { /* Integer_variable_info */ } (2): { /* Float_variable_info */ } (3): { /* Long_variable_info */ } (4): { /* Double_variable_info */ } (5): { /* Null_variable_info */ } (6): { /* UninitializedThis_variable_info */ } (7): { /* Object_variable_info */ cp_ref cpool_index; } (8): { /* Uninitialized_variable_info */ u2 offset; } } } [[format("fmt::verif_type_info")]]; struct same_locals_1_stack_item_frame { verification_type_info stack[1]; }; struct same_locals_1_stack_item_frame_extended { u2 offset_delta; verification_type_info stack[1]; }; struct chop_frame { u2 offset_delta; }; struct same_frame_extended { u2 offset_delta; } [[static]]; struct append_frame { u2 offset_delta; verification_type_info locals[frame_type - 251]; }; struct full_frame { u2 offset_delta; u2 number_of_locals; verification_type_info locals[number_of_locals]; u2 number_of_stack_items; verification_type_info stack[number_of_stack_items]; }; struct stack_map_frame { u1 frame_type; match(frame_type) { (0 ... 63): {} /* nothing */ (64 ... 127): same_locals_1_stack_item_frame child [[inline]]; (247): same_locals_1_stack_item_frame_extended child [[inline]]; (248 ... 250): chop_frame child [[inline]]; (251): same_frame_extended child [[inline]]; (252 ... 254): append_frame child [[inline]]; (255): full_frame child [[inline]]; } } [[format("fmt::stack_map_frame")]]; struct same_frame { u1 frame_type = SAME; /* 0-63 */ }; struct attribute_stack_map_table { u2 number_of_entries; stack_map_frame entries[number_of_entries]; }; struct attribute_exception { u2 number_of_exceptions; cp_ref exception_index_table[number_of_exceptions]; }; struct inner_class { cp_ref inner_class_info_index; u16 __ [[hidden]]; if(__ != 0) { cp_ref outer_class_info_index @ addressof(__); } u16 ___ [[hidden]]; if(___ != 0) { cp_ref inner_name_index @ addressof(___); } u2 inner_class_access_flags; }; struct attribute_inner_classes { u2 number_of_classes; inner_class classes[number_of_classes]; }; struct attribute_enclosing_method { cp_ref class_index; cp_ref method_index; } [[static]]; struct attribute_synthetic { }; struct attribute_signature { cp_ref signature_index; } [[static]]; struct attribute_source_file { cp_ref sourcefile_index; } [[static]]; struct attribute_source_debug_extension { u1 debug_extension[attribute_length]; }; struct line_number_table_entry { u2 start_pc; u2 line_number; } [[static]]; struct attribute_line_number_table { u2 line_number_table_length; line_number_table_entry line_number_table[line_number_table_length]; }; struct local_variable_table_entry { u2 start_pc; u2 length; cp_ref name_index; cp_ref descriptor_index; u2 index; } [[static]]; struct attribute_local_variable_table { u2 local_variable_table_length; local_variable_table_entry local_variable_table[local_variable_table_length]; }; struct local_variable_type_table_entry { u2 start_pc; u2 length; cp_ref name_index; cp_ref signature_index; u2 index; } [[static]]; struct attribute_local_variable_type_table { u2 local_variable_type_table_length; local_variable_type_table_entry local_variable_type_table[local_variable_type_table_length]; }; struct attribute_deprecated { }; using annotation; using element_value; struct element_value { char tag; match(tag) { ('B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' | 's'): { cp_ref const_value_index; } ('e'): { cp_ref type_name_index; cp_ref const_name_index; } ('c'): { cp_ref class_info_index; } ('@'): { annotation annotation_value; } ('['): { u2 num_values; element_value values[num_values]; } (_): { std::error("Unknown element_value tag: %c", tag); } } } [[format("fmt::element_value")]]; struct element_value_pair { cp_ref element_name_index; element_value value; }; struct annotation { cp_ref type_index; u2 num_element_value_pairs; element_value_pair element_value_pairs[num_element_value_pairs]; }; struct annotation_base { u2 num_annotations; annotation annotations[num_annotations]; }; struct attribute_runtime_visible_annotations { annotation_base [[inline]]; }; struct attribute_runtime_invisible_annotations { annotation_base [[inline]]; }; struct attribute_runtime_visible_parameter_annotations { u1 num_parameters; annotation_base parameter_annotations[num_parameters]; }; struct attribute_runtime_invisible_parameter_annotations { u1 num_parameters; annotation_base parameter_annotations[num_parameters]; }; struct path_element { u1 type_path_kind; u1 type_argument_index; }; struct type_path { u1 path_length; path_element path[path_length]; }; struct localvar_target_entry { u2 start_pc; u2 length; u2 index; }; struct target_info { match(target_type) { (0x00 | 0x01): { /* type_parameter_target */ u1 type_parameter_index; } (0x10): { /* supertype_target */ u2 supertype_index; } (0x11 | 0x12): { /* type_parameter_bound_target */ u1 type_parameter_index; u1 bound_index; } (0x13 | 0x14 | 0x15): { /* empty_target */ } (0x16): { /* formal_parameter_target */ u1 formal_parameter_index; } (0x17): { /* throws_target */ u2 throws_type_index; } (0x40 | 0x41): { /* localvar_target */ u2 table_length; localvar_target_entry table[table_length]; } (0x42): { /* catch_target */ u2 exception_table_index; } (0x43 | 0x44 | 0x45 | 0x46): { /* offset_target */ u2 offset; } (0x47 | 0x48 | 0x49 | 0x4A): { /* type_argument_target */ u2 offset; u1 type_argument_index; } } }; struct type_annotation { u1 target_type; target_info target_info; type_path type_path; annotation annotation [[inline]]; }; struct attribute_runtime_visible_type_annotations { u2 num_annotations; type_annotation annotations[num_annotations]; }; struct attribute_runtime_invisible_type_annotations { u2 num_annotations; type_annotation annotations[num_annotations]; }; struct attribute_annotation_default { element_value default_value; }; struct bootstrap_method { cp_ref bootstrap_method_ref; u2 num_bootstrap_arguments; cp_ref bootstrap_arguments[num_bootstrap_arguments]; }; struct attribute_bootstrap_methods { u2 num_bootstrap_methods; bootstrap_method bootstrap_methods[num_bootstrap_methods]; }; struct method_parameter { u2 name_index [[hidden]]; if (name_index != 0) { cp_ref name_index @ addressof(name_index); } u2 access_flags; }; struct attribute_method_parameters { u1 parameters_count; method_parameter parameters[parameters_count]; }; struct require { cp_ref require_index; access_flags_module require_flags; u2 require_version_index [[hidden]]; if (require_version_index != 0) { cp_ref require_version_index @ addressof(require_version_index); } }; struct export { cp_ref exports_index; access_flags_module exports_flags; u2 exports_to_count; cp_ref exports_to_index[exports_to_count]; }; struct open { cp_ref opens_index; access_flags_module opens_flags; u2 opens_to_count; cp_ref opens_to_index[opens_to_count]; }; struct provide { cp_ref provides_index; u2 provides_with_count; cp_ref provides_with_index[provides_with_count]; }; struct attribute_module { cp_ref module_name_index; u2 module_flags; u2 module_version_index [[hidden]]; if (module_version_index != 0) { cp_ref module_version_index @ addressof(module_version_index); } u2 requires_count; require requires[requires_count]; u2 exports_count; export exports[exports_count]; u2 opens_count; open opens[opens_count]; u2 uses_count; cp_ref uses_index[uses_count]; u2 provides_count; provide provides[provides_count]; }; struct attribute_module_packages { u2 package_count; cp_ref package_index[package_count]; }; struct attribute_module_main_class { cp_ref main_class_index; }; struct attribute_nest_host { cp_ref host_class_index; }; struct attribute_nest_members { u2 number_of_classes; cp_ref classes[number_of_classes]; }; using record_component_info; struct attribute_record { u2 component_count; record_component_info components[component_count]; }; struct attribute_permitted_subclasses { u2 number_of_classes; cp_ref classes[number_of_classes]; }; struct attribute_info { cp_ref attribute_name_index; u4 attribute_length; match(constant_pool[attribute_name_index-1].bytes) { ("Code"): attribute_code child [[inline]]; ("ConstantValue"): attribute_constant_value [[inline]]; ("StackMapTable"): attribute_stack_map_table [[inline]]; ("Exceptions"): attribute_exception [[inline]]; ("InnerClasses"): attribute_inner_classes [[inline]]; ("EnclosingMethod"): attribute_enclosing_method [[inline]]; ("Synthetic"): attribute_synthetic [[inline]]; ("Signature"): attribute_signature [[inline]]; ("SourceFile"): attribute_source_file [[inline]]; ("SourceDebugExtension"): attribute_source_debug_extension [[inline]]; ("LineNumberTable"): attribute_line_number_table [[inline]]; ("LocalVariableTable"): attribute_local_variable_table [[inline]]; ("LocalVariableTypeTable"): attribute_local_variable_type_table [[inline]]; ("Deprecated"): attribute_deprecated [[inline]]; ("RuntimeVisibleAnnotations"): attribute_runtime_visible_annotations [[inline]]; ("RuntimeInvisibleAnnotations"): attribute_runtime_invisible_annotations [[inline]]; ("RuntimeVisibleParameterAnnotations"): attribute_runtime_visible_parameter_annotations [[inline]]; ("RuntimeInvisibleParameterAnnotations"): attribute_runtime_invisible_parameter_annotations [[inline]]; ("RuntimeVisibleTypeAnnotations"): attribute_runtime_visible_type_annotations [[inline]]; ("RuntimeInvisibleTypeAnnotations"): attribute_runtime_invisible_type_annotations [[inline]]; ("AnnotationDefault"): attribute_annotation_default [[inline]]; ("BootstrapMethods"): attribute_bootstrap_methods [[inline]]; ("MethodParameters"): attribute_method_parameters [[inline]]; ("Module"): attribute_module [[inline]]; ("ModulePackages"): attribute_module_packages [[inline]]; ("ModuleMainClass"): attribute_module_main_class [[inline]]; ("NestHost"): attribute_nest_host [[inline]]; ("NestMembers"): attribute_nest_members [[inline]]; ("Record"): attribute_record [[inline]]; (_): u1 info[attribute_length]; } if(($-(addressof(this)+6)) != attribute_length) std::warning("Invalid attribute length at " + std::format("{:x}", addressof(this)) + " " + std::string::to_string($-(addressof(this)+6)) + "!=" + std::string::to_string(attribute_length)); } [[format("fmt::attribute")]]; struct record_component_info { cp_ref name_index; cp_ref descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; }; struct exception { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; } [[static]]; struct attribute_code { u2 max_stack; u2 max_locals; u4 code_length; u1 code[code_length]; u2 exception_table_length; exception exception_table[exception_table_length]; u2 attributes_count; attribute_info attributes[attributes_count]; }; struct field_info { access_flags_field access_flags; cp_ref name_index; cp_ref descriptor_index; u2 attribute_count; attribute_info attributes[attribute_count]; }; struct method_info { access_flags_method access_flags; cp_ref name_index; cp_ref descriptor_index; u2 attribute_count; attribute_info attributes[attribute_count]; }; struct ClassFile { u1 magic[4]; u2 minor_version; major_version major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; access_flags_class access_flags; cp_ref this_class; cp_ref super_class; u2 interfaces_count; cp_ref interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; }; ClassFile file @ 0x0;