/* packet-jdwp.c * Routines for JDWP (Java Debug Wire Protocol) dissection * Copyright 2020, Eugene Adell * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include #include #include #include #include "packet-tcp.h" void proto_register_jdwp(void); void proto_reg_handoff_jdwp(void); /* IMPORTANT IMPLEMENTATION NOTES * * You need to be looking at: * * https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/jdwp-spec.html * * */ #define JDWP_PORT 9009 /* Not IANA registered */ #define FRAME_HEADER_LEN 11 #define JDWP_MIN_LENGTH 11 #define JDWP_HANDSHAKE_LENGTH 14 #define JDWP_HANDSHAKE_MSG "JDWP-Handshake" #define PACKET_TYPE_COMMAND 0 #define PACKET_TYPE_REPLY 128 #define COMMAND_SET_VIRTUALMACHINE 1 #define COMMAND_SET_REFERENCETYPE 2 #define COMMAND_SET_CLASSTYPE 3 #define COMMAND_SET_ARRAYTYPE 4 #define COMMAND_SET_INTERFACETYPE 5 #define COMMAND_SET_METHOD 6 #define COMMAND_SET_FIELD 8 #define COMMAND_SET_OBJECTREFERENCE 9 #define COMMAND_SET_STRINGREFERENCE 10 #define COMMAND_SET_THREADREFERENCE 11 #define COMMAND_SET_THREADGROUPREFERENCE 12 #define COMMAND_SET_ARRAYREFERENCE 13 #define COMMAND_SET_CLASSLOADERREFERENCE 14 #define COMMAND_SET_EVENTREQUEST 15 #define COMMAND_SET_STACKFRAME 16 #define COMMAND_SET_CLASSOBJECTREFERENCE 17 #define COMMAND_SET_EVENT 64 static int proto_jdwp = -1; static int hf_jdwp_type = -1; static int hf_jdwp_length = -1; static int hf_jdwp_id = -1; static int hf_jdwp_flags = -1; static int hf_jdwp_commandset = -1; static int hf_jdwp_commandset_virtualmachine = -1; static int hf_jdwp_commandset_referencetype = -1; static int hf_jdwp_commandset_classtype = -1; static int hf_jdwp_commandset_arraytype = -1; static int hf_jdwp_commandset_interfacetype = -1; static int hf_jdwp_commandset_method = -1; static int hf_jdwp_commandset_field = -1; static int hf_jdwp_commandset_objectreference = -1; static int hf_jdwp_commandset_stringreference = -1; static int hf_jdwp_commandset_threadreference = -1; static int hf_jdwp_commandset_threadgroupreference = -1; static int hf_jdwp_commandset_arrayreference = -1; static int hf_jdwp_commandset_classloaderreference = -1; static int hf_jdwp_commandset_eventrequest = -1; static int hf_jdwp_commandset_stackframe = -1; static int hf_jdwp_commandset_classobjectreference = -1; static int hf_jdwp_commandset_event = -1; static int hf_jdwp_errorcode = -1; static int hf_jdwp_data = -1; static gint ett_jdwp = -1; static expert_field ei_jdwp_hlen_invalid = EI_INIT; static expert_field ei_jdwp_flags_invalid = EI_INIT; // contains the command set names static const value_string commandsetnames[] = { {1, "VirtualMachine"}, {2, "ReferenceType"}, {3, "ClassType"}, {4, "ArrayType"}, {5, "InterfaceType"}, {6, "Method"}, {8, "Field"}, {9, "ObjectReference"}, {10, "StringReference"}, {11, "ThreadReference"}, {12, "ThreadGroupReference"}, {13, "ArrayReference"}, {14, "ClassLoaderReference"}, {15, "EventRequest"}, {16, "StackFrame"}, {17, "ClassObjectReference"}, {64, "Event"}, {0, NULL} }; // contains the commands for the command set of type Virtual Machine static const value_string commandset_virtualmachine[] = { {1, "Version"}, {2, "ClassesBySignature"}, {3, "AllClasses"}, {4, "AllThreads"}, {5, "TopLevelThreadGroups"}, {6, "Dispose"}, {7, "IDSizes"}, {8, "Suspend"}, {9, "Resume"}, {10, "Exit"}, {11, "CreateString"}, {12, "Capabilities"}, {13, "ClassPaths"}, {14, "DisposeObjects"}, {15, "HoldEvents"}, {16, "ReleaseEvents"}, {17, "CapabilitiesNew"}, {18, "RedefineClasses"}, {19, "SetDefaultStratum"}, {20, "AllClassesWithGeneric"}, {21, "InstanceCounts"}, {0, NULL} }; // contains the commands for the command set of type Reference static const value_string commandset_referencetype[] = { {1, "Signature"}, {2, "ClassLoader"}, {3, "Modifiers"}, {4, "Fields"}, {5, "Methods"}, {6, "GetValues"}, {7, "SourceFile"}, {8, "NestedTypes"}, {9, "Status"}, {10, "Interfaces"}, {11, "ClassObject"}, {12, "SourceDebugExtension"}, {13, "SignatureWithGeneric"}, {14, "FieldsWithGeneric"}, {15, "MethodsWithGeneric"}, {16, "Instances"}, {17, "ClassFileVersion"}, {18, "ConstantPool"}, {0, NULL} }; // contains the commands for the command set of type Class static const value_string commandset_classtype[] = { {1, "Superclass"}, {2, "SetValues"}, {3, "InvokeMethod"}, {4, "NewInstance"}, {0, NULL} }; // contains the commands for the command set of type Array static const value_string commandset_arraytype[] = { {1, "NewInstance"}, {0, NULL} }; // contains the commands for the command set of type Interface static const value_string commandset_interfacetype[] = { {1, "InvokeMethod"}, {0, NULL} }; // contains the commands for the command set of type Method static const value_string commandset_method[] = { {1, "LineTable"}, {2, "VariableTable"}, {3, "Bytecodes"}, {4, "IsObsolete"}, {5, "VariableTableWithGeneric"}, {0, NULL} }; // contains the commands for the command set of type Field static const value_string commandset_field[] = { {0, NULL} }; // contains the commands for the command set of type Object Reference static const value_string commandset_objectreference[] = { {1, "ReferenceType"}, {2, "GetValues"}, {3, "SetValues"}, {5, "MonitorInfo"}, {6, "InvokeMethod"}, {7, "DisableCollection"}, {8, "EnableCollection"}, {9, "IsCollected"}, {10, "ReferringObjects"}, {0, NULL} }; // contains the commands for the command set of type String Reference static const value_string commandset_stringreference[] = { {1, "Value"}, {0, NULL} }; // contains the commands for the command set of type Thread Reference static const value_string commandset_threadreference[] = { {1, "Name"}, {2, "Suspend"}, {3, "Resume"}, {4, "Status"}, {5, "ThreadGroup"}, {6, "Frames"}, {7, "FrameCount"}, {8, "OwnedMonitors"}, {9, "CurrentContentedMonitor"}, {10, "Stop"}, {11, "Interrupt"}, {12, "SuspendCount"}, {13, "OwnedMonitorsStackDepthInfo"}, {14, "ForceEarlyReturn"}, {0, NULL} }; // contains the commands for the command set of type ThreadGroup Reference static const value_string commandset_threadgroupreference[] = { {1, "Name"}, {2, "Parent"}, {3, "Children"}, {0, NULL} }; // contains the commands for the command set of type Array Reference static const value_string commandset_arrayreference[] = { {1, "Length"}, {2, "GetValues"}, {3, "SetValues"}, {0, NULL} }; // contains the commands for the command set of type ClassLoader Reference static const value_string commandset_classloaderreference[] = { {1, "VisibleClasses"}, {0, NULL} }; // contains the commands for the command set of type EventRequest static const value_string commandset_eventrequest[] = { {1, "Set"}, {2, "Clear"}, {3, "ClearAllBreakpoints"}, {0, NULL} }; // contains the commands for the command set of type StackFrame static const value_string commandset_stackframe[] = { {1, "GetValues"}, {2, "SetValues"}, {3, "ThisObject"}, {4, "PopFrames"}, {0, NULL} }; // contains the commands for the command set of type ClassObject Reference static const value_string commandset_classobjectreference[] = { {1, "ReflectedType"}, {0, NULL} }; // contains the commands for the command set of type Event static const value_string commandset_event[] = { {100, "Composite"}, {0, NULL} }; /* translates the error code to human readable value * value 0 ("NONE") means SUCCESS, all other values mean FAILURE */ static const value_string error_codes[] = { {0, "NONE"}, {10, "INVALID_THREAD"}, {11, "INVALID_THREAD_GROUP"}, {12, "INVALID_PRIORITY"}, {13, "THREAD_NOT_SUSPENDED"}, {14, "THREAD_SUSPENDED"}, {20, "INVALID_OBJECT"}, {21, "INVALID_CLASS"}, {22, "CLASS_NOT_PREPARED"}, {23, "INVALID_METHODID"}, {24, "INVALID_LOCATION"}, {25, "INVALID_FIELDID"}, {30, "INVALID_FRAMEID"}, {31, "NO_MORE_FRAMES"}, {32, "OPAQUE_FRAME"}, {33, "NOT_CURRENT_FRAME"}, {34, "TYPE_MISMATCH"}, {35, "INVALID_SLOT"}, {40, "DUPLICATE"}, {41, "NOT_FOUND"}, {50, "INVALID_MONITOR"}, {51, "NOT_MONITOR_OWNER"}, {52, "INTERRUPT"}, {60, "INVALID_CLASS_FORMAT"}, {61, "CIRCULAR_CLASS_DEFINITION"}, {62, "FAILS_VERIFICATION"}, {63, "ADD_METHOD_NOT_IMPLEMENTED"}, {64, "SCHEMA_CHANGE_NOT_IMPLEMENTED"}, {65, "INVALID_TYPESTATE"}, {66, "HIERARCHY_CHANGE_NOT_IMPLEMENTED"}, {67, "DELETE_METHOD_NOT_IMPLEMENTED"}, {68, "UNSUPPORTED_VERSION"}, {69, "NAMES_DONT_MATCH"}, {70, "CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED"}, {71, "METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED"}, {99, "NOT_IMPLEMENTED"}, {100, "NULL_POINTER"}, {101, "ABSENT_INFORMATION"}, {102, "INVALID_EVENT_TYPE"}, {103, "ILLEGAL_ARGUMENT"}, {110, "OUT_OF_MEMORY"}, {111, "ACCESS_DENIED"}, {112, "VM_DEAD"}, {113, "INTERNAL"}, {115, "UNATTACHED_THREAD"}, {500, "INVALID_TAG"}, {502, "ALREADY_INVOKING"}, {503, "INVALID_INDEX"}, {504, "INVALID_LENGTH"}, {506, "INVALID_STRING"}, {507, "INVALID_CLASS_LOADER"}, {508, "INVALID_ARRAY"}, {509, "TRANSPORT_LOAD"}, {510, "TRANSPORT_INIT"}, {511, "NATIVE_METHOD"}, {512, "INVALID_COUNT"}, {0, NULL} }; /* determine PDU length of protocol JDWP */ static guint get_jdwp_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) { /* Handshake messages don't contain the length field and * they all are strictly identical in length and content */ if (tvb_reported_length(tvb) == JDWP_HANDSHAKE_LENGTH) { if (tvb_strneql(tvb, offset, JDWP_HANDSHAKE_MSG, JDWP_HANDSHAKE_LENGTH) == 0) { return JDWP_HANDSHAKE_LENGTH; } } /* All other packets are either a Command or a Reply, of different lengths * and this length is indicated on the 4 first bytes */ return (guint)tvb_get_ntohl(tvb, offset); } static int dissect_jdwp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { int offset = 0; /* packet type can take 3 values (handshake, command, reply) */ gint packet_type; /* length */ gint32 hlen = 0; /* flag can take 2 values (0, 128) */ guint32 flags; /* fields that need to be remembered */ guint32 mem_commandset = -1; guint32 mem_errorcode = -1; /* Check that there's enough data */ if (tvb_reported_length(tvb) < JDWP_MIN_LENGTH) return 0; /* Set the Protocol Column */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "JDWP"); col_clear(pinfo->cinfo, COL_INFO); proto_item *ti, *hlen_item, *flags_item; proto_tree *jdwp_tree; /* Clear out stuff in the info column */ col_clear(pinfo->cinfo,COL_INFO); ti = proto_tree_add_item(tree, proto_jdwp, tvb, 0, -1, ENC_NA); jdwp_tree = proto_item_add_subtree(ti, ett_jdwp); /* The two first packets are Handshake packets and * their content is always "JDWP-Handshake" * All other packets are either a Command or a Reply */ packet_type = 1; if (tvb_reported_length(tvb) == JDWP_HANDSHAKE_LENGTH) { if (tvb_strneql(tvb, offset, JDWP_HANDSHAKE_MSG, JDWP_HANDSHAKE_LENGTH) == 0) { col_append_fstr(pinfo->cinfo, COL_INFO, "JDWP Handshake"); packet_type = 0; } } if (packet_type == 0) { proto_tree_add_item(jdwp_tree, hf_jdwp_type, tvb, offset, 14, ENC_ASCII|ENC_NA); return tvb_captured_length(tvb); } /* LENGTH */ hlen_item = proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_length, tvb, offset, 4, ENC_BIG_ENDIAN, &hlen); offset += 4; /* ID */ proto_tree_add_item(jdwp_tree, hf_jdwp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* FLAGS */ flags_item = proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_flags, tvb, offset, 1, ENC_BIG_ENDIAN, &flags); offset += 1; /* COMMAND */ switch (flags) { case PACKET_TYPE_COMMAND: col_append_fstr(pinfo->cinfo, COL_INFO, "Command"); proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_commandset, tvb, offset, 1, ENC_BIG_ENDIAN, &mem_commandset); offset += 1; switch (mem_commandset) { case COMMAND_SET_VIRTUALMACHINE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_virtualmachine, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_REFERENCETYPE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_referencetype, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_CLASSTYPE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_classtype, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_ARRAYTYPE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_arraytype, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_INTERFACETYPE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_interfacetype, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_METHOD: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_method, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_FIELD: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_field, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_OBJECTREFERENCE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_objectreference, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_STRINGREFERENCE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_stringreference, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_THREADREFERENCE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_threadreference, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_THREADGROUPREFERENCE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_threadgroupreference, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_ARRAYREFERENCE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_arrayreference, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_CLASSLOADERREFERENCE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_classloaderreference, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_EVENTREQUEST: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_eventrequest, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_STACKFRAME: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_stackframe, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_CLASSOBJECTREFERENCE: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_classobjectreference, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case COMMAND_SET_EVENT: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_event, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; default: proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_virtualmachine, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; } /* command comes with data when the minimal length is 12 */ if (hlen > 11) { proto_tree_add_item(jdwp_tree, hf_jdwp_data, tvb, offset, hlen - 11, ENC_NA); } else if (hlen < 11) { expert_add_info(pinfo, hlen_item, &ei_jdwp_hlen_invalid); } break; case PACKET_TYPE_REPLY: proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_errorcode, tvb, offset, 2, ENC_BIG_ENDIAN, &mem_errorcode); offset += 2; if(mem_errorcode == 0) { col_append_fstr(pinfo->cinfo, COL_INFO, "Reply (Success)"); } else { col_append_fstr(pinfo->cinfo, COL_INFO, "Reply (Failure)"); } /* reply comes with data when the minimal length is 12 */ if (hlen > 11) { proto_tree_add_item(jdwp_tree, hf_jdwp_data, tvb, offset, hlen - 11, ENC_NA); } else if (hlen < 11) { expert_add_info(pinfo, hlen_item, &ei_jdwp_hlen_invalid); } break; default: expert_add_info(pinfo, flags_item, &ei_jdwp_flags_invalid); break; } return tvb_captured_length(tvb); } static int dissect_jdwp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN, get_jdwp_message_len, dissect_jdwp_message, data); return tvb_captured_length(tvb); } void proto_register_jdwp(void) { expert_module_t* expert_jdwp; static hf_register_info hf[] = { { &hf_jdwp_type, { "Packet Type", "jdwp.type", FT_STRING, BASE_NONE, NULL, 0x0, "Type", HFILL } }, { &hf_jdwp_length, { "Length", "jdwp.length", FT_UINT32, BASE_DEC, NULL, 0x0, "Data Length", HFILL } }, { &hf_jdwp_id, { "id", "jdwp.id", FT_UINT32, BASE_DEC, NULL, 0x0, "unique identifier", HFILL } }, { &hf_jdwp_flags, { "flags", "jdwp.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "tag packets as a command or reply", HFILL } }, { &hf_jdwp_commandset, { "command set", "jdwp.commandset", FT_UINT8, BASE_DEC, VALS(commandsetnames), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_virtualmachine, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_virtualmachine), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_referencetype, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_referencetype), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_classtype, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_classtype), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_arraytype, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_arraytype), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_interfacetype, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_interfacetype), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_method, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_method), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_field, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_field), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_objectreference, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_objectreference), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_stringreference, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_stringreference), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_threadreference, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_threadreference), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_threadgroupreference, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_threadgroupreference), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_arrayreference, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_arrayreference), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_classloaderreference, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_classloaderreference), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_eventrequest, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_eventrequest), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_stackframe, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_stackframe), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_classobjectreference, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_classobjectreference), 0x0, NULL, HFILL } }, { &hf_jdwp_commandset_event, { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_event), 0x0, NULL, HFILL } }, { &hf_jdwp_errorcode, { "error code", "jdwp.errorcode", FT_UINT8, BASE_DEC, VALS(error_codes), 0x0, NULL, HFILL } }, { &hf_jdwp_data, { "data", "jdwp.data", FT_BYTES, BASE_NONE, NULL, 0x0, "details of the command or reply", HFILL } } }; static ei_register_info ei[] = { { &ei_jdwp_hlen_invalid, { "jdwp.hlen.invalid", PI_MALFORMED, PI_ERROR, "Decode aborted: invalid packet length", EXPFILL }}, { &ei_jdwp_flags_invalid, { "jdwp.flags.invalid", PI_MALFORMED, PI_ERROR, "Decode aborted: invalid flags value", EXPFILL }} }; static gint *ett[] = { &ett_jdwp }; proto_jdwp = proto_register_protocol("Java Debug Wire Protocol", "JDWP", "jdwp"); proto_register_field_array(proto_jdwp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_jdwp = expert_register_protocol(proto_jdwp); expert_register_field_array(expert_jdwp, ei, array_length(ei)); } void proto_reg_handoff_jdwp(void) { dissector_handle_t jdwp_handle; jdwp_handle = create_dissector_handle(dissect_jdwp, proto_jdwp); dissector_add_uint_with_preference("tcp.port", JDWP_PORT, jdwp_handle); } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 2 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=2 tabstop=8 expandtab: * :indentSize=2:tabSize=8:noTabs=true: */