From 838b05b660dfd1bdd333411674aa397868a09af4 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Fri, 13 Feb 2026 02:59:43 +0000 Subject: [PATCH 01/23] v0 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 62 +++++++++++++++++++++++++++ ddprof-lib/src/main/cpp/vmStructs.h | 50 +++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 5cec56cc9..9405dd0c0 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -113,6 +113,19 @@ const void* VMStructs::_interpreted_frame_valid_end = NULL; DECLARE_TYPES_DO(INIT_TYPE_SIZE) #undef INIT_TYPE_SIZE +#define offset_value -1 +#define address_value nullptr +// Do nothing macro +#define DO_NOTHING(...) +#define INIT_OFFSET_OR_ADDRESS(type, field, field_type, ...) \ + field_type VMStructs::_##type##_##field##_##field_type = field_type##_value; + +DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) + +#undef INIT_OFFSET_OR_ADDRESS +#undef DO_NOTHING +#undef offset_value +#undef address_value jfieldID VMStructs::_eetop; jfieldID VMStructs::_tid; @@ -178,6 +191,55 @@ bool initTypeSize(uint64_t& size, const char* type, uint64_t value, ...) { return found; } +bool matchAny(const char* target_name, const char** names) { + for (const char** name = names; *name != nullptr; name++) { + if (strcmp(target_name, *name) == 0) { + return true; + } + } + return false; +} + + +void VMStructs::init_offsets_and_addresses() { + uintptr_t entry = readSymbol("gHotSpotVMStructs"); + uintptr_t stride = readSymbol("gHotSpotVMStructEntryArrayStride"); + uintptr_t type_offset = readSymbol("gHotSpotVMStructEntryTypeNameOffset"); + uintptr_t field_offset = readSymbol("gHotSpotVMStructEntryFieldNameOffset"); + uintptr_t offset_offset = readSymbol("gHotSpotVMStructEntryOffsetOffset"); + uintptr_t address_offset = readSymbol("gHotSpotVMStructEntryAddressOffset"); + + auto read_offset = [&]() -> int { + return *(int*)(entry + offset_offset); + }; + + auto read_address = [&]() -> const void* { + return *(const void**)(entry + address_offset); + }; + + if (entry != 0 && stride != 0) { + for (;; entry += stride) { + const char* type_name = *(const char**)(entry + type_offset); + const char* field_name = *(const char**)(entry + field_offset); + if (type_name == NULL || field_name == NULL) { + break; + } +#define MATCH_TYPE_NAMES(type, ...) \ + if (matchAny(type_name, (const char*[]){ #__VA_ARGS__, nullptr})) { +#define READ_FIELD_VALUE(type, field, field_type, ...) \ + if (matchAny(field_name, (const char*[]){ #__VA_ARGS__, nullptr})) { \ + _##type##_##field##_##field_type = read_##field_type(); \ + } +#define END_TYPE() } + + DECLARE_TYPE_FILED_DO(MATCH_TYPE_NAMES, READ_FIELD_VALUE, END_TYPE) +#undef MATCH_TYPE_NAMES +#undef READ_FIELD_VALUE +#undef END_TYPE + } + } +} + void VMStructs::initOffsets() { uintptr_t entry = readSymbol("gHotSpotVMStructs"); uintptr_t stride = readSymbol("gHotSpotVMStructEntryArrayStride"); diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 4db172c49..65e6c19d2 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -55,6 +55,45 @@ inline T* cast_to(const void* ptr) { f(VMSymbol, MATCH_SYMBOLS("Symbol")) \ f(VMThread, MATCH_SYMBOLS("Thread")) + + +#define POSSIBLE_NAMES(...) { __VA_ARGS__, nullptr } +#define POSSIBLE_TYPE_NAMES POSSIBLE_NAMES +#define POSSIBLE_FIELD_NAMES POSSIBLE_NAMES + +typedef int offset; +typedef const void* address; + +#define DECLARE_TYPE_FILED_DO(type, field, type_end) \ + type(VMMemRegion, POSSIBLE_TYPE_NAMES("MemRegion")) \ + field(VMMemRegion, start, offset, POSSIBLE_FIELD_NAMES("_start")) \ + field(VMMemRegion, size, offset, POSSIBLE_FIELD_NAMES("_word_size")) \ + type_end() \ + type(VMNMethod, POSSIBLE_TYPE_NAMES(CompiledMethod, nmethod)) \ + field(VMNMethod, method, offset, POSSIBLE_FIELD_NAMES("_method")) \ + field(VMNMethod, method_entry, offset, POSSIBLE_FIELD_NAMES("_verified_entry_offset", "_verified_entry_point")) \ + field(VMNMethod, state, offset, POSSIBLE_FIELD_NAMES("_state")) \ + field(VMNMethod, level, offset, POSSIBLE_FIELD_NAMES("_comp_level")) \ + field(VMNMethod, metadata, offset, POSSIBLE_FIELD_NAMES("_metadata_offset")) \ + field(VMNMethod, immutable_data, offset, POSSIBLE_FIELD_NAMES("_immutable_data")) \ + field(VMNMethod, scopes_pcs, offset, POSSIBLE_FIELD_NAMES("_scopes_pcs_offset")) \ + field(VMNMethod, scopes_data, offset, POSSIBLE_FIELD_NAMES("_scopes_data_offset", "_scopes_data_begin")) \ + type_end() \ + type(VMKlass, POSSIBLE_TYPE_NAMES(Klass)) \ + field(VMKlass, name, offset, POSSIBLE_FIELD_NAMES("_name")) \ + type_end() \ + type(VMSymbol, POSSIBLE_TYPE_NAMES(Symbol)) \ + field(VMSymbol, length, offset, POSSIBLE_FIELD_NAMES("_length")) \ + field(VMSymbol, body, offset, POSSIBLE_FIELD_NAMES("_body")) \ + type_end() \ + type(VMUniverse, POSSIBLE_TYPE_NAMES(Universe, CompressedKlassPointers)) \ + field(VMUniverse, narrow_klass_base, address, POSSIBLE_FIELD_NAMES("_narrow_klass._base", "_base")) \ + field(VMUniverse, narrow_klass_shift, offset, POSSIBLE_FIELD_NAMES("_narrow_klass._shift", "_shift")) \ + type_end() \ + type(VMOop, POSSIBLE_TYPE_NAMES(oopDesc)) \ + field(VMOop, _oop_klass, offset, POSSIBLE_FIELD_NAMES("_metadata._klass")) \ + type_end() \ + class VMStructs { public: typedef bool (*IsValidMethodFunc)(void *); @@ -64,6 +103,16 @@ class VMStructs { static CodeCache* _libjvm; +// Do nothing macro +#define DO_NOTHING(...) + +#define DECLARE_TYPE_FIELD(type, field, field_type, ...) \ + static field_type _##type##_##field##_##field_type; + + DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DO_NOTHING) +#undef DECL_TYPE_FIELD +#undef DO_NOTHING + static bool _has_class_names; static bool _has_method_structs; static bool _has_compiler_structs; @@ -188,6 +237,7 @@ class VMStructs { static IsValidMethodFunc _is_valid_method_func; static uintptr_t readSymbol(const char* symbol_name); + static void init_offsets_and_addresses(); static void initOffsets(); static void resolveOffsets(); static void patchSafeFetch(); From ff915b594cc356724890649ea949dbdeebf5d8ca Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Sat, 14 Feb 2026 01:22:58 +0000 Subject: [PATCH 02/23] v1 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 510 ++++++-------------------- ddprof-lib/src/main/cpp/vmStructs.h | 308 +++++++++------- 2 files changed, 299 insertions(+), 519 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 9405dd0c0..f80aac3e4 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -15,7 +15,7 @@ #include "spinLock.h" -CodeCache* VMStructs::_libjvm = NULL; +CodeCache* VMStructs::_libjvm = nullptr; bool VMStructs::_has_class_names = false; bool VMStructs::_has_method_structs = false; @@ -26,87 +26,17 @@ bool VMStructs::_has_native_thread_id = false; bool VMStructs::_can_dereference_jmethod_id = false; bool VMStructs::_compact_object_headers = false; -int VMStructs::_klass_name_offset = -1; -int VMStructs::_symbol_length_offset = -1; -int VMStructs::_symbol_length_and_refcount_offset = -1; -int VMStructs::_symbol_body_offset = -1; -int VMStructs::_oop_klass_offset = -1; -int VMStructs::_class_loader_data_offset = -1; -int VMStructs::_class_loader_data_next_offset = -1; -int VMStructs::_methods_offset = -1; -int VMStructs::_jmethod_ids_offset = -1; -int VMStructs::_thread_osthread_offset = -1; -int VMStructs::_thread_anchor_offset = -1; -int VMStructs::_thread_state_offset = -1; -int VMStructs::_thread_vframe_offset = -1; -int VMStructs::_thread_exception_offset = -1; -int VMStructs::_osthread_id_offset = -1; -int VMStructs::_call_wrapper_anchor_offset = -1; -int VMStructs::_comp_env_offset = -1; -int VMStructs::_comp_task_offset = -1; -int VMStructs::_comp_method_offset = -1; -int VMStructs::_anchor_sp_offset = -1; -int VMStructs::_anchor_pc_offset = -1; -int VMStructs::_anchor_fp_offset = -1; -int VMStructs::_blob_size_offset = -1; -int VMStructs::_frame_size_offset = -1; -int VMStructs::_frame_complete_offset = -1; -int VMStructs::_code_offset = -1; -int VMStructs::_data_offset = -1; -int VMStructs::_mutable_data_offset = -1; -int VMStructs::_relocation_size_offset = -1; -int VMStructs::_scopes_pcs_offset = -1; -int VMStructs::_scopes_data_offset = -1; -int VMStructs::_nmethod_name_offset = -1; -int VMStructs::_nmethod_method_offset = -1; -int VMStructs::_nmethod_entry_offset = -1; -int VMStructs::_nmethod_state_offset = -1; -int VMStructs::_nmethod_level_offset = -1; -int VMStructs::_nmethod_metadata_offset = -1; -int VMStructs::_nmethod_immutable_offset = -1; -int VMStructs::_method_constmethod_offset = -1; -int VMStructs::_method_code_offset = -1; -int VMStructs::_constmethod_constants_offset = -1; -int VMStructs::_constmethod_idnum_offset = -1; -int VMStructs::_pool_holder_offset = -1; -int VMStructs::_array_len_offset = 0; -int VMStructs::_array_data_offset = -1; -int VMStructs::_code_heap_memory_offset = -1; -int VMStructs::_code_heap_segmap_offset = -1; -int VMStructs::_code_heap_segment_shift = -1; -int VMStructs::_heap_block_used_offset = -1; -int VMStructs::_vs_low_bound_offset = -1; -int VMStructs::_vs_high_bound_offset = -1; -int VMStructs::_vs_low_offset = -1; -int VMStructs::_vs_high_offset = -1; -int VMStructs::_flag_name_offset = -1; -int VMStructs::_flag_addr_offset = -1; -int VMStructs::_flag_origin_offset = -1; -const char* VMStructs::_flags_addr = NULL; -int VMStructs::_flag_count = 0; char* VMStructs::_code_heap[3] = {}; const void* VMStructs::_code_heap_low = NO_MIN_ADDRESS; const void* VMStructs::_code_heap_high = NO_MAX_ADDRESS; -char** VMStructs::_code_heap_addr = NULL; -const void** VMStructs::_code_heap_low_addr = NULL; -const void** VMStructs::_code_heap_high_addr = NULL; -int* VMStructs::_klass_offset_addr = NULL; -char** VMStructs::_narrow_klass_base_addr = NULL; -char* VMStructs::_narrow_klass_base = NULL; -int* VMStructs::_narrow_klass_shift_addr = NULL; +char* VMStructs::_narrow_klass_base = nullptr; int VMStructs::_narrow_klass_shift = -1; -char** VMStructs::_collected_heap_addr = NULL; -int VMStructs::_region_start_offset = -1; -int VMStructs::_region_size_offset = -1; -int VMStructs::_markword_klass_shift = -1; -int VMStructs::_markword_monitor_value = -1; -int VMStructs::_entry_frame_call_wrapper_offset = -1; int VMStructs::_interpreter_frame_bcp_offset = 0; unsigned char VMStructs::_unsigned5_base = 0; -const void** VMStructs::_call_stub_return_addr = NULL; -const void* VMStructs::_call_stub_return = NULL; -const void* VMStructs::_interpreted_frame_valid_start = NULL; -const void* VMStructs::_interpreted_frame_valid_end = NULL; +const void* VMStructs::_call_stub_return = nullptr; +const void* VMStructs::_interpreted_frame_valid_start = nullptr; +const void* VMStructs::_interpreted_frame_valid_end = nullptr; + // Initialize type size to 0 #define INIT_TYPE_SIZE(name, ...) uint64_t VMStructs::TYPE_SIZE_NAME(name) = 0; @@ -115,10 +45,16 @@ DECLARE_TYPES_DO(INIT_TYPE_SIZE) #define offset_value -1 #define address_value nullptr +#define value_value -1 + +// Initialize field variables +// offset = -1 +// address = nullptr + // Do nothing macro #define DO_NOTHING(...) -#define INIT_OFFSET_OR_ADDRESS(type, field, field_type, ...) \ - field_type VMStructs::_##type##_##field##_##field_type = field_type##_value; +#define INIT_OFFSET_OR_ADDRESS(field, field_type, ...) \ + field_type VMStructs::_##field##_##field_type = field_type##_value; DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) @@ -127,6 +63,18 @@ DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) #undef offset_value #undef address_value +// Initialize constant variables to -1 +#define INIT_INT_CONSTANT(type, field) \ + int VMStructs::_##type##_##field = -1; +DECLARE_INT_CONSTANTS_DO(INIT_INT_CONSTANT) +#undef INIT_INT_CONSTANT + +#define INIT_LONG_CONSTANT(type, field) \ + long VMStructs::_##type##_##field = -1; +DECLARE_LONG_CONSTANTS_DO(INIT_LONG_CONSTANT) +#undef INIT_LONG_CONSTANT + + jfieldID VMStructs::_eetop; jfieldID VMStructs::_tid; jfieldID VMStructs::_klass = NULL; @@ -138,8 +86,6 @@ VMStructs::LockFunc VMStructs::_lock_func; VMStructs::LockFunc VMStructs::_unlock_func; // Datadog-specific static variables -int VMStructs::_osthread_state_offset = -1; -int VMStructs::_flag_type_offset = -1; CodeCache VMStructs::_unsafe_to_walk("unwalkable code"); VMStructs::HeapUsageFunc VMStructs::_heap_usage_func = NULL; VMStructs::MemoryUsageFunc VMStructs::_memory_usage_func = NULL; @@ -200,7 +146,6 @@ bool matchAny(const char* target_name, const char** names) { return false; } - void VMStructs::init_offsets_and_addresses() { uintptr_t entry = readSymbol("gHotSpotVMStructs"); uintptr_t stride = readSymbol("gHotSpotVMStructEntryArrayStride"); @@ -213,25 +158,29 @@ void VMStructs::init_offsets_and_addresses() { return *(int*)(entry + offset_offset); }; - auto read_address = [&]() -> const void* { - return *(const void**)(entry + address_offset); + auto read_address = [&]() -> address { + return *(address*)(entry + address_offset); + }; + + auto read_value = [&]() -> int { + return **(int**)(entry + offset_offset); }; if (entry != 0 && stride != 0) { for (;; entry += stride) { const char* type_name = *(const char**)(entry + type_offset); const char* field_name = *(const char**)(entry + field_offset); - if (type_name == NULL || field_name == NULL) { + if (type_name == nullptr || field_name == nullptr) { break; } -#define MATCH_TYPE_NAMES(type, ...) \ - if (matchAny(type_name, (const char*[]){ #__VA_ARGS__, nullptr})) { -#define READ_FIELD_VALUE(type, field, field_type, ...) \ - if (matchAny(field_name, (const char*[]){ #__VA_ARGS__, nullptr})) { \ - _##type##_##field##_##field_type = read_##field_type(); \ +#define MATCH_TYPE_NAMES(type, ...) \ + if (matchAny(type_name, (const char*[]){ #__VA_ARGS__ })) { +#define READ_FIELD_VALUE(field, field_type, ...) \ + if (matchAny(field_name, (const char*[]){ #__VA_ARGS__ })) { \ + _##field##_##field_type = read_##field_type(); \ + continue; \ } #define END_TYPE() } - DECLARE_TYPE_FILED_DO(MATCH_TYPE_NAMES, READ_FIELD_VALUE, END_TYPE) #undef MATCH_TYPE_NAMES #undef READ_FIELD_VALUE @@ -240,242 +189,10 @@ void VMStructs::init_offsets_and_addresses() { } } -void VMStructs::initOffsets() { - uintptr_t entry = readSymbol("gHotSpotVMStructs"); - uintptr_t stride = readSymbol("gHotSpotVMStructEntryArrayStride"); - uintptr_t type_offset = readSymbol("gHotSpotVMStructEntryTypeNameOffset"); - uintptr_t field_offset = readSymbol("gHotSpotVMStructEntryFieldNameOffset"); - uintptr_t offset_offset = readSymbol("gHotSpotVMStructEntryOffsetOffset"); - uintptr_t address_offset = readSymbol("gHotSpotVMStructEntryAddressOffset"); - - if (entry != 0 && stride != 0) { - for (;; entry += stride) { - const char* type = *(const char**)(entry + type_offset); - const char* field = *(const char**)(entry + field_offset); - if (type == NULL || field == NULL) { - break; - } - - if (strcmp(type, "Klass") == 0) { - if (strcmp(field, "_name") == 0) { - _klass_name_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "Symbol") == 0) { - if (strcmp(field, "_length") == 0) { - _symbol_length_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_length_and_refcount") == 0) { - _symbol_length_and_refcount_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_body") == 0) { - _symbol_body_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "oopDesc") == 0) { - if (strcmp(field, "_metadata._klass") == 0) { - _oop_klass_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "Universe") == 0 || strcmp(type, "CompressedKlassPointers") == 0) { - if (strcmp(field, "_narrow_klass._base") == 0 || strcmp(field, "_base") == 0) { - _narrow_klass_base_addr = *(char***)(entry + address_offset); - } else if (strcmp(field, "_narrow_klass._shift") == 0 || strcmp(field, "_shift") == 0) { - _narrow_klass_shift_addr = *(int**)(entry + address_offset); - } else if (strcmp(field, "_collectedHeap") == 0) { - _collected_heap_addr = *(char***)(entry + address_offset); - } - } else if (strcmp(type, "MemRegion") == 0) { - if (strcmp(field, "_start") == 0) { - _region_start_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_word_size") == 0) { - _region_size_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CompiledMethod") == 0 || strcmp(type, "nmethod") == 0) { - if (strcmp(field, "_method") == 0) { - _nmethod_method_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_verified_entry_offset") == 0) { - _nmethod_entry_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_verified_entry_point") == 0) { - _nmethod_entry_offset = - *(int*)(entry + offset_offset); - } else if (strcmp(field, "_state") == 0) { - _nmethod_state_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_comp_level") == 0) { - _nmethod_level_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_metadata_offset") == 0) { - _nmethod_metadata_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_immutable_data") == 0) { - _nmethod_immutable_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_scopes_pcs_offset") == 0) { - _scopes_pcs_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_scopes_data_offset") == 0) { - _scopes_data_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_scopes_data_begin") == 0) { - _scopes_data_offset = - *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "Method") == 0) { - if (strcmp(field, "_constMethod") == 0) { - _method_constmethod_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_code") == 0) { - _method_code_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ConstMethod") == 0) { - if (strcmp(field, "_constants") == 0) { - _constmethod_constants_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_method_idnum") == 0) { - _constmethod_idnum_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ConstantPool") == 0) { - if (strcmp(field, "_pool_holder") == 0) { - _pool_holder_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "InstanceKlass") == 0) { - if (strcmp(field, "_class_loader_data") == 0) { - _class_loader_data_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_methods") == 0) { - _methods_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_methods_jmethod_ids") == 0) { - _jmethod_ids_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ClassLoaderData") == 0) { - if (strcmp(field, "_next") == 0) { - _class_loader_data_next_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "java_lang_Class") == 0) { - if (strcmp(field, "_klass_offset") == 0) { - _klass_offset_addr = *(int**)(entry + address_offset); - } - } else if (strcmp(type, "Thread") == 0) { - // Since JDK 25, _osthread field belongs to Thread rather than JavaThread - if (strcmp(field, "_osthread") == 0) { - _thread_osthread_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "JavaThread") == 0) { - if (strcmp(field, "_osthread") == 0) { - _thread_osthread_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_anchor") == 0) { - _thread_anchor_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_thread_state") == 0) { - _thread_state_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_vframe_array_head") == 0) { - _thread_vframe_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ThreadShadow") == 0) { - if (strcmp(field, "_exception_file") == 0) { - _thread_exception_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "OSThread") == 0) { - if (strcmp(field, "_thread_id") == 0) { - _osthread_id_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_state") == 0) { - _osthread_state_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CompilerThread") == 0) { - if (strcmp(field, "_env") == 0) { - _comp_env_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ciEnv") == 0) { - if (strcmp(field, "_task") == 0) { - _comp_task_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CompileTask") == 0) { - if (strcmp(field, "_method") == 0) { - _comp_method_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "JavaCallWrapper") == 0) { - if (strcmp(field, "_anchor") == 0) { - _call_wrapper_anchor_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "JavaFrameAnchor") == 0) { - if (strcmp(field, "_last_Java_sp") == 0) { - _anchor_sp_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_last_Java_pc") == 0) { - _anchor_pc_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_last_Java_fp") == 0) { - _anchor_fp_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CodeBlob") == 0) { - if (strcmp(field, "_size") == 0) { - _blob_size_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_frame_size") == 0) { - _frame_size_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_frame_complete_offset") == 0) { - _frame_complete_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_code_offset") == 0) { - _code_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_code_begin") == 0) { - _code_offset = - *(int*)(entry + offset_offset); - } else if (strcmp(field, "_data_offset") == 0) { - _data_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_mutable_data") == 0) { - _mutable_data_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_relocation_size") == 0) { - _relocation_size_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_name") == 0) { - _nmethod_name_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CodeCache") == 0) { - if (strcmp(field, "_heap") == 0) { - _code_heap_addr = *(char***)(entry + address_offset); - } else if (strcmp(field, "_heaps") == 0) { - _code_heap_addr = *(char***)(entry + address_offset); - } else if (strcmp(field, "_low_bound") == 0) { - _code_heap_low_addr = *(const void***)(entry + address_offset); - } else if (strcmp(field, "_high_bound") == 0) { - _code_heap_high_addr = *(const void***)(entry + address_offset); - } - } else if (strcmp(type, "CodeHeap") == 0) { - if (strcmp(field, "_memory") == 0) { - _code_heap_memory_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_segmap") == 0) { - _code_heap_segmap_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_log2_segment_size") == 0) { - _code_heap_segment_shift = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "HeapBlock::Header") == 0) { - if (strcmp(field, "_used") == 0) { - _heap_block_used_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "VirtualSpace") == 0) { - if (strcmp(field, "_low_boundary") == 0) { - _vs_low_bound_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_high_boundary") == 0) { - _vs_high_bound_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_low") == 0) { - _vs_low_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_high") == 0) { - _vs_high_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "StubRoutines") == 0) { - if (strcmp(field, "_call_stub_return_address") == 0) { - _call_stub_return_addr = *(const void***)(entry + address_offset); - } - } else if (strcmp(type, "GrowableArrayBase") == 0 || strcmp(type, "GenericGrowableArray") == 0) { - if (strcmp(field, "_len") == 0) { - _array_len_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "GrowableArray") == 0) { - if (strcmp(field, "_data") == 0) { - _array_data_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "JVMFlag") == 0 || strcmp(type, "Flag") == 0) { - if (strcmp(field, "_name") == 0 || strcmp(field, "name") == 0) { - _flag_name_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_addr") == 0 || strcmp(field, "addr") == 0) { - _flag_addr_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_flags") == 0 || strcmp(field, "origin") == 0) { - _flag_origin_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "flags") == 0) { - _flags_addr = **(char***)(entry + address_offset); - } else if (strcmp(field, "numFlags") == 0) { - _flag_count = **(int**)(entry + address_offset); - } else if (strcmp(field, "_type") == 0 || strcmp(field, "type") == 0) { - _flag_type_offset = *(int *)(entry + offset_offset); - } - } else if (strcmp(type, "PcDesc") == 0) { - // TODO - } - } - } - - entry = readSymbol("gHotSpotVMTypes"); - stride = readSymbol("gHotSpotVMTypeEntryArrayStride"); - type_offset = readSymbol("gHotSpotVMTypeEntryTypeNameOffset"); +void VMStructs::init_type_sizes() { + uintptr_t entry = readSymbol("gHotSpotVMTypes"); + uintptr_t stride = readSymbol("gHotSpotVMTypeEntryArrayStride"); + uintptr_t type_offset = readSymbol("gHotSpotVMTypeEntryTypeNameOffset"); uintptr_t size_offset = readSymbol("gHotSpotVMTypeEntrySizeOffset"); if (entry != 0 && stride != 0) { @@ -487,71 +204,88 @@ void VMStructs::initOffsets() { uint64_t size = *(uint64_t*)(entry + size_offset); - #define TYPE_SIZE_MATCH(name, ...) \ - if (initTypeSize(VMStructs::TYPE_SIZE_NAME(name), type, size, ##__VA_ARGS__)) continue; + #define READ_TYPE_SIZE(name, ...) \ + if (matchAny(type, (const char*[]){ #__VA_ARGS__ })) { \ + TYPE_SIZE_NAME(name) = size; \ + continue; \ + } - DECLARE_TYPES_DO(TYPE_SIZE_MATCH) + DECLARE_TYPES_DO(READ_TYPE_SIZE) -#undef TYPE_SIZE_MATCH +#undef READ_TYPE_SIZE } } +} - entry = readSymbol("gHotSpotVMLongConstants"); - stride = readSymbol("gHotSpotVMLongConstantEntryArrayStride"); - uintptr_t name_offset = readSymbol("gHotSpotVMLongConstantEntryNameOffset"); - uintptr_t value_offset = readSymbol("gHotSpotVMLongConstantEntryValueOffset"); +#define READ_CONSTANT(type, field) \ + if (strcmp(type_name, #type "::" #field) == 0) { \ + _##type##_##field = value; \ + continue; \ + } + + +void VMStructs::init_constants() { + // Int constants + uintptr_t entry = readSymbol("gHotSpotVMIntConstants"); + uintptr_t stride = readSymbol("gHotSpotVMIntConstantEntryArrayStride"); + uintptr_t name_offset = readSymbol("gHotSpotVMIntConstantEntryNameOffset"); + uintptr_t value_offset = readSymbol("gHotSpotVMIntConstantEntryValueOffset"); if (entry != 0 && stride != 0) { for (;; entry += stride) { - const char* name = *(const char**)(entry + name_offset); - if (name == NULL) { + const char* type_name = *(const char**)(entry + name_offset); + if (nullptr == nullptr) { break; } - - if (strncmp(name, "markWord::", 10) == 0) { - if (strcmp(name + 10, "klass_shift") == 0) { - _markword_klass_shift = *(long*)(entry + value_offset); - } else if (strcmp(name + 10, "monitor_value") == 0) { - _markword_monitor_value = *(long*)(entry + value_offset); - } - } + int value = *(int*)(entry + value_offset); + DECLARE_INT_CONSTANTS_DO(READ_CONSTANT) } } + // Sepcial case + _frame_entry_frame_call_wrapper_offset *= sizeof(uintptr_t); - entry = readSymbol("gHotSpotVMIntConstants"); - stride = readSymbol("gHotSpotVMIntConstantEntryArrayStride"); - name_offset = readSymbol("gHotSpotVMIntConstantEntryNameOffset"); - value_offset = readSymbol("gHotSpotVMIntConstantEntryValueOffset"); + + // Long constants + entry = readSymbol("gHotSpotVMLongConstants"); + stride = readSymbol("gHotSpotVMLongConstantEntryArrayStride"); + name_offset = readSymbol("gHotSpotVMLongConstantEntryNameOffset"); + value_offset = readSymbol("gHotSpotVMLongConstantEntryValueOffset"); if (entry != 0 && stride != 0) { for (;; entry += stride) { - const char* name = *(const char**)(entry + name_offset); - if (name == NULL) { + const char* type_name = *(const char**)(entry + name_offset); + if (type_name == nullptr) { break; } - if (strcmp(name, "frame::entry_frame_call_wrapper_offset") == 0) { - _entry_frame_call_wrapper_offset = *(int*)(entry + value_offset) * sizeof(uintptr_t); - break; // remove it for reading more constants - } + long value = *(long*)(entry + value_offset); + DECLARE_LONG_CONSTANTS_DO(READ_CONSTANT) } } } +#undef READ_CONSTANT + +void VMStructs::initOffsets() { + init_type_sizes(); + init_offsets_and_addresses(); + init_constants(); +} + void VMStructs::resolveOffsets() { if (VM::isOpenJ9() || VM::isZing()) { return; } - if (_klass_offset_addr != NULL) { - _klass = (jfieldID)(uintptr_t)(*_klass_offset_addr << 2 | 2); + if (_klass_offset_address != NULL) { + _klass = (jfieldID)(uintptr_t)(*(uintptr_t*)_klass_offset_address << 2 | 2); } VMFlag* ccp = VMFlag::find("UseCompressedClassPointers"); - if (ccp != NULL && ccp->get() && _narrow_klass_base_addr != NULL && _narrow_klass_shift_addr != NULL) { - _narrow_klass_base = *_narrow_klass_base_addr; - _narrow_klass_shift = *_narrow_klass_shift_addr; + if (ccp != NULL && ccp->get() && _narrow_klass_base_address != NULL && _narrow_klass_shift_offset >= 0) { + _narrow_klass_base = *(char**)_narrow_klass_base_address; + _narrow_klass_shift = _narrow_klass_shift_offset; } VMFlag* coh = VMFlag::find("UseCompactObjectHeaders"); @@ -560,7 +294,7 @@ void VMStructs::resolveOffsets() { } _has_class_names = _klass_name_offset >= 0 - && (_compact_object_headers ? (_markword_klass_shift >= 0 && _markword_monitor_value == MONITOR_BIT) + && (_compact_object_headers ? (_markWord_klass_shift >= 0 && _markWord_monitor_value == MONITOR_BIT) : _oop_klass_offset >= 0) && (_symbol_length_offset >= 0 || _symbol_length_and_refcount_offset >= 0) && _symbol_body_offset >= 0 @@ -592,10 +326,10 @@ void VMStructs::resolveOffsets() { #elif defined(__aarch64__) _interpreter_frame_bcp_offset = VM::hotspot_version() >= 11 ? -9 : VM::hotspot_version() == 8 ? -7 : 0; // The constant is missing on ARM, but fortunately, it has been stable for years across all JDK versions - _entry_frame_call_wrapper_offset = -64; + _frame_entry_frame_call_wrapper_offset = -64; #elif defined(__arm__) || defined(__thumb__) _interpreter_frame_bcp_offset = VM::hotspot_version() >= 11 ? -8 : 0; - _entry_frame_call_wrapper_offset = 0; + _frame_entry_frame_call_wrapper_offset = 0; #endif // JDK-8292758 has slightly changed ScopeDesc encoding @@ -603,8 +337,8 @@ void VMStructs::resolveOffsets() { _unsigned5_base = 1; } - if (_call_stub_return_addr != NULL) { - _call_stub_return = *_call_stub_return_addr; + if (_call_stub_return_address != NULL) { + _call_stub_return = (const void*)_call_stub_return_address; } // Since JDK 23, _metadata_offset is relative to _data_offset. See metadata() @@ -614,7 +348,7 @@ void VMStructs::resolveOffsets() { _has_stack_structs = _has_method_structs && _call_wrapper_anchor_offset >= 0 - && _entry_frame_call_wrapper_offset != -1 + && _frame_entry_frame_call_wrapper_offset != -1 && _interpreter_frame_bcp_offset != 0 && _code_offset != -1 && _data_offset >= 0 @@ -628,27 +362,27 @@ void VMStructs::resolveOffsets() { // Since JDK-8268406, it is no longer possible to get VMMethod* by dereferencing jmethodID _can_dereference_jmethod_id = _has_method_structs && VM::hotspot_version() <= 25; - if (_code_heap_addr != NULL && _code_heap_low_addr != NULL && _code_heap_high_addr != NULL) { - char* code_heaps = *_code_heap_addr; + if (_code_heap_address != nullptr && _code_heap_low_address != nullptr && _code_heap_high_address != nullptr) { + char* code_heaps = (char*)_code_heap_address; unsigned int code_heap_count = *(unsigned int*)(code_heaps + _array_len_offset); if (code_heap_count <= 3 && _array_data_offset >= 0) { char* code_heap_array = *(char**)(code_heaps + _array_data_offset); memcpy(_code_heap, code_heap_array, code_heap_count * sizeof(_code_heap[0])); } - _code_heap_low = *_code_heap_low_addr; - _code_heap_high = *_code_heap_high_addr; - } else if (_code_heap_addr != NULL && _code_heap_memory_offset >= 0) { - _code_heap[0] = *_code_heap_addr; + _code_heap_low = _code_heap_low_address; + _code_heap_high = _code_heap_high_address; + } else if (_code_heap_address != NULL && _code_heap_memory_offset >= 0) { + _code_heap[0] = (char*)_code_heap_address; _code_heap_low = *(const void**)(_code_heap[0] + _code_heap_memory_offset + _vs_low_bound_offset); _code_heap_high = *(const void**)(_code_heap[0] + _code_heap_memory_offset + _vs_high_bound_offset); } // Invariant: _code_heap[i] != NULL iff all CodeHeap structures are available - if (_code_heap[0] != NULL && _code_heap_segment_shift >= 0) { - _code_heap_segment_shift = *(int*)(_code_heap[0] + _code_heap_segment_shift); + if (_code_heap[0] != NULL && _code_heap_segment_shift_value >= 0) { + _code_heap_segment_shift_value = *(int*)(_code_heap[0] + _code_heap_segment_shift_value); } if (_code_heap_memory_offset < 0 || _code_heap_segmap_offset < 0 || - _code_heap_segment_shift < 0 || _code_heap_segment_shift > 16 || + _code_heap_segment_shift_value < 0 || _code_heap_segment_shift_value > 16 || _heap_block_used_offset < 0) { memset(_code_heap, 0, sizeof(_code_heap)); } @@ -923,7 +657,7 @@ jmethodID VMMethod::validatedId() { VMNMethod* CodeHeap::findNMethod(char* heap, const void* pc) { unsigned char* heap_start = *(unsigned char**)(heap + _code_heap_memory_offset + _vs_low_offset); unsigned char* segmap = *(unsigned char**)(heap + _code_heap_segmap_offset + _vs_low_offset); - size_t idx = ((unsigned char*)pc - heap_start) >> _code_heap_segment_shift; + size_t idx = ((unsigned char*)pc - heap_start) >> _code_heap_segment_shift_value; if (segmap[idx] == 0xff) { return NULL; @@ -932,7 +666,7 @@ VMNMethod* CodeHeap::findNMethod(char* heap, const void* pc) { idx -= segmap[idx]; } - unsigned char* block = heap_start + (idx << _code_heap_segment_shift) + _heap_block_used_offset; + unsigned char* block = heap_start + (idx << _code_heap_segment_shift_value) + _heap_block_used_offset; return *block ? align(block + sizeof(uintptr_t)) : NULL; } @@ -976,9 +710,9 @@ int ScopeDesc::readInt() { } VMFlag* VMFlag::find(const char* name) { - if (_flags_addr != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count; i++) { - VMFlag* f = VMFlag::cast(_flags_addr + i * VMFlag::type_size()); + if (_flags_address != NULL && VMFlag::type_size() > 0) { + for (int i = 0; i < _flag_count_value; i++) { + VMFlag* f = VMFlag::cast(_flags_address + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0 && f->addr() != NULL) { return f; } @@ -996,9 +730,9 @@ VMFlag *VMFlag::find(const char *name, std::initializer_list types } VMFlag *VMFlag::find(const char *name, int type_mask) { - if (_flags_addr != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count; i++) { - VMFlag* f = VMFlag::cast(_flags_addr + i * VMFlag::type_size()); + if (_flags_address != NULL && VMFlag::type_size() > 0) { + for (int i = 0; i < _flag_count_value; i++) { + VMFlag* f = VMFlag::cast(_flags_address + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0) { int masked = 0x1 << f->type(); if (masked & type_mask) { @@ -1204,11 +938,11 @@ bool HeapUsage::isLastGCUsageSupported() { // only supported for JDK 17+ // the CollectedHeap structure is vastly different in JDK 11 and earlier so // we can't support it - return _collected_heap_addr != NULL && _heap_usage_func != NULL; + return _collected_heap_address != NULL && _heap_usage_func != NULL; } bool HeapUsage::needsNativeBindingInterception() { - return _collected_heap_addr == NULL || + return _collected_heap_address == NULL || (_heap_usage_func == NULL && _gc_heap_summary_func == NULL); } @@ -1247,16 +981,16 @@ HeapUsage HeapUsage::get() { HeapUsage HeapUsage::get(bool allow_jmx) { HeapUsage usage; - if (_collected_heap_addr != NULL) { + if (_collected_heap_address != NULL) { if (_heap_usage_func != NULL) { // this is the JDK 17+ path - usage = _heap_usage_func(*_collected_heap_addr); + usage = _heap_usage_func(*_collected_heap_address); usage._used_at_last_gc = - ((CollectedHeapWrapper *)*_collected_heap_addr)->_used_at_last_gc; + ((CollectedHeapWrapper *)*_collected_heap_address)->_used_at_last_gc; } else if (_gc_heap_summary_func != NULL) { // this is the JDK 11 path // we need to collect GCHeapSummary information first - GCHeapSummary summary = _gc_heap_summary_func(*_collected_heap_addr); + GCHeapSummary summary = _gc_heap_summary_func((void*)_collected_heap_address); usage._initSize = -1; usage._used = summary.used(); usage._committed = -1; diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 65e6c19d2..b3fa70c30 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -39,7 +39,7 @@ inline T* cast_to(const void* ptr) { #define DECLARE_END }; -#define MATCH_SYMBOLS(...) __VA_ARGS__, nullptr +#define MATCH_SYMBOLS(...) { #__VA_ARGS__, nullptr } // Defines a type and its matching symbols in vmStructs. // A type may match multiple names in different JVM versions. @@ -56,43 +56,144 @@ inline T* cast_to(const void* ptr) { f(VMThread, MATCH_SYMBOLS("Thread")) - -#define POSSIBLE_NAMES(...) { __VA_ARGS__, nullptr } -#define POSSIBLE_TYPE_NAMES POSSIBLE_NAMES -#define POSSIBLE_FIELD_NAMES POSSIBLE_NAMES - typedef int offset; -typedef const void* address; - -#define DECLARE_TYPE_FILED_DO(type, field, type_end) \ - type(VMMemRegion, POSSIBLE_TYPE_NAMES("MemRegion")) \ - field(VMMemRegion, start, offset, POSSIBLE_FIELD_NAMES("_start")) \ - field(VMMemRegion, size, offset, POSSIBLE_FIELD_NAMES("_word_size")) \ - type_end() \ - type(VMNMethod, POSSIBLE_TYPE_NAMES(CompiledMethod, nmethod)) \ - field(VMNMethod, method, offset, POSSIBLE_FIELD_NAMES("_method")) \ - field(VMNMethod, method_entry, offset, POSSIBLE_FIELD_NAMES("_verified_entry_offset", "_verified_entry_point")) \ - field(VMNMethod, state, offset, POSSIBLE_FIELD_NAMES("_state")) \ - field(VMNMethod, level, offset, POSSIBLE_FIELD_NAMES("_comp_level")) \ - field(VMNMethod, metadata, offset, POSSIBLE_FIELD_NAMES("_metadata_offset")) \ - field(VMNMethod, immutable_data, offset, POSSIBLE_FIELD_NAMES("_immutable_data")) \ - field(VMNMethod, scopes_pcs, offset, POSSIBLE_FIELD_NAMES("_scopes_pcs_offset")) \ - field(VMNMethod, scopes_data, offset, POSSIBLE_FIELD_NAMES("_scopes_data_offset", "_scopes_data_begin")) \ - type_end() \ - type(VMKlass, POSSIBLE_TYPE_NAMES(Klass)) \ - field(VMKlass, name, offset, POSSIBLE_FIELD_NAMES("_name")) \ - type_end() \ - type(VMSymbol, POSSIBLE_TYPE_NAMES(Symbol)) \ - field(VMSymbol, length, offset, POSSIBLE_FIELD_NAMES("_length")) \ - field(VMSymbol, body, offset, POSSIBLE_FIELD_NAMES("_body")) \ - type_end() \ - type(VMUniverse, POSSIBLE_TYPE_NAMES(Universe, CompressedKlassPointers)) \ - field(VMUniverse, narrow_klass_base, address, POSSIBLE_FIELD_NAMES("_narrow_klass._base", "_base")) \ - field(VMUniverse, narrow_klass_shift, offset, POSSIBLE_FIELD_NAMES("_narrow_klass._shift", "_shift")) \ - type_end() \ - type(VMOop, POSSIBLE_TYPE_NAMES(oopDesc)) \ - field(VMOop, _oop_klass, offset, POSSIBLE_FIELD_NAMES("_metadata._klass")) \ - type_end() \ +typedef const unsigned char** address; +typedef int value; + +#define DECLARE_TYPE_FILED_DO(type_begin, field, type_end) \ + type_begin(VMMemRegion, MATCH_SYMBOLS("MemRegion")) \ + field(region_start, offset, MATCH_SYMBOLS("_start")) \ + field(region_size, offset, MATCH_SYMBOLS("_word_size")) \ + type_end() \ + type_begin(VMNMethod, MATCH_SYMBOLS("CompiledMethod", "nmethod")) \ + field(nmethod_method, offset, MATCH_SYMBOLS("_method")) \ + field(nmethod_entry, offset, MATCH_SYMBOLS("_verified_entry_offset", "_verified_entry_point")) \ + field(nmethod_state, offset, MATCH_SYMBOLS("_state")) \ + field(nmethod_level, offset, MATCH_SYMBOLS("_comp_level")) \ + field(nmethod_metadata, offset, MATCH_SYMBOLS("_metadata_offset")) \ + field(nmethod_immutable, offset, MATCH_SYMBOLS("_immutable_data")) \ + field(scopes_pcs, offset, MATCH_SYMBOLS("_scopes_pcs_offset")) \ + field(scopes_data, offset, MATCH_SYMBOLS("_scopes_data_offset", "_scopes_data_begin")) \ + type_end() \ + type_begin(VMMethod, MATCH_SYMBOLS("Method")) \ + field(method_constmethod, offset, MATCH_SYMBOLS("_constMethod")) \ + field(method_code, offset, MATCH_SYMBOLS("_code")) \ + type_end() \ + type_begin(VMConstMethod, MATCH_SYMBOLS("ConstMethod")) \ + field(constmethod_constants, offset, MATCH_SYMBOLS("_constants")) \ + field(constmethod_idnum, offset, MATCH_SYMBOLS("_method_idnum")) \ + type_end() \ + type_begin(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ + field(pool_holder, offset, MATCH_SYMBOLS("_pool_holder")) \ + type_end() \ + type_begin(VMKlass, MATCH_SYMBOLS("Klass", "InstanceKlass")) \ + field(klass_name, offset, MATCH_SYMBOLS("_name")) \ + field(class_loader_data, offset, MATCH_SYMBOLS("_class_loader_data")) \ + field(methods, offset, MATCH_SYMBOLS("_methods")) \ + field(jmethod_ids, offset, MATCH_SYMBOLS("_methods_jmethod_ids")) \ + type_end() \ + type_begin(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) \ + field(class_loader_data_next, offset, MATCH_SYMBOLS("_next")) \ + type_end() \ + type_begin(VMJavaClass, MATCH_SYMBOLS("java_lang_Class")) \ + field(klass_offset, address, MATCH_SYMBOLS("_klass_offset")) \ + type_end() \ + type_begin(VMSymbol, MATCH_SYMBOLS("Symbol")) \ + field(symbol_length, offset, MATCH_SYMBOLS("_length")) \ + field(symbol_body, offset, MATCH_SYMBOLS("_body")) \ + field(symbol_length_and_refcount, offset, MATCH_SYMBOLS("_length_and_refcount")) \ + type_end() \ + type_begin(VMThread, MATCH_SYMBOLS("Thread", "JavaThread")) \ + field(thread_osthread, offset, MATCH_SYMBOLS("_osthread")) \ + field(thread_anchor, offset, MATCH_SYMBOLS("_anchor")) \ + field(thread_state, offset, MATCH_SYMBOLS("_thread_state")) \ + field(thread_vframe, offset, MATCH_SYMBOLS("_vframe_array_head")) \ + type_end() \ + type_begin(VMOSThread, MATCH_SYMBOLS("OSThread")) \ + field(osthread_id, offset, MATCH_SYMBOLS("_thread_id")) \ + field(osthread_state, offset, MATCH_SYMBOLS("_state")) \ + type_end() \ + type_begin(VMThreadShow, MATCH_SYMBOLS("ThreadShadow")) \ + field(thread_exception, offset, MATCH_SYMBOLS("_exception_file")) \ + type_end() \ + type_begin(VMCompilerThread, MATCH_SYMBOLS("CompilerThread")) \ + field(comp_env, offset, MATCH_SYMBOLS("_env")) \ + type_end() \ + type_begin(VMciEnv, MATCH_SYMBOLS("ciEnv")) \ + field(comp_task, offset, MATCH_SYMBOLS("_task")) \ + type_end() \ + type_begin(VMCompileTask, MATCH_SYMBOLS("CompileTask")) \ + field(comp_method, offset, MATCH_SYMBOLS("_method")) \ + type_end() \ + type_begin(VMJavaCallWrapper, MATCH_SYMBOLS("JavaCallWrapper")) \ + field(call_wrapper_anchor, offset, MATCH_SYMBOLS("_anchor")) \ + type_end() \ + type_begin(VMJavaFrameAnchor, MATCH_SYMBOLS("JavaFrameAnchor")) \ + field(anchor_sp, offset, MATCH_SYMBOLS("_last_Java_sp")) \ + field(anchor_pc, offset, MATCH_SYMBOLS("_last_Java_pc")) \ + field(anchor_fp, offset, MATCH_SYMBOLS("_last_Java_fp")) \ + type_end() \ + type_begin(VMCodeBlob, MATCH_SYMBOLS("CodeBlob")) \ + field(blob_size, offset, MATCH_SYMBOLS("_size")) \ + field(frame_size, offset, MATCH_SYMBOLS("_frame_size")) \ + field(frame_complete, offset, MATCH_SYMBOLS("_frame_complete_offset")) \ + field(code, offset, MATCH_SYMBOLS("_code_offset", "_code_begin")) \ + field(data, offset, MATCH_SYMBOLS("_data_offset")) \ + field(mutable_data, offset, MATCH_SYMBOLS("_mutable_data")) \ + field(relocation_size, offset, MATCH_SYMBOLS("_relocation_size")) \ + field(nmethod_name, offset, MATCH_SYMBOLS("_name")) \ + type_end() \ + type_begin(VMCodeCache, MATCH_SYMBOLS("CodeCache")) \ + field(code_heap, address, MATCH_SYMBOLS("_heap", "_heaps")) \ + field(code_heap_low, address, MATCH_SYMBOLS("_low_bound")) \ + field(code_heap_high, address, MATCH_SYMBOLS("_high_bound")) \ + type_end() \ + type_begin(VMCodeHeap, MATCH_SYMBOLS("CodeHeap")) \ + field(code_heap_memory, offset, MATCH_SYMBOLS("_memory")) \ + field(code_heap_segmap, offset, MATCH_SYMBOLS("_segmap")) \ + field(code_heap_segment_shift, value, MATCH_SYMBOLS("_log2_segment_size")) \ + type_end() \ + type_begin(VMHeapBlock, MATCH_SYMBOLS("HeapBlock::Header")) \ + field(heap_block_used, offset, MATCH_SYMBOLS("_used")) \ + type_end() \ + type_begin(VMVirtualSpace, MATCH_SYMBOLS("VirtualSpace")) \ + field(vs_low_bound, offset, MATCH_SYMBOLS("_low_boundary")) \ + field(vs_high_bound, offset, MATCH_SYMBOLS("_high_boundary")) \ + field(vs_low, offset, MATCH_SYMBOLS("_low")) \ + field(vs_high, offset, MATCH_SYMBOLS("_high")) \ + type_end() \ + type_begin(VMStubRoutine, MATCH_SYMBOLS("StubRoutines")) \ + field(call_stub_return, address, MATCH_SYMBOLS("_call_stub_return_address")) \ + type_end() \ + type_begin(VMGrowableArray, MATCH_SYMBOLS("GrowableArrayBase", "GenericGrowableArray")) \ + field(array_len, offset, MATCH_SYMBOLS("_len")) \ + type_end() \ + type_begin(VMGrowableArrayInt, MATCH_SYMBOLS("GrowableArray")) \ + field(array_data, offset, MATCH_SYMBOLS("_data")) \ + type_end() \ + type_begin(VMFlag, MATCH_SYMBOLS("JVMFlag", "Flag")) \ + field(flag_name, offset, MATCH_SYMBOLS("_name", "name")) \ + field(flag_addr, offset, MATCH_SYMBOLS("_addr", "addr")) \ + field(flag_origin, offset, MATCH_SYMBOLS("_flags", "origin")) \ + field(flags, address, MATCH_SYMBOLS("flags")) \ + field(flag_count, value, MATCH_SYMBOLS("numFlags")) \ + field(flag_type, offset, MATCH_SYMBOLS("_type", "type")) \ + type_end() \ + type_begin(VMOop, MATCH_SYMBOLS("oopDesc")) \ + field(oop_klass, offset, MATCH_SYMBOLS("_metadata._klass")) \ + type_end() \ + type_begin(VMUniverse, MATCH_SYMBOLS("Universe", "CompressedKlassPointers")) \ + field(narrow_klass_base, address, MATCH_SYMBOLS("_narrow_klass._base", "_base")) \ + field(narrow_klass_shift, offset, MATCH_SYMBOLS("_narrow_klass._shift", "_shift")) \ + field(collected_heap, address, MATCH_SYMBOLS("_collectedHeap")) \ + type_end() + +#define DECLARE_INT_CONSTANTS_DO(constant) \ + constant(frame, entry_frame_call_wrapper_offset) + +#define DECLARE_LONG_CONSTANTS_DO(constant) \ + constant(markWord, klass_shift) \ + constant(markWord, monitor_value) class VMStructs { public: @@ -103,16 +204,6 @@ class VMStructs { static CodeCache* _libjvm; -// Do nothing macro -#define DO_NOTHING(...) - -#define DECLARE_TYPE_FIELD(type, field, field_type, ...) \ - static field_type _##type##_##field##_##field_type; - - DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DO_NOTHING) -#undef DECL_TYPE_FIELD -#undef DO_NOTHING - static bool _has_class_names; static bool _has_method_structs; static bool _has_compiler_structs; @@ -121,97 +212,49 @@ class VMStructs { static bool _has_native_thread_id; static bool _can_dereference_jmethod_id; static bool _compact_object_headers; - - static int _klass_name_offset; - static int _symbol_length_offset; - static int _symbol_length_and_refcount_offset; - static int _symbol_body_offset; - static int _oop_klass_offset; - static int _class_loader_data_offset; - static int _class_loader_data_next_offset; - static int _methods_offset; - static int _jmethod_ids_offset; - static int _thread_osthread_offset; - static int _thread_anchor_offset; - static int _thread_state_offset; - static int _thread_vframe_offset; - static int _thread_exception_offset; - static int _osthread_id_offset; - static int _call_wrapper_anchor_offset; - static int _comp_env_offset; - static int _comp_task_offset; - static int _comp_method_offset; - static int _anchor_sp_offset; - static int _anchor_pc_offset; - static int _anchor_fp_offset; - static int _blob_size_offset; - static int _frame_size_offset; - static int _frame_complete_offset; - static int _code_offset; - static int _data_offset; - static int _mutable_data_offset; - static int _relocation_size_offset; - static int _scopes_pcs_offset; - static int _scopes_data_offset; - static int _nmethod_name_offset; - static int _nmethod_method_offset; - static int _nmethod_entry_offset; - static int _nmethod_state_offset; - static int _nmethod_level_offset; - static int _nmethod_metadata_offset; - static int _nmethod_immutable_offset; - static int _method_constmethod_offset; - static int _method_code_offset; - static int _constmethod_constants_offset; - static int _constmethod_idnum_offset; - static int _pool_holder_offset; - static int _array_len_offset; - static int _array_data_offset; - static int _code_heap_memory_offset; - static int _code_heap_segmap_offset; - static int _code_heap_segment_shift; - static int _heap_block_used_offset; - static int _vs_low_bound_offset; - static int _vs_high_bound_offset; - static int _vs_low_offset; - static int _vs_high_offset; - static int _flag_name_offset; - static int _flag_addr_offset; - static int _flag_origin_offset; - static const char* _flags_addr; - static int _flag_count; - static char* _code_heap[3]; + + static int _narrow_klass_shift; static const void* _code_heap_low; static const void* _code_heap_high; - static char** _code_heap_addr; - static const void** _code_heap_low_addr; - static const void** _code_heap_high_addr; - static int* _klass_offset_addr; - static char** _narrow_klass_base_addr; static char* _narrow_klass_base; - static int* _narrow_klass_shift_addr; - static int _narrow_klass_shift; - static char** _collected_heap_addr; - static int _region_start_offset; - static int _region_size_offset; - static int _markword_klass_shift; - static int _markword_monitor_value; - static int _entry_frame_call_wrapper_offset; + static const void* _call_stub_return; + static char* _code_heap[3]; static int _interpreter_frame_bcp_offset; static unsigned char _unsigned5_base; - static const void** _call_stub_return_addr; - static const void* _call_stub_return; static const void* _interpreted_frame_valid_start; static const void* _interpreted_frame_valid_end; + // Declare type size variables #define DECLARE_TYPE_SIZE_VAR(name, ...) \ static uint64_t TYPE_SIZE_NAME(name); - - DECLARE_TYPES_DO(DECLARE_TYPE_SIZE_VAR) + DECLARE_TYPES_DO(DECLARE_TYPE_SIZE_VAR) #undef DECLARE_TYPE_SIZE_VAR - + +// Declare vmStructs' field offsets and addresses + +// Do nothing macro +#define DO_NOTHING(...) +#define DECLARE_TYPE_FIELD(field, field_type, ...) \ + static field_type _##field##_##field_type; + + DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DO_NOTHING) +#undef DECLARE_TYPE_FIELD +#undef DO_NOTHING + +// Declare int constant variables +#define DECLARE_INT_CONSTANT_VAR(type, field) \ + static int _##type##_##field; + DECLARE_INT_CONSTANTS_DO(DECLARE_INT_CONSTANT_VAR) +#undef DECLARE_INT_CONSTANT_VAR + +// Declare long constant variables +#define DECLARE_LONG_CONSTANT_VAR(type, field) \ + static long _##type##_##field; + DECLARE_LONG_CONSTANTS_DO(DECLARE_LONG_CONSTANT_VAR) +#undef DECLARE_LONG_CONSTANT_VAR + static jfieldID _eetop; static jfieldID _tid; @@ -226,8 +269,6 @@ class VMStructs { // Datadog-specific extensions static CodeCache _unsafe_to_walk; - static int _osthread_state_offset; - static int _flag_type_offset; typedef HeapUsage (*HeapUsageFunc)(const void *); static HeapUsageFunc _heap_usage_func; typedef void *(*MemoryUsageFunc)(void *, void *, bool); @@ -237,8 +278,13 @@ class VMStructs { static IsValidMethodFunc _is_valid_method_func; static uintptr_t readSymbol(const char* symbol_name); + + // Read VM information from vmStructs + static void init_type_sizes(); static void init_offsets_and_addresses(); + static void init_constants(); static void initOffsets(); + static void resolveOffsets(); static void patchSafeFetch(); static void initJvmFunctions(); @@ -458,7 +504,7 @@ DECLARE(VMKlass) if (mark & MONITOR_BIT) { mark = *(uintptr_t*)(mark ^ MONITOR_BIT); } - narrow_klass = mark >> _markword_klass_shift; + narrow_klass = mark >> _markWord_klass_shift; } else { narrow_klass = *(unsigned int*)(oop + _oop_klass_offset); } @@ -496,9 +542,9 @@ DECLARE(VMJavaFrameAnchor) public: static VMJavaFrameAnchor* fromEntryFrame(uintptr_t fp) { - assert(_entry_frame_call_wrapper_offset != -1); + assert(_frame_entry_frame_call_wrapper_offset != -1); assert(_call_wrapper_anchor_offset >= 0); - const char* call_wrapper = (const char*) SafeAccess::loadPtr((void**)(fp + _entry_frame_call_wrapper_offset), nullptr); + const char* call_wrapper = (const char*) SafeAccess::loadPtr((void**)(fp + _frame_entry_frame_call_wrapper_offset), nullptr); if (!goodPtr(call_wrapper) || (uintptr_t)call_wrapper - fp > MAX_CALL_WRAPPER_DISTANCE) { return NULL; } @@ -789,7 +835,7 @@ class CodeHeap : VMStructs { public: static bool available() { - return _code_heap_addr != NULL; + return _code_heap_address != nullptr; } static bool contains(const void* pc) { From d5a835669ca5aa33556650fd9c61d78b663bda5c Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Sat, 14 Feb 2026 02:45:00 +0000 Subject: [PATCH 03/23] v2 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 39 +++++++-------------------- ddprof-lib/src/main/cpp/vmStructs.h | 30 ++++++++++----------- 2 files changed, 25 insertions(+), 44 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index f80aac3e4..b2ca53899 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -14,9 +14,7 @@ #include "safeAccess.h" #include "spinLock.h" - CodeCache* VMStructs::_libjvm = nullptr; - bool VMStructs::_has_class_names = false; bool VMStructs::_has_method_structs = false; bool VMStructs::_has_compiler_structs = false; @@ -39,7 +37,7 @@ const void* VMStructs::_interpreted_frame_valid_end = nullptr; // Initialize type size to 0 -#define INIT_TYPE_SIZE(name, ...) uint64_t VMStructs::TYPE_SIZE_NAME(name) = 0; +#define INIT_TYPE_SIZE(name, names) uint64_t VMStructs::TYPE_SIZE_NAME(name) = 0; DECLARE_TYPES_DO(INIT_TYPE_SIZE) #undef INIT_TYPE_SIZE @@ -53,7 +51,7 @@ DECLARE_TYPES_DO(INIT_TYPE_SIZE) // Do nothing macro #define DO_NOTHING(...) -#define INIT_OFFSET_OR_ADDRESS(field, field_type, ...) \ +#define INIT_OFFSET_OR_ADDRESS(field, field_type, names) \ field_type VMStructs::_##field##_##field_type = field_type##_value; DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) @@ -120,23 +118,6 @@ void VMStructs::ready() { initThreadBridge(); } -bool initTypeSize(uint64_t& size, const char* type, uint64_t value, ...) { - va_list args; - va_start(args, value); - const char* match_type = nullptr; - bool found = false; - while ((match_type = va_arg(args, const char*)) != nullptr) { - if (strcmp(type, match_type) == 0) { - size = value; - found = true; - break; - } - } - - va_end(args); - return found; -} - bool matchAny(const char* target_name, const char** names) { for (const char** name = names; *name != nullptr; name++) { if (strcmp(target_name, *name) == 0) { @@ -163,7 +144,7 @@ void VMStructs::init_offsets_and_addresses() { }; auto read_value = [&]() -> int { - return **(int**)(entry + offset_offset); + return *(int*)(entry + offset_offset); }; if (entry != 0 && stride != 0) { @@ -173,14 +154,14 @@ void VMStructs::init_offsets_and_addresses() { if (type_name == nullptr || field_name == nullptr) { break; } -#define MATCH_TYPE_NAMES(type, ...) \ - if (matchAny(type_name, (const char*[]){ #__VA_ARGS__ })) { -#define READ_FIELD_VALUE(field, field_type, ...) \ - if (matchAny(field_name, (const char*[]){ #__VA_ARGS__ })) { \ +#define MATCH_TYPE_NAMES(type, type_names) \ + if (matchAny(type_name, type_names)) { +#define READ_FIELD_VALUE(field, field_type, field_names) \ + if (matchAny(field_name, field_names)) { \ _##field##_##field_type = read_##field_type(); \ continue; \ } -#define END_TYPE() } +#define END_TYPE() continue; } DECLARE_TYPE_FILED_DO(MATCH_TYPE_NAMES, READ_FIELD_VALUE, END_TYPE) #undef MATCH_TYPE_NAMES #undef READ_FIELD_VALUE @@ -204,8 +185,8 @@ void VMStructs::init_type_sizes() { uint64_t size = *(uint64_t*)(entry + size_offset); - #define READ_TYPE_SIZE(name, ...) \ - if (matchAny(type, (const char*[]){ #__VA_ARGS__ })) { \ + #define READ_TYPE_SIZE(name, names) \ + if (matchAny(type, names)) { \ TYPE_SIZE_NAME(name) = size; \ continue; \ } diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index b3fa70c30..d86a32ce6 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -39,20 +39,20 @@ inline T* cast_to(const void* ptr) { #define DECLARE_END }; -#define MATCH_SYMBOLS(...) { #__VA_ARGS__, nullptr } +#define MATCH_SYMBOLS(...) (const char*[]) { __VA_ARGS__, nullptr } // Defines a type and its matching symbols in vmStructs. // A type may match multiple names in different JVM versions. #define DECLARE_TYPES_DO(f) \ - f(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) \ - f(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ - f(VMConstMethod, MATCH_SYMBOLS("ConstMethod")) \ - f(VMFlag, MATCH_SYMBOLS("JVMFlag", "Flag")) \ - f(VMJavaFrameAnchor, MATCH_SYMBOLS("JavaFrameAnchor")) \ - f(VMKlass, MATCH_SYMBOLS("Klass")) \ - f(VMMethod, MATCH_SYMBOLS("Method")) \ - f(VMNMethod, MATCH_SYMBOLS("nmethod")) \ - f(VMSymbol, MATCH_SYMBOLS("Symbol")) \ + f(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) \ + f(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ + f(VMConstMethod, MATCH_SYMBOLS("ConstMethod")) \ + f(VMFlag, MATCH_SYMBOLS("JVMFlag", "Flag")) \ + f(VMJavaFrameAnchor, MATCH_SYMBOLS("JavaFrameAnchor")) \ + f(VMKlass, MATCH_SYMBOLS("Klass")) \ + f(VMMethod, MATCH_SYMBOLS("Method")) \ + f(VMNMethod, MATCH_SYMBOLS("nmethod")) \ + f(VMSymbol, MATCH_SYMBOLS("Symbol")) \ f(VMThread, MATCH_SYMBOLS("Thread")) @@ -188,11 +188,11 @@ typedef int value; field(collected_heap, address, MATCH_SYMBOLS("_collectedHeap")) \ type_end() -#define DECLARE_INT_CONSTANTS_DO(constant) \ +#define DECLARE_INT_CONSTANTS_DO(constant) \ constant(frame, entry_frame_call_wrapper_offset) -#define DECLARE_LONG_CONSTANTS_DO(constant) \ - constant(markWord, klass_shift) \ +#define DECLARE_LONG_CONSTANTS_DO(constant) \ + constant(markWord, klass_shift) \ constant(markWord, monitor_value) class VMStructs { @@ -226,7 +226,7 @@ class VMStructs { // Declare type size variables - #define DECLARE_TYPE_SIZE_VAR(name, ...) \ + #define DECLARE_TYPE_SIZE_VAR(name, names) \ static uint64_t TYPE_SIZE_NAME(name); DECLARE_TYPES_DO(DECLARE_TYPE_SIZE_VAR) @@ -236,7 +236,7 @@ class VMStructs { // Do nothing macro #define DO_NOTHING(...) -#define DECLARE_TYPE_FIELD(field, field_type, ...) \ +#define DECLARE_TYPE_FIELD(field, field_type, names) \ static field_type _##field##_##field_type; DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DO_NOTHING) From 62fc720c8db5395867492ac9a2a8acff9724fa9e Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 17 Feb 2026 14:32:43 +0000 Subject: [PATCH 04/23] Add verification phase --- ddprof-lib/src/main/cpp/common.h | 6 ++++ ddprof-lib/src/main/cpp/vmStructs.cpp | 51 ++++++++++++++++++++++----- ddprof-lib/src/main/cpp/vmStructs.h | 8 +++-- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/ddprof-lib/src/main/cpp/common.h b/ddprof-lib/src/main/cpp/common.h index 1dae50f14..b1df7a499 100644 --- a/ddprof-lib/src/main/cpp/common.h +++ b/ddprof-lib/src/main/cpp/common.h @@ -12,8 +12,14 @@ constexpr size_t KNUTH_MULTIPLICATIVE_CONSTANT = 0x9e3779b97f4a7c15ULL; fprintf(stdout, "[TEST::INFO] " fmt "\n", ##__VA_ARGS__); \ fflush(stdout); \ } while (0) + +#define DEBUG_ONLY(s) s + #else #define TEST_LOG(fmt, ...) // No-op in non-debug mode + +#define DEBUG_ONLY(s) + #endif #endif // _COMMON_H \ No newline at end of file diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index b2ca53899..f79fbfa58 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -60,17 +60,14 @@ DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) #undef DO_NOTHING #undef offset_value #undef address_value +#undef value_value // Initialize constant variables to -1 -#define INIT_INT_CONSTANT(type, field) \ +#define INIT_CONSTANT(type, field) \ int VMStructs::_##type##_##field = -1; -DECLARE_INT_CONSTANTS_DO(INIT_INT_CONSTANT) -#undef INIT_INT_CONSTANT - -#define INIT_LONG_CONSTANT(type, field) \ - long VMStructs::_##type##_##field = -1; -DECLARE_LONG_CONSTANTS_DO(INIT_LONG_CONSTANT) -#undef INIT_LONG_CONSTANT +DECLARE_INT_CONSTANTS_DO(INIT_CONSTANT) +DECLARE_LONG_CONSTANTS_DO(INIT_CONSTANT) +#undef INIT_CONSTANT jfieldID VMStructs::_eetop; @@ -248,10 +245,48 @@ void VMStructs::init_constants() { #undef READ_CONSTANT + +#ifdef DEBUG +void VMStructs::verify_offsets() { +// Verify type sizes +#define VERIFY_TYPE_SIZE(name, names) assert(TYPE_SIZE_NAME(name) > 0); + DECLARE_TYPES_DO(VERIFY_TYPE_SIZE); +#undef VERIFY_TYPE_SIZE + + +// Verify offsets and addresses +#define offset_value -1 +#define address_value nullptr +#define value_value -1 + +// Do nothing macro +#define DO_NOTHING(...) +#define VERIFY_OFFSET_OR_ADDRESS(field, field_type, names) \ + assert(_##field##_##field_type != field_type##_value); + DECLARE_TYPE_FILED_DO(DO_NOTHING, VERIFY_OFFSET_OR_ADDRESS, DO_NOTHING) +#undef VERIFY_OFFSET_OR_ADDRESS +#undef DO_NOTHING +#undef offset_value +#undef address_value +#undef value_value + +// Verify constants +// Initialize constant variables to -1 +#define VERIFY_CONSTANT(type, field) \ + assert(_##type##_##field != -1); + DECLARE_INT_CONSTANTS_DO(VERIFY_CONSTANT) + DECLARE_LONG_CONSTANTS_DO(VERIFY_CONSTANT) +#undef INIT_CONSTANT +} + +#endif // DEBUG + void VMStructs::initOffsets() { init_type_sizes(); init_offsets_and_addresses(); init_constants(); + + DEBUG_ONLY(verify_offsets();) } void VMStructs::resolveOffsets() { diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index d86a32ce6..0271e3ff8 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -87,7 +87,7 @@ typedef int value; field(pool_holder, offset, MATCH_SYMBOLS("_pool_holder")) \ type_end() \ type_begin(VMKlass, MATCH_SYMBOLS("Klass", "InstanceKlass")) \ - field(klass_name, offset, MATCH_SYMBOLS("_name")) \ + field(klass_name, offset, MATCH_SYMBOLS("_name")) \ field(class_loader_data, offset, MATCH_SYMBOLS("_class_loader_data")) \ field(methods, offset, MATCH_SYMBOLS("_methods")) \ field(jmethod_ids, offset, MATCH_SYMBOLS("_methods_jmethod_ids")) \ @@ -103,8 +103,10 @@ typedef int value; field(symbol_body, offset, MATCH_SYMBOLS("_body")) \ field(symbol_length_and_refcount, offset, MATCH_SYMBOLS("_length_and_refcount")) \ type_end() \ - type_begin(VMThread, MATCH_SYMBOLS("Thread", "JavaThread")) \ + type_begin(VMThread, MATCH_SYMBOLS"Thread") \ field(thread_osthread, offset, MATCH_SYMBOLS("_osthread")) \ + type_end() \ + type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread")) \ field(thread_anchor, offset, MATCH_SYMBOLS("_anchor")) \ field(thread_state, offset, MATCH_SYMBOLS("_thread_state")) \ field(thread_vframe, offset, MATCH_SYMBOLS("_vframe_array_head")) \ @@ -285,6 +287,8 @@ class VMStructs { static void init_constants(); static void initOffsets(); + DEBUG_ONLY(static void verify_offsets();) + static void resolveOffsets(); static void patchSafeFetch(); static void initJvmFunctions(); From 89f98d28d81044bafc66f6be004e1679109c0b86 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 17 Feb 2026 15:31:22 +0000 Subject: [PATCH 05/23] Fix compilation --- ddprof-lib/src/main/cpp/common.h | 6 ------ ddprof-lib/src/main/cpp/vmStructs.cpp | 17 ++++++++++++----- ddprof-lib/src/main/cpp/vmStructs.h | 8 +++++--- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/ddprof-lib/src/main/cpp/common.h b/ddprof-lib/src/main/cpp/common.h index b1df7a499..1dae50f14 100644 --- a/ddprof-lib/src/main/cpp/common.h +++ b/ddprof-lib/src/main/cpp/common.h @@ -12,14 +12,8 @@ constexpr size_t KNUTH_MULTIPLICATIVE_CONSTANT = 0x9e3779b97f4a7c15ULL; fprintf(stdout, "[TEST::INFO] " fmt "\n", ##__VA_ARGS__); \ fflush(stdout); \ } while (0) - -#define DEBUG_ONLY(s) s - #else #define TEST_LOG(fmt, ...) // No-op in non-debug mode - -#define DEBUG_ONLY(s) - #endif #endif // _COMMON_H \ No newline at end of file diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index f79fbfa58..c9d69368d 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -63,11 +63,15 @@ DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) #undef value_value // Initialize constant variables to -1 -#define INIT_CONSTANT(type, field) \ +#define INIT_INT_CONSTANT(type, field) \ int VMStructs::_##type##_##field = -1; -DECLARE_INT_CONSTANTS_DO(INIT_CONSTANT) -DECLARE_LONG_CONSTANTS_DO(INIT_CONSTANT) -#undef INIT_CONSTANT +#define INIT_LONG_CONSTANT(type, field) \ + long VMStructs::_##type##_##field = -1; + +DECLARE_INT_CONSTANTS_DO(INIT_INT_CONSTANT) +DECLARE_LONG_CONSTANTS_DO(INIT_LONG_CONSTANT) +#undef INIT_INT_CONSTANT +#undef INIT_LONG_CONSTANT jfieldID VMStructs::_eetop; @@ -286,7 +290,10 @@ void VMStructs::initOffsets() { init_offsets_and_addresses(); init_constants(); - DEBUG_ONLY(verify_offsets();) + +#ifdef DEBUG + verify_offsets(); +#endif } void VMStructs::resolveOffsets() { diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 0271e3ff8..5d31fd84e 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -103,10 +103,10 @@ typedef int value; field(symbol_body, offset, MATCH_SYMBOLS("_body")) \ field(symbol_length_and_refcount, offset, MATCH_SYMBOLS("_length_and_refcount")) \ type_end() \ - type_begin(VMThread, MATCH_SYMBOLS"Thread") \ + type_begin(VMThread, MATCH_SYMBOLS("Thread")) \ field(thread_osthread, offset, MATCH_SYMBOLS("_osthread")) \ type_end() \ - type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread")) \ + type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread")) \ field(thread_anchor, offset, MATCH_SYMBOLS("_anchor")) \ field(thread_state, offset, MATCH_SYMBOLS("_thread_state")) \ field(thread_vframe, offset, MATCH_SYMBOLS("_vframe_array_head")) \ @@ -287,7 +287,9 @@ class VMStructs { static void init_constants(); static void initOffsets(); - DEBUG_ONLY(static void verify_offsets();) +#ifdef DEBUG + static void verify_offsets(); +#endif static void resolveOffsets(); static void patchSafeFetch(); From 6d7417d3b48e2b6d739211e597ca0be974b257c3 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 17 Feb 2026 18:50:54 +0000 Subject: [PATCH 06/23] field_no_check --- ddprof-lib/src/main/cpp/vmStructs.cpp | 8 ++++---- ddprof-lib/src/main/cpp/vmStructs.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index c9d69368d..fb06bdede 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -54,7 +54,7 @@ DECLARE_TYPES_DO(INIT_TYPE_SIZE) #define INIT_OFFSET_OR_ADDRESS(field, field_type, names) \ field_type VMStructs::_##field##_##field_type = field_type##_value; -DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) +DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) #undef INIT_OFFSET_OR_ADDRESS #undef DO_NOTHING @@ -163,7 +163,7 @@ void VMStructs::init_offsets_and_addresses() { continue; \ } #define END_TYPE() continue; } - DECLARE_TYPE_FILED_DO(MATCH_TYPE_NAMES, READ_FIELD_VALUE, END_TYPE) + DECLARE_TYPE_FILED_DO(MATCH_TYPE_NAMES, READ_FIELD_VALUE, READ_FIELD_VALUE, END_TYPE) #undef MATCH_TYPE_NAMES #undef READ_FIELD_VALUE #undef END_TYPE @@ -267,7 +267,7 @@ void VMStructs::verify_offsets() { #define DO_NOTHING(...) #define VERIFY_OFFSET_OR_ADDRESS(field, field_type, names) \ assert(_##field##_##field_type != field_type##_value); - DECLARE_TYPE_FILED_DO(DO_NOTHING, VERIFY_OFFSET_OR_ADDRESS, DO_NOTHING) + DECLARE_TYPE_FILED_DO(DO_NOTHING, VERIFY_OFFSET_OR_ADDRESS, DO_NOTHING, DO_NOTHING) #undef VERIFY_OFFSET_OR_ADDRESS #undef DO_NOTHING #undef offset_value @@ -292,7 +292,7 @@ void VMStructs::initOffsets() { #ifdef DEBUG - verify_offsets(); +// verify_offsets(); #endif } diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 5d31fd84e..8ff445fbd 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -60,7 +60,7 @@ typedef int offset; typedef const unsigned char** address; typedef int value; -#define DECLARE_TYPE_FILED_DO(type_begin, field, type_end) \ +#define DECLARE_TYPE_FILED_DO(type_begin, field, field_no_check, type_end) \ type_begin(VMMemRegion, MATCH_SYMBOLS("MemRegion")) \ field(region_start, offset, MATCH_SYMBOLS("_start")) \ field(region_size, offset, MATCH_SYMBOLS("_word_size")) \ @@ -71,7 +71,7 @@ typedef int value; field(nmethod_state, offset, MATCH_SYMBOLS("_state")) \ field(nmethod_level, offset, MATCH_SYMBOLS("_comp_level")) \ field(nmethod_metadata, offset, MATCH_SYMBOLS("_metadata_offset")) \ - field(nmethod_immutable, offset, MATCH_SYMBOLS("_immutable_data")) \ + field_no_check(nmethod_immutable, offset, MATCH_SYMBOLS("_immutable_data")) \ field(scopes_pcs, offset, MATCH_SYMBOLS("_scopes_pcs_offset")) \ field(scopes_data, offset, MATCH_SYMBOLS("_scopes_data_offset", "_scopes_data_begin")) \ type_end() \ @@ -241,7 +241,7 @@ class VMStructs { #define DECLARE_TYPE_FIELD(field, field_type, names) \ static field_type _##field##_##field_type; - DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DO_NOTHING) + DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DECLARE_TYPE_FIELD, DO_NOTHING) #undef DECLARE_TYPE_FIELD #undef DO_NOTHING From 45946cdbcd1c5a1092c3f5d09c9a555359d4525f Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 18 Feb 2026 00:47:40 +0000 Subject: [PATCH 07/23] v3 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 44 +++++++----- ddprof-lib/src/main/cpp/vmStructs.h | 100 ++++++++++++++++++++++---- 2 files changed, 113 insertions(+), 31 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index fb06bdede..d810ab5ec 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -43,11 +43,14 @@ DECLARE_TYPES_DO(INIT_TYPE_SIZE) #define offset_value -1 #define address_value nullptr -#define value_value -1 +#define off_value_value -1 +#define addr_value_value -1 // Initialize field variables // offset = -1 // address = nullptr +// off_value = -1 int value from an offset +// addr_value = -1 int value from an address // Do nothing macro #define DO_NOTHING(...) @@ -60,7 +63,8 @@ DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, INIT_OFFSET_OR_ADDRESS #undef DO_NOTHING #undef offset_value #undef address_value -#undef value_value +#undef off_value_value +#undef addr_value_value // Initialize constant variables to -1 #define INIT_INT_CONSTANT(type, field) \ @@ -144,7 +148,11 @@ void VMStructs::init_offsets_and_addresses() { return *(address*)(entry + address_offset); }; - auto read_value = [&]() -> int { + auto read_addr_value = [&]() -> int { + return **(int**)(entry + address_offset); + }; + + auto read_off_value = [&]() -> int { return *(int*)(entry + offset_offset); }; @@ -261,23 +269,27 @@ void VMStructs::verify_offsets() { // Verify offsets and addresses #define offset_value -1 #define address_value nullptr -#define value_value -1 +#define off_value_value -1 +#define addr_value_value -1 // Do nothing macro #define DO_NOTHING(...) #define VERIFY_OFFSET_OR_ADDRESS(field, field_type, names) \ assert(_##field##_##field_type != field_type##_value); + DECLARE_TYPE_FILED_DO(DO_NOTHING, VERIFY_OFFSET_OR_ADDRESS, DO_NOTHING, DO_NOTHING) #undef VERIFY_OFFSET_OR_ADDRESS #undef DO_NOTHING #undef offset_value #undef address_value -#undef value_value +#undef off_value_value +#undef addr_value_value // Verify constants // Initialize constant variables to -1 #define VERIFY_CONSTANT(type, field) \ - assert(_##type##_##field != -1); + // assert(_##type##_##field != -1); + DECLARE_INT_CONSTANTS_DO(VERIFY_CONSTANT) DECLARE_LONG_CONSTANTS_DO(VERIFY_CONSTANT) #undef INIT_CONSTANT @@ -292,7 +304,7 @@ void VMStructs::initOffsets() { #ifdef DEBUG -// verify_offsets(); + verify_offsets(); #endif } @@ -306,9 +318,9 @@ void VMStructs::resolveOffsets() { } VMFlag* ccp = VMFlag::find("UseCompressedClassPointers"); - if (ccp != NULL && ccp->get() && _narrow_klass_base_address != NULL && _narrow_klass_shift_offset >= 0) { + if (ccp != NULL && ccp->get() && _narrow_klass_base_address != NULL && _narrow_klass_shift_address != nullptr) { _narrow_klass_base = *(char**)_narrow_klass_base_address; - _narrow_klass_shift = _narrow_klass_shift_offset; + _narrow_klass_shift = *(int*)_narrow_klass_shift_address; } VMFlag* coh = VMFlag::find("UseCompactObjectHeaders"); @@ -401,11 +413,11 @@ void VMStructs::resolveOffsets() { } // Invariant: _code_heap[i] != NULL iff all CodeHeap structures are available - if (_code_heap[0] != NULL && _code_heap_segment_shift_value >= 0) { - _code_heap_segment_shift_value = *(int*)(_code_heap[0] + _code_heap_segment_shift_value); + if (_code_heap[0] != NULL && _code_heap_segment_shift_off_value >= 0) { + _code_heap_segment_shift_off_value = *(int*)(_code_heap[0] + _code_heap_segment_shift_off_value); } if (_code_heap_memory_offset < 0 || _code_heap_segmap_offset < 0 || - _code_heap_segment_shift_value < 0 || _code_heap_segment_shift_value > 16 || + _code_heap_segment_shift_off_value < 0 || _code_heap_segment_shift_off_value > 16 || _heap_block_used_offset < 0) { memset(_code_heap, 0, sizeof(_code_heap)); } @@ -680,7 +692,7 @@ jmethodID VMMethod::validatedId() { VMNMethod* CodeHeap::findNMethod(char* heap, const void* pc) { unsigned char* heap_start = *(unsigned char**)(heap + _code_heap_memory_offset + _vs_low_offset); unsigned char* segmap = *(unsigned char**)(heap + _code_heap_segmap_offset + _vs_low_offset); - size_t idx = ((unsigned char*)pc - heap_start) >> _code_heap_segment_shift_value; + size_t idx = ((unsigned char*)pc - heap_start) >> _code_heap_segment_shift_off_value; if (segmap[idx] == 0xff) { return NULL; @@ -689,7 +701,7 @@ VMNMethod* CodeHeap::findNMethod(char* heap, const void* pc) { idx -= segmap[idx]; } - unsigned char* block = heap_start + (idx << _code_heap_segment_shift_value) + _heap_block_used_offset; + unsigned char* block = heap_start + (idx << _code_heap_segment_shift_off_value) + _heap_block_used_offset; return *block ? align(block + sizeof(uintptr_t)) : NULL; } @@ -734,7 +746,7 @@ int ScopeDesc::readInt() { VMFlag* VMFlag::find(const char* name) { if (_flags_address != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count_value; i++) { + for (int i = 0; i < _flag_count_addr_value; i++) { VMFlag* f = VMFlag::cast(_flags_address + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0 && f->addr() != NULL) { return f; @@ -754,7 +766,7 @@ VMFlag *VMFlag::find(const char *name, std::initializer_list types VMFlag *VMFlag::find(const char *name, int type_mask) { if (_flags_address != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count_value; i++) { + for (int i = 0; i < _flag_count_addr_value; i++) { VMFlag* f = VMFlag::cast(_flags_address + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0) { int masked = 0x1 << f->type(); diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 8ff445fbd..39a2ce7a1 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -19,7 +19,6 @@ class GCHeapSummary; class HeapUsage; -#define TYPE_SIZE_NAME(name) _##name##_size template inline T* cast_to(const void* ptr) { @@ -28,6 +27,27 @@ inline T* cast_to(const void* ptr) { return reinterpret_cast(const_cast(ptr)); } +#define TYPE_SIZE_NAME(name) _##name##_size + +// MATCH_SYMBOLS macro expands into an nullptr terminated char string array, +// that is consumed by matchAny() method +#define MATCH_SYMBOLS(...) (const char*[]) { __VA_ARGS__, nullptr } + +/** + * This macro defines a counterpart of a JVM class, e.g. VMKass -> Klass. + * By the convention, we prefix the class name with 'VM' to avoid namespace collision + * with JVM inside a debug session. E.g. + * gdb > p this + * gdb > (VMKlass*)0x123456 + * gdb > p (Klass*)this + * .... + * + * The macro implicitly defines three static functions: + * - type_size() Return class size defined in JVM. + * - cast() It performs memory readability check before casts a void* pointer to this type. + * It ensures the memory range [ptr, ptr + type_size()) is readable. + * - load_then_cast() It loads a pointer from specified location, then does above cast. + */ #define DECLARE(name) \ class name : VMStructs { \ public: \ @@ -39,10 +59,43 @@ inline T* cast_to(const void* ptr) { #define DECLARE_END }; -#define MATCH_SYMBOLS(...) (const char*[]) { __VA_ARGS__, nullptr } +/** + * Defines a type and its matching symbols in vmStructs. + * A type may match multiple names in different JVM versions. + * Macro expansion: + * - Declaration phase + * static uint64_t _TYPE_size; + * + * For example: + * f(VMClassLoaderData) -> static uint64_t _VMClassLoaderData_size; + * + * - Initialization phase + * uint64_t VMStructs::_TYPE_size = 0; + * + * For exmaple: + * f(VMClassLoaderData) -> uint64_t VMStructs::_VMClassLoaderData_size = 0; + * + * - Value population phase + * if (matchAny((char*)[]) { typeName, nullptr}) { + * _TYPE_size = size; + * continue; + * } + * + * For example: + * f(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) -> + * if (matchAny((char*)[] {"ClassLoaderData", nullptr})) { + * _ClassLoaderData_size = size; + * continue; + * } + * + * - Value verification phase + * assert(_TYPE_size > 0); + * + * For example: + * f(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) -> + * assert(_VMClassLoaderData_size > 0); + */ -// Defines a type and its matching symbols in vmStructs. -// A type may match multiple names in different JVM versions. #define DECLARE_TYPES_DO(f) \ f(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) \ f(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ @@ -55,12 +108,26 @@ inline T* cast_to(const void* ptr) { f(VMSymbol, MATCH_SYMBOLS("Symbol")) \ f(VMThread, MATCH_SYMBOLS("Thread")) +/** + * Following macros define field offsets, addresses or values of JVM classes that are exported by + * vmStructs. + * - type_begin() Start a definition of a type. The type name is not used at this moment, but + * improves readability. + * - field() Define a field of a class, can be either an offset, an address or a value + * - field_no_check Define a field of a class, just like above. But the field may not be exported + * by JVMs. Therefore, it is skiped by verify_offsets() + * - type_end() End of a type definition +*/ typedef int offset; typedef const unsigned char** address; -typedef int value; -#define DECLARE_TYPE_FILED_DO(type_begin, field, field_no_check, type_end) \ +// int value from an offset +typedef int off_value; +// int value from an address +typedef int addr_value; + +#define DECLARE_TYPE_FILED_DO(type_begin, field, field_no_check, type_end) \ type_begin(VMMemRegion, MATCH_SYMBOLS("MemRegion")) \ field(region_start, offset, MATCH_SYMBOLS("_start")) \ field(region_size, offset, MATCH_SYMBOLS("_word_size")) \ @@ -101,12 +168,10 @@ typedef int value; type_begin(VMSymbol, MATCH_SYMBOLS("Symbol")) \ field(symbol_length, offset, MATCH_SYMBOLS("_length")) \ field(symbol_body, offset, MATCH_SYMBOLS("_body")) \ - field(symbol_length_and_refcount, offset, MATCH_SYMBOLS("_length_and_refcount")) \ - type_end() \ - type_begin(VMThread, MATCH_SYMBOLS("Thread")) \ - field(thread_osthread, offset, MATCH_SYMBOLS("_osthread")) \ + field_no_check(symbol_length_and_refcount, offset, MATCH_SYMBOLS("_length_and_refcount")) \ type_end() \ type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread")) \ + field(thread_osthread, offset, MATCH_SYMBOLS("_osthread")) \ field(thread_anchor, offset, MATCH_SYMBOLS("_anchor")) \ field(thread_state, offset, MATCH_SYMBOLS("_thread_state")) \ field(thread_vframe, offset, MATCH_SYMBOLS("_vframe_array_head")) \ @@ -141,8 +206,8 @@ typedef int value; field(frame_complete, offset, MATCH_SYMBOLS("_frame_complete_offset")) \ field(code, offset, MATCH_SYMBOLS("_code_offset", "_code_begin")) \ field(data, offset, MATCH_SYMBOLS("_data_offset")) \ - field(mutable_data, offset, MATCH_SYMBOLS("_mutable_data")) \ - field(relocation_size, offset, MATCH_SYMBOLS("_relocation_size")) \ + field_no_check(mutable_data, offset, MATCH_SYMBOLS("_mutable_data")) \ + field_no_check(relocation_size, offset, MATCH_SYMBOLS("_relocation_size")) \ field(nmethod_name, offset, MATCH_SYMBOLS("_name")) \ type_end() \ type_begin(VMCodeCache, MATCH_SYMBOLS("CodeCache")) \ @@ -153,7 +218,7 @@ typedef int value; type_begin(VMCodeHeap, MATCH_SYMBOLS("CodeHeap")) \ field(code_heap_memory, offset, MATCH_SYMBOLS("_memory")) \ field(code_heap_segmap, offset, MATCH_SYMBOLS("_segmap")) \ - field(code_heap_segment_shift, value, MATCH_SYMBOLS("_log2_segment_size")) \ + field(code_heap_segment_shift, off_value, MATCH_SYMBOLS("_log2_segment_size")) \ type_end() \ type_begin(VMHeapBlock, MATCH_SYMBOLS("HeapBlock::Header")) \ field(heap_block_used, offset, MATCH_SYMBOLS("_used")) \ @@ -178,7 +243,7 @@ typedef int value; field(flag_addr, offset, MATCH_SYMBOLS("_addr", "addr")) \ field(flag_origin, offset, MATCH_SYMBOLS("_flags", "origin")) \ field(flags, address, MATCH_SYMBOLS("flags")) \ - field(flag_count, value, MATCH_SYMBOLS("numFlags")) \ + field(flag_count, addr_value, MATCH_SYMBOLS("numFlags")) \ field(flag_type, offset, MATCH_SYMBOLS("_type", "type")) \ type_end() \ type_begin(VMOop, MATCH_SYMBOLS("oopDesc")) \ @@ -186,10 +251,15 @@ typedef int value; type_end() \ type_begin(VMUniverse, MATCH_SYMBOLS("Universe", "CompressedKlassPointers")) \ field(narrow_klass_base, address, MATCH_SYMBOLS("_narrow_klass._base", "_base")) \ - field(narrow_klass_shift, offset, MATCH_SYMBOLS("_narrow_klass._shift", "_shift")) \ + field(narrow_klass_shift, address, MATCH_SYMBOLS("_narrow_klass._shift", "_shift")) \ field(collected_heap, address, MATCH_SYMBOLS("_collectedHeap")) \ type_end() +/** + * The follwing macros declare JVM constants that are exported by vmStructs + * - constant defines a constant of a class + */ + #define DECLARE_INT_CONSTANTS_DO(constant) \ constant(frame, entry_frame_call_wrapper_offset) From e7849541da902955b0a9c0d08f7db4e71462c80b Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 18 Feb 2026 01:53:44 +0000 Subject: [PATCH 08/23] v4 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 4 ++-- ddprof-lib/src/main/cpp/vmStructs.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index d810ab5ec..8632cb731 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -747,7 +747,7 @@ int ScopeDesc::readInt() { VMFlag* VMFlag::find(const char* name) { if (_flags_address != NULL && VMFlag::type_size() > 0) { for (int i = 0; i < _flag_count_addr_value; i++) { - VMFlag* f = VMFlag::cast(_flags_address + i * VMFlag::type_size()); + VMFlag* f = VMFlag::cast(*_flags_address + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0 && f->addr() != NULL) { return f; } @@ -767,7 +767,7 @@ VMFlag *VMFlag::find(const char *name, std::initializer_list types VMFlag *VMFlag::find(const char *name, int type_mask) { if (_flags_address != NULL && VMFlag::type_size() > 0) { for (int i = 0; i < _flag_count_addr_value; i++) { - VMFlag* f = VMFlag::cast(_flags_address + i * VMFlag::type_size()); + VMFlag* f = VMFlag::cast(*_flags_address + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0) { int masked = 0x1 << f->type(); if (masked & type_mask) { diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 39a2ce7a1..82276916e 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -153,9 +153,11 @@ typedef int addr_value; type_begin(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ field(pool_holder, offset, MATCH_SYMBOLS("_pool_holder")) \ type_end() \ - type_begin(VMKlass, MATCH_SYMBOLS("Klass", "InstanceKlass")) \ + type_begin(VMKlass, MATCH_SYMBOLS("Klass")) \ field(klass_name, offset, MATCH_SYMBOLS("_name")) \ field(class_loader_data, offset, MATCH_SYMBOLS("_class_loader_data")) \ + type_end() \ + type_begin(VMInstanceKlass, MATCH_SYMBOLS("InstanceKlass")) \ field(methods, offset, MATCH_SYMBOLS("_methods")) \ field(jmethod_ids, offset, MATCH_SYMBOLS("_methods_jmethod_ids")) \ type_end() \ From 0d0ac8d6d885c5ff93a1d1a5588531c5d8ee4b64 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 18 Feb 2026 02:10:02 +0000 Subject: [PATCH 09/23] v5 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 8632cb731..247ffa9cb 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -314,7 +314,7 @@ void VMStructs::resolveOffsets() { } if (_klass_offset_address != NULL) { - _klass = (jfieldID)(uintptr_t)(*(uintptr_t*)_klass_offset_address << 2 | 2); + _klass = (jfieldID)(uintptr_t)(*(int*)_klass_offset_address << 2 | 2); } VMFlag* ccp = VMFlag::find("UseCompressedClassPointers"); From 9fc0f56209adb1eaedebb601258570e20477133a Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 18 Feb 2026 12:57:01 +0000 Subject: [PATCH 10/23] v7 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 2 ++ ddprof-lib/src/main/cpp/vmStructs.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 247ffa9cb..62ccb2e96 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -13,6 +13,7 @@ #include "jvmHeap.h" #include "safeAccess.h" #include "spinLock.h" +#include "common.h" CodeCache* VMStructs::_libjvm = nullptr; bool VMStructs::_has_class_names = false; @@ -168,6 +169,7 @@ void VMStructs::init_offsets_and_addresses() { #define READ_FIELD_VALUE(field, field_type, field_names) \ if (matchAny(field_name, field_names)) { \ _##field##_##field_type = read_##field_type(); \ + TEST_LOG(#field "_" #field_type " = %ld", (long)_##field##_##field_type); \ continue; \ } #define END_TYPE() continue; } diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 82276916e..805389564 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -172,7 +172,7 @@ typedef int addr_value; field(symbol_body, offset, MATCH_SYMBOLS("_body")) \ field_no_check(symbol_length_and_refcount, offset, MATCH_SYMBOLS("_length_and_refcount")) \ type_end() \ - type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread")) \ + type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread", "Thread")) \ field(thread_osthread, offset, MATCH_SYMBOLS("_osthread")) \ field(thread_anchor, offset, MATCH_SYMBOLS("_anchor")) \ field(thread_state, offset, MATCH_SYMBOLS("_thread_state")) \ From 8a5e27f77f23fdf90c6f3094b91092d7636a2125 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 18 Feb 2026 16:11:17 +0000 Subject: [PATCH 11/23] v8 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 62ccb2e96..0a8fa307e 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -169,7 +169,6 @@ void VMStructs::init_offsets_and_addresses() { #define READ_FIELD_VALUE(field, field_type, field_names) \ if (matchAny(field_name, field_names)) { \ _##field##_##field_type = read_##field_type(); \ - TEST_LOG(#field "_" #field_type " = %ld", (long)_##field##_##field_type); \ continue; \ } #define END_TYPE() continue; } @@ -227,7 +226,7 @@ void VMStructs::init_constants() { if (entry != 0 && stride != 0) { for (;; entry += stride) { const char* type_name = *(const char**)(entry + name_offset); - if (nullptr == nullptr) { + if (type_name == nullptr) { break; } int value = *(int*)(entry + value_offset); From ead95e144675be73554da318355516c1b3c8dfde Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 18 Feb 2026 16:28:05 +0000 Subject: [PATCH 12/23] v9 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 0a8fa307e..b0b73a4e5 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -399,7 +399,7 @@ void VMStructs::resolveOffsets() { _can_dereference_jmethod_id = _has_method_structs && VM::hotspot_version() <= 25; if (_code_heap_address != nullptr && _code_heap_low_address != nullptr && _code_heap_high_address != nullptr) { - char* code_heaps = (char*)_code_heap_address; + char* code_heaps = *(char**)_code_heap_address; unsigned int code_heap_count = *(unsigned int*)(code_heaps + _array_len_offset); if (code_heap_count <= 3 && _array_data_offset >= 0) { char* code_heap_array = *(char**)(code_heaps + _array_data_offset); From dae553a793aa4a669634789cb8faf29f62145026 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 18 Feb 2026 18:42:23 +0000 Subject: [PATCH 13/23] v10 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 72 ++++++------- ddprof-lib/src/main/cpp/vmStructs.h | 146 +++++++++++++------------- 2 files changed, 109 insertions(+), 109 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index b0b73a4e5..fce223952 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -55,8 +55,8 @@ DECLARE_TYPES_DO(INIT_TYPE_SIZE) // Do nothing macro #define DO_NOTHING(...) -#define INIT_OFFSET_OR_ADDRESS(field, field_type, names) \ - field_type VMStructs::_##field##_##field_type = field_type##_value; +#define INIT_OFFSET_OR_ADDRESS(var, field_type, names) \ + field_type VMStructs::var = field_type##_value; DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) @@ -166,9 +166,9 @@ void VMStructs::init_offsets_and_addresses() { } #define MATCH_TYPE_NAMES(type, type_names) \ if (matchAny(type_name, type_names)) { -#define READ_FIELD_VALUE(field, field_type, field_names) \ +#define READ_FIELD_VALUE(var, field_type, field_names) \ if (matchAny(field_name, field_names)) { \ - _##field##_##field_type = read_##field_type(); \ + var = read_##field_type(); \ continue; \ } #define END_TYPE() continue; } @@ -275,8 +275,8 @@ void VMStructs::verify_offsets() { // Do nothing macro #define DO_NOTHING(...) -#define VERIFY_OFFSET_OR_ADDRESS(field, field_type, names) \ - assert(_##field##_##field_type != field_type##_value); +#define VERIFY_OFFSET_OR_ADDRESS(var, field_type, names) \ + assert(var != field_type##_value); DECLARE_TYPE_FILED_DO(DO_NOTHING, VERIFY_OFFSET_OR_ADDRESS, DO_NOTHING, DO_NOTHING) #undef VERIFY_OFFSET_OR_ADDRESS @@ -314,14 +314,14 @@ void VMStructs::resolveOffsets() { return; } - if (_klass_offset_address != NULL) { - _klass = (jfieldID)(uintptr_t)(*(int*)_klass_offset_address << 2 | 2); + if (_klass_offset_addr != NULL) { + _klass = (jfieldID)(uintptr_t)(*(int*)_klass_offset_addr << 2 | 2); } VMFlag* ccp = VMFlag::find("UseCompressedClassPointers"); - if (ccp != NULL && ccp->get() && _narrow_klass_base_address != NULL && _narrow_klass_shift_address != nullptr) { - _narrow_klass_base = *(char**)_narrow_klass_base_address; - _narrow_klass_shift = *(int*)_narrow_klass_shift_address; + if (ccp != NULL && ccp->get() && _narrow_klass_base_addr != NULL && _narrow_klass_shift_addr != nullptr) { + _narrow_klass_base = *(char**)_narrow_klass_base_addr; + _narrow_klass_shift = *(int*)_narrow_klass_shift_addr; } VMFlag* coh = VMFlag::find("UseCompactObjectHeaders"); @@ -373,8 +373,8 @@ void VMStructs::resolveOffsets() { _unsigned5_base = 1; } - if (_call_stub_return_address != NULL) { - _call_stub_return = (const void*)_call_stub_return_address; + if (_call_stub_return_addr != NULL) { + _call_stub_return = *(const void**)_call_stub_return_addr; } // Since JDK 23, _metadata_offset is relative to _data_offset. See metadata() @@ -398,27 +398,27 @@ void VMStructs::resolveOffsets() { // Since JDK-8268406, it is no longer possible to get VMMethod* by dereferencing jmethodID _can_dereference_jmethod_id = _has_method_structs && VM::hotspot_version() <= 25; - if (_code_heap_address != nullptr && _code_heap_low_address != nullptr && _code_heap_high_address != nullptr) { - char* code_heaps = *(char**)_code_heap_address; + if (_code_heap_addr != nullptr && _code_heap_low_addr != nullptr && _code_heap_high_addr != nullptr) { + char* code_heaps = *(char**)_code_heap_addr; unsigned int code_heap_count = *(unsigned int*)(code_heaps + _array_len_offset); if (code_heap_count <= 3 && _array_data_offset >= 0) { char* code_heap_array = *(char**)(code_heaps + _array_data_offset); memcpy(_code_heap, code_heap_array, code_heap_count * sizeof(_code_heap[0])); } - _code_heap_low = _code_heap_low_address; - _code_heap_high = _code_heap_high_address; - } else if (_code_heap_address != NULL && _code_heap_memory_offset >= 0) { - _code_heap[0] = (char*)_code_heap_address; + _code_heap_low = *(const void**)_code_heap_low_addr; + _code_heap_high = *(const void**)_code_heap_high_addr; + } else if (_code_heap_addr != NULL && _code_heap_memory_offset >= 0) { + _code_heap[0] = *(char**)_code_heap_addr; _code_heap_low = *(const void**)(_code_heap[0] + _code_heap_memory_offset + _vs_low_bound_offset); _code_heap_high = *(const void**)(_code_heap[0] + _code_heap_memory_offset + _vs_high_bound_offset); } // Invariant: _code_heap[i] != NULL iff all CodeHeap structures are available - if (_code_heap[0] != NULL && _code_heap_segment_shift_off_value >= 0) { - _code_heap_segment_shift_off_value = *(int*)(_code_heap[0] + _code_heap_segment_shift_off_value); + if (_code_heap[0] != NULL && _code_heap_segment_shift >= 0) { + _code_heap_segment_shift = *(int*)(_code_heap[0] + _code_heap_segment_shift); } if (_code_heap_memory_offset < 0 || _code_heap_segmap_offset < 0 || - _code_heap_segment_shift_off_value < 0 || _code_heap_segment_shift_off_value > 16 || + _code_heap_segment_shift < 0 || _code_heap_segment_shift > 16 || _heap_block_used_offset < 0) { memset(_code_heap, 0, sizeof(_code_heap)); } @@ -693,7 +693,7 @@ jmethodID VMMethod::validatedId() { VMNMethod* CodeHeap::findNMethod(char* heap, const void* pc) { unsigned char* heap_start = *(unsigned char**)(heap + _code_heap_memory_offset + _vs_low_offset); unsigned char* segmap = *(unsigned char**)(heap + _code_heap_segmap_offset + _vs_low_offset); - size_t idx = ((unsigned char*)pc - heap_start) >> _code_heap_segment_shift_off_value; + size_t idx = ((unsigned char*)pc - heap_start) >> _code_heap_segment_shift; if (segmap[idx] == 0xff) { return NULL; @@ -702,7 +702,7 @@ VMNMethod* CodeHeap::findNMethod(char* heap, const void* pc) { idx -= segmap[idx]; } - unsigned char* block = heap_start + (idx << _code_heap_segment_shift_off_value) + _heap_block_used_offset; + unsigned char* block = heap_start + (idx << _code_heap_segment_shift) + _heap_block_used_offset; return *block ? align(block + sizeof(uintptr_t)) : NULL; } @@ -746,9 +746,9 @@ int ScopeDesc::readInt() { } VMFlag* VMFlag::find(const char* name) { - if (_flags_address != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count_addr_value; i++) { - VMFlag* f = VMFlag::cast(*_flags_address + i * VMFlag::type_size()); + if (_flags_addr != NULL && VMFlag::type_size() > 0) { + for (int i = 0; i < _flag_count; i++) { + VMFlag* f = VMFlag::cast(*_flags_addr + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0 && f->addr() != NULL) { return f; } @@ -766,9 +766,9 @@ VMFlag *VMFlag::find(const char *name, std::initializer_list types } VMFlag *VMFlag::find(const char *name, int type_mask) { - if (_flags_address != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count_addr_value; i++) { - VMFlag* f = VMFlag::cast(*_flags_address + i * VMFlag::type_size()); + if (_flags_addr != NULL && VMFlag::type_size() > 0) { + for (int i = 0; i < _flag_count; i++) { + VMFlag* f = VMFlag::cast(*_flags_addr + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0) { int masked = 0x1 << f->type(); if (masked & type_mask) { @@ -974,11 +974,11 @@ bool HeapUsage::isLastGCUsageSupported() { // only supported for JDK 17+ // the CollectedHeap structure is vastly different in JDK 11 and earlier so // we can't support it - return _collected_heap_address != NULL && _heap_usage_func != NULL; + return _collected_heap_addr != NULL && _heap_usage_func != NULL; } bool HeapUsage::needsNativeBindingInterception() { - return _collected_heap_address == NULL || + return _collected_heap_addr == NULL || (_heap_usage_func == NULL && _gc_heap_summary_func == NULL); } @@ -1017,16 +1017,16 @@ HeapUsage HeapUsage::get() { HeapUsage HeapUsage::get(bool allow_jmx) { HeapUsage usage; - if (_collected_heap_address != NULL) { + if (_collected_heap_addr != NULL) { if (_heap_usage_func != NULL) { // this is the JDK 17+ path - usage = _heap_usage_func(*_collected_heap_address); + usage = _heap_usage_func(*_collected_heap_addr); usage._used_at_last_gc = - ((CollectedHeapWrapper *)*_collected_heap_address)->_used_at_last_gc; + ((CollectedHeapWrapper *)*_collected_heap_addr)->_used_at_last_gc; } else if (_gc_heap_summary_func != NULL) { // this is the JDK 11 path // we need to collect GCHeapSummary information first - GCHeapSummary summary = _gc_heap_summary_func((void*)_collected_heap_address); + GCHeapSummary summary = _gc_heap_summary_func(*(void**)_collected_heap_addr); usage._initSize = -1; usage._used = summary.used(); usage._committed = -1; diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 805389564..c43103b9e 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -129,132 +129,132 @@ typedef int addr_value; #define DECLARE_TYPE_FILED_DO(type_begin, field, field_no_check, type_end) \ type_begin(VMMemRegion, MATCH_SYMBOLS("MemRegion")) \ - field(region_start, offset, MATCH_SYMBOLS("_start")) \ - field(region_size, offset, MATCH_SYMBOLS("_word_size")) \ + field(_region_start_offset, offset, MATCH_SYMBOLS("_start")) \ + field(_region_size_offset, offset, MATCH_SYMBOLS("_word_size")) \ type_end() \ type_begin(VMNMethod, MATCH_SYMBOLS("CompiledMethod", "nmethod")) \ - field(nmethod_method, offset, MATCH_SYMBOLS("_method")) \ - field(nmethod_entry, offset, MATCH_SYMBOLS("_verified_entry_offset", "_verified_entry_point")) \ - field(nmethod_state, offset, MATCH_SYMBOLS("_state")) \ - field(nmethod_level, offset, MATCH_SYMBOLS("_comp_level")) \ - field(nmethod_metadata, offset, MATCH_SYMBOLS("_metadata_offset")) \ - field_no_check(nmethod_immutable, offset, MATCH_SYMBOLS("_immutable_data")) \ - field(scopes_pcs, offset, MATCH_SYMBOLS("_scopes_pcs_offset")) \ - field(scopes_data, offset, MATCH_SYMBOLS("_scopes_data_offset", "_scopes_data_begin")) \ + field(_nmethod_method_offset, offset, MATCH_SYMBOLS("_method")) \ + field(_nmethod_entry_offset, offset, MATCH_SYMBOLS("_verified_entry_offset", "_verified_entry_point")) \ + field(_nmethod_state_offset, offset, MATCH_SYMBOLS("_state")) \ + field(_nmethod_level_offset, offset, MATCH_SYMBOLS("_comp_level")) \ + field(_nmethod_metadata_offset, offset, MATCH_SYMBOLS("_metadata_offset")) \ + field_no_check(_nmethod_immutable_offset, offset, MATCH_SYMBOLS("_immutable_data")) \ + field(_scopes_pcs_offset, offset, MATCH_SYMBOLS("_scopes_pcs_offset")) \ + field(_scopes_data_offset, offset, MATCH_SYMBOLS("_scopes_data_offset", "_scopes_data_begin")) \ type_end() \ type_begin(VMMethod, MATCH_SYMBOLS("Method")) \ - field(method_constmethod, offset, MATCH_SYMBOLS("_constMethod")) \ - field(method_code, offset, MATCH_SYMBOLS("_code")) \ + field(_method_constmethod_offset, offset, MATCH_SYMBOLS("_constMethod")) \ + field(_method_code_offset, offset, MATCH_SYMBOLS("_code")) \ type_end() \ type_begin(VMConstMethod, MATCH_SYMBOLS("ConstMethod")) \ - field(constmethod_constants, offset, MATCH_SYMBOLS("_constants")) \ - field(constmethod_idnum, offset, MATCH_SYMBOLS("_method_idnum")) \ + field(_constmethod_constants_offset, offset, MATCH_SYMBOLS("_constants")) \ + field(_constmethod_idnum_offset, offset, MATCH_SYMBOLS("_method_idnum")) \ type_end() \ type_begin(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ - field(pool_holder, offset, MATCH_SYMBOLS("_pool_holder")) \ + field(_pool_holder_offset, offset, MATCH_SYMBOLS("_pool_holder")) \ type_end() \ type_begin(VMKlass, MATCH_SYMBOLS("Klass")) \ - field(klass_name, offset, MATCH_SYMBOLS("_name")) \ - field(class_loader_data, offset, MATCH_SYMBOLS("_class_loader_data")) \ + field(_klass_name_offset, offset, MATCH_SYMBOLS("_name")) \ + field(_class_loader_data_offset, offset, MATCH_SYMBOLS("_class_loader_data")) \ type_end() \ type_begin(VMInstanceKlass, MATCH_SYMBOLS("InstanceKlass")) \ - field(methods, offset, MATCH_SYMBOLS("_methods")) \ - field(jmethod_ids, offset, MATCH_SYMBOLS("_methods_jmethod_ids")) \ + field(_methods_offset, offset, MATCH_SYMBOLS("_methods")) \ + field(_jmethod_ids_offset, offset, MATCH_SYMBOLS("_methods_jmethod_ids")) \ type_end() \ type_begin(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) \ - field(class_loader_data_next, offset, MATCH_SYMBOLS("_next")) \ + field(_class_loader_data_next_offset, offset, MATCH_SYMBOLS("_next")) \ type_end() \ type_begin(VMJavaClass, MATCH_SYMBOLS("java_lang_Class")) \ - field(klass_offset, address, MATCH_SYMBOLS("_klass_offset")) \ + field(_klass_offset_addr, address, MATCH_SYMBOLS("_klass_offset")) \ type_end() \ type_begin(VMSymbol, MATCH_SYMBOLS("Symbol")) \ - field(symbol_length, offset, MATCH_SYMBOLS("_length")) \ - field(symbol_body, offset, MATCH_SYMBOLS("_body")) \ - field_no_check(symbol_length_and_refcount, offset, MATCH_SYMBOLS("_length_and_refcount")) \ + field(_symbol_length_offset, offset, MATCH_SYMBOLS("_length")) \ + field(_symbol_body_offset, offset, MATCH_SYMBOLS("_body")) \ + field_no_check(_symbol_length_and_refcount_offset, offset, MATCH_SYMBOLS("_length_and_refcount")) \ type_end() \ type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread", "Thread")) \ - field(thread_osthread, offset, MATCH_SYMBOLS("_osthread")) \ - field(thread_anchor, offset, MATCH_SYMBOLS("_anchor")) \ - field(thread_state, offset, MATCH_SYMBOLS("_thread_state")) \ - field(thread_vframe, offset, MATCH_SYMBOLS("_vframe_array_head")) \ + field(_thread_osthread_offset, offset, MATCH_SYMBOLS("_osthread")) \ + field(_thread_anchor_offset, offset, MATCH_SYMBOLS("_anchor")) \ + field(_thread_state_offset, offset, MATCH_SYMBOLS("_thread_state")) \ + field(_thread_vframe_offset, offset, MATCH_SYMBOLS("_vframe_array_head")) \ type_end() \ type_begin(VMOSThread, MATCH_SYMBOLS("OSThread")) \ - field(osthread_id, offset, MATCH_SYMBOLS("_thread_id")) \ - field(osthread_state, offset, MATCH_SYMBOLS("_state")) \ + field(_osthread_id_offset, offset, MATCH_SYMBOLS("_thread_id")) \ + field(_osthread_state_offset, offset, MATCH_SYMBOLS("_state")) \ type_end() \ type_begin(VMThreadShow, MATCH_SYMBOLS("ThreadShadow")) \ - field(thread_exception, offset, MATCH_SYMBOLS("_exception_file")) \ + field(_thread_exception_offset, offset, MATCH_SYMBOLS("_exception_file")) \ type_end() \ type_begin(VMCompilerThread, MATCH_SYMBOLS("CompilerThread")) \ - field(comp_env, offset, MATCH_SYMBOLS("_env")) \ + field(_comp_env_offset, offset, MATCH_SYMBOLS("_env")) \ type_end() \ type_begin(VMciEnv, MATCH_SYMBOLS("ciEnv")) \ - field(comp_task, offset, MATCH_SYMBOLS("_task")) \ + field(_comp_task_offset, offset, MATCH_SYMBOLS("_task")) \ type_end() \ type_begin(VMCompileTask, MATCH_SYMBOLS("CompileTask")) \ - field(comp_method, offset, MATCH_SYMBOLS("_method")) \ + field(_comp_method_offset, offset, MATCH_SYMBOLS("_method")) \ type_end() \ type_begin(VMJavaCallWrapper, MATCH_SYMBOLS("JavaCallWrapper")) \ - field(call_wrapper_anchor, offset, MATCH_SYMBOLS("_anchor")) \ + field(_call_wrapper_anchor_offset, offset, MATCH_SYMBOLS("_anchor")) \ type_end() \ type_begin(VMJavaFrameAnchor, MATCH_SYMBOLS("JavaFrameAnchor")) \ - field(anchor_sp, offset, MATCH_SYMBOLS("_last_Java_sp")) \ - field(anchor_pc, offset, MATCH_SYMBOLS("_last_Java_pc")) \ - field(anchor_fp, offset, MATCH_SYMBOLS("_last_Java_fp")) \ + field(_anchor_sp_offset, offset, MATCH_SYMBOLS("_last_Java_sp")) \ + field(_anchor_pc_offset, offset, MATCH_SYMBOLS("_last_Java_pc")) \ + field(_anchor_fp_offset, offset, MATCH_SYMBOLS("_last_Java_fp")) \ type_end() \ type_begin(VMCodeBlob, MATCH_SYMBOLS("CodeBlob")) \ - field(blob_size, offset, MATCH_SYMBOLS("_size")) \ - field(frame_size, offset, MATCH_SYMBOLS("_frame_size")) \ - field(frame_complete, offset, MATCH_SYMBOLS("_frame_complete_offset")) \ - field(code, offset, MATCH_SYMBOLS("_code_offset", "_code_begin")) \ - field(data, offset, MATCH_SYMBOLS("_data_offset")) \ - field_no_check(mutable_data, offset, MATCH_SYMBOLS("_mutable_data")) \ - field_no_check(relocation_size, offset, MATCH_SYMBOLS("_relocation_size")) \ - field(nmethod_name, offset, MATCH_SYMBOLS("_name")) \ + field(_blob_size_offset, offset, MATCH_SYMBOLS("_size")) \ + field(_frame_size_offset, offset, MATCH_SYMBOLS("_frame_size")) \ + field(_frame_complete_offset, offset, MATCH_SYMBOLS("_frame_complete_offset")) \ + field(_code_offset, offset, MATCH_SYMBOLS("_code_offset", "_code_begin")) \ + field(_data_offset, offset, MATCH_SYMBOLS("_data_offset")) \ + field_no_check(_mutable_data_offset, offset, MATCH_SYMBOLS("_mutable_data")) \ + field_no_check(_relocation_size_offset, offset, MATCH_SYMBOLS("_relocation_size")) \ + field(_nmethod_name_offset, offset, MATCH_SYMBOLS("_name")) \ type_end() \ type_begin(VMCodeCache, MATCH_SYMBOLS("CodeCache")) \ - field(code_heap, address, MATCH_SYMBOLS("_heap", "_heaps")) \ - field(code_heap_low, address, MATCH_SYMBOLS("_low_bound")) \ - field(code_heap_high, address, MATCH_SYMBOLS("_high_bound")) \ + field(_code_heap_addr, address, MATCH_SYMBOLS("_heap", "_heaps")) \ + field(_code_heap_low_addr, address, MATCH_SYMBOLS("_low_bound")) \ + field(_code_heap_high_addr, address, MATCH_SYMBOLS("_high_bound")) \ type_end() \ type_begin(VMCodeHeap, MATCH_SYMBOLS("CodeHeap")) \ - field(code_heap_memory, offset, MATCH_SYMBOLS("_memory")) \ - field(code_heap_segmap, offset, MATCH_SYMBOLS("_segmap")) \ - field(code_heap_segment_shift, off_value, MATCH_SYMBOLS("_log2_segment_size")) \ + field(_code_heap_memory_offset, offset, MATCH_SYMBOLS("_memory")) \ + field(_code_heap_segmap_offset, offset, MATCH_SYMBOLS("_segmap")) \ + field(_code_heap_segment_shift, off_value, MATCH_SYMBOLS("_log2_segment_size")) \ type_end() \ type_begin(VMHeapBlock, MATCH_SYMBOLS("HeapBlock::Header")) \ - field(heap_block_used, offset, MATCH_SYMBOLS("_used")) \ + field(_heap_block_used_offset, offset, MATCH_SYMBOLS("_used")) \ type_end() \ type_begin(VMVirtualSpace, MATCH_SYMBOLS("VirtualSpace")) \ - field(vs_low_bound, offset, MATCH_SYMBOLS("_low_boundary")) \ - field(vs_high_bound, offset, MATCH_SYMBOLS("_high_boundary")) \ - field(vs_low, offset, MATCH_SYMBOLS("_low")) \ - field(vs_high, offset, MATCH_SYMBOLS("_high")) \ + field(_vs_low_bound_offset, offset, MATCH_SYMBOLS("_low_boundary")) \ + field(_vs_high_bound_offset, offset, MATCH_SYMBOLS("_high_boundary")) \ + field(_vs_low_offset, offset, MATCH_SYMBOLS("_low")) \ + field(_vs_high_offset, offset, MATCH_SYMBOLS("_high")) \ type_end() \ type_begin(VMStubRoutine, MATCH_SYMBOLS("StubRoutines")) \ - field(call_stub_return, address, MATCH_SYMBOLS("_call_stub_return_address")) \ + field(_call_stub_return_addr, address, MATCH_SYMBOLS("_call_stub_return_address")) \ type_end() \ type_begin(VMGrowableArray, MATCH_SYMBOLS("GrowableArrayBase", "GenericGrowableArray")) \ - field(array_len, offset, MATCH_SYMBOLS("_len")) \ + field(_array_len_offset, offset, MATCH_SYMBOLS("_len")) \ type_end() \ type_begin(VMGrowableArrayInt, MATCH_SYMBOLS("GrowableArray")) \ - field(array_data, offset, MATCH_SYMBOLS("_data")) \ + field(_array_data_offset, offset, MATCH_SYMBOLS("_data")) \ type_end() \ type_begin(VMFlag, MATCH_SYMBOLS("JVMFlag", "Flag")) \ - field(flag_name, offset, MATCH_SYMBOLS("_name", "name")) \ - field(flag_addr, offset, MATCH_SYMBOLS("_addr", "addr")) \ - field(flag_origin, offset, MATCH_SYMBOLS("_flags", "origin")) \ - field(flags, address, MATCH_SYMBOLS("flags")) \ - field(flag_count, addr_value, MATCH_SYMBOLS("numFlags")) \ - field(flag_type, offset, MATCH_SYMBOLS("_type", "type")) \ + field(_flag_name_offset, offset, MATCH_SYMBOLS("_name", "name")) \ + field(_flag_addr_offset, offset, MATCH_SYMBOLS("_addr", "addr")) \ + field(_flag_origin_offset, offset, MATCH_SYMBOLS("_flags", "origin")) \ + field(_flags_addr, address, MATCH_SYMBOLS("flags")) \ + field(_flag_count, addr_value, MATCH_SYMBOLS("numFlags")) \ + field(_flag_type_offset, offset, MATCH_SYMBOLS("_type", "type")) \ type_end() \ type_begin(VMOop, MATCH_SYMBOLS("oopDesc")) \ - field(oop_klass, offset, MATCH_SYMBOLS("_metadata._klass")) \ + field(_oop_klass_offset, offset, MATCH_SYMBOLS("_metadata._klass")) \ type_end() \ type_begin(VMUniverse, MATCH_SYMBOLS("Universe", "CompressedKlassPointers")) \ - field(narrow_klass_base, address, MATCH_SYMBOLS("_narrow_klass._base", "_base")) \ - field(narrow_klass_shift, address, MATCH_SYMBOLS("_narrow_klass._shift", "_shift")) \ - field(collected_heap, address, MATCH_SYMBOLS("_collectedHeap")) \ + field(_narrow_klass_base_addr, address, MATCH_SYMBOLS("_narrow_klass._base", "_base")) \ + field(_narrow_klass_shift_addr, address, MATCH_SYMBOLS("_narrow_klass._shift", "_shift")) \ + field(_collected_heap_addr, address, MATCH_SYMBOLS("_collectedHeap")) \ type_end() /** @@ -310,8 +310,8 @@ class VMStructs { // Do nothing macro #define DO_NOTHING(...) -#define DECLARE_TYPE_FIELD(field, field_type, names) \ - static field_type _##field##_##field_type; +#define DECLARE_TYPE_FIELD(var, field_type, names) \ + static field_type var; DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DECLARE_TYPE_FIELD, DO_NOTHING) #undef DECLARE_TYPE_FIELD @@ -913,7 +913,7 @@ class CodeHeap : VMStructs { public: static bool available() { - return _code_heap_address != nullptr; + return _code_heap_addr != nullptr; } static bool contains(const void* pc) { From bce49bce644277624f6874f459c23bccc13b9898 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 18 Feb 2026 19:30:32 +0000 Subject: [PATCH 14/23] v11 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 2 +- ddprof-lib/src/main/cpp/vmStructs.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index fce223952..dea06175e 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -398,7 +398,7 @@ void VMStructs::resolveOffsets() { // Since JDK-8268406, it is no longer possible to get VMMethod* by dereferencing jmethodID _can_dereference_jmethod_id = _has_method_structs && VM::hotspot_version() <= 25; - if (_code_heap_addr != nullptr && _code_heap_low_addr != nullptr && _code_heap_high_addr != nullptr) { + if (_code_heap_addr != NULL && _code_heap_low_addr != NULL && _code_heap_high_addr != NULL) { char* code_heaps = *(char**)_code_heap_addr; unsigned int code_heap_count = *(unsigned int*)(code_heaps + _array_len_offset); if (code_heap_count <= 3 && _array_data_offset >= 0) { diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index c43103b9e..b5f1d0d2e 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -120,7 +120,7 @@ inline T* cast_to(const void* ptr) { */ typedef int offset; -typedef const unsigned char** address; +typedef char** address; // int value from an offset typedef int off_value; @@ -220,7 +220,7 @@ typedef int addr_value; type_begin(VMCodeHeap, MATCH_SYMBOLS("CodeHeap")) \ field(_code_heap_memory_offset, offset, MATCH_SYMBOLS("_memory")) \ field(_code_heap_segmap_offset, offset, MATCH_SYMBOLS("_segmap")) \ - field(_code_heap_segment_shift, off_value, MATCH_SYMBOLS("_log2_segment_size")) \ + field(_code_heap_segment_shift, offset, MATCH_SYMBOLS("_log2_segment_size")) \ type_end() \ type_begin(VMHeapBlock, MATCH_SYMBOLS("HeapBlock::Header")) \ field(_heap_block_used_offset, offset, MATCH_SYMBOLS("_used")) \ @@ -288,13 +288,13 @@ class VMStructs { static bool _compact_object_headers; static int _narrow_klass_shift; + static char* _code_heap[3]; static const void* _code_heap_low; static const void* _code_heap_high; static char* _narrow_klass_base; - static const void* _call_stub_return; - static char* _code_heap[3]; static int _interpreter_frame_bcp_offset; static unsigned char _unsigned5_base; + static const void* _call_stub_return; static const void* _interpreted_frame_valid_start; static const void* _interpreted_frame_valid_end; @@ -913,7 +913,7 @@ class CodeHeap : VMStructs { public: static bool available() { - return _code_heap_addr != nullptr; + return _code_heap_addr != NULL; } static bool contains(const void* pc) { From 1f0a436c4bf07158ddecaa57410b9a98fc3f5959 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 18 Feb 2026 23:11:33 +0000 Subject: [PATCH 15/23] v11 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 38 +++++++++++---------------- ddprof-lib/src/main/cpp/vmStructs.h | 9 ++----- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index dea06175e..2a7169b0f 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -44,14 +44,10 @@ DECLARE_TYPES_DO(INIT_TYPE_SIZE) #define offset_value -1 #define address_value nullptr -#define off_value_value -1 -#define addr_value_value -1 // Initialize field variables // offset = -1 // address = nullptr -// off_value = -1 int value from an offset -// addr_value = -1 int value from an address // Do nothing macro #define DO_NOTHING(...) @@ -64,8 +60,6 @@ DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, INIT_OFFSET_OR_ADDRESS #undef DO_NOTHING #undef offset_value #undef address_value -#undef off_value_value -#undef addr_value_value // Initialize constant variables to -1 #define INIT_INT_CONSTANT(type, field) \ @@ -139,28 +133,26 @@ void VMStructs::init_offsets_and_addresses() { uintptr_t type_offset = readSymbol("gHotSpotVMStructEntryTypeNameOffset"); uintptr_t field_offset = readSymbol("gHotSpotVMStructEntryFieldNameOffset"); uintptr_t offset_offset = readSymbol("gHotSpotVMStructEntryOffsetOffset"); + uintptr_t isStatic_offset = readSymbol("gHotSpotVMStructEntryIsStaticOffset"); uintptr_t address_offset = readSymbol("gHotSpotVMStructEntryAddressOffset"); + bool isStatic; auto read_offset = [&]() -> int { + assert(!isStatic); return *(int*)(entry + offset_offset); }; auto read_address = [&]() -> address { + assert(isStatic); return *(address*)(entry + address_offset); }; - auto read_addr_value = [&]() -> int { - return **(int**)(entry + address_offset); - }; - - auto read_off_value = [&]() -> int { - return *(int*)(entry + offset_offset); - }; - if (entry != 0 && stride != 0) { for (;; entry += stride) { const char* type_name = *(const char**)(entry + type_offset); const char* field_name = *(const char**)(entry + field_offset); + isStatic = *(int32_t*)(entry + isStatic_offset) != 0; + if (type_name == nullptr || field_name == nullptr) { break; } @@ -209,7 +201,6 @@ void VMStructs::init_type_sizes() { } } - #define READ_CONSTANT(type, field) \ if (strcmp(type_name, #type "::" #field) == 0) { \ _##type##_##field = value; \ @@ -747,8 +738,10 @@ int ScopeDesc::readInt() { VMFlag* VMFlag::find(const char* name) { if (_flags_addr != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count; i++) { - VMFlag* f = VMFlag::cast(*_flags_addr + i * VMFlag::type_size()); + size_t count = *(size_t*)_flag_count; + + for (size_t i = 0; i < count; i++) { + VMFlag* f = VMFlag::cast(*(const char**)_flags_addr + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0 && f->addr() != NULL) { return f; } @@ -767,8 +760,9 @@ VMFlag *VMFlag::find(const char *name, std::initializer_list types VMFlag *VMFlag::find(const char *name, int type_mask) { if (_flags_addr != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count; i++) { - VMFlag* f = VMFlag::cast(*_flags_addr + i * VMFlag::type_size()); + size_t count = *(size_t*)_flag_count; + for (size_t i = 0; i < count; i++) { + VMFlag* f = VMFlag::cast(*(const char**)_flags_addr + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0) { int masked = 0x1 << f->type(); if (masked & type_mask) { @@ -1020,13 +1014,13 @@ HeapUsage HeapUsage::get(bool allow_jmx) { if (_collected_heap_addr != NULL) { if (_heap_usage_func != NULL) { // this is the JDK 17+ path - usage = _heap_usage_func(*_collected_heap_addr); + usage = _heap_usage_func(*(char**)_collected_heap_addr); usage._used_at_last_gc = - ((CollectedHeapWrapper *)*_collected_heap_addr)->_used_at_last_gc; + ((CollectedHeapWrapper *)*(char**)_collected_heap_addr)->_used_at_last_gc; } else if (_gc_heap_summary_func != NULL) { // this is the JDK 11 path // we need to collect GCHeapSummary information first - GCHeapSummary summary = _gc_heap_summary_func(*(void**)_collected_heap_addr); + GCHeapSummary summary = _gc_heap_summary_func(*(char**)_collected_heap_addr); usage._initSize = -1; usage._used = summary.used(); usage._committed = -1; diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index b5f1d0d2e..4aabd1d96 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -120,12 +120,7 @@ inline T* cast_to(const void* ptr) { */ typedef int offset; -typedef char** address; - -// int value from an offset -typedef int off_value; -// int value from an address -typedef int addr_value; +typedef void* address; #define DECLARE_TYPE_FILED_DO(type_begin, field, field_no_check, type_end) \ type_begin(VMMemRegion, MATCH_SYMBOLS("MemRegion")) \ @@ -245,7 +240,7 @@ typedef int addr_value; field(_flag_addr_offset, offset, MATCH_SYMBOLS("_addr", "addr")) \ field(_flag_origin_offset, offset, MATCH_SYMBOLS("_flags", "origin")) \ field(_flags_addr, address, MATCH_SYMBOLS("flags")) \ - field(_flag_count, addr_value, MATCH_SYMBOLS("numFlags")) \ + field(_flag_count, address, MATCH_SYMBOLS("numFlags")) \ field(_flag_type_offset, offset, MATCH_SYMBOLS("_type", "type")) \ type_end() \ type_begin(VMOop, MATCH_SYMBOLS("oopDesc")) \ From 3a8b403db3618557870f52ab731dc355005329f2 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Thu, 19 Feb 2026 01:07:45 +0000 Subject: [PATCH 16/23] v12 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 2a7169b0f..4d834355f 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -170,6 +170,17 @@ void VMStructs::init_offsets_and_addresses() { #undef END_TYPE } } + + // Special cases + // JDK23 + // CodeBlob::_code_begin -> CodeBlob::_code_offset + // CodeBlob::_code_begin -> CodeBlob::_code_offset + // nmethod::_verified_entry_point -> nmethod::_verified_entry_offset + if (VM::hotspot_version() < 23) { + _code_offset = - _code_offset; + _scopes_data_offset = - _scopes_data_offset; + _nmethod_entry_offset = - _nmethod_entry_offset; + } } void VMStructs::init_type_sizes() { From dbaf3a5f5ae1606ccaeeabd5c23a44e4fb48f33b Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Thu, 19 Feb 2026 01:43:57 +0000 Subject: [PATCH 17/23] Disable verifier --- ddprof-lib/src/main/cpp/vmStructs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 4d834355f..062ae5b4b 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -307,7 +307,7 @@ void VMStructs::initOffsets() { #ifdef DEBUG - verify_offsets(); +// verify_offsets(); #endif } From ba7840952224688cc98d953174cbb7ba30f2ad46 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Thu, 19 Feb 2026 14:18:07 +0000 Subject: [PATCH 18/23] v13 --- ddprof-lib/src/main/cpp/vmStructs.cpp | 17 +-- ddprof-lib/src/main/cpp/vmStructs.h | 159 +++++++++++++------------- 2 files changed, 83 insertions(+), 93 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 062ae5b4b..0aeb87bee 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -170,17 +170,6 @@ void VMStructs::init_offsets_and_addresses() { #undef END_TYPE } } - - // Special cases - // JDK23 - // CodeBlob::_code_begin -> CodeBlob::_code_offset - // CodeBlob::_code_begin -> CodeBlob::_code_offset - // nmethod::_verified_entry_point -> nmethod::_verified_entry_offset - if (VM::hotspot_version() < 23) { - _code_offset = - _code_offset; - _scopes_data_offset = - _scopes_data_offset; - _nmethod_entry_offset = - _nmethod_entry_offset; - } } void VMStructs::init_type_sizes() { @@ -340,7 +329,7 @@ void VMStructs::resolveOffsets() { _has_method_structs = _jmethod_ids_offset >= 0 && _nmethod_method_offset >= 0 - && _nmethod_entry_offset != -1 + && (_nmethod_entry_offset != -1 || _nmethod_entry_address != -1) && _nmethod_state_offset >= 0 && _method_constmethod_offset >= 0 && _method_code_offset >= 0 @@ -388,9 +377,9 @@ void VMStructs::resolveOffsets() { && _call_wrapper_anchor_offset >= 0 && _frame_entry_frame_call_wrapper_offset != -1 && _interpreter_frame_bcp_offset != 0 - && _code_offset != -1 + && (_code_offset != -1 || _code_address != -1) && _data_offset >= 0 - && _scopes_data_offset != -1 + && (_scopes_data_offset != -1 || _scopes_data_address != -1) && _scopes_pcs_offset >= 0 && ((_mutable_data_offset >= 0 && _relocation_size_offset >= 0) || _nmethod_metadata_offset >= 0) && _thread_vframe_offset >= 0 diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 4aabd1d96..6f0bc2365 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -124,132 +124,133 @@ typedef void* address; #define DECLARE_TYPE_FILED_DO(type_begin, field, field_no_check, type_end) \ type_begin(VMMemRegion, MATCH_SYMBOLS("MemRegion")) \ - field(_region_start_offset, offset, MATCH_SYMBOLS("_start")) \ - field(_region_size_offset, offset, MATCH_SYMBOLS("_word_size")) \ + field(_region_start_offset, offset, MATCH_SYMBOLS("_start")) \ + field(_region_size_offset, offset, MATCH_SYMBOLS("_word_size")) \ type_end() \ type_begin(VMNMethod, MATCH_SYMBOLS("CompiledMethod", "nmethod")) \ - field(_nmethod_method_offset, offset, MATCH_SYMBOLS("_method")) \ - field(_nmethod_entry_offset, offset, MATCH_SYMBOLS("_verified_entry_offset", "_verified_entry_point")) \ - field(_nmethod_state_offset, offset, MATCH_SYMBOLS("_state")) \ - field(_nmethod_level_offset, offset, MATCH_SYMBOLS("_comp_level")) \ - field(_nmethod_metadata_offset, offset, MATCH_SYMBOLS("_metadata_offset")) \ - field_no_check(_nmethod_immutable_offset, offset, MATCH_SYMBOLS("_immutable_data")) \ - field(_scopes_pcs_offset, offset, MATCH_SYMBOLS("_scopes_pcs_offset")) \ - field(_scopes_data_offset, offset, MATCH_SYMBOLS("_scopes_data_offset", "_scopes_data_begin")) \ + field(_nmethod_method_offset, offset, MATCH_SYMBOLS("_method")) \ + field(_nmethod_entry_offset, offset, MATCH_SYMBOLS("_verified_entry_offset")) \ + field(_nmethod_entry_address, offset, MATCH_SYMBOLS("_verified_entry_point")) \ + field(_nmethod_state_offset, offset, MATCH_SYMBOLS("_state")) \ + field(_nmethod_level_offset, offset, MATCH_SYMBOLS("_comp_level")) \ + field(_nmethod_metadata_offset, offset, MATCH_SYMBOLS("_metadata_offset")) \ + field_no_check(_nmethod_immutable_offset, offset, MATCH_SYMBOLS("_immutable_data")) \ + field(_scopes_pcs_offset, offset, MATCH_SYMBOLS("_scopes_pcs_offset")) \ + field(_scopes_data_offset, offset, MATCH_SYMBOLS("_scopes_data_offset")) \ + field(_scopes_data_address, offset, MATCH_SYMBOLS("_scopes_data_begin")) \ type_end() \ type_begin(VMMethod, MATCH_SYMBOLS("Method")) \ - field(_method_constmethod_offset, offset, MATCH_SYMBOLS("_constMethod")) \ - field(_method_code_offset, offset, MATCH_SYMBOLS("_code")) \ + field(_method_constmethod_offset, offset, MATCH_SYMBOLS("_constMethod")) \ + field(_method_code_offset, offset, MATCH_SYMBOLS("_code")) \ type_end() \ type_begin(VMConstMethod, MATCH_SYMBOLS("ConstMethod")) \ - field(_constmethod_constants_offset, offset, MATCH_SYMBOLS("_constants")) \ - field(_constmethod_idnum_offset, offset, MATCH_SYMBOLS("_method_idnum")) \ + field(_constmethod_constants_offset, offset, MATCH_SYMBOLS("_constants")) \ + field(_constmethod_idnum_offset, offset, MATCH_SYMBOLS("_method_idnum")) \ type_end() \ type_begin(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ - field(_pool_holder_offset, offset, MATCH_SYMBOLS("_pool_holder")) \ + field(_pool_holder_offset, offset, MATCH_SYMBOLS("_pool_holder")) \ type_end() \ - type_begin(VMKlass, MATCH_SYMBOLS("Klass")) \ - field(_klass_name_offset, offset, MATCH_SYMBOLS("_name")) \ - field(_class_loader_data_offset, offset, MATCH_SYMBOLS("_class_loader_data")) \ - type_end() \ - type_begin(VMInstanceKlass, MATCH_SYMBOLS("InstanceKlass")) \ - field(_methods_offset, offset, MATCH_SYMBOLS("_methods")) \ - field(_jmethod_ids_offset, offset, MATCH_SYMBOLS("_methods_jmethod_ids")) \ + type_begin(VMKlass, MATCH_SYMBOLS("Klass", "InstanceKlass")) \ + field(_klass_name_offset, offset, MATCH_SYMBOLS("_name")) \ + field(_class_loader_data_offset, offset, MATCH_SYMBOLS("_class_loader_data")) \ + field(_methods_offset, offset, MATCH_SYMBOLS("_methods")) \ + field(_jmethod_ids_offset, offset, MATCH_SYMBOLS("_methods_jmethod_ids")) \ type_end() \ type_begin(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) \ - field(_class_loader_data_next_offset, offset, MATCH_SYMBOLS("_next")) \ + field(_class_loader_data_next_offset, offset, MATCH_SYMBOLS("_next")) \ type_end() \ type_begin(VMJavaClass, MATCH_SYMBOLS("java_lang_Class")) \ - field(_klass_offset_addr, address, MATCH_SYMBOLS("_klass_offset")) \ + field(_klass_offset_addr, address, MATCH_SYMBOLS("_klass_offset")) \ type_end() \ type_begin(VMSymbol, MATCH_SYMBOLS("Symbol")) \ - field(_symbol_length_offset, offset, MATCH_SYMBOLS("_length")) \ - field(_symbol_body_offset, offset, MATCH_SYMBOLS("_body")) \ - field_no_check(_symbol_length_and_refcount_offset, offset, MATCH_SYMBOLS("_length_and_refcount")) \ + field(_symbol_length_offset, offset, MATCH_SYMBOLS("_length")) \ + field(_symbol_body_offset, offset, MATCH_SYMBOLS("_body")) \ + field_no_check(_symbol_length_and_refcount_offset, offset, MATCH_SYMBOLS("_length_and_refcount")) \ type_end() \ type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread", "Thread")) \ - field(_thread_osthread_offset, offset, MATCH_SYMBOLS("_osthread")) \ - field(_thread_anchor_offset, offset, MATCH_SYMBOLS("_anchor")) \ - field(_thread_state_offset, offset, MATCH_SYMBOLS("_thread_state")) \ - field(_thread_vframe_offset, offset, MATCH_SYMBOLS("_vframe_array_head")) \ + field(_thread_osthread_offset, offset, MATCH_SYMBOLS("_osthread")) \ + field(_thread_anchor_offset, offset, MATCH_SYMBOLS("_anchor")) \ + field(_thread_state_offset, offset, MATCH_SYMBOLS("_thread_state")) \ + field(_thread_vframe_offset, offset, MATCH_SYMBOLS("_vframe_array_head")) \ type_end() \ type_begin(VMOSThread, MATCH_SYMBOLS("OSThread")) \ - field(_osthread_id_offset, offset, MATCH_SYMBOLS("_thread_id")) \ - field(_osthread_state_offset, offset, MATCH_SYMBOLS("_state")) \ + field(_osthread_id_offset, offset, MATCH_SYMBOLS("_thread_id")) \ + field(_osthread_state_offset, offset, MATCH_SYMBOLS("_state")) \ type_end() \ type_begin(VMThreadShow, MATCH_SYMBOLS("ThreadShadow")) \ - field(_thread_exception_offset, offset, MATCH_SYMBOLS("_exception_file")) \ + field(_thread_exception_offset, offset, MATCH_SYMBOLS("_exception_file")) \ type_end() \ type_begin(VMCompilerThread, MATCH_SYMBOLS("CompilerThread")) \ - field(_comp_env_offset, offset, MATCH_SYMBOLS("_env")) \ + field(_comp_env_offset, offset, MATCH_SYMBOLS("_env")) \ type_end() \ type_begin(VMciEnv, MATCH_SYMBOLS("ciEnv")) \ - field(_comp_task_offset, offset, MATCH_SYMBOLS("_task")) \ + field(_comp_task_offset, offset, MATCH_SYMBOLS("_task")) \ type_end() \ type_begin(VMCompileTask, MATCH_SYMBOLS("CompileTask")) \ - field(_comp_method_offset, offset, MATCH_SYMBOLS("_method")) \ + field(_comp_method_offset, offset, MATCH_SYMBOLS("_method")) \ type_end() \ type_begin(VMJavaCallWrapper, MATCH_SYMBOLS("JavaCallWrapper")) \ - field(_call_wrapper_anchor_offset, offset, MATCH_SYMBOLS("_anchor")) \ + field(_call_wrapper_anchor_offset, offset, MATCH_SYMBOLS("_anchor")) \ type_end() \ type_begin(VMJavaFrameAnchor, MATCH_SYMBOLS("JavaFrameAnchor")) \ - field(_anchor_sp_offset, offset, MATCH_SYMBOLS("_last_Java_sp")) \ - field(_anchor_pc_offset, offset, MATCH_SYMBOLS("_last_Java_pc")) \ - field(_anchor_fp_offset, offset, MATCH_SYMBOLS("_last_Java_fp")) \ + field(_anchor_sp_offset, offset, MATCH_SYMBOLS("_last_Java_sp")) \ + field(_anchor_pc_offset, offset, MATCH_SYMBOLS("_last_Java_pc")) \ + field(_anchor_fp_offset, offset, MATCH_SYMBOLS("_last_Java_fp")) \ type_end() \ type_begin(VMCodeBlob, MATCH_SYMBOLS("CodeBlob")) \ - field(_blob_size_offset, offset, MATCH_SYMBOLS("_size")) \ - field(_frame_size_offset, offset, MATCH_SYMBOLS("_frame_size")) \ - field(_frame_complete_offset, offset, MATCH_SYMBOLS("_frame_complete_offset")) \ - field(_code_offset, offset, MATCH_SYMBOLS("_code_offset", "_code_begin")) \ - field(_data_offset, offset, MATCH_SYMBOLS("_data_offset")) \ - field_no_check(_mutable_data_offset, offset, MATCH_SYMBOLS("_mutable_data")) \ - field_no_check(_relocation_size_offset, offset, MATCH_SYMBOLS("_relocation_size")) \ - field(_nmethod_name_offset, offset, MATCH_SYMBOLS("_name")) \ + field(_blob_size_offset, offset, MATCH_SYMBOLS("_size")) \ + field(_frame_size_offset, offset, MATCH_SYMBOLS("_frame_size")) \ + field(_frame_complete_offset, offset, MATCH_SYMBOLS("_frame_complete_offset")) \ + field(_code_offset, offset, MATCH_SYMBOLS("_code_offset")) \ + field(_code_address, offset, MATCH_SYMBOLS("_code_begin")) \ + field(_data_offset, offset, MATCH_SYMBOLS("_data_offset")) \ + field_no_check(_mutable_data_offset, offset, MATCH_SYMBOLS("_mutable_data")) \ + field_no_check(_relocation_size_offset, offset, MATCH_SYMBOLS("_relocation_size")) \ + field(_nmethod_name_offset, offset, MATCH_SYMBOLS("_name")) \ type_end() \ type_begin(VMCodeCache, MATCH_SYMBOLS("CodeCache")) \ - field(_code_heap_addr, address, MATCH_SYMBOLS("_heap", "_heaps")) \ - field(_code_heap_low_addr, address, MATCH_SYMBOLS("_low_bound")) \ - field(_code_heap_high_addr, address, MATCH_SYMBOLS("_high_bound")) \ + field(_code_heap_addr, address, MATCH_SYMBOLS("_heap", "_heaps")) \ + field(_code_heap_low_addr, address, MATCH_SYMBOLS("_low_bound")) \ + field(_code_heap_high_addr, address, MATCH_SYMBOLS("_high_bound")) \ type_end() \ type_begin(VMCodeHeap, MATCH_SYMBOLS("CodeHeap")) \ - field(_code_heap_memory_offset, offset, MATCH_SYMBOLS("_memory")) \ - field(_code_heap_segmap_offset, offset, MATCH_SYMBOLS("_segmap")) \ - field(_code_heap_segment_shift, offset, MATCH_SYMBOLS("_log2_segment_size")) \ + field(_code_heap_memory_offset, offset, MATCH_SYMBOLS("_memory")) \ + field(_code_heap_segmap_offset, offset, MATCH_SYMBOLS("_segmap")) \ + field(_code_heap_segment_shift, offset, MATCH_SYMBOLS("_log2_segment_size")) \ type_end() \ type_begin(VMHeapBlock, MATCH_SYMBOLS("HeapBlock::Header")) \ - field(_heap_block_used_offset, offset, MATCH_SYMBOLS("_used")) \ + field(_heap_block_used_offset, offset, MATCH_SYMBOLS("_used")) \ type_end() \ type_begin(VMVirtualSpace, MATCH_SYMBOLS("VirtualSpace")) \ - field(_vs_low_bound_offset, offset, MATCH_SYMBOLS("_low_boundary")) \ - field(_vs_high_bound_offset, offset, MATCH_SYMBOLS("_high_boundary")) \ - field(_vs_low_offset, offset, MATCH_SYMBOLS("_low")) \ - field(_vs_high_offset, offset, MATCH_SYMBOLS("_high")) \ + field(_vs_low_bound_offset, offset, MATCH_SYMBOLS("_low_boundary")) \ + field(_vs_high_bound_offset, offset, MATCH_SYMBOLS("_high_boundary")) \ + field(_vs_low_offset, offset, MATCH_SYMBOLS("_low")) \ + field(_vs_high_offset, offset, MATCH_SYMBOLS("_high")) \ type_end() \ type_begin(VMStubRoutine, MATCH_SYMBOLS("StubRoutines")) \ - field(_call_stub_return_addr, address, MATCH_SYMBOLS("_call_stub_return_address")) \ + field(_call_stub_return_addr, address, MATCH_SYMBOLS("_call_stub_return_address")) \ type_end() \ type_begin(VMGrowableArray, MATCH_SYMBOLS("GrowableArrayBase", "GenericGrowableArray")) \ - field(_array_len_offset, offset, MATCH_SYMBOLS("_len")) \ + field(_array_len_offset, offset, MATCH_SYMBOLS("_len")) \ type_end() \ type_begin(VMGrowableArrayInt, MATCH_SYMBOLS("GrowableArray")) \ - field(_array_data_offset, offset, MATCH_SYMBOLS("_data")) \ + field(_array_data_offset, offset, MATCH_SYMBOLS("_data")) \ type_end() \ type_begin(VMFlag, MATCH_SYMBOLS("JVMFlag", "Flag")) \ - field(_flag_name_offset, offset, MATCH_SYMBOLS("_name", "name")) \ - field(_flag_addr_offset, offset, MATCH_SYMBOLS("_addr", "addr")) \ - field(_flag_origin_offset, offset, MATCH_SYMBOLS("_flags", "origin")) \ - field(_flags_addr, address, MATCH_SYMBOLS("flags")) \ - field(_flag_count, address, MATCH_SYMBOLS("numFlags")) \ - field(_flag_type_offset, offset, MATCH_SYMBOLS("_type", "type")) \ + field(_flag_name_offset, offset, MATCH_SYMBOLS("_name", "name")) \ + field(_flag_addr_offset, offset, MATCH_SYMBOLS("_addr", "addr")) \ + field(_flag_origin_offset, offset, MATCH_SYMBOLS("_flags", "origin")) \ + field(_flags_addr, address, MATCH_SYMBOLS("flags")) \ + field(_flag_count, address, MATCH_SYMBOLS("numFlags")) \ + field(_flag_type_offset, offset, MATCH_SYMBOLS("_type", "type")) \ type_end() \ type_begin(VMOop, MATCH_SYMBOLS("oopDesc")) \ - field(_oop_klass_offset, offset, MATCH_SYMBOLS("_metadata._klass")) \ + field(_oop_klass_offset, offset, MATCH_SYMBOLS("_metadata._klass")) \ type_end() \ type_begin(VMUniverse, MATCH_SYMBOLS("Universe", "CompressedKlassPointers")) \ - field(_narrow_klass_base_addr, address, MATCH_SYMBOLS("_narrow_klass._base", "_base")) \ - field(_narrow_klass_shift_addr, address, MATCH_SYMBOLS("_narrow_klass._shift", "_shift")) \ - field(_collected_heap_addr, address, MATCH_SYMBOLS("_collectedHeap")) \ + field(_narrow_klass_base_addr, address, MATCH_SYMBOLS("_narrow_klass._base", "_base")) \ + field(_narrow_klass_shift_addr, address, MATCH_SYMBOLS("_narrow_klass._shift", "_shift")) \ + field(_collected_heap_addr, address, MATCH_SYMBOLS("_collectedHeap")) \ type_end() /** @@ -801,26 +802,26 @@ DECLARE(VMNMethod) } const char* code() { - if (_code_offset > 0) { + if (_code_offset != -1) { // JDK23+ return at(*(int*) at(_code_offset)); } else { - return *(const char**) at(-_code_offset); + return *(const char**) at(_code_address); } } const char* scopes() { - if (_scopes_data_offset > 0) { + if (_scopes_data_offset != -1) { // JDK23+ return immutableDataAt(*(int*) at(_scopes_data_offset)); } else { - return *(const char**) at(-_scopes_data_offset); + return *(const char**) at(_scopes_data_address); } } const void* entry() { - if (_nmethod_entry_offset > 0) { + if (_nmethod_entry_offset != -1) { // JDK23+ return at(*(int*) at(_code_offset) + *(unsigned short*) at(_nmethod_entry_offset)); } else { - return *(void**) at(-_nmethod_entry_offset); + return *(void**) at(_nmethod_entry_address); } } From 680548cb65a0ec1b90c73c8056ce98dfc13f1852 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Thu, 19 Feb 2026 20:19:42 +0000 Subject: [PATCH 19/23] Enable verifier --- ddprof-lib/src/main/cpp/vmStructs.cpp | 49 ++++++++++++++-------- ddprof-lib/src/main/cpp/vmStructs.h | 60 ++++++++++++++------------- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 0aeb87bee..0af0e49fb 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -51,20 +51,24 @@ DECLARE_TYPES_DO(INIT_TYPE_SIZE) // Do nothing macro #define DO_NOTHING(...) -#define INIT_OFFSET_OR_ADDRESS(var, field_type, names) \ +#define INIT_FILED(var, field_type, names) \ field_type VMStructs::var = field_type##_value; -DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) +#define INIT_FILED_WITH_VERSION(var, field_type, min_version, max_version, names) \ + field_type VMStructs::var = field_type##_value; + +DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_FILED, INIT_FILED_WITH_VERSION, DO_NOTHING) -#undef INIT_OFFSET_OR_ADDRESS +#undef INIT_FILED +#undef INIT_FILED_WITH_VERSION #undef DO_NOTHING #undef offset_value #undef address_value // Initialize constant variables to -1 -#define INIT_INT_CONSTANT(type, field) \ +#define INIT_INT_CONSTANT(type, field) \ int VMStructs::_##type##_##field = -1; -#define INIT_LONG_CONSTANT(type, field) \ +#define INIT_LONG_CONSTANT(type, field) \ long VMStructs::_##type##_##field = -1; DECLARE_INT_CONSTANTS_DO(INIT_INT_CONSTANT) @@ -163,10 +167,17 @@ void VMStructs::init_offsets_and_addresses() { var = read_##field_type(); \ continue; \ } +#define READ_FIELD_VALUE_WITH_VERSION(var, field_type, min_version, max_version, field_names) \ + if (matchAny(field_name, field_names)) { \ + var = read_##field_type(); \ + continue; \ + } + #define END_TYPE() continue; } - DECLARE_TYPE_FILED_DO(MATCH_TYPE_NAMES, READ_FIELD_VALUE, READ_FIELD_VALUE, END_TYPE) + DECLARE_TYPE_FILED_DO(MATCH_TYPE_NAMES, READ_FIELD_VALUE, READ_FIELD_VALUE_WITH_VERSION, END_TYPE) #undef MATCH_TYPE_NAMES #undef READ_FIELD_VALUE +#undef READ_FIELD_VALUE_WITH_VERSION #undef END_TYPE } } @@ -187,10 +198,10 @@ void VMStructs::init_type_sizes() { uint64_t size = *(uint64_t*)(entry + size_offset); - #define READ_TYPE_SIZE(name, names) \ + #define READ_TYPE_SIZE(name, names) \ if (matchAny(type, names)) { \ - TYPE_SIZE_NAME(name) = size; \ - continue; \ + TYPE_SIZE_NAME(name) = size; \ + continue; \ } DECLARE_TYPES_DO(READ_TYPE_SIZE) @@ -201,10 +212,10 @@ void VMStructs::init_type_sizes() { } } -#define READ_CONSTANT(type, field) \ - if (strcmp(type_name, #type "::" #field) == 0) { \ - _##type##_##field = value; \ - continue; \ +#define READ_CONSTANT(type, field) \ + if (strcmp(type_name, #type "::" #field) == 0) { \ + _##type##_##field = value; \ + continue; \ } @@ -252,6 +263,8 @@ void VMStructs::init_constants() { #ifdef DEBUG void VMStructs::verify_offsets() { + int hotspot_version = VM::hotspot_version(); + // Verify type sizes #define VERIFY_TYPE_SIZE(name, names) assert(TYPE_SIZE_NAME(name) > 0); DECLARE_TYPES_DO(VERIFY_TYPE_SIZE); @@ -266,10 +279,12 @@ void VMStructs::verify_offsets() { // Do nothing macro #define DO_NOTHING(...) -#define VERIFY_OFFSET_OR_ADDRESS(var, field_type, names) \ +#define VERIFY_FIELD(var, field_type, names) \ assert(var != field_type##_value); +#define VERSION_FIELD_WITH_VERSION(var, field_type, min_ver, max_ver, names) \ + assert(hotspot_version < min_ver || hotspot_version > max_ver || var != field_type##_value); - DECLARE_TYPE_FILED_DO(DO_NOTHING, VERIFY_OFFSET_OR_ADDRESS, DO_NOTHING, DO_NOTHING) + DECLARE_TYPE_FILED_DO(DO_NOTHING, VERIFY_FIELD, VERSION_FIELD_WITH_VERSION, DO_NOTHING) #undef VERIFY_OFFSET_OR_ADDRESS #undef DO_NOTHING #undef offset_value @@ -296,7 +311,7 @@ void VMStructs::initOffsets() { #ifdef DEBUG -// verify_offsets(); + verify_offsets(); #endif } @@ -323,7 +338,7 @@ void VMStructs::resolveOffsets() { _has_class_names = _klass_name_offset >= 0 && (_compact_object_headers ? (_markWord_klass_shift >= 0 && _markWord_monitor_value == MONITOR_BIT) : _oop_klass_offset >= 0) - && (_symbol_length_offset >= 0 || _symbol_length_and_refcount_offset >= 0) + && _symbol_length_offset >= 0 && _symbol_body_offset >= 0 && _klass != NULL; diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 6f0bc2365..545519b51 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -111,33 +111,37 @@ inline T* cast_to(const void* ptr) { /** * Following macros define field offsets, addresses or values of JVM classes that are exported by * vmStructs. - * - type_begin() Start a definition of a type. The type name is not used at this moment, but - * improves readability. - * - field() Define a field of a class, can be either an offset, an address or a value - * - field_no_check Define a field of a class, just like above. But the field may not be exported - * by JVMs. Therefore, it is skiped by verify_offsets() - * - type_end() End of a type definition + * - type_begin() Start a definition of a type. The type name is not used at this moment, but + * improves readability. + * - field() Define a field of a class, can be either an offset, an address or a value + * - field_with_version A field that only exits in the specified JVM version range + * - type_end() End of a type definition */ typedef int offset; typedef void* address; -#define DECLARE_TYPE_FILED_DO(type_begin, field, field_no_check, type_end) \ +#define MIN_VERSION 8 + +// JDK 128 :-) +#define MAX_VERSION 128 + +#define DECLARE_TYPE_FILED_DO(type_begin, field, field_with_version, type_end) \ type_begin(VMMemRegion, MATCH_SYMBOLS("MemRegion")) \ field(_region_start_offset, offset, MATCH_SYMBOLS("_start")) \ field(_region_size_offset, offset, MATCH_SYMBOLS("_word_size")) \ type_end() \ type_begin(VMNMethod, MATCH_SYMBOLS("CompiledMethod", "nmethod")) \ - field(_nmethod_method_offset, offset, MATCH_SYMBOLS("_method")) \ - field(_nmethod_entry_offset, offset, MATCH_SYMBOLS("_verified_entry_offset")) \ - field(_nmethod_entry_address, offset, MATCH_SYMBOLS("_verified_entry_point")) \ + field(_nmethod_method_offset, offset,MATCH_SYMBOLS("_method")) \ + field_with_version(_nmethod_entry_offset, offset, 23, MAX_VERSION, MATCH_SYMBOLS("_verified_entry_offset")) \ + field_with_version(_nmethod_entry_address, offset, 8, 22, MATCH_SYMBOLS("_verified_entry_point")) \ field(_nmethod_state_offset, offset, MATCH_SYMBOLS("_state")) \ field(_nmethod_level_offset, offset, MATCH_SYMBOLS("_comp_level")) \ - field(_nmethod_metadata_offset, offset, MATCH_SYMBOLS("_metadata_offset")) \ - field_no_check(_nmethod_immutable_offset, offset, MATCH_SYMBOLS("_immutable_data")) \ + field_with_version(_nmethod_metadata_offset, offset, MIN_VERSION, 24, MATCH_SYMBOLS("_metadata_offset")) \ + field_with_version(_nmethod_immutable_offset, offset, 23, MAX_VERSION, MATCH_SYMBOLS("_immutable_data")) \ field(_scopes_pcs_offset, offset, MATCH_SYMBOLS("_scopes_pcs_offset")) \ - field(_scopes_data_offset, offset, MATCH_SYMBOLS("_scopes_data_offset")) \ - field(_scopes_data_address, offset, MATCH_SYMBOLS("_scopes_data_begin")) \ + field_with_version(_scopes_data_offset, offset, 23, MAX_VERSION, MATCH_SYMBOLS("_scopes_data_offset")) \ + field_with_version(_scopes_data_address, offset, 9, 22, MATCH_SYMBOLS("_scopes_data_begin")) \ type_end() \ type_begin(VMMethod, MATCH_SYMBOLS("Method")) \ field(_method_constmethod_offset, offset, MATCH_SYMBOLS("_constMethod")) \ @@ -165,7 +169,6 @@ typedef void* address; type_begin(VMSymbol, MATCH_SYMBOLS("Symbol")) \ field(_symbol_length_offset, offset, MATCH_SYMBOLS("_length")) \ field(_symbol_body_offset, offset, MATCH_SYMBOLS("_body")) \ - field_no_check(_symbol_length_and_refcount_offset, offset, MATCH_SYMBOLS("_length_and_refcount")) \ type_end() \ type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread", "Thread")) \ field(_thread_osthread_offset, offset, MATCH_SYMBOLS("_osthread")) \ @@ -175,7 +178,7 @@ typedef void* address; type_end() \ type_begin(VMOSThread, MATCH_SYMBOLS("OSThread")) \ field(_osthread_id_offset, offset, MATCH_SYMBOLS("_thread_id")) \ - field(_osthread_state_offset, offset, MATCH_SYMBOLS("_state")) \ + field_with_version(_osthread_state_offset, offset, 10, MAX_VERSION, MATCH_SYMBOLS("_state")) \ type_end() \ type_begin(VMThreadShow, MATCH_SYMBOLS("ThreadShadow")) \ field(_thread_exception_offset, offset, MATCH_SYMBOLS("_exception_file")) \ @@ -201,17 +204,17 @@ typedef void* address; field(_blob_size_offset, offset, MATCH_SYMBOLS("_size")) \ field(_frame_size_offset, offset, MATCH_SYMBOLS("_frame_size")) \ field(_frame_complete_offset, offset, MATCH_SYMBOLS("_frame_complete_offset")) \ - field(_code_offset, offset, MATCH_SYMBOLS("_code_offset")) \ - field(_code_address, offset, MATCH_SYMBOLS("_code_begin")) \ + field_with_version(_code_offset, offset, 23, MAX_VERSION, MATCH_SYMBOLS("_code_offset")) \ + field_with_version(_code_address, offset, 9, 22, MATCH_SYMBOLS("_code_begin")) \ field(_data_offset, offset, MATCH_SYMBOLS("_data_offset")) \ - field_no_check(_mutable_data_offset, offset, MATCH_SYMBOLS("_mutable_data")) \ - field_no_check(_relocation_size_offset, offset, MATCH_SYMBOLS("_relocation_size")) \ + field_with_version(_mutable_data_offset, offset, 25, MAX_VERSION, MATCH_SYMBOLS("_mutable_data")) \ + field_with_version(_relocation_size_offset, offset, 23, MAX_VERSION, MATCH_SYMBOLS("_relocation_size")) \ field(_nmethod_name_offset, offset, MATCH_SYMBOLS("_name")) \ type_end() \ type_begin(VMCodeCache, MATCH_SYMBOLS("CodeCache")) \ field(_code_heap_addr, address, MATCH_SYMBOLS("_heap", "_heaps")) \ - field(_code_heap_low_addr, address, MATCH_SYMBOLS("_low_bound")) \ - field(_code_heap_high_addr, address, MATCH_SYMBOLS("_high_bound")) \ + field_with_version(_code_heap_low_addr, address, 9, MAX_VERSION, MATCH_SYMBOLS("_low_bound")) \ + field_with_version(_code_heap_high_addr, address, 9, MAX_VERSION, MATCH_SYMBOLS("_high_bound")) \ type_end() \ type_begin(VMCodeHeap, MATCH_SYMBOLS("CodeHeap")) \ field(_code_heap_memory_offset, offset, MATCH_SYMBOLS("_memory")) \ @@ -308,9 +311,12 @@ class VMStructs { #define DO_NOTHING(...) #define DECLARE_TYPE_FIELD(var, field_type, names) \ static field_type var; +#define DECLARE_TYPE_FIELD_WITH_VERSION(var, field_type, min_version, max_version, names) \ + static field_type var; - DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DECLARE_TYPE_FIELD, DO_NOTHING) + DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DECLARE_TYPE_FIELD_WITH_VERSION, DO_NOTHING) #undef DECLARE_TYPE_FIELD +#undef DECLARE_TYPE_FIELD_WITH_VERSION #undef DO_NOTHING // Declare int constant variables @@ -524,14 +530,12 @@ class VMMethod; DECLARE(VMSymbol) public: unsigned short length() { - if (_symbol_length_offset >= 0) { - return *(unsigned short*) at(_symbol_length_offset); - } else { - return *(unsigned int*) at(_symbol_length_and_refcount_offset) >> 16; - } + assert(_symbol_length_offset >= 0); + return *(unsigned short*) at(_symbol_length_offset); } const char* body() { + assert(_symbol_body_offset >= 0); return at(_symbol_body_offset); } DECLARE_END From cdd83caa34fd1ae4c9524a33e75f05d0aa674e1a Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Fri, 20 Feb 2026 15:55:24 +0000 Subject: [PATCH 20/23] Disable VMStructs for J9 and Zing --- ddprof-lib/src/main/cpp/vmStructs.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 0af0e49fb..4dfe98a93 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -305,6 +305,11 @@ void VMStructs::verify_offsets() { #endif // DEBUG void VMStructs::initOffsets() { + // J9 and Zing don't support vmStructs + if (VM::isOpenJ9() || VM::isZing()) { + return; + } + init_type_sizes(); init_offsets_and_addresses(); init_constants(); From 22b56254e0e110665945db051f94a5d8248ac9d9 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Fri, 20 Feb 2026 17:09:54 +0000 Subject: [PATCH 21/23] Enable verifier for Zing --- ddprof-lib/src/main/cpp/vmStructs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 4dfe98a93..99a086a0c 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -305,8 +305,8 @@ void VMStructs::verify_offsets() { #endif // DEBUG void VMStructs::initOffsets() { - // J9 and Zing don't support vmStructs - if (VM::isOpenJ9() || VM::isZing()) { + // J9 does not support vmStructs + if (VM::isOpenJ9()) { return; } From 7514b863a1e9baa40e35d0312d5eef0cfac9e2b8 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Fri, 20 Feb 2026 21:33:42 +0000 Subject: [PATCH 22/23] v15 --- ddprof-lib/src/main/cpp/safeAccess.cpp | 2 +- ddprof-lib/src/main/cpp/vmStructs.cpp | 4 +++- ddprof-lib/src/main/cpp/vmStructs.h | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ddprof-lib/src/main/cpp/safeAccess.cpp b/ddprof-lib/src/main/cpp/safeAccess.cpp index 8f1db9a3e..b5342681c 100644 --- a/ddprof-lib/src/main/cpp/safeAccess.cpp +++ b/ddprof-lib/src/main/cpp/safeAccess.cpp @@ -102,7 +102,7 @@ extern "C" int64_t safefetch64_cont(int64_t* adr, int64_t errValue); asm(R"( .globl _safefetch32_impl .private_extern _safefetch32_impl - _safefetch32_impl: + safefetch32_impl: ldr w0, [x0] ret .globl _safefetch32_cont diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 99a086a0c..feea6c5d0 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -263,6 +263,8 @@ void VMStructs::init_constants() { #ifdef DEBUG void VMStructs::verify_offsets() { + // Hotspot only + assert(VM::isHotspot()); int hotspot_version = VM::hotspot_version(); // Verify type sizes @@ -306,7 +308,7 @@ void VMStructs::verify_offsets() { void VMStructs::initOffsets() { // J9 does not support vmStructs - if (VM::isOpenJ9()) { + if (VM::isOpenJ9() || VM::isZing()) { return; } diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 545519b51..f4c236a46 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -22,8 +22,8 @@ class HeapUsage; template inline T* cast_to(const void* ptr) { - assert(T::type_size() > 0); // Ensure type size has been initialized - assert(ptr == nullptr || SafeAccess::isReadableRange(ptr, T::type_size())); + assert(!VM::isHotspot() || T::type_size() > 0); // Ensure type size has been initialized + assert(ptr == nullptr || !VM::isHotspot() || SafeAccess::isReadableRange(ptr, T::type_size())); return reinterpret_cast(const_cast(ptr)); } From e26449f69cd80b2a5c2cb360f847d850a4b4af42 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Fri, 20 Feb 2026 21:58:53 +0000 Subject: [PATCH 23/23] v16 --- ddprof-lib/src/main/cpp/vmStructs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index f4c236a46..6264de310 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -379,7 +379,7 @@ class VMStructs { const char* at(int offset) { const char* ptr = (const char*)this + offset; - assert(SafeAccess::isReadable(ptr)); + assert(!VM::isHotspot() || SafeAccess::isReadable(ptr)); return ptr; }